如何用C语言描述最高效的AES256加密算法?

 2024-02-16 02:01:28  阅读 0

加密算法用C语言描述,然后在硬件中加速。

高级加密标准 (AES) 已成为许多应用程序(例如嵌入式系统中的应用程序)日益流行的加密规范。 自 2002 年该规范被美国国家标准与技术研究所 (NIST) 选择为标准以来,处理器、微控制器、FPGA 和 SoC 应用程序的开发人员已使用 AES 来保护系统中存储的输入、输出和数据。 数据。 我们可以在更高的抽象层次上非常有效地描述算法,就像我们在传统软件开发中一样; 但由于所涉及的运算,该算法在 FPGA 中实现效率最高。 开发人员甚至可以在布线中“免费”进行一些操作。

出于这些原因,AES 是一个很好的示例,说明开发人员如何通过用 C 语言描述算法,然后加速在硬件中的实现,从 SDSoC® 开发环境中受益。 这就是我们在本文中要做的,首先熟悉 AES 算法,然后在 Zynq?-7000 All SoC(256 位密钥长度)的处理系统(PS)上实现它,建立软件性能基准,然后在片上实现它 在可编程逻辑(PL)中执行加速。 为了充分了解可用的优势,我们将在 SDSoC 环境支持的所有三种操作系统上执行这些步骤:Linux 和裸机。

第620章 620

算法

AES 是一种对称分组密码,可以使用 128、192 和 256 位等不同的密钥长度。 密钥长度决定加密或解密数据所需的处理步骤数。 顾名思义,分组密码算法使用数据块。 AES 算法一次处理 16 字节的固定块。 因此,如果我们的密码内容小于16字节,则必须填充未使用的字节。

由于 AES 是一种对称密码,因此使用相同的方法和密钥来加密和解密信息。 相比之下,非对称算法(例如 RSA)使用不同的密钥进行数据加密和解密。

AES 算法的四个阶段中的每一个阶段都代表一个状态。 四个 AES 阶段的组合称为一个循环。 所需的周期数取决于密钥长度。

很简单,AES 状态以我们要加密的 16 个字节开始。 每个新步骤都会更新状态。 在处理状态之前,我们需要将输入字节字符串更改为初始状态,这是一个 4 x 4 矩阵(图 1)。

c语言的算法_算法语言技术发展_算法语言程序之间的关系

第620章 620

图 1 – 16 字节初始状态转换为 4 x 4 矩阵

现在我们已经以 4x4 矩阵的形式将前 16 个字节重新排列为初始状态,我们可以研究每个步骤如何操纵其输入状态。

():这是唯一使用加密密钥的步骤。 我们已经注意到,所需的加密算法周期数取决于密钥长度(128、192 或 256 位)。 加密密钥必须进行密钥扩展,以确保密钥中的字节不会在每个周期中重复使用。 果然,不同的密钥长度,扩展的密钥长度是不一样的。 扩展密钥长度为:

扩展密钥长度(字节)= 16 *(循环+ 1)

这一步的操作很简单。 输入状态字节与扩展密钥的 16 个字节进行异或。 每个周期使用扩展密钥的不同部分; 周期 0 使用字节 0 到 15,周期 1 使用字节 16 到 31,依此类推。 对于每个周期,状态的字节 1 与扩展秘密的最低有效字节进行异或,字节 2 与“最低有效字节 + 1”进行异或,依此类推。

字节替换():此步骤使用字节替换将状态值替换为另一个值。 替换框中的值是预先设定的,并且输入与输出位之间的相关性较小。 替换框 (S-box) 是一个 16 x 16 矩阵。 我们使用被替换字节的高半字节和低半字节作为替换表中的索引。 例如,使用图2中的S盒加密,如果第一个初始状态字节是0x69,则使用替代值0xF9代替。 状态字节的高四位选择替代表的行; 低四位选择列。 注意图2中加密和解密使用了不同的替换盒子,盒子中的内容也不同。

算法语言程序之间的关系_算法语言技术发展_c语言的算法

第620章 620

图 2 - AES S-box 内容

