基于SSE2和查表法的AES的软件优化

AES的软件优化

实验环境

  • 编程语言:C语言

  • 编辑器(含调试):VsCode

  • 操作系统:Windows 10

AES的查表法与SSE2优化

一、算法原理

1、查表法简述

常规的AES实现中,每轮要经历四种运算:字节代替、行移位、列混淆和轮密钥加。如果严格遵照AES算法实现,无疑每轮加密会具有较大的运算量,因此寻找一种能够合并多个运算过程的算法是十分必要的。查表法通过查表的方式,采取空间效率换取时间效率的方式,通过建立多个查找表实行查找操作合并字节代替、移位运算和有限域运算,优点是加速了每轮的加密效率,缺点是增大了内存的开销。

下面对加密过程为例说明建立查找表的过程。

假设状态数组 s t a t e = [ A 0 A 4 A 8 A 12 A 1 A 5 A 9 A 13 A 2 A 6 A 10 A 14 A 3 A 7 A 11 A 15 ] state=\left[ \begin{matrix} A_{0}&A_{4}&A_{8}&A_{12}\\ A_{1}&A_{5}&A_{9}&A_{13}\\ A_{2}&A_{6}&A_{10}&A_{14}\\ A_{3}&A_{7}&A_{11}&A_{15}\\ \end{matrix} \right] state=A0A1A2A3A4A5A6A7A8A9A10A11A12A13A14A15。经过字节代替和行移位后,可得到新的state矩阵 s t a t e = [ S ( A 0 ) S ( A 4 ) S ( A 8 ) S ( A 12 ) S ( A 5 ) S ( A 9 ) S ( A 13 ) S ( A 1 ) S ( A 10 ) S ( A 14 ) S ( A 2 ) S ( A 6 ) S ( A 15 ) S ( A 3 ) S ( A 7 ) S ( A 11 ) ] state=\left[ \begin{matrix} S(A_{0})&S(A_{4})&S(A_{8})&S(A_{12})\\ S(A_{5})&S(A_{9})&S(A_{13})&S(A_{1})\\ S(A_{10})&S(A_{14})&S(A_{2})&S(A_{6})\\ S(A_{15})&S(A_{3})&S(A_{7})&S(A_{11})\\ \end{matrix} \right] state=S(A0)S(A5)S(A10)S(A15)S(A4)S(A9)S(A14)S(A3)S(A8)S(A13)S(A2)S(A7)S(A12)S(A1)S(A6)S(A11)。进行列混淆的过程相当于state右乘一个列混淆矩阵 [ 02 03 01 01 01 02 03 01 01 01 02 03 03 01 01 02 ] \left[ \begin{matrix} 02&03&01&01\\ 01&02&03&01\\01&01&02&03\\03&01&01&02\\ \end{matrix} \right] 02010103030201010103020101010302。可以将矩阵乘法的结果拆分来看,如下所示:
[ C 0 C 1 C 2 C 3 ] = [ 02 01 01 03 ] S ( A 0 ) + [ 03 02 01 01 ] S ( A 5 ) + [ 01 03 02 01 ] S ( A 10 ) + [ 01 01 03 02 ] S ( A 15 ) [ C 4 C 5 C 6 C 7 ] = [ 02 01 01 03 ] S ( A 4 ) + [ 03 02 01 01 ] S ( A 9 ) + [ 01 03 02 01 ] S ( A 14 ) + [ 01 01 03 02 ] S ( A 3 ) [ C 8 C 9 C 10 C 11 ] = [ 02 01 01 03 ] S ( A 8 ) + [ 03 02 01 01 ] S ( A 13 ) + [ 01 03 02 01 ] S ( A 2 ) + [ 01 01 03 02 ] S ( A 7 ) [ C 12 C 13 C 14 C 15 ] = [ 02 01 01 03 ] S ( A 12 ) + [ 03 02 01 01 ] S ( A 1 ) + [ 01 03 02 01 ] S ( A 6 ) + [ 01 01 03 02 ] S ( A 11 ) \left[ \begin{matrix}C_0\\C_1\\C_2\\C_3\end{matrix} \right]= \left[ \begin{matrix}02\\01\\01\\03\end{matrix} \right]S(A_0)+ \left[ \begin{matrix}03\\02\\01\\01\end{matrix} \right]S(A_5)+ \left[ \begin{matrix}01\\03\\02\\01\end{matrix} \right]S(A_{10})+ \left[ \begin{matrix}01\\01\\03\\02\end{matrix} \right]S(A_{15})\\ \left[ \begin{matrix}C_4\\C_5\\C_6\\C_7\end{matrix} \right]= \left[ \begin{matrix}02\\01\\01\\03\end{matrix} \right]S(A_4)+ \left[ \begin{matrix}03\\02\\01\\01\end{matrix} \right]S(A_9)+ \left[ \begin{matrix}01\\03\\02\\01\end{matrix} \right]S(A_{14})+ \left[ \begin{matrix}01\\01\\03\\02\end{matrix} \right]S(A_3)\\ \left[ \begin{matrix}C_8\\C_9\\C_{10}\\C_{11}\end{matrix} \right]= \left[ \begin{matrix}02\\01\\01\\03\end{matrix} \right]S(A_8)+ \left[ \begin{matrix}03\\02\\01\\01\end{matrix} \right]S(A_{13})+ \left[ \begin{matrix}01\\03\\02\\01\end{matrix} \right]S(A_2)+ \left[ \begin{matrix}01\\01\\03\\02\end{matrix} \right]S(A_7)\\ \left[ \begin{matrix}C_{12}\\C_{13}\\C_{14}\\C_{15}\end{matrix} \right]= \left[ \begin{matrix}02\\01\\01\\03\end{matrix} \right]S(A_{12})+ \left[ \begin{matrix}03\\02\\01\\01\end{matrix} \right]S(A_1)+ \left[ \begin{matrix}01\\03\\02\\01\end{matrix} \right]S(A_6)+ \left[ \begin{matrix}01\\01\\03\\02\end{matrix} \right]S(A_{11})\\ C0C1C2C3=02010103S(A0)+03020101S(A5)+01030201S(A10)+01010302S(A15)C4C5C6C7=02010103S(A4)+03020101S(A9)+01030201S(A14)+01010302S(A3)C8C9C10C11=02010103S(A8)+03020101S(A13)+01030201S(A2)+01010302S(A7)C12C13C14C15=02010103S(A12)+03020101S(A1)+01030201S(A6)+01010302S(A11)
由此可见,对于这三步运算的合并需要建立四个表: [ 02 01 01 03 ] S ( X ) \left[ \begin{matrix}02\\01\\01\\03\end{matrix} \right]S(X) 02010103S(X) [ 03 02 01 01 ] S ( X ) \left[ \begin{matrix}03\\02\\01\\01\end{matrix} \right]S(X) 03020101S(X) [ 01 03 02 01 ] S ( X ) \left[ \begin{matrix}01\\03\\02\\01\end{matrix} \right]S(X) 01030201S(X) [ 01 01 03 02 ] S ( X ) \left[ \begin{matrix}01\\01\\03\\02\end{matrix} \right]S(X) 01010302S(X)。这些表的输入输出格式为8比特输入-32比特输出。

