OpenSSL中AES算法实现与标准加密流程不对应问题咨询
OpenSSL AES实现与标准流程差异疑问
我目前正在学习AES算法,发现OpenSSL中的AES实现似乎缺失了部分标准流程步骤。学习过程中参考了AES加密算法的公开动画演示资料与标准流程截图。
经梳理,OpenSSL的AES实现核心包含两个函数:
int private_AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); void AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);
- 第一个函数用于生成每一轮加密所需使用的轮密钥
- 第二个函数执行具体的加密操作
我梳理AES_encrypt函数的执行逻辑如下:
- 函数首先执行AddRoundKey操作,对应初始轮运算;
- 初始轮之后共执行10轮运算,按照AES标准,最后一轮不应包含MixColumns操作,以下是其中9轮运算的代码片段:
#ifdef FULL_UNROLL /* round 1: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; /* round 2: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; /* round 3: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; /* round 4: */ ........
根据代码注释,Te数组的定义如下:
Te0[x] = S [x].[02, 01, 01, 03]; Te1[x] = S [x].[03, 02, 01, 01]; Te2[x] = S [x].[01, 03, 02, 01]; Te3[x] = S [x].[01, 01, 03, 02];
我存在两点疑问:
- 代码中为何没有显式的SubBytes、ShiftRows操作?
- 最后一轮似乎也执行了MixColumn操作,为何与标准AES流程不一致?或是我对代码的理解存在偏差?
解答
这是高性能AES实现的常规优化手段,OpenSSL的实现完全符合AES标准,你觉得缺步骤是因为代码做了深度合并优化,两个疑问分别解释:
为什么看不到单独的SubBytes、ShiftRows步骤
代码里的Te0到Te3是预计算生成的T盒(T-table),已经把多个轮操作合并进了查表逻辑:
- 定义里的
S[x]就是AES标准规定的S盒,查表取值的第一步就完成了SubBytes字节替换; - 代码里取状态值时做的移位、按位与操作(比如
(s1 >> 16) & 0xff、s3 & 0xff),本质是把ShiftRows行移位要调整的字节位置,提前对应到了取不同状态字节的偏移上,不需要单独写循环做行移位操作; - 查表自带的固定系数伽罗瓦域乘法,就是MixColumns列混合的计算内容。
等于OpenSSL把原本要分三个独立步骤、跑多层循环的操作,全部合并成了4次查表加异或运算,运算量大幅降低,性能比完全按教材逐步骤写的朴素实现高很多。
为什么最后一轮看起来执行了MixColumns
你贴的只是前9轮的代码片段,最后一轮根本没有使用这几个带列混合系数的Te表。顺着完整代码往下翻就能看到,最后一轮是直接调用原始S盒做字节替换,配合移位操作,最后异或最后一轮轮密钥,完全跳过了MixColumns步骤,和标准流程完全一致,不存在实现偏差。
内容的提问来源于stack exchange,提问作者Gerrie
相关产品推荐
相关产品推荐

