OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 89|回复: 0

AT32 MCU AES应用笔记分享

[复制链接]

56

主题

56

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
228
金钱
228
注册时间
2024-12-9
在线时间
13 小时
发表于 昨天 14:41 | 显示全部楼层 |阅读模式
AN0249
  
应用笔记
AT32 MCU AES  Application Note
前言
本应用笔记主要介绍以下几部分内容:
1.     基于雅特力提供的V2.x.x的BSP板级支持包来进行AES的配置及操作
2.     各种AES工作串接模式的使用方法
支持型号列表:
  
支持型号
  
具备AES的型号

备注说明:本文档仅供有需求的小伙伴参考,文档中所涉及的图片或视频,代码等资料,如有不清楚的,可访问雅特力官网获取https://www.arterytek.com/cn/support/index.jsp?index=1
1                 概述
进阶加密标准Advanced Encryption Standard缩写:AES)是对称式的分组加密算法,以128比特为一个数据分组。使用128192,与256位长度之密钥,进行加解密运算。
Artery提供的AES硬件加密单元,主要有以下特点:
l  符合 NISTFIPS PUB-197 Advanced Encryption Standard (AES)的设计
l  支持 128,192,与256位密钥长度
l  支持多种常用的工作模式 :
n  电子密码本模式(ECB)
n  密码块链接模式(CBC)
n  计数器模式(CTR)
n  伽罗瓦/计数器模式(GCM)
n  计数器模式搭配密码块链接消息验证代码(CCM)
l  支持以伽罗瓦/计数器模式(GCM)实现伽罗瓦消息验证代码(GMAC)模式
l  支持4个字的初始化向量(IV),可使用于 CBC,CTR,GCM,CCM
l  可支持以两路直接存储器访问进行数据传输
l  以字为单位,支持输入/输出数据的半字,字节,与位交换
l  以分组为单位,支持由软件打断加密/解密运作,以及恢复先前运作的能力
2                 功能配置2.1           加解密
配置AES_CTRL的寄存器OPR0,可启用加密模式。此模式下,用户通过访问AES输入数据寄存器(AES_IDT)输入信息明文进行加密。加密完成之密文存放于输出缓冲中,通过访问AES输出数据寄存器(AES_ODT),用户可取得信息密文。AES密钥寄存器(AES_KEYx)AES初始向量寄存器(AES_IVx)AES控制寄存器(AES_CTRL)需要在AES使能前配置完成,详细操作方式请见28.4工作串接模式中各模式之说明。
AES以迭代方式进行运算,解密所使用的轮密钥为加密轮密钥之反序排列。故欲将密文解密回信息明文,AES硬件加密单元(AES)需先将私密钥匙扩展成轮密钥后在解密,与加密时的实时扩展有所不同。依据信息的分组数量,AES硬件加密单元可以两种模式进行解密:
n  单一分组信息解密:欲解密的密文仅只一个分组
n  串接分组信息解密:欲解密多于一个分组的密文
2.2           工作串接模式
对于信息长度超过一个数据分组(即128 比特位)的明文或密文,AES 支持多种常用的工作串接模式,使用同一组密钥对其进行加密或解密。
2.2.1       电子密码本模式 (ECB)
电子密码本模式(ECB)是最基本的串接模式,配置AES_CTRL的寄存器CHN0,可选用此模式进行加解密。此模式下,信息以16字节拆分分组,各分组独立进行加密或解密,如下图所示:

2.2.2       密码块链接模式 (CBC)
密码块链接模式(CBC)的分组密文为前面所有的分组明文经运算所形成,配置AES_CTRL的寄存器CHN1,可选用此模式进行加解密。此模式下,信息明文拆分分组后,将前次分组密文与此次分组明文取异或之后,再由加解密核心单元进行加密。为确保信息之唯一性,需在第一个分组上使用初始化向量代替前组密文,初始化向量配置于AES初始向量寄存器(AES_IVx)。加密流程如下图所示:
此模式解密时,将接收密文拆分分组后,先由加解密核心单元进行解密,在与前次分组密文取异或取得明文。在第一个分组上,需使用与加密相同之初始化向量代替前组密文进行解密。解密流程如下图所示:

2.2.3       计数器模式 (CTR)
计数器模式以流密码的方式进行加解密,透过加密一次性随机数与逐次累加的计数器值组合产生密钥流分组,将其与信息明文分组取异或即获得密文。由于异或运算之对称性,加密与解密流程完全相同。配置AES_CTRL的寄存器CHN2可选用此模式,加解密流程如下图所示

2.2.4       伽罗瓦/计数器模式 (GCM)
伽罗瓦/计数器模式结合计数器模式与伽罗瓦哈希函数,以同时保证信息的机密性与完整性。信息之加解密以计数器模式完成,如2.2.3之介绍。加密产生的密文与附加身份验证数据以分组为单位,使用伽罗瓦哈希函数的运算产生卷标。配置AES_CTRL的寄存器CHN3可选用此模式,加密与卷标产生流程如下图所示:

2.2.5       伽罗瓦消息验证代码(GMAC)
伽罗瓦消息验证代码(GMAC)是伽罗瓦/计数器模式结合计数器模式的变形体,仅以伽罗瓦哈希函数的运算产生卷标确保信息之完整性,无须进行加密。其卷标产生流程请参考2.2.4伽罗瓦/计数器模式 (GCM)的加解密配置流程,并跳过阶段4的加解密阶段。卷标产生流程如下图所示:

2.2.6       计数器模式搭配密码块链接消息验证代码(CCM)
计数器模式搭配密码块链接消息验证代码结合计数器模式与密码块链接消息验证代码,以同时保证信息的机密性与完整性。信息之加解密以计数器模式完成,如2.2.3之介绍。加密产生的密文与附加身份验证数据以分组为单位,使用密码块链接消息验证代码产生标签。配置AES_CTRL的寄存器CHN4可选用此模式,加密与卷标产生流程如下图所示:

2.3           数据格式
依据 NIST FIPS PUB-197所规范,AES128比特为一个数据分组进行加解密,以字节为单位进行二维矩阵运算。数据于AES硬件加密单元(AES)中是以小端格式取用,明文、密文于寄存器之格式如下