Row Shift ():此步骤对每一行执行循环字节移位以重新排列输入状态矩阵。 我们将每一行右旋转不同的因子(图 3)。 1号线保持不变。 将第 2 行移动 1 个字节,将第 3 行移动 2 个字节,将第 4 行移动 3 个字节。 解密时,做同样的事情,但将其旋转到左侧而不是右侧。

c语言的算法_算法语言程序之间的关系_算法语言技术发展

第620章 620

图 3 – () 操作

():这是循环中最复杂的步骤,需要 16 次乘法和 12 次 XOR 运算。 此操作对输入状态矩阵逐列执行,将输入状态矩阵与固定矩阵相乘以获得新的状态列(图 4)。 列中的每一项都乘以矩阵中的一行。 对每次乘法的结果进行异或以获得新的状态值。 要相乘的第一列和第一行在图 4 中突出显示。

第620章 620

图 4 – 用于加密和解密的 () 函数

以下是第一列的 () 方程:

B1' = (B1 * 2) 异或 (B2 * 3) 异或 (B3 * 1) 异或 (B4 * 1)

B2' = (B1 * 1) 异或 (B2 * 2) 异或 (B3 * 3) 异或 (B4 * 1)

B3' = (B1 * 1) 异或 (B2 * 1) 异或 (B3 * 2) 异或 (B4 * 3)

B4' = (B1 * 3) 异或 (B2 * 1) 异或 (B3 * 1) 异或 (B4 * 2)

然后对输入状态中的下一列使用相同的乘法矩阵重复此过程,直到处理完所有输入状态列。

现在我们已经了解了 AES 加密和解密算法所需的详细步骤,我们还需要知道这些步骤在循环中应用的顺序以及是否必须为每个循环应用所有步骤。 每个 AES 加密周期包含所有四个步骤,按以下顺序排列:

1、字节替换();

2、行位移变换();

3. Mixed ()(仅适用于循环1到N–1);

4. 轮密钥plus()(使用扩展密钥)。

当然,我们需要能够逆转这个过程,将不可读的密文转回纯文本,使加密的信息变得有用。 为此,我们按如下顺序执行步骤:

1.逆行位移变换;

2、反向字节替换;

3. 轮密钥添加(使用扩展密钥);

4. 反转列混合变换(仅适用于循环 1 至 N–1)。

在执行第一轮加密之前,我们需要执行第一轮()操作来进行加密和解密。

与传统软件开发一样,AES 可以在更高的抽象级别上进行有效描述,但在 FPGA 中实现效率最高。 开发人员甚至可以在布线中“免费”进行一些操作。

让我们看一下必须用于扩展密钥的算法,以便提供足够的密钥位来执行相应数量的轮密钥加法 () 步骤(图 5)。 进行密钥扩展时,密钥长度为16、24或32字节分别需要44、52或60个周期。 扩展密钥的第一个字节等于初始密钥。 这意味着对于我们的示例,扩展密钥的前 32 个字节是密钥本身。 密钥扩展操作在每次迭代中为扩展密钥生成 32 个附加位。

第620章 620

图 5 – 密钥扩展算法

扩展密钥的第一个字节等于初始密钥。 这意味着对于我们的示例,扩展密钥的前 32 个字节是密钥本身。

以下是重要的缩放步骤:

:与 () 类似,此步骤重新组织 32 位字,使最高有效字节变成最低有效字节。

:此步骤使用与加密期间字节替换相同的替换框。

rcon:此阶段将用户定义的值提高到 2 次方。

与列混合()阶段类似,rcon也在有限域中执行(28); 因此,此步骤通常使用预先计算的查找表。

EK:从扩展密钥返回 4 个字节。

K:与 EK 类似,返回密钥的 4 个字节。

我们如何知道我们已经正确实现了加密和密钥扩展算法? AES 的 NIST 规范包含几个工作示例,可用于检查我们自己实现的结果。

创建代码

为了确保我们能够加速 Zynq SoC PL 中 AES 代码的加密部分,我们必须从一开始就以这个目标来开发代码(请参阅此处的编码规则)。 首先要考虑的是算法的架构; 我们需要正确地分割它。 AES 非常适合这种场景,因为我们可以为每个阶段编写函数,然后根据需要调用它们。 我们还必须将要加速的函数编写在自己的文件中。 软件架构包括以下内容。

