[STM32U5] 【NUCLEO-U575ZI-Q测评】+第一篇_硬件Hash使用

[复制链接]
2525|1
 楼主| zhanzr21 发表于 2023-3-5 14:34 | 显示全部楼层 |阅读模式
本帖最后由 zhanzr21 于 2023-3-5 14:42 编辑

#申请原创#
很幸运又拿到了STM32的板子,周末用了下,发几篇贴子分享下.
首先还是不免俗地上几张图,虽说STM32的Nucleo144板子的图各位坛友早就有点"审美疲劳了", 不过拿到板子后我还是忍不住拍两张.
security_IMG_20230218_165100480_HDR.jpg

security_IMG_20230218_164959271_HDR.jpg

security_IMG_20230218_164904417_HDR.jpg

板子的主控是STM32U575ZIT6QU, 是主打低功耗应用的新的系列. 这个系列功能非常强大,同时兼顾低功耗和安全.
Cortex M33自带的Trust Zone, 其余常规外设也非常丰富.
stm32u575_block.png

除了以太网接口和无线接口之外,暂时想不到还缺少什么外设. Flash和SRAM更是高达2MB和784KB. 对于大多数的嵌入式应用来说,外设存储都不是问题了.
当然硬件这些都是基础, 本人对STM系列的产品感觉最靠谱的是开发生态. 以STM32CubeMX为代表的开发工具,让应用设计者开发起来非常便捷.
本篇分享一个使用片上硬件Hash加速单元的例子.
8126564043165c2daa.png

应用设计中,尤其是通信/安全相关的设计中,  计算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基本特性一致.
cubemx_new_project_without_trustzone.png

选择激活Hash加速单元
cubemx_activate_hash_IP.png

这个单元激活即可, 底下配置框内的设置都可以用通过代码在运行时修改的,现在不用太在意.
可以看到这个硬件加速单元支持这几种硬件加速运算:
SHA1
MD5
SHA224
SHA256
HMAC-SHA1
HMAC-MD5
HMAC-SHA224
HMAC-SHA256
cubemx_hash_ip_algorithm_list.png