2.3.1       DMA设定
AES硬件加速器支持DMA加载输入和读取输出。因为AES的区块长度固定为128位,加上AES硬件加速器的加载输入和读取输出以32位为单位,所以DMA长度设置必须为4个字节的倍数。
AES硬件加速器通过NDD的设置,补上数据长度不够的部分。只能以字节为单位,来源和输出的地址也需字节对齐。
n DMA设定示例代码
  1. static void aes_dma_config(uint8_t* out_buffer, uint8_t* in_buffer, uint32_t sz)
  2. {
  3.   dma_init_type  dma_init_struct;

  4.   if(sz % 16 != 0)  /* fill 0 to multiples of 16 bytes */
  5.   {
  6.     memset(in_buffer + sz, 0, 16 - sz % 16);
  7.   }
  8.   sz += 15;
  9.   sz /= 16;
  10.   sz *= 4;

  11.   if(out_buffer)
  12.   {
  13.     dma_reset(DMA1_CHANNEL1);
  14.     dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
  15.     dma_init_struct.buffer_size = sz;
  16.     dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_WORD;
  17.     dma_init_struct.peripheral_base_addr = (uint32_t)(&(AES->odt));
  18.     dma_init_struct.peripheral_inc_enable =  FALSE;
  19.     dma_init_struct.memory_base_addr  = (uint32_t)out_buffer;
  20.     dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_WORD;
  21.     dma_init_struct.memory_inc_enable = TRUE;
  22.     dma_init_struct.loop_mode_enable = FALSE;
  23.     dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
  24.     dma_init(DMA1_CHANNEL1,&dma_init_struct);
  25.    
  26.     dma_flexible_config(DMA1, DMA1MUX_CHANNEL1, DMAMUX_DMAREQ_ID_AES_OUT);
  27.     dmamux_enable(DMA1, TRUE);
  28.   }
  29.   /* config in */
  30.   dma_reset(DMA1_CHANNEL2);
  31.   dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
  32.   dma_init_struct.buffer_size = sz;
  33.   dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_WORD;
  34.   dma_init_struct.peripheral_base_addr = (uint32_t)(&(AES->idt));
  35.   dma_init_struct.peripheral_inc_enable =  FALSE;
  36.   dma_init_struct.memory_base_addr = (uint32_t)in_buffer;
  37.   dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_WORD;
  38.   dma_init_struct.memory_inc_enable = TRUE;
  39.   dma_init_struct.loop_mode_enable = FALSE;
  40.   dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
  41.   dma_init(DMA1_CHANNEL2,&dma_init_struct);
  42.   
  43.   dma_flexible_config(DMA1, DMA1MUX_CHANNEL2, DMAMUX_DMAREQ_ID_AES_IN);
  44.   dmamux_enable(DMA1, TRUE);
  45.   
  46.   dma_channel_enable(DMA1_CHANNEL2, TRUE);   
  47.   dma_channel_enable(DMA1_CHANNEL1, TRUE);   
  48. }
复制代码

2.4           停滞与恢复流程
对于正在进行数据充填的工作串接模式,AES硬件加密单元(AES)支持以数据分组为单位的停滞操作。停滞操作的目的是暂停并记录当下运算之任务,释放资源以供更高优先权之任务使用,如下图所示意:

当有其他AES动作想要优先完成时,可以先暂停目前的AES动作。若AES有使用DMA时,可参考2.4.2使用DMA时的注意事项。暂停的步骤如下:
1.    等待目前的资料区块完成。
2.    备份必须的寄存器
3.   清除ctrl的aesen
4.   备份ctrl寄存器
5.   可以开始新的AES的流程动作并等待结束。
6.   复原ctrl寄存器
7.    复原已经备份的寄存器
8.    始能ctrl的aesen
9.   继续未完成的数据区块和步骤。
n  停滞与恢复示例代码

  1. while(USR_IN_SZ)
  2. {
  3.   if(now is last 128bit data) aes_last_block_enable(TRUE);
  4.   USR_IN_PTR = aes_data_input(USR_IN_PTR);
  5.   USR_IN_SZ -= 16;
  6.   while(aes_flags_get(AES_PDFS_FLAG) == RESET)
  7.   {
  8.   }
  9.   aes_flags_clear(AES_PDFS_FLAG);
  10.   USR_OUT_PTR = aes_data_output(USR_OUT_PTR);
  11.   /***** suspend handling begin *****/
  12.   backup_registers_needed (…);
  13.   aes_enable(FALSE);
  14.   other_aes_process (…);
  15.   restore_registers_needed (…);
  16.   aes_enable(TRUE);
  17.   /***** suspend handling end *****/
  18. }
  19. while(aes_flags_get(AES_NZDFS_FLAG) == RESET )
  20. {
  21. }
  22. aes_flags_clear(AES_NZDFS_FLAG);
复制代码

2.4.1       需备份的寄存器资料
AES硬件加速器将运算过程中的变化反应在寄存器上,使用者备份这些寄存器后就可以进行另外一次新的加解密动作。如果要继续被暂停的后续动作,只要将之前的备份重写回寄存器,就可以继续后续的步骤。需要备份的寄存器描述如下:
n  AES控制寄存器
  1. {
  2.   suspend_ctrl = AES->ctrl;
  3. }
复制代码
n  AES初始向量寄存器
  1. {
  2.   suspend_iv[0] = AES->iv0;
  3.   suspend_iv[1] = AES->iv1;
  4.   suspend_iv[2] = AES->iv2;
  5.   suspend_iv[3] = AES->iv3;
  6. }
复制代码
n  AES密钥寄存器
  1. {
  2.   suspend_key[0] = AES->key0;
  3.   suspend_key[1] = AES->key1;
  4.   suspend_key[2] = AES->key2;
  5.   suspend_key[3] = AES->key3;
  6.   suspend_key[4] = AES->key4;
  7.   suspend_key[5] = AES->key5;
  8.   suspend_key[6] = AES->key6;
  9.   suspend_key[7] = AES->key7;
  10. }
复制代码
n  AES停滞讯息寄存器
  1. {
  2.   suspend_si[0] = AES->si0;
  3.   suspend_si[1] = AES->si1;
  4.   suspend_si[2] = AES->si2;
  5.   suspend_si[3] = AES->si3;
  6.   suspend_si[4] = AES->si4;
  7.   suspend_si[5] = AES->si5;
  8.   suspend_si[6] = AES->si6;
  9.   suspend_si[7] = AES->si7;
  10. }
复制代码

