本帖最后由 zhanzr21 于 2023-3-5 14:42 编辑
#申请原创#
很幸运又拿到了STM32的板子,周末用了下,发几篇贴子分享下.
首先还是不免俗地上几张图,虽说STM32的Nucleo144板子的图各位坛友早就有点"审美疲劳了", 不过拿到板子后我还是忍不住拍两张.
板子的主控是STM32U575ZIT6QU, 是主打低功耗应用的新的系列. 这个系列功能非常强大,同时兼顾低功耗和安全.
Cortex M33自带的Trust Zone, 其余常规外设也非常丰富.
除了以太网接口和无线接口之外,暂时想不到还缺少什么外设. Flash和SRAM更是高达2MB和784KB. 对于大多数的嵌入式应用来说,外设存储都不是问题了.
当然硬件这些都是基础, 本人对STM系列的产品感觉最靠谱的是开发生态. 以STM32CubeMX为代表的开发工具,让应用设计者开发起来非常便捷.
本篇分享一个使用片上硬件Hash加速单元的例子.
应用设计中,尤其是通信/安全相关的设计中, 计算Hash/HMAC的场景很多, 比如校验下载数据的完整性,正确性. 但是Hash/HMAC计算很吃CPU资源. 尤其是需要频繁计算的场景下, CPU资源的很大一部分都给这种计算占去了. 所以即使是非嵌入式的CPU, 近年来也纷纷把这种计算进行硬件加速. 原因无他, 即CPU做这种计算不是很合算, CPU适合处理变化复杂的运算, Hash/Hmac这种运算变化不大,但需要很多指令周期去完成.
参考:Intel的Hash扩展,
https://edc.intel.com/content/ww ... e%20a%20family%20of,processing%20SHA-1%20and%20SHA-256%20on%20Intel%20architecture-based%20processors.
说到Hash的硬件加速, 大家也可以想象 "+密 货B Wa 矿",那是典型的使用ASIC或者GPU对Hash进行加速的场景.
所以STM32的一些系列就带有这种硬件Hash加速单元, 将这种不适合软件运算的工作从CPU那里解放出来.而且这个硬件单元使用起来也非常简单, 还支持DMA.
首先创建一个STM32CubeMX的工程, 选择不需要TrustZone, 关于TrustZone的使用, 以后会另外发贴分享. 当不使用TrustZone时, Cortex M33和Cortex M7基本特性一致.
选择激活Hash加速单元
这个单元激活即可, 底下配置框内的设置都可以用通过代码在运行时修改的,现在不用太在意.
可以看到这个硬件加速单元支持这几种硬件加速运算:
SHA1
MD5
SHA224
SHA256
HMAC-SHA1
HMAC-MD5
HMAC-SHA224
HMAC-SHA256
值得注意的是, SHA1,MD5以及它们对应的HMAC算法现在已经被认为是不安全的了, 即攻击它们的成本现在并不高. 包含在这里, 可能还是为了兼容之前的数据和应用吧. 毕竟一下子淘汰SHA1,MD5还不现实. 如果大家设计新的应用,建议不要选择MD5,SHA1算法.反正都是通过硬件加速, MD5,SHA1运算的优势也没那么明显.
其余就都选默认即可, 生成代码框架.
主函数里分别对以上算法进行测试,即给一个输入,把计算结果打印出来.printf("Core Freq:%u Hz\n", SystemCoreClock);
/****************************************************************************/
/*************************** HMAC-SHA1 **************************************/
/****************************************************************************/
if (HAL_HMAC_SHA1_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
aHashDigest, 0xFF) != HAL_OK) {
Error_Handler();
}
printf("HMAC-SHA1 test passed.\n");
print_hex(aHashDigest, 20);
/****************************************************************************/
/*************************** HMAC-MD5 ***************************************/
/****************************************************************************/
if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
Error_Handler();
}
MX_HASH_Init();
if (HAL_HMAC_MD5_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE, aHashDigest,
0xFF) != HAL_OK) {
Error_Handler();
}
printf("HMAC-MD5 test passed.\n");
print_hex(aHashDigest, 16);
/****************************************************************************/
/*************************** HMAC-SHA224
* ***************************************/
/****************************************************************************/
if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
Error_Handler();
}
MX_HASH_Init();
if (HAL_HMACEx_SHA224_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
aHashDigest, 0xFF) != HAL_OK) {
Error_Handler();
}
printf("HMAC-SHA224 test passed.\n");
print_hex(aHashDigest, 28);
/****************************************************************************/
/*************************** HMAC-SHA256
* ***************************************/
/****************************************************************************/
if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
Error_Handler();
}
MX_HASH_Init();
if (HAL_HMACEx_SHA256_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
aHashDigest, 0xFF) != HAL_OK) {
Error_Handler();
}
printf("HMAC-SHA256 test passed.\n");
print_hex(aHashDigest, 32);
/****************************************************************************/
/*************************** Hash-SHA1
* ***************************************/
/****************************************************************************/
if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
Error_Handler();
}
MX_HASH_Init();
if (HAL_HASH_SHA1_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
aHashDigest, 0xFF) != HAL_OK) {
Error_Handler();
}
printf("Hash-SHA1 test passed.\n");
print_hex(aHashDigest, 20);
/****************************************************************************/
/*************************** Hash-MD5 ***************************************/
/****************************************************************************/
if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
Error_Handler();
}
MX_HASH_Init();
if (HAL_HASH_MD5_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE, aHashDigest,
0xFF) != HAL_OK) {
Error_Handler();
}
printf("Hash-MD5 test passed.\n");
print_hex(aHashDigest, 16);
/****************************************************************************/
/*************************** Hash-SHA224
* ***************************************/
/****************************************************************************/
if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
Error_Handler();
}
MX_HASH_Init();
if (HAL_HASHEx_SHA224_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
aHashDigest, 0xFF) != HAL_OK) {
Error_Handler();
}
printf("Hash-SHA224 test passed.\n");
print_hex(aHashDigest, 28);
/****************************************************************************/
/*************************** Hash-SHA256
* ***************************************/
/****************************************************************************/
if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
Error_Handler();
}
MX_HASH_Init();
if (HAL_HASHEx_SHA256_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
aHashDigest, 0xFF) != HAL_OK) {
Error_Handler();
}
printf("Hash-SHA256 test passed.\n");
print_hex(aHashDigest, 32);
printf("%u %u\n", SystemCoreClock, HAL_GetTick());
其中打印Hex数据函数和测试数据:
#define INPUT_TAB_SIZE ((uint32_t) 261)/* The size of the input data "aInput" */
__ALIGN_BEGIN static const uint8_t pKeyHASH[261] __ALIGN_END = {
0x54,0x68,0x65,0x20,0x68,0x61,0x73,0x68,0x20,0x70,
0x72,0x6f,0x63,0x65,0x73,0x73,0x6f,0x72,0x20,0x69,
0x73,0x20,0x61,0x20,0x66,0x75,0x6c,0x6c,0x79,0x20,
0x63,0x6f,0x6d,0x70,0x6c,0x69,0x61,0x6e,0x74,0x20,
0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,
0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,
0x65,0x20,0x73,0x65,0x63,0x75,0x72,0x65,0x20,0x68,
0x61,0x73,0x68,0x20,0x61,0x6c,0x67,0x6f,0x72,0x69,
0x74,0x68,0x6d,0x20,0x28,0x53,0x48,0x41,0x2d,0x31,
0x29,0x2c,0x20,0x74,0x68,0x65,0x20,0x4d,0x44,0x35,
0x20,0x28,0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x2d,
0x64,0x69,0x67,0x65,0x73,0x74,0x20,0x61,0x6c,0x67,
0x6f,0x72,0x69,0x74,0x68,0x6d,0x20,0x35,0x29,0x20,
0x68,0x61,0x73,0x68,0x20,0x61,0x6c,0x67,0x6f,0x72,
0x69,0x74,0x68,0x6d,0x20,0x61,0x6e,0x64,0x20,0x74,
0x68,0x65,0x20,0x48,0x4d,0x41,0x43,0x20,0x28,0x6b,
0x65,0x79,0x65,0x64,0x2d,0x68,0x61,0x73,0x68,0x20,
0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x20,0x61,0x75,
0x74,0x68,0x65,0x6e,0x74,0x69,0x63,0x61,0x74,0x69,
0x6f,0x6e,0x20,0x63,0x6f,0x64,0x65,0x29,0x20,0x61,
0x6c,0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x20,0x73,
0x75,0x69,0x74,0x61,0x62,0x6c,0x65,0x20,0x66,0x6f,
0x72,0x20,0x61,0x20,0x76,0x61,0x72,0x69,0x65,0x74,
0x79,0x20,0x6f,0x66,0x20,0x61,0x70,0x70,0x6c,0x69,
0x63,0x61,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x2a,0x2a,
0x2a,0x20,0x53,0x54,0x4d,0x33,0x32,0x20,0x2a,0x2a,
0x2a};
__ALIGN_BEGIN const uint8_t aInput[INPUT_TAB_SIZE] __ALIGN_END =
{0x54,0x68,0x65,0x20,0x68,0x61,0x73,0x68,
0x20,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,
0x6f,0x72,0x20,0x69,0x73,0x20,0x61,0x20,
0x66,0x75,0x6c,0x6c,0x79,0x20,0x63,0x6f,
0x6d,0x70,0x6c,0x69,0x61,0x6e,0x74,0x20,
0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,
0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,
0x66,0x20,0x74,0x68,0x65,0x20,0x73,0x65,
0x63,0x75,0x72,0x65,0x20,0x68,0x61,0x73,
0x68,0x20,0x61,0x6c,0x67,0x6f,0x72,0x69,
0x74,0x68,0x6d,0x20,0x28,0x53,0x48,0x41,
0x2d,0x31,0x29,0x2c,0x20,0x74,0x68,0x65,
0x20,0x4d,0x44,0x35,0x20,0x28,0x6d,0x65,
0x73,0x73,0x61,0x67,0x65,0x2d,0x64,0x69,
0x67,0x65,0x73,0x74,0x20,0x61,0x6c,0x67,
0x6f,0x72,0x69,0x74,0x68,0x6d,0x20,0x35,
0x29,0x20,0x68,0x61,0x73,0x68,0x20,0x61,
0x6c,0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,
0x20,0x61,0x6e,0x64,0x20,0x74,0x68,0x65,
0x20,0x48,0x4d,0x41,0x43,0x20,0x28,0x6b,
0x65,0x79,0x65,0x64,0x2d,0x68,0x61,0x73,
0x68,0x20,0x6d,0x65,0x73,0x73,0x61,0x67,
0x65,0x20,0x61,0x75,0x74,0x68,0x65,0x6e,
0x74,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,
0x20,0x63,0x6f,0x64,0x65,0x29,0x20,0x61,
0x6c,0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,
0x20,0x73,0x75,0x69,0x74,0x61,0x62,0x6c,
0x65,0x20,0x66,0x6f,0x72,0x20,0x61,0x20,
0x76,0x61,0x72,0x69,0x65,0x74,0x79,0x20,
0x6f,0x66,0x20,0x61,0x70,0x70,0x6c,0x69,
0x63,0x61,0x74,0x69,0x6f,0x6e,0x73,0x2e,
0x2a,0x2a,0x2a,0x20,0x53,0x54,0x4d,0x33,
0x32,0x20,0x2a,0x2a,0x2a};
__ALIGN_BEGIN static uint8_t aHashDigest[32] __ALIGN_END;
void print_hex(uint8_t* buf, uint32_t len) {
for(uint32_t i=0; i<len; ++i) {
printf("%02X", *(buf+i));
}
printf("\r\n");
}
构建, 获取计算结果:
计算起来很快的, 具体相对于软件计算的加速倍数跟优化选项和是否选择DMA有关, 之前在其他系列上测试过, 跟软件计算的速度相比至少是两个数量级. 感兴趣的同学可以做一个精确的Benchmark.
另外使用一个Python程序来验证运算的结果准确性:
import hmac
import hashlib
import sys
import binascii
import json
def main_str(key, msg) -> None:
print("key:%s\nmsg:%s\n" % (key, msg))
bkey = bytes(key, 'utf-8')
bmsg = bytes(msg, 'utf-8')
main_bin(bkey, bmsg)
return
def main_bin(bkey, bmsg) -> None:
print("bkey:%s\nbmsg:%s\n" % (binascii.hexlify(bkey), binascii.hexlify(bmsg)))
result = hashlib.md5(bmsg).hexdigest()
print("hash md5:\t" + result)
result = hashlib.sha1(bmsg).hexdigest()
print("hash sha1:\t" + result)
result = hashlib.sha224(bmsg).hexdigest()
print("hash sha224:\t" + result)
result = hashlib.sha256(bmsg).hexdigest()
print("hash sha256:\t" + result)
result = hmac.new(bkey, bmsg, hashlib.md5).hexdigest()
print("hmac md5:\t" + result)
result = hmac.new(bkey, bmsg, hashlib.sha1).hexdigest()
print("hmac sha1:\t" + result)
result = hmac.new(bkey, bmsg, hashlib.sha224).hexdigest()
print("hmac sha224:\t" + result)
result = hmac.new(bkey, bmsg, hashlib.sha256).hexdigest()
print("hmac sha256:\t" + result)
return
if __name__ == "__main__":
read_mode='string'
if 1 < len(sys.argv):
if sys.argv[1] == 's':
read_mode = 'string'
test_key='The hash processor is a fully compliant implementation of the secure hash algorithm (SHA-1), the MD5 (message-digest algorithm 5) hash algorithm and the HMAC (keyed-hash message authentication code) algorithm suitable for a variety of applications.*** STM32 ***'
test_msg='The hash processor is a fully compliant implementation of the secure hash algorithm (SHA-1), the MD5 (message-digest algorithm 5) hash algorithm and the HMAC (keyed-hash message authentication code) algorithm suitable for a variety of applications.*** STM32 ***'
if 2 < len(sys.argv):
test_key=sys.argv[2]
if 3 < len(sys.argv):
test_msg=sys.argv[3]
main_str(test_key, test_msg)
pass
elif sys.argv[1] == 'f':
read_mode = 'file'
test_hex_input_file='hexInput.json'
test_bkey=b'\x12\x34'
test_bmsg=b'\x45\x67'
if 2 < len(sys.argv):
test_hex_input_file=sys.argv[2]
json_load=''
with open(test_hex_input_file, mode='rb') as fin:
json_load = json.load(fin)
test_bkey = bytearray.fromhex(json_load['key'])
test_bmsg = bytearray.fromhex(json_load['msg'])
main_bin(test_bkey, test_bmsg)
pass
else:
print("invalid read mode:" + sys.argv[1])
pass
else:
print("no read mode provided!")
pass
pass
测试数据文件:
{
"key":"54686520686173682070726f636573736f7220697320612066756c6c7920636f6d706c69616e7420696d706c656d656e746174696f6e206f662074686520736563757265206861736820616c676f726974686d20285348412d31292c20746865204d443520286d6573736167652d64696765737420616c676f726974686d203529206861736820616c676f726974686d20616e642074686520484d414320286b657965642d68617368206d6573736167652061757468656e7469636174696f6e20636f64652920616c676f726974686d207375697461626c6520666f7220612076617269657479206f66206170706c69636174696f6e732e2a2a2a2053544d3332202a2a2a",
"msg":"54686520686173682070726f636573736f7220697320612066756c6c7920636f6d706c69616e7420696d706c656d656e746174696f6e206f662074686520736563757265206861736820616c676f726974686d20285348412d31292c20746865204d443520286d6573736167652d64696765737420616c676f726974686d203529206861736820616c676f726974686d20616e642074686520484d414320286b657965642d68617368206d6573736167652061757468656e7469636174696f6e20636f64652920616c676f726974686d207375697461626c6520666f7220612076617269657479206f66206170706c69636174696f6e732e2a2a2a2053544d3332202a2a2a"
}
验证:
$ python3 t1.py f
bkey:b'54686520686173682070726f636573736f7220697320612066756c6c7920636f6d706c69616e7420696d706c656d656e746174696f6e206f662074686520736563757265206861736820616c676f726974686d20285348412d31292c20746865204d443520286d6573736167652d64696765737420616c676f726974686d203529206861736820616c676f726974686d20616e642074686520484d414320286b657965642d68617368206d6573736167652061757468656e7469636174696f6e20636f64652920616c676f726974686d207375697461626c6520666f7220612076617269657479206f66206170706c69636174696f6e732e2a2a2a2053544d3332202a2a2a'
bmsg:b'54686520686173682070726f636573736f7220697320612066756c6c7920636f6d706c69616e7420696d706c656d656e746174696f6e206f662074686520736563757265206861736820616c676f726974686d20285348412d31292c20746865204d443520286d6573736167652d64696765737420616c676f726974686d203529206861736820616c676f726974686d20616e642074686520484d414320286b657965642d68617368206d6573736167652061757468656e7469636174696f6e20636f64652920616c676f726974686d207375697461626c6520666f7220612076617269657479206f66206170706c69636174696f6e732e2a2a2a2053544d3332202a2a2a'
hash md5: 6707862c7cd0b522b2dd22d8477be318
hash sha1: f859c18dec9472427924fb61ef7c6a6b670bf9c3
hash sha224: 76ccdd1fde036cde39c9d23ce6bdb169ff743b89d15791bfba109a55
hash sha256: 9691cf47c93807990b049ad4d2e7f60133ab48aada53a80889a3da46170f4afe
hmac md5: 877ebbbfc8a9c08578a2c331d67ec70e
hmac sha1: 2b47ef34f66658be3b2ac6ec5885f21ed59fddad
hmac sha224: 6bd3132e89c7715c9cbaee0150d0b25c577297e4264031cae9656078
hmac sha256: c501fc6c173778e69744ae06944f094c9eaf1c562f58debc478cdea85a421f58
所有代码在这个仓库:
git@github.com:zhanzr/Nucelo144-STM32U575.git
分支:
hash_test
谢谢阅读, 下一篇再见!
|
此文章已获得独家原创/原创奖标签,著作权归21ic所有,未经允许禁止转载。
|