值得注意的是, SHA1,MD5以及它们对应的HMAC算法现在已经被认为是不安全的了, 即攻击它们的成本现在并不高. 包含在这里, 可能还是为了兼容之前的数据和应用吧. 毕竟一下子淘汰SHA1,MD5还不现实. 如果大家设计新的应用,建议不要选择MD5,SHA1算法.反正都是通过硬件加速, MD5,SHA1运算的优势也没那么明显.
其余就都选默认即可, 生成代码框架.
主函数里分别对以上算法进行测试,即给一个输入,把计算结果打印出来.
  1. printf("Core Freq:%u Hz\n", SystemCoreClock);
  2.   /****************************************************************************/
  3.   /*************************** HMAC-SHA1 **************************************/
  4.   /****************************************************************************/
  5.   if (HAL_HMAC_SHA1_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
  6.                           aHashDigest, 0xFF) != HAL_OK) {
  7.     Error_Handler();
  8.   }
  9.   printf("HMAC-SHA1 test passed.\n");
  10.   print_hex(aHashDigest, 20);

  11.   /****************************************************************************/
  12.   /*************************** HMAC-MD5 ***************************************/
  13.   /****************************************************************************/
  14.   if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
  15.     Error_Handler();
  16.   }
  17.   MX_HASH_Init();

  18.   if (HAL_HMAC_MD5_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE, aHashDigest,
  19.                          0xFF) != HAL_OK) {
  20.     Error_Handler();
  21.   }
  22.   printf("HMAC-MD5 test passed.\n");
  23.   print_hex(aHashDigest, 16);
  24.   /****************************************************************************/
  25.   /*************************** HMAC-SHA224
  26.    * ***************************************/
  27.   /****************************************************************************/
  28.   if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
  29.     Error_Handler();
  30.   }
  31.   MX_HASH_Init();

  32.   if (HAL_HMACEx_SHA224_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
  33.                               aHashDigest, 0xFF) != HAL_OK) {
  34.     Error_Handler();
  35.   }
  36.   printf("HMAC-SHA224 test passed.\n");
  37.   print_hex(aHashDigest, 28);

  38.   /****************************************************************************/
  39.   /*************************** HMAC-SHA256
  40.    * ***************************************/
  41.   /****************************************************************************/
  42.   if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
  43.     Error_Handler();
  44.   }
  45.   MX_HASH_Init();

  46.   if (HAL_HMACEx_SHA256_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
  47.                               aHashDigest, 0xFF) != HAL_OK) {
  48.     Error_Handler();
  49.   }
  50.   printf("HMAC-SHA256 test passed.\n");
  51.   print_hex(aHashDigest, 32);

  52.   /****************************************************************************/
  53.   /*************************** Hash-SHA1
  54.    * ***************************************/
  55.   /****************************************************************************/
  56.   if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
  57.     Error_Handler();
  58.   }
  59.   MX_HASH_Init();

  60.   if (HAL_HASH_SHA1_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
  61.                           aHashDigest, 0xFF) != HAL_OK) {
  62.     Error_Handler();
  63.   }
  64.   printf("Hash-SHA1 test passed.\n");
  65.   print_hex(aHashDigest, 20);

  66.   /****************************************************************************/
  67.   /*************************** Hash-MD5 ***************************************/
  68.   /****************************************************************************/
  69.   if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
  70.     Error_Handler();
  71.   }
  72.   MX_HASH_Init();

  73.   if (HAL_HASH_MD5_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE, aHashDigest,
  74.                          0xFF) != HAL_OK) {
  75.     Error_Handler();
  76.   }
  77.   printf("Hash-MD5 test passed.\n");
  78.   print_hex(aHashDigest, 16);
  79.   /****************************************************************************/
  80.   /*************************** Hash-SHA224
  81.    * ***************************************/
  82.   /****************************************************************************/
  83.   if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
  84.     Error_Handler();
  85.   }
  86.   MX_HASH_Init();

  87.   if (HAL_HASHEx_SHA224_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
  88.                               aHashDigest, 0xFF) != HAL_OK) {
  89.     Error_Handler();
  90.   }
  91.   printf("Hash-SHA224 test passed.\n");
  92.   print_hex(aHashDigest, 28);

  93.   /****************************************************************************/
  94.   /*************************** Hash-SHA256
  95.    * ***************************************/
  96.   /****************************************************************************/
  97.   if (HAL_HASH_DeInit(&hhash) != HAL_OK) {
  98.     Error_Handler();
  99.   }
  100.   MX_HASH_Init();

  101.   if (HAL_HASHEx_SHA256_Start(&hhash, (uint8_t *)aInput, INPUT_TAB_SIZE,
  102.                               aHashDigest, 0xFF) != HAL_OK) {
  103.     Error_Handler();
  104.   }
  105.   printf("Hash-SHA256 test passed.\n");
  106.   print_hex(aHashDigest, 32);

  107.   printf("%u %u\n", SystemCoreClock, HAL_GetTick());