2.4.2       使用DMA时的注意事项
AES硬件加速器使用DMA,如果同时NDD不为0时,会导致运算结果不正确。想要在使用DMA时进行停滞的动作,如果处理的数据输入长度不是128位的倍数,可以将数据输入的部分分割成两步骤处理。第一步,先处理前面128位倍数的数据部分,在这步骤中可以正常进行停滞的流程;第二步,处理剩余不足128位的资料区块,因为是最后的区块,这部分也不需要进行停滞流程,所以可以正常使用NDD的功能。
3                 案例 ECB模式3.1           功能简介
下面将介绍如何使用ECB工作串接模式进行数据的加解密。
3.2           资源准备
1) 硬件环境:
对应产品型号的AT-START BOARD
2) 软件环境
分别提供了CPUDMA两种数据填充方式的案例代码:
project\at_start_f4xx\examples\aes\ecb
project\at_start_f4xx\examples\aes\ecb_using_dma
3.3           软件设计
ECB每次只处理一个数据分组 (128位),可将大量资料分成许多数据分组,再针对各数据分组独立处理。加解密以三个阶段进行:准备阶段、解密密钥扩展和加解密阶段。
3.3.1       ECB encryption
  1. void aes_encrypt_process(uint8_t* encrypt_buf, uint8_t* original_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;
  4.   uint32_t temp_block_buf[4];
  5.   uint32_t i;

  6.   aes_reset();
  7.   aes_default_para_init(&aes_init_struct);
  8.   aes_init_struct.operate_mode = AES_OPMODE_ENCRYPT;
  9.   aes_init_struct.chaining_mode = AES_CHMODE_ECB;
  10.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  11.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  12.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  13.   aes_init(&aes_init_struct);
  14.   aes_suspend_info_init();

  15.   /* data phase */
  16.   aes_enable(TRUE);
  17.   for(i=0; i< buf_len / 16; i++)
  18.   {
  19.     aes_data_input((uint32_t *)original_buf + i * 4);
  20.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  21.     aes_flag_clear(AES_PDFS_FLAG);
  22.     aes_data_output((uint32_t *)encrypt_buf + i * 4);
  23.   }
  24.   if(buf_len % 16 != 0)
  25.   {
  26.     memcpy((uint8_t *)temp_block_buf, (uint8_t *)original_buf + i * 16, (buf_len % 16));
  27.     memset((uint8_t *)temp_block_buf + (buf_len % 16), 0, 16 - buf_len % 16);   
  28.     aes_data_input((uint32_t *)temp_block_buf);
  29.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  30.     aes_flag_clear(AES_PDFS_FLAG);
  31.     aes_data_output((uint32_t *)encrypt_buf + i * 4);
  32.   }  
  33.   aes_enable(FALSE);
  34. }
复制代码


3.3.2       ECB encryption using DMA
  1. void aes_encrypt_process(uint8_t* encrypt_buf, uint8_t* original_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;
  4.   aes_reset();
  5.   aes_default_para_init(&aes_init_struct);
  6.   aes_init_struct.operate_mode = AES_OPMODE_ENCRYPT;
  7.   aes_init_struct.chaining_mode = AES_CHMODE_ECB;
  8.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  9.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  10.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  11.   aes_init(&aes_init_struct);
  12.   aes_suspend_info_init();

  13.   /* data phase */
  14.   aes_dma_config((uint8_t *)encrypt_buf, (uint8_t *)original_buf, buf_len);
  15.   aes_dma_in_enable(TRUE);
  16.   aes_dma_out_enable(TRUE);
  17.   aes_enable(TRUE);
  18.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  19.   aes_flag_clear(AES_PDFS_FLAG);  
  20.   aes_dma_in_enable(FALSE);
  21.   aes_dma_out_enable(FALSE);   
  22.   aes_enable(FALSE);
  23. }
复制代码



3.3.3       ECB decryption
  1. void aes_decrypt_process(uint8_t* decrypt_buf, uint8_t* encrypt_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;
  4.   uint32_t i;
  5.   
  6.   aes_reset();
  7. #if (OPERATE_MODE == 1)
  8.   aes_default_para_init(&aes_init_struct);
  9.   aes_init_struct.operate_mode = AES_OPMODE_KEY_SCHEDULING_DECRYPT;
  10.   aes_init_struct.chaining_mode = AES_CHMODE_ECB;
  11.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  12.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  13.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  14.   aes_init(&aes_init_struct);
  15.   aes_suspend_info_init();

  16.   /* data phase */
  17.   for(i=0; i< buf_len / 16; i++)
  18.   {
  19.     aes_enable(TRUE);
  20.     aes_data_input((uint32_t *)encrypt_buf + i * 4);
  21.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  22.     aes_flag_clear(AES_PDFS_FLAG);
  23.     aes_data_output((uint32_t *)decrypt_buf + i * 4);
  24.     aes_enable(FALSE);   
  25.   }
  26.   if(buf_len % 16 != 0)
  27.   {
  28.     aes_enable(TRUE);
  29.     aes_data_input((uint32_t *)encrypt_buf + i * 4);
  30.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  31.     aes_flag_clear(AES_PDFS_FLAG);
  32.     aes_data_output((uint32_t *)decrypt_buf + i * 4);
  33.     aes_enable(FALSE);
  34.   }
  35. #else
  36.   aes_default_para_init(&aes_init_struct);
  37.   aes_init_struct.operate_mode = AES_OPMODE_KEY_SCHEDULING;
  38.   aes_init_struct.chaining_mode = AES_CHMODE_ECB;
  39.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  40.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  41.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  42.   aes_init(&aes_init_struct);
  43.   aes_suspend_info_init();

  44.   aes_enable(TRUE);
  45.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  46.   aes_flag_clear(AES_PDFS_FLAG);
  47.   aes_enable(FALSE);

  48.   aes_operate_mode_set(AES_OPMODE_DECRYPT);

  49.   /* data phase */
  50.   aes_enable(TRUE);
  51.   for(i=0; i< buf_len / 16; i++)
  52.   {
  53.     aes_data_input((uint32_t *)encrypt_buf + i * 4);
  54.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  55.     aes_flag_clear(AES_PDFS_FLAG);
  56.     aes_data_output((uint32_t *)decrypt_buf + i * 4);
  57.   }
  58.   if(buf_len % 16 != 0)
  59.   {
  60.     aes_data_input((uint32_t *)encrypt_buf + i * 4);
  61.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  62.     aes_flag_clear(AES_PDFS_FLAG);
  63.     aes_data_output((uint32_t *)decrypt_buf + i * 4);
  64.   }
  65.   aes_enable(FALSE);
  66. #endif
  67. }
复制代码


