用C 言语描绘AES256 加密算法,然后在硬件中加快功用。
高档加密标准 (AES) 现已成为许多运用(比如嵌入式体系中的运用等)中日渐盛行的暗码标准。自从 2002 年美国国家标准技能研讨所 (NIST) 将此标准选为标准标准以来,处理器、微操控器、FPGA和 SoC 运用的开发人员就开端运用 AES 来维护输入、输出及保存在体系中的数据。咱们可在更高笼统层上十分高效地描绘算法,就像用于传统软件开发中那样;但由于涉及到的操作,该算法在 FPGA中完结起来最为高效。开发人员乃至可在布线中“免费”取得一些操作。
依据这些原因,AES 是个绝佳的比如,即开发人员可运用 C 言语描绘算法,然后在硬件中加快完结,然后获益于赛灵思 SDSoC ? 开发环境。本文中咱们便是要这样做,首要了解一下 AES 算法,然后在赛灵思 Zynq?-7000 All Programmable SoC 的处理体系 (PS) 上完结 AES256(256 位秘钥长度)以树立软件功用基准,然后再在片上可编程逻辑 (PL)中进行加快。为了彻底了解可取得的优势,咱们将在 SDSoC 环境所支撑的悉数三个操作体系中履行这几个进程,三个操作体系为:Linux、FreeRTOS 和裸机。
算法
AES 归于对称块暗码,可选用 128、192 和 256位不同的秘钥长度。秘钥长度决议加密或解密数据所需的处理进程数。望文生义,块暗码算法选用的是数据块。AES 算法一次处理 16 字节的固定模块。因而,假如咱们暗码内容少于 16 字节,就有必要将未运用的字节进行填充。
由于 AES 是对称暗码,信息加密宽和密都选用相同的做法和秘钥。相反,非对称算法(例如RSA)则运用不同秘钥进行数据加密宽和密。
AES 算法中四个阶段中每个阶段都代表一个状况。四个 AES 阶段的组合称为一个循环。所需循环的数量取决于秘钥长度。
很简略,AES 状况开端于咱们要加密的 16 个字节。每个新进程都会对状况进行更新。处理状况之前,咱们需求将输入字节串变为初始状况,即 4 x 4矩阵(图 1)。
图 1 — 16 字节的初始状况转换为 4 x 4 矩阵
现在,咱们将开端的 16 个字节从头编列为 4 x4 矩阵方式的初始状况,便可研讨每个进程怎么操作它的输入状况。
轮密钥加(AddRoundKey) : 这是仅有运用加密秘钥的进程。咱们现已注意到,所需的加密算法循环的数量取决于秘钥长度(128、192 或 256 位)。有必要对加密秘钥进行秘钥扩展,以保证在每个循环中不会从头运用秘钥中的字节。公然,关于不同的秘钥长度而言扩展秘钥长度并不相同。扩展秘钥长度为:
扩展秘钥长度(字节)= 16 *(循环 + 1)
这个进程中的操作很简略。输入状况字节与扩展秘钥的 16 个字节进行异或运算。每个循环运用扩展秘钥的不同部分;循环 0 运用字节 0 至 15,循环1 运用字节 16 至 31,以此类推。关于每个循环,状况的字节 1 与扩展秘钥的最低有用字节进行异或运算,字节 2 与“最低有用字节+1”进行异或运算,以此类推。
字节替换 (SubBytes) : 该进程运用字节替换将状况值用另一个值替换出去。替换盒中的值是预先设定的,并且输入坐落输出位之间的相关较小。替换盒 (S-box) 是一个 16 x 16 矩阵。咱们运用被代替字节的高四位和低四位作为代替表格中的索引。例如,运用图 2 中的 S-box 加密,假如榜首个初始状况字节为 0 x 69,那么用代替值 0 x F9 代替。状况字节的高四位挑选代替表格的行; 低四位挑选列。注意在图 2 中,加密宽和密运用不同的替换盒,并且盒中内容不同。
图 2 — AES S-box 内容
行位移改换 (ShiftRows) :该进程对每行履行循环字节移位,以从头排列输入状况矩阵。 咱们将每行右旋不同个因数(图 3)。第 1 行不变。将第 2 行移动 1 个字节,第 3 行移动 2 个字节,第 4 行移动3 个字节。解密时履行相同操作,但向左旋转而非向右。
图 3 — 行位移改换 (ShiftRows) 操作
列混合改换 (MixColumns) :这是循环中最杂乱的进程,需求进行 16 次乘法和 12 次异或运算。逐列对输入状况矩阵进行此操作,将输入状况矩阵与固定矩阵相乘以取得新的状况列(图 4)。列中的每项与矩阵中的一行相乘。将每次乘法成果进行异或运算,以取得新的状况值。榜首个要进行相乘运算的列和行在图 4 中加亮显现。
图 4 — 用于加密宽和密的列混合改换 (MixColumns) 函数
以下是榜首列的列混合改换(MixColumns) 方程:
B1’ = (B1 * 2) XOR (B2 * 3) XOR (B3 * 1) XOR (B4 * 1)
B2’ = (B1 * 1) XOR (B2 * 2) XOR (B3 * 3) XOR (B4 * 1)
B3’ = (B1 * 1) XOR (B2 * 1) XOR (B3 * 2) XOR (B4 * 3)
B4’ = (B1 * 3) XOR (B2 * 1) XOR (B3 * 1) XOR (B4 * 2)
然后,为输入状况中的下一个列选用相同乘法矩阵重复这个进程,直到处理完一切输入状况列。
已然咱们现已理解了 AES 加密宽和密算法所需的具体进程,那么还需求知道一个循环中这些进程的运用次序以及咱们是否有必要为每个循环运用一切进程。每个 AES 加密循环都包括悉数四个进程,并依照以下次序:
1. 字节替换 (SubBytes) ;
2. 行位移改换 (ShiftRows);
3. 列混合改换 (MixColumns) (只针对循环 1 至N–1);
4. 轮密钥加 (AddRoundKey)( 运用扩展秘钥)。
当然,咱们需求可以回转这个进程,将不可读的密文变回纯文本,让加密信息有用。为此,咱们将进程进行如下排序:
1. 回转行位移改换;
2. 回转字节替换;
3. 轮密钥加(运用扩展秘钥);
4. 回转列混合改换(只针对循环 1 至 N–1)。
履行榜首轮加密之前,咱们需求为加密宽和密履行初始轮密钥加 (AddRoundKey) 操作。
可在更高笼统层上高效地描绘 AES,就像在传统软件开发中那样,但在 FPGA 中完结起来最为高效。开发人员乃至可在布线中“免费”取得一些操作。
咱们看一下扩展秘钥有必要运用的算法,以便供给满足的秘钥位,用以履行相应数量的轮密钥加(AddRoundKey) 进程(图 5)。进行秘钥扩展时,16、24 或 32 字节的秘钥长度别离需求 44、52 或 60个循环。扩展秘钥的榜首个字节等于初始秘钥。这意味着关于咱们的 AES256 实例来说,扩展秘钥的最开端的 32 个字节便是秘钥本身。秘钥扩展操作在每次迭代中为扩展秘钥生成 32 个附加位。
图 5 — 秘钥扩展算法
扩展秘钥的榜首个字节等于初始秘钥。这意味着关于咱们的 AES256 实例来说,扩展秘钥的最开端的 32 个字节便是秘钥本身。
以下是重要的扩展进程:
RotateWord: 与行位移改换 (ShiftRows) 相似,这个进程从头组织 32 位字,以使最高有用字节变为最低有用字节。
SubWord: 这个进程运用的替换盒与加密时进行字节替换所运用的替换盒相同。
rcon: 该阶段对用户界说的值进行 2 次幂运算。
与列混合改换 (MixColumns) 阶段相似,rcon 也在有限域 (28) 中履行; 因而这个进程遍及运用预先核算的查找表。
EK: 从扩展秘钥回来 4 个字节。
K: 与 EK 相似,从秘钥回来 4 个字节。
怎么知道咱们现已正确完结了加密和秘钥扩展算法? AES 的 NIST 标准包括多个有用实例,可用来查看咱们自己的完结成果。
创立代码
为了保证可以加快 Zynq SoC 的 PL 中 AES 代码的加密部分,咱们有必要一开端就要以这个方针来开发代码(见这儿的编码规矩)。要考虑的榜首件事是算法的架构;咱们需求正确对其进行分段。AES 很合适这种计划,由于咱们可认为每个阶段编写函数,然后再依据需求调用。 咱们还有必要编写要在本身的文件中进行加快的函数。软件架构包括以下内容。
main.c: 该文件包括秘钥扩展算法、加密秘钥和纯文本输入,以及对 AES 加密函数的调用。
aes_enc.c: 该文件履行加密。咱们将每个阶段编写为独自的函数,这样就能依据 AES 循环的需求进行调用。为保证程序规划关于处理器上履行的程序具有通用性,咱们为混合进程的乘法运用查找表。
aes_enc.h: 这个文件包括 aes_funcTIon 的界说以及用来确认巨细的参数(例如 mk、nb 和 nr)。
sbox.h: 这个文件包括用于替换字节的替换盒、履行秘钥扩展的 rcon 函数的查找表以及用于列混合改换乘法的乘法查找表。
在这个结构中,咱们可以挑选 AES 加密函数( 图 6) 作为要进行加快的函数,只需右键点击该函数并挑选“ Toggle HW/SW”即可。
图 6 — 要加快的函数
为了能确认基准功用以及经过函数加快取得的保存成果,咱们有必要对函数的履行进行时刻操控。为此,咱们运用 sds_lib.h 中的sds_clock_counter。
编写源代码(在 github 供给)之后,在用 ZynqSoC 中的单个 ARM? Cortex ? -A9 处理器内核在软件中履行 AES 算法时,我记录了 36,662 个处理器周期。
为加快而进行的优化
加快 AES 算法比前一个问题中的矩阵乘法算法还要稍稍杂乱一些。这是由于 AES 算法的主循环包括相互依靠的阶段。
我加快 AES 算法时所选用的办法是:查看循环以找出可以打开的当地; 优化存储器带宽; 挑选正确的数据移动时钟频率和硬件功用频率。
AES 加密函数的主循环包括用于履行每个 AES进程的函数。AES 算法中的每个函数有必要完好履行,并在下个函数运转之前核算出成果。这种相互依靠性需求咱们将精力集中于作为独立函数的 AES进程。这些进程中存在满足多的优化潜力。
咱们可将轮密钥加 (AddRoundKey) 、字节替换(SubBytes) 和列混合改换 (MixColumns) 进程流水线化,以进步功用。在这些函数中,咱们经过将编译指示放在榜首个循环中来履行 HLS Pipeline 指令。咱们应打开内部循环。这些函数中有几个函数从查找表(一般从 block RAM 构建)读取数据。咱们需求添加存储器带宽,在本例中,我将编译指示参数指定为“完结”,这样可将存储器内容完结为分立寄存器而非BRAM。
在 Zynq SoC 上的 PS 与 PL 之间传输数据的才能对提高功用而言也十分重要。我所做的榜首步是将数据移动时钟网络设定为最高时钟频率:200MHz。第二个计划是保证为 PS 与 PL 之间的数据传输运用直接存储器拜访。为此,我有必要将接口稍加修正,并运用 sds_alloc 函数依照 DMA 传输的要求保证数据在存储器中的连续性(图 7)。
图 7 — PS 与 PL 之间的数据移动网络
第二个也是最终的优化进程是将硬件功用的时钟速率设定在所支撑的最高频率:166.67 MHz。
操作体系支撑
当我最终将一切内容放在一同并构建出这个实例时,经 PL 加快的 AES 代码在 Linux 上运转16,544 个处理器时钟周期; 当在独自在软件中运转
AES 代码时,只需求 45%(16,544/36,662) 的周期数量。这可将这个具有相互依靠联系且适当杂乱的算法的履行时刻缩短 55%。
当然,咱们也可在 SDSoC 环境中挑选 BareMetal或 FreeRTOS 操作体系。创立 BareMetal 和 FreeRTOS项目并从头运用代码可以在三种操作体系之间进行功用比照。关于给定项目而言,操作体系的挑选取决于使命要求、功用预算以及呼应时刻。
图 8 给出了 Zynq SoC 的 PS 和 PL 中三种操作体系的功用( 图 8)。
图 8 — Zynq PS 和 PL 中的操作体系功用。FreeRTOS 和 BareMetal 供给相似的缩短作用。
不出预料,FreeRTOS 和 BareMetal 完结了相似的时刻缩短作用,由于两种操作体系都比完好的 LinuxOS 简略得多。
正如咱们的成果所示,运用 SDSoC 开发环境加快 AES 加密,能完结真实的功用提高,并且易于完结—— 无需深化的 FPGA 规划经历。