2、SSE2简述

SSE2指令集(Streaming SIMD Extensions 2)是Intel公司在SSE指令集的基础上发展起来的。SSE2使用了128位的存储单元,对于加密分组为128比特的AES来说是比较契合的。SSE2的128位存储单元能够存储16个8位整数,或8个16位整数,或4个32位整数,或2个64位整数(这里只讨论整数,不讨论浮点数)。SSE2的一条指令能够同时操作存储单元内的多数据,因此比传统的多数据运算更快。

二、算法流程

对于查表法的实现,生成查找表的过程是比较繁琐的。下面以加密过程为例进行说明。

首先,根据AES的S盒和有限域乘法生成加密所需的经过有限域乘法处理的长度为256的盒:(01*S(x)、02*S(X)、03*S(X))

BoxGen(SBOX, n)
{
    set Box[256];
    for i from 0 to 255
        set Table[i] = GF-multiply(SBOX[i], n);
    return Box;
}

然后根据查表法需要的四个表进行生成:

TableGen(S_01, S_02, S_03)	//S_01表示S盒经过乘01处理的盒
{
    set Table1[256], Table2[256], Table3[256], Table4[256];
    // 符号||表示将二者的16进制字串连接在一起形成新的整数
    for i from 0 to 255
    {
        set Table1[i] = S_02[i]||S_01[i]||S_01[i]||S_03[i];
        set Table2[i] = S_03[i]||S_02[i]||S_01[i]||S_01[i];
        set Table3[i] = S_01[i]||S_03[i]||S_02[i]||S_01[i];
        set Table4[i] = S_01[i]||S_01[i]||S_03[i]||S_02[i];
    }
    return Table1, Table2, Table3, Table4;
}

以上步骤都是准备工作,生成的查找表作为全局变量写入C程序。

加密部分可以分为三部分:多轮加密前的轮密钥加操作、每轮的加密操作和最后一轮的加密操作。轮密钥加操作与正常的轮密钥加无异。下面对每轮的加密操作和最后一轮的加密操作进行说明。

每轮的加密操作可以通过“查表—异或—轮密钥加”的方式进行。根据算法原理一节的讨论可知,每个字的生成都是由4个表的输出异或得出。因此每轮的加密操作的伪代码如下:

