AES T-Tables加密实现问题:轮逻辑与T表正确性排查
AES T-Tables加密实现问题排查
我正在实现基于AES T-Tables的加密函数,已确认roundKeys(轮密钥)正确,且初始轮密钥加操作无误。但主轮逻辑存在错误,目前锁定两个问题:
- 每轮中T表查找的逻辑是否正确?对应代码如下:
temp[i] = T0[(state[i] >>> 24) & 0xFF] ^ T1[(state[(i + 3) % 4] >>> 16) & 0xFF] ^ T2[(state[(i + 2) % 4] >>> 8) & 0xFF] ^ T3[state[(i + 1) % 4] & 0xFF] ^ roundKeys[round][i];
我是按照Rijndael提案第18页的描述实现的,该逻辑是否正确?
2. 可能使用了错误的T表进行查找。我不确定哪组T表正确:在BouncyCastle的Java实现和Go语言的AES实现中找到的T表不同,我尝试了两组但均无效,哪组才是正确的?
附完整加密函数代码:
public byte[] blockEncryption(byte[] plaintext, int[][] roundKeys) { // Convert plaintext bytes to state matrix int[] state = new int[4]; for (int i = 0; i < 4; i++) { state[i] = ((plaintext[4 * i] & 0xFF) << 24) | ((plaintext[4 * i + 1] & 0xFF) << 16) | ((plaintext[4 * i + 2] & 0xFF) << 8) | (plaintext[4 * i + 3] & 0xFF); } // Initial round key addition for (int i = 0; i < 4; i++) { state[i] ^= roundKeys[0][i]; } // Main rounds for (int round = 1; round < 10; round++) { int[] temp = new int[4]; for (int i = 0; i < 4; i++) { temp[i] = T0[(state[i] >>> 24) & 0xFF] ^ T1[(state[(i + 3) % 4] >>> 16) & 0xFF] ^ T2[(state[(i + 2) % 4] >>> 8) & 0xFF] ^ T3[state[(i + 1) % 4] & 0xFF] ^ roundKeys[round][i]; };System.arraycopy(temp, 0, state, 0, 4); } // Final round (without MixColumns) byte[] ciphertext = new byte[16]; for (int i = 0; i < 4; i++) { int word = roundKeys[roundKeys.length - 1][i]; ciphertext[4 * i] = (byte) (S[(state[i] >>> 24) & 0xFF] ^ (word >>> 24)); ciphertext[4 * i + 1] = (byte) (S[(state[(i + 3) % 4] >>> 16) & 0xFF] ^ (word >>> 16)); ciphertext[4 * i + 2] = (byte) (S[(state[(i + 2) % 4] >>> 8) & 0xFF] ^ (word >>> 8)); ciphertext[4 * i + 3] = (byte) (S[state[(i + 1) % 4] & 0xFF] ^ word); } System.out.println("Endzustand: " + intArrayToHex(state)); return ciphertext; }
问题解答
1. T表查找逻辑是否正确?
你的T表查找逻辑完全符合Rijndael提案第18页的描述,逻辑本身没有问题:
- 你的state采用列优先存储,每个
state[i]对应AES状态矩阵的第i列,四个字节从高位到低位依次对应行0、行1、行2、行3,存储方式正确。 - 代码中
temp[i]的计算逻辑对应:取当前列i的行0字节查T0,前一列((i+3)%4)的行1字节查T1,前两列((i+2)%4)的行2字节查T2,前三列((i+1)%4)的行3字节查T3,最后异或当前轮密钥。这正好是提案中SubBytes+ShiftRows+MixColumns三个操作的合并查表实现,逻辑匹配无误。
另外,主轮循环次数for (int round = 1; round < 10; round++)对应AES-128的9轮主轮(初始轮后+9轮主轮+1轮最终轮),次数也是正确的。
2. 正确的T表定义
AES的T表是基于标准S盒和GF(2^8)域内乘法生成的,四个T表的核心生成规则如下(以32位整数形式存储,高位到低位对应状态矩阵的行0到行3):
// 标准AES S盒(完整256个元素需使用官方定义) private static final byte[] S = { 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, // ... 剩余240个元素省略 }; // GF(2^8)乘法:乘以0x02 private static int mul02(byte b) { int val = b & 0xFF; return (val << 1) ^ ((val & 0x80) != 0 ? 0x1B : 0); } // GF(2^8)乘法:乘以0x03(等价于mul02(b) ^ b) private static int mul03(byte b) { return mul02(b) ^ (b & 0xFF); } // 生成T表 private static final int[] T0 = new int[256]; private static final int[] T1 = new int[256]; private static final int[] T2 = new int[256]; private static final int[] T3 = new int[256]; static { for (int i = 0; i < 256; i++) { byte s = S[i]; int s0 = s & 0xFF; int s2 = mul02(s); int s3 = mul03(s); T0[i] = (s2 << 24) | (s3 << 16) | (s0 << 8) | s0; T1[i] = (s0 << 24) | (s2 << 16) | (s3 << 8) | s0; T2[i] = (s0 << 24) | (s0 << 16) | (s2 << 8) | s3; T3[i] = (s3 << 24) | (s0 << 16) | (s0 << 8) | s2; } }
不同实现(如BouncyCastle、Go)的T表看起来不同,通常是因为字节存储顺序或整数位序差异(比如有些实现将32位整数的低位对应行0),但核心生成逻辑必须符合上述规则。你可以用上述代码自行生成标准T表,再替换测试。
内容的提问来源于stack exchange,提问作者schegga_BC
相关产品推荐
相关产品推荐