其中打印Hex数据函数和测试数据:
  1. #define INPUT_TAB_SIZE    ((uint32_t) 261)/* The size of the input data "aInput" */
  2. __ALIGN_BEGIN static const uint8_t pKeyHASH[261] __ALIGN_END = {
  3.                             0x54,0x68,0x65,0x20,0x68,0x61,0x73,0x68,0x20,0x70,
  4.                             0x72,0x6f,0x63,0x65,0x73,0x73,0x6f,0x72,0x20,0x69,
  5.                             0x73,0x20,0x61,0x20,0x66,0x75,0x6c,0x6c,0x79,0x20,
  6.                             0x63,0x6f,0x6d,0x70,0x6c,0x69,0x61,0x6e,0x74,0x20,
  7.                             0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,
  8.                             0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,
  9.                             0x65,0x20,0x73,0x65,0x63,0x75,0x72,0x65,0x20,0x68,
  10.                             0x61,0x73,0x68,0x20,0x61,0x6c,0x67,0x6f,0x72,0x69,
  11.                             0x74,0x68,0x6d,0x20,0x28,0x53,0x48,0x41,0x2d,0x31,
  12.                             0x29,0x2c,0x20,0x74,0x68,0x65,0x20,0x4d,0x44,0x35,
  13.                             0x20,0x28,0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x2d,
  14.                             0x64,0x69,0x67,0x65,0x73,0x74,0x20,0x61,0x6c,0x67,
  15.                             0x6f,0x72,0x69,0x74,0x68,0x6d,0x20,0x35,0x29,0x20,
  16.                             0x68,0x61,0x73,0x68,0x20,0x61,0x6c,0x67,0x6f,0x72,
  17.                             0x69,0x74,0x68,0x6d,0x20,0x61,0x6e,0x64,0x20,0x74,
  18.                             0x68,0x65,0x20,0x48,0x4d,0x41,0x43,0x20,0x28,0x6b,
  19.                             0x65,0x79,0x65,0x64,0x2d,0x68,0x61,0x73,0x68,0x20,
  20.                             0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x20,0x61,0x75,
  21.                             0x74,0x68,0x65,0x6e,0x74,0x69,0x63,0x61,0x74,0x69,
  22.                             0x6f,0x6e,0x20,0x63,0x6f,0x64,0x65,0x29,0x20,0x61,
  23.                             0x6c,0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x20,0x73,
  24.                             0x75,0x69,0x74,0x61,0x62,0x6c,0x65,0x20,0x66,0x6f,
  25.                             0x72,0x20,0x61,0x20,0x76,0x61,0x72,0x69,0x65,0x74,
  26.                             0x79,0x20,0x6f,0x66,0x20,0x61,0x70,0x70,0x6c,0x69,
  27.                             0x63,0x61,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x2a,0x2a,
  28.                             0x2a,0x20,0x53,0x54,0x4d,0x33,0x32,0x20,0x2a,0x2a,
  29.                             0x2a};
  30. __ALIGN_BEGIN const uint8_t aInput[INPUT_TAB_SIZE] __ALIGN_END =
  31.                         {0x54,0x68,0x65,0x20,0x68,0x61,0x73,0x68,
  32.                          0x20,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,
  33.                          0x6f,0x72,0x20,0x69,0x73,0x20,0x61,0x20,
  34.                          0x66,0x75,0x6c,0x6c,0x79,0x20,0x63,0x6f,
  35.                          0x6d,0x70,0x6c,0x69,0x61,0x6e,0x74,0x20,
  36.                          0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,
  37.                          0x74,0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,
  38.                          0x66,0x20,0x74,0x68,0x65,0x20,0x73,0x65,
  39.                          0x63,0x75,0x72,0x65,0x20,0x68,0x61,0x73,
  40.                          0x68,0x20,0x61,0x6c,0x67,0x6f,0x72,0x69,
  41.                          0x74,0x68,0x6d,0x20,0x28,0x53,0x48,0x41,
  42.                          0x2d,0x31,0x29,0x2c,0x20,0x74,0x68,0x65,
  43.                          0x20,0x4d,0x44,0x35,0x20,0x28,0x6d,0x65,
  44.                          0x73,0x73,0x61,0x67,0x65,0x2d,0x64,0x69,
  45.                          0x67,0x65,0x73,0x74,0x20,0x61,0x6c,0x67,
  46.                          0x6f,0x72,0x69,0x74,0x68,0x6d,0x20,0x35,
  47.                          0x29,0x20,0x68,0x61,0x73,0x68,0x20,0x61,
  48.                          0x6c,0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,
  49.                          0x20,0x61,0x6e,0x64,0x20,0x74,0x68,0x65,
  50.                          0x20,0x48,0x4d,0x41,0x43,0x20,0x28,0x6b,
  51.                          0x65,0x79,0x65,0x64,0x2d,0x68,0x61,0x73,
  52.                          0x68,0x20,0x6d,0x65,0x73,0x73,0x61,0x67,
  53.                          0x65,0x20,0x61,0x75,0x74,0x68,0x65,0x6e,
  54.                          0x74,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,
  55.                          0x20,0x63,0x6f,0x64,0x65,0x29,0x20,0x61,
  56.                          0x6c,0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,
  57.                          0x20,0x73,0x75,0x69,0x74,0x61,0x62,0x6c,
  58.                          0x65,0x20,0x66,0x6f,0x72,0x20,0x61,0x20,
  59.                          0x76,0x61,0x72,0x69,0x65,0x74,0x79,0x20,
  60.                          0x6f,0x66,0x20,0x61,0x70,0x70,0x6c,0x69,
  61.                          0x63,0x61,0x74,0x69,0x6f,0x6e,0x73,0x2e,
  62.                          0x2a,0x2a,0x2a,0x20,0x53,0x54,0x4d,0x33,
  63.                          0x32,0x20,0x2a,0x2a,0x2a};
  64. __ALIGN_BEGIN static uint8_t aHashDigest[32] __ALIGN_END;

  65. void print_hex(uint8_t* buf, uint32_t len) {
  66.         for(uint32_t i=0; i<len; ++i) {
  67.                 printf("%02X", *(buf+i));
  68.         }
  69.         printf("\r\n");
  70. }