3.3.4       ECB decryption using DMA
  1. void aes_decrypt_process(uint8_t* decrypt_buf, uint8_t* encrypt_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;
  4.   
  5.   aes_reset();
  6. #if (OPERATE_MODE == 1)
  7.   uint32_t i;
  8.   aes_default_para_init(&aes_init_struct);
  9.   aes_init_struct.operate_mode = AES_OPMODE_KEY_SCHEDULING_DECRYPT;
  10.   aes_init_struct.chaining_mode = AES_CHMODE_ECB;
  11.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  12.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  13.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  14.   aes_init(&aes_init_struct);
  15.   aes_suspend_info_init();

  16.   /* data phase */
  17.   for(i=0; i< buf_len / 16; i++)
  18.   {
  19.     aes_dma_config((uint8_t *)decrypt_buf + i * 16, (uint8_t *)encrypt_buf + i * 16, 16);
  20.     aes_dma_in_enable(TRUE);
  21.     aes_dma_out_enable(TRUE);
  22.     aes_enable(TRUE);
  23.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  24.     aes_flag_clear(AES_PDFS_FLAG);  
  25.     aes_dma_in_enable(FALSE);
  26.     aes_dma_out_enable(FALSE);   
  27.     aes_enable(FALSE);
  28.   }
  29.   if(buf_len % 16 != 0)
  30.   {
  31.     aes_dma_config((uint8_t *)decrypt_buf + i * 16, (uint8_t *)encrypt_buf + i * 16, 16);
  32.     aes_dma_in_enable(TRUE);
  33.     aes_dma_out_enable(TRUE);
  34.     aes_enable(TRUE);
  35.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  36.     aes_flag_clear(AES_PDFS_FLAG);  
  37.     aes_dma_in_enable(FALSE);
  38.     aes_dma_out_enable(FALSE);   
  39.     aes_enable(FALSE);
  40.   }
  41. #else
  42.   aes_default_para_init(&aes_init_struct);
  43.   aes_init_struct.operate_mode = AES_OPMODE_KEY_SCHEDULING;
  44.   aes_init_struct.chaining_mode = AES_CHMODE_ECB;
  45.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  46.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  47.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  48.   aes_init(&aes_init_struct);
  49.   aes_suspend_info_init();

  50.   aes_enable(TRUE);
  51.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  52.   aes_flag_clear(AES_PDFS_FLAG);
  53.   aes_enable(FALSE);

  54.   aes_operate_mode_set(AES_OPMODE_DECRYPT);

  55.   /* data phase */
  56.   if(buf_len % 16 != 0)
  57.     buf_len += (16 - buf_len % 16);
  58.   aes_dma_config((uint8_t *)decrypt_buf, (uint8_t *)encrypt_buf, buf_len);
  59.   aes_dma_in_enable(TRUE);
  60.   aes_dma_out_enable(TRUE);
  61.   aes_enable(TRUE);
  62.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  63.   aes_flag_clear(AES_PDFS_FLAG);  
  64.   aes_dma_in_enable(FALSE);
  65.   aes_dma_out_enable(FALSE);   
  66.   aes_enable(FALSE);
  67. #endif
  68. }
复制代码


3.4           实验效果
将原始数据经过加密并解密后的数据与原始数据进行对比,对比结果正确则LED2会闪烁,否则LED4闪烁。
4                 案例 CBC模式4.1           功能简介
密码块链接模式(CBC),引入了IV(初始化向量:InitializationVector)的概念。下面将介绍如何使用CBC工作串接模式进行数据的加解密。
4.2           资源准备
1) 硬件环境:
对应产品型号的AT-START BOARD
2) 软件环境
分别提供了CPUDMA两种数据填充方式的案例代码:
project\at_start_f4xx\examples\aes\cbc
project\at_start_f4xx\examples\aes\cbc_using_dma
4.3           软件设计
IV是长度为分组大小的一组随机,通常情况下不用保密,不过在大多数情况下,针对同一密钥不应多次使用同一组IV 第一个分组的明文在加密运算前先与IV进行异或;从第二组开始,所有的明文先与前一分组加密后的密文进行异或。在此模式下,加解密以三个阶段进行:准备阶段、解密密钥扩展和加解密阶段。
4.3.1       CBC encryption
  1. void aes_encrypt_process(uint8_t* encrypt_buf, uint8_t* original_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;
  4.   uint32_t temp_block_buf[4];
  5.   uint32_t i;

  6.   aes_reset();
  7.   aes_default_para_init(&aes_init_struct);
  8.   aes_init_struct.operate_mode = AES_OPMODE_ENCRYPT;
  9.   aes_init_struct.chaining_mode = AES_CHMODE_CBC;
  10.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  11.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  12.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  13.   aes_init(&aes_init_struct);
  14.   aes_suspend_info_init();
  15.   aes_iv_set(iv_buf);

  16.   aes_enable(TRUE);
  17.   /* data phase */
  18.   for(i=0; i< buf_len / 16; i++)
  19.   {
  20.     aes_data_input((uint32_t *)original_buf + i * 4);
  21.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  22.     aes_flag_clear(AES_PDFS_FLAG);
  23.     aes_data_output((uint32_t *)encrypt_buf + i * 4);
  24.   }
  25.   if(buf_len % 16 != 0)
  26.   {
  27.     memcpy((uint8_t *)temp_block_buf, (uint8_t *)original_buf + i * 16, buf_len % 16);
  28.     memset((uint8_t *)temp_block_buf + (buf_len % 16), 0, 16 - buf_len % 16);   
  29.     aes_data_input((uint32_t *)temp_block_buf);
  30.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  31.     aes_flag_clear(AES_PDFS_FLAG);
  32.     aes_data_output((uint32_t *)encrypt_buf + i * 4);
  33.   }  
  34.   aes_enable(FALSE);
  35. }
复制代码



4.3.2       CBC encryption using DMA
  1. void aes_encrypt_process(uint8_t* encrypt_buf, uint8_t* original_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;

  4.   aes_reset();
  5.   aes_default_para_init(&aes_init_struct);
  6.   aes_init_struct.operate_mode = AES_OPMODE_ENCRYPT;
  7.   aes_init_struct.chaining_mode = AES_CHMODE_CBC;
  8.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  9.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  10.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  11.   aes_init(&aes_init_struct);
  12.   aes_suspend_info_init();
  13.   aes_iv_set(iv_buf);

  14.   /* data phase */
  15.   aes_dma_config(encrypt_buf, original_buf, buf_len);
  16.   aes_dma_in_enable(TRUE);
  17.   aes_dma_out_enable(TRUE);
  18.   aes_enable(TRUE);
  19.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  20.   aes_flag_clear(AES_PDFS_FLAG);
  21.   aes_dma_in_enable(FALSE);
  22.   aes_dma_out_enable(FALSE);
  23.   aes_enable(FALSE);
  24. }
复制代码



