一、AES简介
AES 加解密算法是一个密钥迭代分组密码,包含了轮变换对状态的重复作用。加密过程的轮变换由四个操作组成:SubBytes、ShiftRows、MixColumns、AddRoundKey。其中,SubBytes 是求每个字节在 GF(2^8)中的模逆元和一个仿射变换;ShiftRows 是一个字节换位,它将状态中的行按照不同的偏移量进行循环移位;MixColumns 对状态各列进行线性变换;AddRoundKey,状态中的各字节与轮密钥进行逐位异或操作。下图所示是加密流程的示意图:
上图中Sub_Key 是指每一轮的子密钥,除了初始变换用初始密钥外,后面的轮变换所用子密钥需要由初始密钥扩展而来,且密钥的扩展过程和加密过程是同步进行的。由于明文固定为 128bits,加密过程运行的轮数就取决于密钥的长度。比如,密钥为128bits 时,运行轮数为 10 轮;密钥为 192bits 时,运行轮数为 12 轮;密钥为 256bits时,运行轮数为 14 轮。除了最后一轮缺少 MixColumn 变换,其余各轮均进行完整的轮变换操作。本产品搭载的 AES 仅支持 128bits 密钥长度的加解密过程。解密流程与加密流程有所区别,首先必须完成所有密钥的扩展,解密过程从扩展的最后一轮子密钥往回使用,然后轮变换的四个操作变成了相应的逆运算:InvSubBytes、InvShiftRows、InvMixColumns、AddRoundKey。InvSubBytes 中的模逆运算仍然保持,但仿射变换改为逆变换;InvShiftRows 和 InvMixColumns 变成相应的逆变换;AddRoundKey 保持不变
二、操作流程
1.加密操作流程
AES 的加密操作流程例如下:
1) 将128bits 明文写入数据寄存器(AES_DR)中。
2) 将加密密钥写入密钥寄存器(AES_KR)中。
3) 设置控制寄存器(AES_CR)中的各位,包括:
a) 将 CR.Mode 设置为0
b) 向AES_CR.START 写入1,启动模块进行运算
注:步骤 a, b 可同时进行
4) 判断模块运算是否结束。
不断读取AES_CR.START,如果其值变为0,则表示运算结束
5) 读取数据寄存器(AES_DR),获得 128 位密文。
6) 如果要继续进行新的运算,回到步骤1),否则结束
2.解密操作流程
AES 的解密操作流程例如下:
1) 将 128bits 密文写入数据寄存器(AES_DR)中。
2) 将解密密钥写入密钥寄存器(AES_KR)中。
3) 设置控制寄存器(AES_CR)中的各位,包括:
a) 将CR.Mode 设置为1
b) 向AES_CR.START 写入1,启动模块进行运算
注:步骤 a, b 可同时进行
4) 判断模块运算是否结束。
不断读取 AES_CR.START,如果其值变为0,则表示运算结束
5) 读取数据寄存器(AES_DR),获得 128 位明文。
6) 如果要继续进行新的运算,回到步骤1),否则结束。
3.加密解密时间
AES 模块从启动一次运算(AES_CR.START 写入1)到该次运算结束(AES_CR.START恢复到0)所需时间如下:
4.操作注意事项
1) 上电后,本模块进行一次异步复位操作。时钟需在复位脱离前稳定有效,并且在后续运行中持续稳定。
2) 在加解密过程中,数据寄存器会改变,如果下次运算操作的数据就是本次运算的结果,就无需重新写入数据。
3) 在用相同的密钥加解密大量数据的情况下,不需要重复写入密钥。
4) 判断模块运算结束的方法:不断读取 AES_CR.START,如果其值变为0,则表示运算结束。
三、测试
测试程序如下:
/*******************************************************************************
* Copyright (C) 2020, Huada Semiconductor Co., Ltd. All rights reserved.
*
* This software component is licensed by HDSC under BSD 3-Clause license
* (the "License"); You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*/
/******************************************************************************/
/** \file main.c
**
** \brief This sample demonstrates how to set GPIO as output function.
**
** - 2021-04-16 CDT first version for Device Driver Library of GPIO.
**
******************************************************************************/
/*******************************************************************************
* Include files
******************************************************************************/
#include "hc32_ddl.h"
#include "ev_hc32f460_lqfp100_v1.h"
#include "TIM_Measure.h"
/*******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/
/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
/* AES key length in bytes is 16. */
#define AES_KEYLEN ((uint8_t)16)
/*******************************************************************************
* Global variable definitions (declared in header file with 'extern')
******************************************************************************/
/*******************************************************************************
* Local function prototypes ('static')
******************************************************************************/
/*******************************************************************************
* Local variable definitions ('static')
******************************************************************************/
float t = 0.0f;
const static uint8_t m_au8AesKey[AES_KEYLEN] =
{
0x12, 0x34, 0x56, 0x78, 0x9A, 0xCD, 0xEF,
0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7
};
/* Word alignment. */
__ALIGN_BEGIN static uint8_t m_au8Plaintext[64u] = {0u};
__ALIGN_BEGIN static uint8_t m_au8Ciphertext[64u];
/*******************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/
/**
*******************************************************************************
** \brief Main function of GPIO output
**
** \param None
**
** \retval int32_t Return value, if needed
**
******************************************************************************/
int32_t main(void)
{
uint32_t i;
BSP_CLK_Init();
DDL_PrintfInit(BSP_PRINTF_DEVICE, BSP_PRINTF_BAUDRATE, BSP_PRINTF_PortInit);
TIM_Measure_Init();
/* Enable AES peripheral clock. */
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AES, Enable);
for (i = 0u; i < sizeof(m_au8Plaintext); i++)
{
m_au8Plaintext[i] = (uint8_t)(i + 1u);
}
while(1)
{
TIM_Measure_Start();
/* AES encryption. */
AES_Encrypt(m_au8Plaintext, sizeof(m_au8Plaintext), m_au8AesKey, m_au8Ciphertext);
TIM_Measure_Stop();
t = Get_Time();
DDL_Printf("AES_Encrypt use time: %fus\n",t*1000.0f);
DDL_Printf("AES encryption.\n");
DDL_Printf("Plaintext:\n");
for (i = 0u; i < sizeof(m_au8Plaintext); i++)
{
DDL_Printf("%.2x ", m_au8Plaintext[i]);
}
DDL_Printf("\n");
DDL_Printf("Ciphertext:\n");
for (i = 0u; i < sizeof(m_au8Ciphertext); i++)
{
DDL_Printf("%.2x ", m_au8Ciphertext[i]);
}
DDL_Printf("\n\n");
/* AES decryption. */
DDL_Printf("AES decryption.\n");
TIM_Measure_Start();
AES_Decrypt(m_au8Ciphertext, sizeof(m_au8Ciphertext), m_au8AesKey, m_au8Plaintext);
TIM_Measure_Stop();
t = Get_Time();
DDL_Printf("AES_Decrypt use time: %fus\n",t*1000.0f);
DDL_Printf("Ciphertext:\n");
for (i = 0u; i < sizeof(m_au8Ciphertext); i++)
{
DDL_Printf("%.2x ", m_au8Ciphertext[i]);
}
DDL_Printf("\n");
DDL_Printf("Plaintext:\n");
for (i = 0u; i < sizeof(m_au8Plaintext); i++)
{
DDL_Printf("%.2x ", m_au8Plaintext[i]);
}
DDL_Printf("\n\n");
while(1);
};
}
/*******************************************************************************
* EOF (not truncated)
******************************************************************************/
编译运行:
和网上的运行结果比较:
可以看出结果正确。至于运行时间和说明书中有差异,主要是填充数据比较耗时,实际计算不费时间。
HC32F460_AES.zip
(700.99 KB)
|