构建, 获取计算结果:
96434640435742fcc2.png

计算起来很快的, 具体相对于软件计算的加速倍数跟优化选项和是否选择DMA有关, 之前在其他系列上测试过, 跟软件计算的速度相比至少是两个数量级. 感兴趣的同学可以做一个精确的Benchmark.
另外使用一个Python程序来验证运算的结果准确性:
  1. import hmac
  2. import hashlib
  3. import sys
  4. import binascii
  5. import json

  6. def main_str(key, msg) -> None:
  7.     print("key:%s\nmsg:%s\n" % (key, msg))
  8.     bkey = bytes(key, 'utf-8')
  9.     bmsg = bytes(msg, 'utf-8')
  10.    
  11.     main_bin(bkey, bmsg)
  12.     return

  13. def main_bin(bkey, bmsg) -> None:
  14.     print("bkey:%s\nbmsg:%s\n" % (binascii.hexlify(bkey), binascii.hexlify(bmsg)))
  15.    
  16.     result = hashlib.md5(bmsg).hexdigest()
  17.     print("hash md5:\t" + result)
  18.     result = hashlib.sha1(bmsg).hexdigest()
  19.     print("hash sha1:\t" + result)
  20.     result = hashlib.sha224(bmsg).hexdigest()
  21.     print("hash sha224:\t" + result)
  22.     result = hashlib.sha256(bmsg).hexdigest()
  23.     print("hash sha256:\t" + result)

  24.     result = hmac.new(bkey, bmsg, hashlib.md5).hexdigest()
  25.     print("hmac md5:\t" + result)
  26.     result = hmac.new(bkey, bmsg, hashlib.sha1).hexdigest()
  27.     print("hmac sha1:\t" + result)
  28.     result = hmac.new(bkey, bmsg, hashlib.sha224).hexdigest()
  29.     print("hmac sha224:\t" + result)
  30.     result = hmac.new(bkey, bmsg, hashlib.sha256).hexdigest()
  31.     print("hmac sha256:\t" + result)
  32.     return

  33. if __name__ == "__main__":
  34.     read_mode='string'
  35.     if 1 < len(sys.argv):
  36.         if sys.argv[1] == 's':
  37.             read_mode = 'string'
  38.             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 ***'
  39.             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 ***'
  40.             if 2 < len(sys.argv):
  41.                 test_key=sys.argv[2]
  42.             if 3 < len(sys.argv):
  43.                 test_msg=sys.argv[3]

  44.             main_str(test_key, test_msg)
  45.             pass
  46.         elif sys.argv[1] == 'f':
  47.             read_mode = 'file'
  48.             test_hex_input_file='hexInput.json'
  49.             test_bkey=b'\x12\x34'
  50.             test_bmsg=b'\x45\x67'
  51.             if 2 < len(sys.argv):
  52.                 test_hex_input_file=sys.argv[2]
  53.             json_load=''
  54.             with open(test_hex_input_file, mode='rb') as fin:
  55.                 json_load = json.load(fin)
  56.                 test_bkey = bytearray.fromhex(json_load['key'])
  57.                 test_bmsg = bytearray.fromhex(json_load['msg'])         
  58.             main_bin(test_bkey, test_bmsg)
  59.             pass
  60.         else:
  61.             print("invalid read mode:" + sys.argv[1])
  62.             pass
  63.     else:
  64.         print("no read mode provided!")
  65.         pass
  66.     pass