4.3.3       CBC decryption
  1. void aes_decrypt_process(uint8_t* decrypt_buf, uint8_t* encrypt_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;
  4.   uint32_t i;
  5.   
  6.   aes_reset();
  7. #if (OPERATE_MODE == 1)
  8.   aes_default_para_init(&aes_init_struct);
  9.   aes_init_struct.operate_mode = AES_OPMODE_KEY_SCHEDULING_DECRYPT;
  10.   aes_init_struct.chaining_mode = AES_CHMODE_CBC;
  11.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  12.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  13.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  14.   aes_init(&aes_init_struct);
  15.   aes_suspend_info_init();
  16.   aes_iv_set(iv_buf);

  17.   /* data phase */
  18.   for(i=0; i< buf_len / 16; i++)
  19.   {
  20.     aes_enable(TRUE);
  21.     aes_data_input((uint32_t *)encrypt_buf + i * 4);
  22.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  23.     aes_flag_clear(AES_PDFS_FLAG);
  24.     aes_data_output((uint32_t *)decrypt_buf + i * 4);
  25.     aes_enable(FALSE);
  26.   }
  27.   if(buf_len % 16 != 0)
  28.   {
  29.     aes_enable(TRUE);
  30.     aes_data_input((uint32_t *)encrypt_buf + i * 4);
  31.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  32.     aes_flag_clear(AES_PDFS_FLAG);
  33.     aes_data_output((uint32_t *)decrypt_buf + i * 4);
  34.     aes_enable(FALSE);
  35.   }
  36. #else
  37.   aes_default_para_init(&aes_init_struct);
  38.   aes_init_struct.operate_mode = AES_OPMODE_KEY_SCHEDULING;
  39.   aes_init_struct.chaining_mode = AES_CHMODE_CBC;
  40.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  41.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  42.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  43.   aes_init(&aes_init_struct);
  44.   aes_suspend_info_init();
  45.   aes_iv_set(iv_buf);
  46.   
  47.   aes_enable(TRUE);
  48.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  49.   aes_flag_clear(AES_PDFS_FLAG);
  50.   aes_enable(FALSE);

  51.   aes_operate_mode_set(AES_OPMODE_DECRYPT);

  52.   aes_enable(TRUE);
  53.   /* data phase */
  54.   for(i=0; i< buf_len / 16; i++)
  55.   {
  56.     aes_data_input((uint32_t *)encrypt_buf + i * 4);
  57.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  58.     aes_flag_clear(AES_PDFS_FLAG);
  59.     aes_data_output((uint32_t *)decrypt_buf + i * 4);
  60.   }
  61.   if(buf_len % 16 != 0)
  62.   {
  63.     aes_data_input((uint32_t *)encrypt_buf + i * 4);
  64.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  65.     aes_flag_clear(AES_PDFS_FLAG);
  66.     aes_data_output((uint32_t *)decrypt_buf + i * 4);
  67.   }
  68.   aes_enable(FALSE);
  69. #endif
  70. }
复制代码

4.3.4       CBC decryption using DMA
  1. void aes_decrypt_process(uint8_t* decrypt_buf, uint8_t* encrypt_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;
  4.   
  5.   aes_reset();
  6. #if (OPERATE_MODE == 1)
  7.   uint32_t i;
  8.   aes_default_para_init(&aes_init_struct);
  9.   aes_init_struct.operate_mode = AES_OPMODE_KEY_SCHEDULING_DECRYPT;
  10.   aes_init_struct.chaining_mode = AES_CHMODE_CBC;
  11.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  12.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  13.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  14.   aes_init(&aes_init_struct);
  15.   aes_suspend_info_init();
  16.   aes_iv_set(iv_buf);

  17.   /* data phase */
  18.   for(i=0; i< buf_len / 16; i++)
  19.   {
  20.     aes_dma_config((uint8_t *)decrypt_buf + i * 16, (uint8_t *)encrypt_buf + i * 16, 16);
  21.     aes_dma_in_enable(TRUE);
  22.     aes_dma_out_enable(TRUE);
  23.     aes_enable(TRUE);
  24.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  25.     aes_flag_clear(AES_PDFS_FLAG);  
  26.     aes_dma_in_enable(FALSE);
  27.     aes_dma_out_enable(FALSE);   
  28.     aes_enable(FALSE);
  29.   }
  30.   if(buf_len % 16 != 0)
  31.   {
  32.     aes_dma_config((uint8_t *)decrypt_buf + i * 16, (uint8_t *)encrypt_buf + i * 16, 16);
  33.     aes_dma_in_enable(TRUE);
  34.     aes_dma_out_enable(TRUE);
  35.     aes_enable(TRUE);
  36.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  37.     aes_flag_clear(AES_PDFS_FLAG);  
  38.     aes_dma_in_enable(FALSE);
  39.     aes_dma_out_enable(FALSE);   
  40.     aes_enable(FALSE);
  41.   }
  42. #else
  43.   aes_default_para_init(&aes_init_struct);
  44.   aes_init_struct.operate_mode = AES_OPMODE_KEY_SCHEDULING;
  45.   aes_init_struct.chaining_mode = AES_CHMODE_CBC;
  46.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  47.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  48.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  49.   aes_init(&aes_init_struct);
  50.   aes_suspend_info_init();
  51.   aes_iv_set(iv_buf);
  52.   
  53.   aes_enable(TRUE);
  54.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  55.   aes_flag_clear(AES_PDFS_FLAG);
  56.   aes_enable(FALSE);

  57.   aes_operate_mode_set(AES_OPMODE_DECRYPT);

  58.   /* data phase */
  59.   if(buf_len % 16 != 0)
  60.     buf_len += (16 - buf_len % 16);
  61.   aes_dma_config(decrypt_buf, encrypt_buf, buf_len);
  62.   aes_dma_in_enable(TRUE);
  63.   aes_dma_out_enable(TRUE);
  64.   aes_enable(TRUE);
  65.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  66.   aes_flag_clear(AES_PDFS_FLAG);
  67.   aes_dma_in_enable(FALSE);
  68.   aes_dma_out_enable(FALSE);
  69.   aes_enable(FALSE);
  70. #endif
  71. }
复制代码

4.4           实验效果
将原始数据经过加密并解密后的数据与原始数据进行对比,对比结果正确则LED2会闪烁,否则LED4闪烁。
5                 案例 CTR模式5.1           功能简介
计数器模式 (CTR)CTR摸式是一种通过将逐次累加的计数器进行加密来生成密钥流的流密码。下面将介绍如何使用CTR工作串接模式进行数据的加解密。
5.2           资源准备
1) 硬件环境:
对应产品型号的AT-START BOARD
2) 软件环境
分别提供了CPUDMA两种数据填充方式的案例代码:
project\at_start_f4xx\examples\aes\ctr
project\at_start_f4xx\examples\aes\ctr_using_dma
另提供了DMA数据填充并使用AES中断的案例代码:
project\at_start_f457\examples\aes\ctr_using_interrupt
5.3           软件设计
由于计数器模式是以加密计数器之内容产生密钥流分组,故与电子密码本模式和密码块链接模式不同,计数器模式解密之前,无须进行密钥扩展,加解密以两个阶段进行:准备阶段和加解密阶段。
5.3.1       CTR encryption
  1. void aes_encrypt_process(uint8_t* encrypt_buf, uint8_t* original_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;
  4.   uint32_t temp_block_buf[4];
  5.   uint32_t i;

  6.   aes_reset();
  7.   aes_default_para_init(&aes_init_struct);
  8.   aes_init_struct.operate_mode = AES_OPMODE_ENCRYPT;
  9.   aes_init_struct.chaining_mode = AES_CHMODE_CTR;
  10.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  11.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  12.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  13.   aes_init(&aes_init_struct);
  14.   aes_suspend_info_init();
  15.   aes_iv_set(iv_buf);

  16.   /* data phase */
  17.   aes_enable(TRUE);
  18.   for(i=0; i< buf_len / 16; i++)
  19.   {
  20.     aes_data_input((uint32_t *)original_buf + i * 4);
  21.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  22.     aes_flag_clear(AES_PDFS_FLAG);
  23.     aes_data_output((uint32_t *)encrypt_buf + i * 4);
  24.   }
  25.   if(buf_len % 16 != 0)
  26.   {
  27.     memcpy((uint8_t *)temp_block_buf, (uint8_t *)original_buf + i * 16, (buf_len % 16));
  28.     memset((uint8_t *)temp_block_buf + (buf_len % 16), 0, 16 - buf_len % 16);   
  29.     aes_data_input((uint32_t *)temp_block_buf);
  30.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  31.     aes_flag_clear(AES_PDFS_FLAG);
  32.     aes_data_output((uint32_t *)encrypt_buf + i * 4);
  33.   }
  34.   aes_enable(FALSE);
  35. }