ssma(state, roundkey)	//ssma: subbyte, shift, mixcolumn, addroundkey
{
	copy state into s;
	set state[0~3] = Table1[s[0]] ^ Table2[s[5]] ^ Table3[s[10]] ^ Table4[s[15]];
	set state[4~7] = Table1[s[4]] ^ Table2[s[9]] ^ Table3[s[14]] ^ Table4[s[3]];
	set state[8~11] = Table1[s[8]] ^ Table2[s[13]] ^ Table3[s[2]] ^ Table4[s[7]];
	set state[12~15] = Table1[s[12]] ^ Table2[s[1]] ^ Table3[s[6]] ^ Table4[s[11]];
	set state = state ^ roundkey
	return;
}

最后一轮的加密操作由于没有列混淆,因此只需要查找S盒即可,算法伪代码如下:

ssa(state, roundkey)	//ssa: subbyte, shift, addroundkey
{
	copy state into s
	set state[0] = s[0];	set state[1] = s[5];
	set state[2] = s[10];	set state[3] = s[15];
	set state[4] = s[4];	set state[5] = s[9];
	set state[6] = s[14];	set state[7] = s[3];
	set state[8] = s[8];	set state[9] = s[13];
	set state[10] = s[2];	set state[11] = s[7];
	set state[12] = s[12];	set state[13] = s[1];
	set state[14] = s[6];	set state[15] = s[11];
	return;
}

加密的主函数为:

aes(state)
{
    set state = state ^ roundkey[0];
    for i from 1 to 9
    	ssma(state, roundkey[i]);
    ssa(state, roundkey[10])
    return;
}

三、关于AES优化

1、SSE2的使用

查找表建立之后,影响AES加密速度的主要因素就是如何使用查找表。AES的加密算法中存在许多可以并行处理的数据运算,因此查找表结合SIMD会拥有更好的性能。SIMD中的SSE2存储单元的存储能力为128位,正好等于AES的加密分组长度,因此SSE2是很适合用来对AES进行优化的。

优化AES的过程中,使用最多的SSE2函数是set指令、xor指令和load指令。由于SSE2存储单元不支持对其内某一整数进行操作,因此对__m128i类型(SSE2中存放整数的数据类型)数据的读和写需要额外的操作。读取__m128i数据可采用uint8 *s=(uint8 *)&state将__m128i类型的state“拷贝”给s(这里的“拷贝”意思是将uint8类型的指针指向这块区域)。写入__m128i可用_mm_setr_epi~函数(“~”根据需求而定,可以是8、16、32、64)。对于uint8数组存入__m128i变量可采用__m128 state=_mm_loadu_si128((__m128i *)m)的方式。

2、指针的使用

除了这些可使用的优化资源外,还需要对代码的总体风格进行调整。对于C语言来说,指针是一把双刃剑。使用指针可以提高代码的运行效率,但是也可能出现一系列问题(指针越界、野指针等)。在函数调用中,如果将数组或其他较为复杂的数据类型的变量作为参数传入,无疑会严重影响程序的执行速度。因此,在AES优化的过程中,尽可能地合适地使用指针会很大程度上提高程序的运行效率。例如如下函数的定义和使用:

void ssma(__m128i *state, int round);
void ssa(__m128i *state);
ssma(&state, 9);
ssa(&state);
3、对解密算法的设计

对于解密来说,由于对解密算法向加密算法靠近的调整,轮密钥加的过程中使用的轮密钥是需要进行列混淆的。如果将其放入解密主函数或其调用的子函数中显然会影响解密速度。因此可以在密钥生成的时候将1~9号轮密钥进行列混淆,这样可以使得解密算法的运算量与加密算法的运算量基本相等,从而加快加密过程。

4、其他优化

另外,需要避免不必要的函数调用及其他代码结构。实际上,如果AES的主函数内填写所有加密代码无疑是高效的,因为其内没有任何库函数外的函数调用。但是这显然不符合代码编写的模块化思想, 不便于调试和维护。原本的加密主函数中是采用for循环对加密轮数进行计数的,但是这个for循环在优化的过程中被放弃,因为这是一个不必要的开销。最后加密的主函数呈现如下:

__m128i encrypt(uint8 *m)
{
    __m128i state = _mm_loadu_si128((__m128i *)m);
    state = _mm_xor_si128(state, KEY[0]);
    ssma(&state, 1);
    ssma(&state, 2);
    ssma(&state, 3);
    ssma(&state, 4);
    ssma(&state, 5);
    ssma(&state, 6);
    ssma(&state, 7);
    ssma(&state, 8);
    ssma(&state, 9);
    ssa(&state);
    return state;
}

由测试结果计算,AES的加解密速度可以达到:(r代表运行次数)
s p e e d = 1 0 8   r 15.82   s × 128   b i t / r ( 1024 × 1024 )   b i t / M b i t = 771.6202   M b p s speed=\frac{10^8 \ r}{15.82 \ s}×\frac{128 \ bit/r}{(1024 ×1024) \ bit/Mbit}=771.6202 \ Mbps speed=15.82 s108 r×(1024×1024) bit/Mbit128 bit/r=771.6202 Mbps

四、源代码地址

https://github.com/kascas/AES_SSE2

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值