测试数据文件:
  1. {
  2.     "key":"54686520686173682070726f636573736f7220697320612066756c6c7920636f6d706c69616e7420696d706c656d656e746174696f6e206f662074686520736563757265206861736820616c676f726974686d20285348412d31292c20746865204d443520286d6573736167652d64696765737420616c676f726974686d203529206861736820616c676f726974686d20616e642074686520484d414320286b657965642d68617368206d6573736167652061757468656e7469636174696f6e20636f64652920616c676f726974686d207375697461626c6520666f7220612076617269657479206f66206170706c69636174696f6e732e2a2a2a2053544d3332202a2a2a",
  3.     "msg":"54686520686173682070726f636573736f7220697320612066756c6c7920636f6d706c69616e7420696d706c656d656e746174696f6e206f662074686520736563757265206861736820616c676f726974686d20285348412d31292c20746865204d443520286d6573736167652d64696765737420616c676f726974686d203529206861736820616c676f726974686d20616e642074686520484d414320286b657965642d68617368206d6573736167652061757468656e7469636174696f6e20636f64652920616c676f726974686d207375697461626c6520666f7220612076617269657479206f66206170706c69636174696f6e732e2a2a2a2053544d3332202a2a2a"
  4. }
验证:
  1. $ python3 t1.py f
  2. bkey:b'54686520686173682070726f636573736f7220697320612066756c6c7920636f6d706c69616e7420696d706c656d656e746174696f6e206f662074686520736563757265206861736820616c676f726974686d20285348412d31292c20746865204d443520286d6573736167652d64696765737420616c676f726974686d203529206861736820616c676f726974686d20616e642074686520484d414320286b657965642d68617368206d6573736167652061757468656e7469636174696f6e20636f64652920616c676f726974686d207375697461626c6520666f7220612076617269657479206f66206170706c69636174696f6e732e2a2a2a2053544d3332202a2a2a'
  3. bmsg:b'54686520686173682070726f636573736f7220697320612066756c6c7920636f6d706c69616e7420696d706c656d656e746174696f6e206f662074686520736563757265206861736820616c676f726974686d20285348412d31292c20746865204d443520286d6573736167652d64696765737420616c676f726974686d203529206861736820616c676f726974686d20616e642074686520484d414320286b657965642d68617368206d6573736167652061757468656e7469636174696f6e20636f64652920616c676f726974686d207375697461626c6520666f7220612076617269657479206f66206170706c69636174696f6e732e2a2a2a2053544d3332202a2a2a'

  4. hash md5:       6707862c7cd0b522b2dd22d8477be318
  5. hash sha1:      f859c18dec9472427924fb61ef7c6a6b670bf9c3
  6. hash sha224:    76ccdd1fde036cde39c9d23ce6bdb169ff743b89d15791bfba109a55
  7. hash sha256:    9691cf47c93807990b049ad4d2e7f60133ab48aada53a80889a3da46170f4afe
  8. hmac md5:       877ebbbfc8a9c08578a2c331d67ec70e
  9. hmac sha1:      2b47ef34f66658be3b2ac6ec5885f21ed59fddad
  10. hmac sha224:    6bd3132e89c7715c9cbaee0150d0b25c577297e4264031cae9656078
  11. hmac sha256:    c501fc6c173778e69744ae06944f094c9eaf1c562f58debc478cdea85a421f58

所有代码在这个仓库:
git@github.com:zhanzr/Nucelo144-STM32U575.git
分支:
hash_test

谢谢阅读,  下一篇再见!







lulugl 发表于 2023-3-10 17:02 | 显示全部楼层
楼主大佬,专业呀!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:每天都進步

91

主题

1017

帖子

34

粉丝
快速回复 在线客服 返回列表 返回顶部