暗号化手順はよく紹介されていますが、復号手順はなかなかないのでまとめました。
復号するときのポイント
基本は暗号の手順と逆のことをすればいい。ただ、ラウンドキーに対して、AESIMC(vaesimcq_u8)を行う必要がある。
コード
#define ADD(a, b) vreinterpretq_u8_u32(vaddq_u32(vreinterpretq_u32_u8((a)), (b)))
#define KEY_EXP_256_1(k, i, r) XOR3(TSHIFT_ADD((k)[(i)]), SUBWORD(ROTWORD((k)[(i) + 1])), RCON((r)))
#define KEY_EXP_256_2(k, i) XOR(TSHIFT_ADD((k)[(i)]), SUBWORD(NOROTWORD((k)[(i) + 1])))
#define NOROTWORD(a) vqtbl1q_u8((a), vreinterpretq_u8_u32(vdupq_n_u32(0x0f0e0d0c)))
#define RCON(a) vreinterpretq_u8_u32(vdupq_n_u32((a)))
#define ROTWORD(a) vqtbl1q_u8((a), vreinterpretq_u8_u32(vdupq_n_u32(0x0c0f0e0d)))
#define SHIFT_ADD(a) veorq_u8((a), vextq_u8(vdupq_n_u8(0x00), (a), 12))
#define SUBWORD(a) vaeseq_u8((a), vdupq_n_u8(0x00))
#define TSHIFT_ADD(a) SHIFT_ADD(SHIFT_ADD(SHIFT_ADD((a))))
#define UINT32x4_C(a) vextq_u32(vdupq_n_u32((a)), vdupq_n_u32(0x00000000), 3);
#define XOR(a, b) veorq_u8((a), (b))
#define XOR3(a, b, c) veorq_u8((a), veorq_u8((b), (c)))
void generate_dec_roundkey256(uint8_t* key, uint8x16_t* roundkey)
{
// ラウンドキーを作る(暗号と同じ流れ)
roundkey[0] = vld1q_u8(key);
roundkey[1] = vld1q_u8(key + 16);
roundkey[2] = KEY_EXP_256_1(roundkey, 0, 0x01);
roundkey[3] = KEY_EXP_256_2(roundkey, 1);
roundkey[4] = KEY_EXP_256_1(roundkey, 2, 0x02);
roundkey[5] = KEY_EXP_256_2(roundkey, 3);
roundkey[6] = KEY_EXP_256_1(roundkey, 4, 0x04);
roundkey[7] = KEY_EXP_256_2(roundkey, 5);
roundkey[8] = KEY_EXP_256_1(roundkey, 6, 0x08);
roundkey[9] = KEY_EXP_256_2(roundkey, 7);
roundkey[10] = KEY_EXP_256_1(roundkey, 8, 0x10);
roundkey[11] = KEY_EXP_256_2(roundkey, 9);
roundkey[12] = KEY_EXP_256_1(roundkey, 10, 0x20);
roundkey[13] = KEY_EXP_256_2(roundkey, 11);
roundkey[14] = KEY_EXP_256_1(roundkey, 12, 0x40);
// 復号の場合、以下の処理が必要
for(int i= 1; i<14; i++)
{
roundkey[i] = vaesimcq_u8(roundkey[i]);
}
}
void decrypt256(uint8_t* key, uint8_t* crypt_text, uint8_t* plan_text)
{
uint8x16_t roundkey[15];
generate_dec_roundkey256(key, roundkey);
uint8x16_t state = vld1q_u8(crypt_text);
for(int i = 14; i>1; i--)
{
state = vaesdq_u8( state, roundkey[i] );
state = vaesimcq_u8( state );
}
state = vaesdq_u8( state, roundkey[1] );
state = veorq_u8( state, roundkey[0] );
vst1q_u8(output, state);
}
参考
ARM NEON使って復号できない質問とその答え。
https://stackoverflow.com/questions/75581296/aes-encryption-do-not-work-on-arm-processor
ARM NEON使った実装と復号。
https://github.com/line/aes-gcm-siv/blob/master/lib/src/arm64/aes_arm64.c
https://github.com/microsoft/SymCrypt/blob/main/lib/aes-neon.c
ラウンドキー作るときに、復号の時はvaesimcq_u8を行っているのがわかる。
https://github.com/microsoft/SymCrypt/blob/171f6973dab9b76f0dc61d966d3e977021325bc1/lib/aes-key.c#L187