复制代码



5.3.2       CTR encryption using DMA
  1. void aes_encrypt_process(uint8_t* encrypt_buf, uint8_t* original_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;

  4.   aes_reset();
  5.   aes_default_para_init(&aes_init_struct);
  6.   aes_init_struct.operate_mode = AES_OPMODE_ENCRYPT;
  7.   aes_init_struct.chaining_mode = AES_CHMODE_CTR;
  8.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  9.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  10.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  11.   aes_init(&aes_init_struct);
  12.   aes_suspend_info_init();
  13.   aes_iv_set(iv_buf);

  14.   /* data phase */
  15.   aes_dma_config((uint8_t *)encrypt_buf, (uint8_t *)original_buf, buf_len);
  16.   aes_dma_in_enable(TRUE);
  17.   aes_dma_out_enable(TRUE);
  18.   aes_enable(TRUE);
  19.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  20.   aes_flag_clear(AES_PDFS_FLAG);  
  21.   aes_dma_in_enable(FALSE);
  22.   aes_dma_out_enable(FALSE);   
  23.   aes_enable(FALSE);
  24. }
复制代码

5.3.3       CTR decryption
  1. void aes_decrypt_process(uint8_t* decrypt_buf, uint8_t* encrypt_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;
  4.   uint32_t i;

  5.   aes_reset();
  6.   aes_default_para_init(&aes_init_struct);
  7.   aes_init_struct.operate_mode = AES_OPMODE_DECRYPT;
  8.   aes_init_struct.chaining_mode = AES_CHMODE_CTR;
  9.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  10.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  11.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  12.   aes_init(&aes_init_struct);
  13.   aes_suspend_info_init();
  14.   aes_iv_set(iv_buf);

  15.   /* data phase */
  16.   aes_enable(TRUE);
  17.   for(i=0; i< buf_len / 4; i++)
  18.   {
  19.     aes_data_input((uint32_t *)encrypt_buf + i * 4);
  20.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  21.     aes_flag_clear(AES_PDFS_FLAG);
  22.     aes_data_output((uint32_t *)decrypt_buf + i * 4);
  23.   }
  24.   if(buf_len % 16 != 0)
  25.   {
  26.     aes_enable(TRUE);
  27.     aes_data_input((uint32_t *)encrypt_buf + i * 4);
  28.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  29.     aes_flag_clear(AES_PDFS_FLAG);
  30.     aes_data_output((uint32_t *)decrypt_buf + i * 4);
  31.     aes_enable(FALSE);
  32.   }
  33.   aes_enable(FALSE);
  34. }
复制代码



5.3.4       CTR decryption using DMA
  1. void aes_decrypt_process(uint8_t* decrypt_buf, uint8_t* encrypt_buf, uint32_t buf_len)
  2. {
  3.   aes_init_type aes_init_struct;

  4.   aes_reset();
  5.   aes_default_para_init(&aes_init_struct);
  6.   aes_init_struct.operate_mode = AES_OPMODE_DECRYPT;
  7.   aes_init_struct.chaining_mode = AES_CHMODE_CTR;
  8.   aes_init_struct.key_len = AES_KEY_LENGTH_128;
  9.   aes_init_struct.key_buf = (uint32_t *)key_buf;
  10.   aes_init_struct.data_swap_mode = AES_SWAP_TYPE_NONE;
  11.   aes_init(&aes_init_struct);
  12.   aes_suspend_info_init();
  13.   aes_iv_set(iv_buf);

  14.   /* data phase */
  15.   if(buf_len % 16 != 0)
  16.     buf_len += (16 - buf_len % 16);
  17.   aes_dma_config((uint8_t *)decrypt_buf, (uint8_t *)encrypt_buf, buf_len);
  18.   aes_dma_in_enable(TRUE);
  19.   aes_dma_out_enable(TRUE);
  20.   aes_enable(TRUE);
  21.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  22.   aes_flag_clear(AES_PDFS_FLAG);  
  23.   aes_dma_in_enable(FALSE);
  24.   aes_dma_out_enable(FALSE);   
  25.   aes_enable(FALSE);
  26. }
复制代码

5.3.5       CTR interrupt handler
  1. void AES_IRQHandler(void)
  2. {
  3.   if(aes_interrupt_flag_get(AES_PDFS_FLAG) != RESET)
  4.   {
  5.     aes_flag_clear(AES_PDFS_FLAG);
  6.     aes_dma_in_enable(FALSE);
  7.     aes_dma_out_enable(FALSE);
  8.     aes_enable(FALSE);
  9.     crypt_done = SET;
  10.   }
  11.   if(aes_interrupt_flag_get(AES_REFS_FLAG) != RESET)
  12.   {
  13.     aes_flag_clear(AES_REFS_FLAG);
  14.     /* add user code */
  15.   }
  16.   if(aes_interrupt_flag_get(AES_WEFS_FLAG) != RESET)
  17.   {
  18.     aes_flag_clear(AES_WEFS_FLAG);
  19.     /* add user code */
  20.   }
  21. }
复制代码

