基于亚博K210开发板——安全散列算法加速器测试
开发板
亚博K210开发板
实验目的
本次测试主要学习 K210 芯片中的安全散列算法加速器的功能。
实验准备
实验元件
K210 芯片中的核心 0 和核心 1
元件特性
- SHA256 加速器是用来计算SHA-256的计算单元,SHA256是SHA-2 下细分出的 一种算法。SHA-2,名称来自于安全散列算法2(英语:Secure Hash Algorithm 2) 的缩写,一种密码散列函数算法标准,由美国国家安全局研发,属于 SHA 算法之 一,是 SHA-1 的后继者。SHA-2 下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。简单来说, SHA-256是一个哈希函数,也就是散列算法,它可以从任何一种数据中创建的 数字“指纹”,然后把消息或者数据打乱混合并且压缩成摘要,使数据量变小, 固定数据的格式,重新创建一个叫做散列值(或哈希值)的指纹,散列值通常是 一个短的随机字母和数字组成的字符串表示。经过 SHA256算法处理过后都会 产生一个 256bit 长度的哈希值,称为消息摘要。这个摘要相当于是个长度为 32 个字节的数组,通常由一个长度为 64 的十六进制字符串来表示,其中 1 个字节=8 位,一个十六进制的字符的长度为 4 位。
- SHA-2 下的不同算法标准只是生成摘要的长度、循环运行的次数等微小差异,基本结构算法是一致的。
SDK 中对应 API 功能
以头文件 sha256.h为例
• sha256_init:初始化 SHA256 加速器外设。
• sha256_update:传入一个数据块参与 SHA256 Hash 计算。
• sha256_final:结束对数据的 SHA256 Hash 计算。
• sha256_hard_calculate:一次性对连续的数据计算它的 SHA256 Hash。
实验原理
- 常量初始化
SHA256 算法中用到了 8 个哈希初值以及 64 个哈希常量。其中,SHA256 算法的 8 个哈希初值如下:
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19
这些初值是对自然数中前 8 个质数(2,3,5,7,11,13,17,19)的平方根的小数部分取前 32bit 而来。以 H0 的由来为例,根号 2(√2)的小数点部分约为 0.4142135623730950488016887242097 ≈ 6 ∗ 16−1 + 𝑎 ∗ 16−2 + 0 ∗ 16−3 …
所以,质数 2 的平方根的小数部分取前 32bit 就对应是 0x6a09e667。
在 SHA256 算法中,用到的 64 个哈希常量如下:
428a2f98 71374491 b5c0fbcf e9b5dba5
3956c25b 59f111f1 923f82a4 ab1c5ed5
d807aa98 12835b01 243185be 550c7dc3
72be5d74 80deb1fe 9bdc06a7 c19bf174
e49b69c1 efbe4786 0fc19dc6 240ca1cc
2de92c6f 4a7484aa 5cb0a9dc 76f988da
983e5152 a831c66d b00327c8 bf597fc7
c6e00bf3 d5a79147 06ca6351 14292967
27b70a85 2e1b2138 4d2c6dfc 53380d13
650a7354 766a0abb 81c2c92e 92722c85
a2bfe8a1 a81a664b c24b8b70 c76c51a3
d192e819 d6990624 f40e3585 106aa070
19a4c116 1e376c08 2748774c 34b0bcb5
391c0cb3 4ed8aa4a 5b9cca4f 682e6ff3
748f82ee 78a5636f 84c87814 8cc70208
90befffa a4506ceb bef9a3f7 c67178f2
和 8 个 哈 希 初 值 类 似 , 这 些 常 量 是 对 自 然 数 中 前 64 个 质 数(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97…)的立方根的小数部分取前 32bit 而来。
- 信息预处理(pre-processing)
SHA256 算法中的预处理就是在想要 Hash 的消息后面补充需要的信息,使整个消息满足指定的结构。信息的预处理分为两个步骤:附加填充比特和附加长度。
步骤一:附加填充比特
在报文末尾进行填充,使报文长度在对 512 取模以后的余数是 448填充是这样进行的:先补第一个比特为 1,其他后面都补 0,直到长度满足对 512 取模后余数是 448。需要注意的是,信息必须进行填充,也就是说,即使长度已经满足对 512 取模后余数是 448,补位也必须要进行,这时要填充 512 个比特。因此,填充是至少补一位,最多补 512 位。例:以信息“abc”为例显示补位的过程。a,b,c 对应的 ASCII 码分别是 97,98,99
于是原始信息的二进制编码为:01100001 01100010 01100011
补位第一步,首先补一个“1” : 0110000101100010 01100011 1
补位第二步,补 423 个“0”:01100001 01100010 01100011 10000000 00000000 … 00000000
补位完成后的数据如下(为了简介用 16 进制表示):
61626380 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000
为什么是 448?
因为在第一步的预处理后,第二步会再附加上一个 64bit 的数据,用来表示原始报文的长度信息。而 448+64=512,正好拼成了一个完整的结构。
步骤二:附加长度值
附加长度值就是将原始数据(第一步填充前的消息)的长度信息补到已经进行了填充操作的消息后面。
SHA256 用一个 64 位的数据来表示原始消息的长度。
因此,通过 SHA256 计算的消息长度必须要小于 2^64 ,当然绝大多数情况这足够大了。
长度信息的编码方式为 64-bit big-endian integer
关于 Big endian 的含义,文末给出了补充
回到刚刚的例子,消息“abc”,3 个字符,占用 24 个 bit
因此,在进行了补长度的操作以后,整个消息就变成下面这样了(16 进制格
式)
61626380 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000018
-
逻辑运算
SHA256 散列函数中涉及的操作全部是逻辑的位运算,包括如下的逻辑函数:
-
计算消息摘要
以下 SHA256 算法的主体部分,即消息摘要,是如何计算的。
首先:将消息分解成 512-bit 大小的块
-
假设数据D可以被分解为n个块,于是整个算法需要做的就是完成n次迭代,n 次迭代的结果就是最
-
终的哈希值,即 256bit 的数字摘要。
-
一个 256-bit 的摘要的初始值 H0,经过第一个数据块进行运算,得到 H1,即完成了第一次迭代,H1 经过第二个数据块得到
H2,……,依次处理,最后得到 Hn,Hn 即为最终的 256-bit 消息摘要。 -
将每次迭代进行的映射用$ Map(H_{i-1}) = H_{i} $表示,于是迭代可以更形象的展示为:
-
图中 256-bit 的 Hi 被描述 8 个小块,这是因为 SHA256 算法中的最小运算单 元称为“字”(Word),一个字是 32位。此外,第一次迭代中,映射的初值设置为前面介绍的 8 个哈希初值,如下图所示:
下面开始介绍每一次迭代的内容,即映射$ Map(H_{i-1}) = H_{i} $的具体算法。
实验过程
- 计算字符串‘abc’的哈希值,并且打印出来。
uint32_t i;printf("\n");cycle = read_cycle();sha256_hard_calculate((uint8_t *)"abc", 3, hash);for (i = 0; i < SHA256_HASH_LEN;){if (hash[i] != compare1[i])total_check_tag = 1;printf("%02x", hash[i++]);if (!(i % 4))printf(" ");}printf("\n");
- 计算字符串
‘abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgha’ 的哈希值,并且打印出来。
sha256_hard_calculate((uint8_t *)"abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij", 60, hash);for (i = 0; i < SHA256_HASH_LEN;){if (hash[i] != compare2[i])total_check_tag = 1;printf("%02x", hash[i++]);if (!(i % 4))printf(" ");}printf("\n");
- 计算字符串‘abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij’的哈希值,并且打印出来。
sha256_hard_calculate((uint8_t *)"abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgha", 65, hash);for (i = 0; i < SHA256_HASH_LEN;){if (hash[i] != compare3[i])total_check_tag = 1;printf("%02x", hash[i++]);if (!(i % 4))printf(" ");}printf("\n");
- 计算多个字符‘a’的哈希值,并且打印出来。
memset(data_buf, 'a', sizeof(data_buf));
sha256_hard_calculate(data_buf, sizeof(data_buf), hash);
for (i = 0; i < SHA256_HASH_LEN;)
{if (hash[i] != compare4[i])total_check_tag = 1;printf("%02x", hash[i++]);if (!(i % 4))printf(" ");
}
printf("\n");
- 分块计算多个字符‘a’的哈希值,并打印出来。
sha256_context_t context;sha256_init(&context, sizeof(data_buf));sha256_update(&context, data_buf, 1111);sha256_update(&context, data_buf + 1111, sizeof(data_buf) - 1111);sha256_final(&context, hash);for (i = 0; i < SHA256_HASH_LEN;){if (hash[i] != compare4[i])total_check_tag = 1;printf("%02x", hash[i++]);if (!(i % 4))printf(" ");}printf("\n");
- 编译调试,烧录运行
进入自己项目 build目录,运行以下命令编译。
cmake .. -DPROJ=watchdog -G "MinGW Makefiles"
make
实验现象
烧录固件完成后,系统会自动弹出一个终端窗口,并且打印每一步计算出的哈希值。
以下是一个在线的 SHA256 验证网站,可以到里面输入验证:
https://hash.online-convert.com/sha256-generator
在以下红色方框中输入想要转化的字符串,然后点击 Convert file。可能存在网络比较慢的问题,需要耐心等待完成。
等待转化成功后,就可以看到摘要的哈希值,与上面程序中第一行的哈希值对比,是完全一致的。
实验总结
- SHA256 是 SHA-2 加密系统中的一员,并且所有的 SHA-2 成员的基础加密算法都 是一致的,只是生成摘要的长度和循环次数不同。
- SHA256 每次生成的摘要为 256bit。
- SHA256 是目前安全散列算法中应用比较广的一种。