main.c:该文件包含密钥扩展算法、加密密钥和纯文本输入,以及对 AES 加密函数的调用。

.c:该文件执行加密。 我们将每个阶段编写为单独的函数,以便可以根据 AES 循环的需要调用它。 为了确保程序设计对于处理器上执行的程序是通用的,我们使用查找表来进行混合步骤的乘法。

.h:该文件包含用于确定大小的定义和参数(例如 mk、nb 和 nr)。

sbox.h:该文件包含用于替换字节的替换框、执行键扩展的 rcon 函数的查找表以及用于列混合变换乘法的乘法查找表。

在此结构中,我们可以通过右键单击该函数并选择“HW/SW”来选择AES加密函数(图6)作为要加速的函数。

算法语言程序之间的关系_算法语言技术发展_c语言的算法

第620章 620

图 6 — 要加速的功能

为了能够确定基线性能并保存通过函数加速获得的结果,我们必须对函数的执行进行时间控制。 为此,我们使用 .h。

编写源代码(已提供)后,我在使用的单个 ARM®-A9 处理器内核上以软件执行 AES 算法时记录了 36,662 个处理器周期。

加速优化

加速 AES 算法比上一问题中的矩阵乘法算法稍微复杂一些。 这是因为 AES 算法的主循环包含相互依赖的阶段。

我用来加速 AES 算法的方法是: 检查循环以查看可以在何处展开; 优化内存带宽; 并选择正确的数据运行时钟频率和硬件功能频率。

AES 加密函数的主循环包含执行每个 AES 步骤的函数。 AES 算法中的每个函数必须完整执行并计算结果,然后才能运行下一个函数。 这种相互依赖性要求我们将 AES 步骤作为独立函数来关注。 这些步骤中有足够的优化潜力。

我们可以管道化轮密钥 add()、字节替换() 和列混合转换() 步骤来提高性能。 在这些函数中,我们通过将编译指示放置在第一个循环中来执行 HLS 命令。 我们应该展开内循环。 其中几个函数从查找表(通常从块 RAM 构建)中读取数据。 我们需要增加内存带宽,在这种情况下,我将 参数指定为“done”,它将内存内容实现为离散寄存器而不是 BRAM。

在 Zynq SoC 上的 PS 和 PL 之间传输数据的能力对于提高性能也很重要。 我所做的第一步是将数据移动时钟网络设置为最高时钟频率: 。 第二个选项是确保直接内存访问用于 PS 和 PL 之间的数据传输。 为此,我必须稍微修改接口并使用函数来确保 DMA 传输所需的内存中的数据连续性(图 7)。

算法语言程序之间的关系_算法语言技术发展_c语言的算法

第620章 620

图 7 – PS 和 PL 之间的数据移动网络

第二个也是最后一个优化步骤是以支持的最高频率为硬件功能提供时钟:166.67 MHz。

操作系统支持

当我最终将所有内容放在一起并构建此示例时,PL 加速的 AES 代码在 Linux 上运行了 16,544 个处理器时钟周期; 当单独运行软件时

AES 代码仅需要 45% (16,544/36,662) 的周期数。 这将这种具有相互依赖性的相当复杂的算法的执行时间减少了 55%。

当然,我们也可以选择或运行SDSoC环境中的操作系统。 创建、项目和重用代码以比较三个操作系统之间的性能。 对于给定的项目,操作系统的选择取决于任务要求、性能预算和响应时间。

图 8 显示了 Zynq SoC 的 PS 和 PL 中三种操作系统的性能(图 8)。

第620章 620

图 8 - Zynq PS 和 PL 中的操作系统性能。 并提供类似的缩短效果。

毫不奇怪,并实现了类似的时间减少效果,因为两个操作系统都比完整版本简单得多。

正如我们的结果所示,利用 SDSoC 开发环境加速 AES 加密可提供真正的性能提升,并且易于实施,无需深入的 FPGA 设计经验。

关键词:

加入微信

获取电子行业的最新消息

标签: 字节 加密 算法

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码