5.4           实验效果
将原始数据经过加密并解密后的数据与原始数据进行对比,对比结果正确则LED2会闪烁,否则LED4闪烁。
6                 案例 GCM模式6.1           功能简介
GCM中的G就是指GMACC就是指CTRGCM可以提供对消息的加密和完整性校验,另外,它还可以提供附加消息的完整性校验。在实际应用场景中,有些信息是我们不需要保密,但信息的接收者需要确认它的真实性的,例如源IP,来源端口,目的IPIV,等等。因此,我们可以将这一部分作为附加消息加入到MAC值的计算当中。下面将介绍如何使用GCM工作串接模式进行数据的加解密。
6.2           资源准备
1) 硬件环境:
对应产品型号的AT-START BOARD
2) 软件环境
分别提供了CPUDMA两种数据填充方式的案例代码:
project\at_start_f4xx\examples\aes\gcm
project\at_start_f4xx\examples\aes\gcm_using_dma
6.3           软件设计
使用AES硬件加速器进行GCM模式可分为以下四个部分:prepare stageassoc stagedata stagetag stage,四个部分设置操作将分别描述于本章节。
因为使用AES硬件加速器进行GCM模式有四部阶段,所以四个阶段进行切换时,须注意DMA/NDD的设置的更新。
6.3.1       GCM prepare stage
  1. /* prepare stage */
  2. aes_default_para_init(&aes_init_struct);
  3. aes_init_struct.operate_mode = USR_OPR_MODE;
  4. aes_init_struct.chaining_mode = AES_CHMODE_GCM;
  5. aes_init_struct.key_len = USR_KEY_SZ;
  6. aes_init_struct.key_buf = (uint32_t *) USR_KEY_BUF;
  7. aes_init_struct.data_swap_mode = USR_SWAP_TYPE;
  8. aes_init(&aes_init_struct);
  9. aes_suspend_info_init();
  10. iv_buf[3] = AES_GCM_IV_COUNT0;
  11. aes_iv_set(iv_buf);

  12. /* ghash init stage */
  13. aes_processing_stage_set(AES_PRC_INIT);
  14. aes_enable(TRUE);
  15. while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  16. aes_flag_clear(AES_PDFS_FLAG);
  17. aes_enable(FALSE);
复制代码

6.3.2       GCM assoc stage
  1. /* assoc stage */
  2. if(aad_len)
  3. {
  4.   aes_processing_stage_set(AES_PRC_ASSOC);
  5.   aes_enable(TRUE);
  6.   for(i = 0; i < aad_len / 16; i++)
  7.   {
  8.     aes_data_input((uint32_t *)aad_buf + i * 4);
  9.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  10.     aes_flag_clear(AES_PDFS_FLAG);  
  11.   }
  12.   if(aad_len % 16 != 0)
  13.   {
  14.     aes_dummy_data_num_set(16 - aad_len % 16);
  15.     aes_last_block_enable(TRUE);
  16.     memcpy((uint8_t *)temp_block_buf, (uint8_t *)aad_buf + i * 16, (aad_len % 16));
  17.     memset((uint8_t *)temp_block_buf + (aad_len % 16), 0, 16 - aad_len % 16);
  18.     aes_data_input((uint32_t *)temp_block_buf);
  19.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  20.     aes_flag_clear(AES_PDFS_FLAG);
  21.     while(aes_flag_get(AES_NZDFS_FLAG) == RESET);
  22.     aes_flag_clear(AES_NZDFS_FLAG);   
  23.   }
  24.   aes_enable(FALSE);
  25. }
复制代码

6.3.3       GCM assoc stage using DMA
  1. /* assoc stage */
  2. if(aad_len)
  3. {
  4.   aes_processing_stage_set(AES_PRC_ASSOC);
  5.   aes_dummy_data_num_set(0);
  6.   aes_dma_config(0, (uint8_t *)aad_buf, aad_len, AES_PRC_ASSOC);
  7.   aes_dma_in_enable(TRUE);
  8.   aes_dma_out_enable(TRUE);
  9.   aes_enable(TRUE);
  10.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  11.   aes_flag_clear(AES_PDFS_FLAG);  
  12.   aes_dma_in_enable(FALSE);
  13.   aes_dma_out_enable(FALSE);   
  14.   aes_enable(FALSE);
  15. }
复制代码

6.3.4       GCM data stage
  1. /* data stage */
  2. aes_processing_stage_set(AES_PRC_DATA);
  3. aes_enable(TRUE);
  4. for(i = 0; i < buf_len / 16; i++)
  5. {
  6.   aes_data_input((uint32_t *)original_buf + i * 4);
  7.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  8.   aes_flag_clear(AES_PDFS_FLAG);
  9.   aes_data_output((uint32_t *)encrypt_buf + i * 4);
  10. }

  11. /* last block stage */
  12. if(buf_len % 16 != 0)
  13. {
  14.   aes_dummy_data_num_set(16 - buf_len % 16);
  15.   aes_last_block_enable(TRUE);   
  16.   memcpy((uint8_t *)temp_block_buf, (uint8_t *)original_buf + i * 16, (buf_len % 16));
  17.   memset((uint8_t *)temp_block_buf + (buf_len % 16), 0, 16 - buf_len % 16);   
  18.   aes_data_input((uint32_t *)temp_block_buf);
  19.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  20.   aes_flag_clear(AES_PDFS_FLAG);
  21.   while(aes_flag_get(AES_NZDFS_FLAG) == RESET);
  22.   aes_flag_clear(AES_NZDFS_FLAG);
  23.   aes_data_output((uint32_t *)encrypt_buf + i * 4);
  24. }
  25. aes_enable(FALSE);
复制代码

6.3.5       GCM data stage using DMA
  1. /* data stage */
  2. aes_processing_stage_set(AES_PRC_DATA);
  3. if(buf_len / 16 > 0)
  4. {
  5.   /* dma is used when data length at least 16 bytes */
  6.   aes_dma_config(encrypt_buf, original_buf, buf_len, AES_PRC_DATA);
  7.   aes_dma_in_enable(TRUE);
  8.   aes_dma_out_enable(TRUE);
  9.   aes_enable(TRUE);
  10.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  11.   aes_flag_clear(AES_PDFS_FLAG);
  12.   aes_dma_in_enable(FALSE);
  13.   aes_dma_out_enable(FALSE);
  14.   aes_enable(FALSE);
  15. }

  16. /* last block stage */
  17. if(buf_len % 16 != 0)
  18. {
  19.   aes_dummy_data_num_set(16 - buf_len % 16);
  20.   aes_last_block_enable(TRUE);   
  21.   memcpy((uint8_t *)temp_block_buf, (uint8_t *)original_buf + (buf_len / 16 * 16), (buf_len % 16));
  22.   memset((uint8_t *)temp_block_buf + (buf_len % 16), 0, 16 - buf_len % 16);   
  23.   aes_enable(TRUE);
  24.   aes_data_input((uint32_t *)temp_block_buf);
  25.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  26.   aes_flag_clear(AES_PDFS_FLAG);
  27.   while(aes_flag_get(AES_NZDFS_FLAG) == RESET);
  28.   aes_flag_clear(AES_NZDFS_FLAG);
  29.   aes_data_output((uint32_t *)(encrypt_buf + (buf_len / 16 * 16)));
  30.   aes_enable(FALSE);
  31. }
复制代码

6.3.6       GCM tag stage
  1. /* tag stage */
  2. aes_processing_stage_set(AES_PRC_TAG);
  3. final_block_process(aad_len, buf_len, (uint8_t *)temp_block_buf);
  4. aes_enable(TRUE);
  5. aes_data_input((uint32_t *)temp_block_buf);
  6. while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  7. aes_flag_clear(AES_PDFS_FLAG);
  8. aes_data_output((uint32_t *)tag_buf);
  9. aes_enable(FALSE);
复制代码

