Add helper support for the Octeon SMS4 operation selectors. SMS4 reuses the AES RESINP, IV, and key banks, so the helpers share the existing AES state while implementing the SMS4 ECB/CBC encrypt and decrypt operations.
Signed-off-by: James Hilliard <[email protected]> --- Changes v8 -> v9: - Split SMS4 operation selectors into their own COP2 helper patch. - Replace generic selector dispatch with per-operation SMS4 helpers. - Add matching helper.h declarations with the helper implementation. Changes v1 -> v2: - Add selector dispatch updates in octeon_translate.c after moving COP2 decode out of translate.c. (suggested by Philippe Mathieu-Daudé) Changes v5 -> v6: - Use RESINP wording for the SMS4 shared selector aliases. --- target/mips/helper.h | 4 ++ target/mips/tcg/octeon_crypto.c | 121 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/target/mips/helper.h b/target/mips/helper.h index d8ba1f19dd..d6231917ed 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -70,6 +70,10 @@ DEF_HELPER_2(octeon_cp2_mt_aes_enc_cbc1, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_aes_enc1, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_aes_dec_cbc1, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_aes_dec1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_sms4_enc_cbc1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_sms4_enc1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_sms4_dec_cbc1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_sms4_dec1, void, env, i64) /* microMIPS functions */ DEF_HELPER_4(lwm, void, env, tl, tl, i32) diff --git a/target/mips/tcg/octeon_crypto.c b/target/mips/tcg/octeon_crypto.c index 55d8818ee2..296a507ba1 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -782,6 +782,56 @@ static int octeon_aes_key_bits(const MIPSOcteonCryptoState *crypto) return 0; } } +static inline uint32_t octeon_sms4_t(uint32_t x) +{ + x = sm4_subword(x); + return x ^ rol32(x, 2) ^ rol32(x, 10) ^ + rol32(x, 18) ^ rol32(x, 24); +} + +static inline uint32_t octeon_sms4_t_key(uint32_t x) +{ + x = sm4_subword(x); + return x ^ rol32(x, 13) ^ rol32(x, 23); +} + +static void octeon_sms4_expand_key(const uint8_t *key, uint32_t round_keys[32]) +{ + static const uint32_t fk[4] = { + 0xa3b1bac6U, 0x56aa3350U, 0x677d9197U, 0xb27022dcU, + }; + uint32_t k[36]; + + for (int i = 0; i < 4; i++) { + k[i] = ldl_be_p(key + i * 4) ^ fk[i]; + } + for (int i = 0; i < 32; i++) { + k[i + 4] = k[i] ^ octeon_sms4_t_key(k[i + 1] ^ k[i + 2] ^ + k[i + 3] ^ sm4_ck[i]); + round_keys[i] = k[i + 4]; + } +} + +static void octeon_sms4_crypt_block(const uint8_t *in, uint8_t *out, + const uint32_t round_keys[32], + bool encrypt) +{ + uint32_t x[36]; + + for (int i = 0; i < 4; i++) { + x[i] = ldl_be_p(in + i * 4); + } + for (int i = 0; i < 32; i++) { + uint32_t rk = round_keys[encrypt ? i : 31 - i]; + + x[i + 4] = x[i] ^ octeon_sms4_t(x[i + 1] ^ x[i + 2] ^ + x[i + 3] ^ rk); + } + stl_be_p(out, x[35]); + stl_be_p(out + 4, x[34]); + stl_be_p(out + 8, x[33]); + stl_be_p(out + 12, x[32]); +} static void octeon_aes_load_key(const MIPSOcteonCryptoState *crypto, uint8_t *key, size_t keylen) { @@ -806,6 +856,46 @@ static void octeon_aes_store_block(uint64_t regs[2], const uint8_t *block) regs[0] = ldq_be_p(block); regs[1] = ldq_be_p(block + 8); } +static void octeon_sms4_crypt_common(MIPSOcteonCryptoState *crypto, + bool encrypt, bool cbc) +{ + uint8_t key[16]; + uint8_t in[16]; + uint8_t out[16]; + uint8_t iv[16]; + uint8_t next_iv[16]; + uint32_t round_keys[32]; + + /* + * SMS4 aliases the AES state onto the RESINP, IV, and KEY banks, + * with only the operation selectors remaining distinct. + */ + octeon_aes_load_key(crypto, key, sizeof(key)); + octeon_aes_load_block(crypto->aes_input, in); + if (cbc) { + octeon_aes_load_block(crypto->aes_iv, iv); + if (encrypt) { + for (int i = 0; i < sizeof(in); i++) { + in[i] ^= iv[i]; + } + } else { + memcpy(next_iv, in, sizeof(next_iv)); + } + } + + octeon_sms4_expand_key(key, round_keys); + octeon_sms4_crypt_block(in, out, round_keys, encrypt); + if (cbc && !encrypt) { + for (int i = 0; i < sizeof(out); i++) { + out[i] ^= iv[i]; + } + } + + octeon_aes_store_block(crypto->aes_result, out); + if (cbc) { + octeon_aes_store_block(crypto->aes_iv, encrypt ? out : next_iv); + } +} static void octeon_aes_encrypt_common(MIPSOcteonCryptoState *crypto, bool cbc) { AES_KEY key; @@ -1083,6 +1173,37 @@ void helper_octeon_cp2_mt_gfm_xormul1(CPUMIPSState *env, uint64_t value) } crypto->gfm_xor0 = 0; } +void helper_octeon_cp2_mt_sms4_enc_cbc1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_input[1] = value; + octeon_sms4_crypt_common(crypto, true, true); +} + +void helper_octeon_cp2_mt_sms4_enc1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_input[1] = value; + octeon_sms4_crypt_common(crypto, true, false); +} + +void helper_octeon_cp2_mt_sms4_dec_cbc1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_input[1] = value; + octeon_sms4_crypt_common(crypto, false, true); +} + +void helper_octeon_cp2_mt_sms4_dec1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_input[1] = value; + octeon_sms4_crypt_common(crypto, false, false); +} void helper_octeon_cp2_mt_snow3g_start(CPUMIPSState *env, uint64_t value) { octeon_snow3g_start(&env->octeon_crypto, value); -- 2.54.0