6.4           实验效果
1.      将原始数据经过加密并解密后的数据与原始数据进行对比;
2.      将加密和解密得到的TAG标签进行对比;
以上两项对比结果正确则LED2会闪烁,否则LED4闪烁。
7                 案例 CCM模式7.1           功能简介
CCM模式,全称是Counter withCipher Block Chaining-Message Authentication Code,是CTR工作模式和CMAC认证算法的组合体,可以同时数据加密和鉴别服务。下面将介绍如何使用CCM工作串接模式进行数据的加解密。
7.2           资源准备
1) 硬件环境:
对应产品型号的AT-START BOARD
2) 软件环境
分别提供了CPUDMA两种数据填充方式的案例代码:
project\at_start_f4xx\examples\aes\ccm
project\at_start_f4xx\examples\aes\ccm_using_dma
7.3           软件设计
使用AES硬件加速器进行CCM模式可分为以下四个阶段:prepare stage,assoc stage,data stage,tag stage,四个部分设置操作将分别描述于本章节。
以下对应CCM模式的四部阶段,提供操作方式。在四个阶段进行切换时,须注意DMA或NDD的设置更新。
7.3.1       CCM prepare stage
  1. /* prepare stage */
  2. aes_default_para_init(&aes_init_struct);
  3. aes_init_struct.operate_mode = USR_OPR_MODE;
  4. aes_init_struct.chaining_mode = AES_CHMODE_CCM;
  5. aes_init_struct.key_len = USR_KEY_SZ;
  6. aes_init_struct.key_buf = (uint32_t *) USR_KEY_BUF;
  7. aes_init_struct.data_swap_mode = USR_SWAP_TYPE;
  8. aes_init(&aes_init_struct);
  9. aes_suspend_info_init();
  10. aes_ccm_iv_process();
复制代码

注:示例代码中USR_XX_XX内容是需要用户自行添加、修改的内容,下同
7.3.2       CCM assoc stage
在这个阶段中,用户须将对应的数据内容转换成符合CCM的格式规范。在BSP中提供的aes_ccm_bx_process函数,可以帮助用户依序得到assoc stage需要的资料内容。使用方式参照如下:
  1. /* assoc stage */
  2. if(aad_len)
  3. {
  4.    aes_ccm_bx_init();
  5.   do
  6.   {
  7.     if(aes_ccm_bx_process() == RESET)
  8.     {
  9.       /* end of phase assoc */
  10.       break;
  11.     }
  12.     aes_data_input((uint32_t *)ccm_b0_buf);
  13.     while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  14.     aes_flag_clear(AES_PDFS_FLAG);
  15.   }
  16.   while(1);
  17.   aes_enable(FALSE);
  18. }
  19. else
  20. {
  21.   aes_processing_stage_set(AES_PRC_ASSOC);
  22.   aes_enable(TRUE);
  23.   aes_data_input((uint32_t *)ccm_b0_buf);
  24.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  25.   aes_flag_clear(AES_PDFS_FLAG);
  26.   aes_enable(FALSE);
  27. }
复制代码



7.3.3       CCM data stage
如果没有需要处理的数据,可以略过此阶段。
  1. /* data stage */
  2. aes_processing_stage_set(AES_PRC_DATA);
  3. aes_enable(TRUE);
  4. for(i = 0; i < buf_len / 16; i++)
  5. {
  6.   aes_data_input((uint32_t *)encrypt_buf + i * 4);
  7.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  8.   aes_flag_clear(AES_PDFS_FLAG);
  9.   aes_data_output((uint32_t *)decrypt_buf + i * 4);
  10. }

  11. /* last block stage */  
  12. if(buf_len % 16 != 0)
  13. {
  14.   aes_dummy_data_num_set(16 - buf_len % 16);
  15.   aes_last_block_enable(TRUE);
  16.   aes_data_input((uint32_t *)encrypt_buf + i * 4);
  17.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  18.   aes_flag_clear(AES_PDFS_FLAG);
  19.   while(aes_flag_get(AES_NZDFS_FLAG) == RESET);
  20.   aes_flag_clear(AES_NZDFS_FLAG);
  21.   aes_data_output((uint32_t *)decrypt_buf + i * 4);
  22. }
  23. aes_enable(FALSE);
复制代码


7.3.4       CCM data stage using DMA
  1. /* data stage */
  2. aes_processing_stage_set(AES_PRC_DATA);
  3. if(buf_len / 16 > 0)
  4. {
  5.   /* dma is used when data length at least 16 bytes */
  6.   aes_dummy_data_num_set(0);
  7.   aes_dma_in_enable(TRUE);
  8.   aes_dma_out_enable(TRUE);
  9.   aes_dma_config(encrypt_buf, original_buf, buf_len);
  10.   aes_enable(TRUE);
  11.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  12.   aes_flag_clear(AES_PDFS_FLAG);
  13.   aes_dma_in_enable(FALSE);
  14.   aes_dma_out_enable(FALSE);
  15.   aes_enable(FALSE);
  16. }

  17. /* last block stage */
  18. if(buf_len % 16 != 0)
  19. {
  20.   aes_dummy_data_num_set(16 - buf_len % 16);
  21.   aes_last_block_enable(TRUE);   
  22.   memcpy((uint8_t *)temp_block_buf, (uint8_t *)original_buf + (buf_len / 16 * 16), (buf_len % 16));
  23.   memset((uint8_t *)temp_block_buf + (buf_len % 16), 0, 16 - buf_len % 16);   
  24.   aes_enable(TRUE);
  25.   aes_data_input((uint32_t *)temp_block_buf);
  26.   while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  27.   aes_flag_clear(AES_PDFS_FLAG);
  28.   while(aes_flag_get(AES_NZDFS_FLAG) == RESET);
  29.   aes_flag_clear(AES_NZDFS_FLAG);
  30.   aes_data_output((uint32_t *)(encrypt_buf + (buf_len / 16 * 16)));
  31.   aes_enable(FALSE);
  32. }
复制代码

7.3.5       CCM tag stage
  1. /* tag stage */
  2. aes_processing_stage_set(AES_PRC_TAG);
  3. aes_enable(TRUE);
  4. aes_data_input((uint32_t *)ccm_ctr0_buf);
  5. while(aes_flag_get(AES_PDFS_FLAG) == RESET);
  6. aes_flag_clear(AES_PDFS_FLAG);
  7. aes_data_output((uint32_t *)tag_buf);
  8. aes_enable(FALSE);
复制代码

7.4           实验效果
1.      将原始数据经过加密并解密后的数据与原始数据进行对比;
2.      将加密和解密得到的TAG标签进行对比;
以上两项对比结果正确则LED2会闪烁,否则LED4闪烁。







回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

如发现本坛存在违规或侵权内容, 请点击这里发送邮件举报 (或致电020-38271790)。请提供侵权说明和联系方式。我们将及时审核依法处理,感谢配合。

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-8-25 18:12

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表