CRYP简介
MCU加/解密可分为对称加/解密、非对称加/解密、以及HASH算法,以上加/解密算法均可通过CAVP FIPS认证,用于各类安全相关应用。其中,包含DES、三重DES(TDES)或AES(128、192或256)等算法的加密处理器(CRYP)即为对称加/解密算法。通过CRYP,可实现对数据进行加密或解密,且该加密处理器完全兼容下列标准:
·联邦信息处理标准出版物“FIPS PUB 46-3,1999年10月25日”规定的数据加密标准(DES和TDES)。它遵循美国国家标准协会(ANSI)X9.52标准。
·联邦信息处理标准出版物(FIPS PUB 197,2001年11月26日)规定的高级加密标准(AES)。
CRYP处理器可在电子密码本(ECB)模式或加密分组链接(CBC)模式下使用DES和TDES算法执行数据加密和解密。
CRYP外设为32位AHB2外设。它支持传入数据和已处理数据的DMA传输,并具有输入和输出FIFO(分别为8个字深),本次例程采用DES128 ECB算法进行验证,文章将着重讲解该部分,其余算法详见参考手册。
CRYP 主要特性
·适用于AES、DES和TDES加密和解密操作
·DES
-直接执行简单DES算法(使用单一密钥K1)
-支持ECB和CBC链接算法
-支持64位、128位和192位密钥(包括奇偶校验)
-支持在CBC模式下使用的2×32位初始化向量(IV)
-使用DES处理一个64位块需要16个HCLK周期
CRYP功能说明
加密处理器可实现TDES(同样支持DES)内核和AES加密内核。
由于TDES和AES算法使用块密码,因此,加密前需对不完整的输入数据块进行填充(应将额外的位附加到数据串的尾端),解密后需要丢弃填充项。硬件不处理填充操作,需要通过软件进行处理。图1显示了加密处理器的框图。
图1 加密处理器框图
1.DES加密内核
--DES加密内核由三部分组成
·DES算法(DEA)
·初始化向量(在CBC模式中使用)
·DES模式:密钥=[K1]
--DES和TDES电子密码本(DES/TDES-ECB)模式
·DES-ECB模式加密
DES电子密码本(DES/TDES-ECB)模式中的加密是通过64位明文数据块(P)经过位/字节/半字交换(请参见1.3.2节:数据类型的表1)后作为输入块(I)。输入块通过DEA在加密状态下使用K1进行加密处理。
若是TDES,则会将上述处理过程的输出会直接反馈到DEA的输入,在解密状态下使用K2执行DES,然后重复将上一步处理的输出反馈到DEA的输入,在加密状态下使用K3执行DES,最后生成的64位输出块(O)在执行位/字节/半字交换之后,以密文(C)形式推入OUT FIFO,加密流程如图2所示。
图2 DES-ECB模式加密
①K:密钥;C:密文;I:输入块;O:输出块;P:明文。
·DES/TDES-ECB模式解密
图3介绍了DES-ECB解密流程,64位密文(C)经过位/字节/半字交换后,作为输入块(I),而该密钥序列将使用与加密过程相反的密钥序列来实现。输入块通过DEA在解密状态下使用K3进行解密处理,然后,将上述处理过程的输出会直接反馈到DEA的输入,在加密状态下使用K2执行DES,使得新结果会直接反馈到DEA的输入,在解密状态下使用K1执行DES,最后,将生成的64位输出块(O)再进行位/字节/半字交换后,产生明文(P),以上便是解密过程。
图3 DES-ECB 模式解密
①K:密钥;C:密文;I:输入块;O:输出块;P:明文
2.数据类型
将数据写入CRYP_DIN寄存器时,会一次性向CRYP处理器输入32位(字)数据。由于DES的原则是每隔64位对数据流进行处理,因此,针对每个64位块,DES都会对其进行M1到M64的对位编号,其中M1为块最左侧的位,M64为块最右侧的位。
系统存储器结构采用小端模式:即无论使用何种数据类型(位、字节、16位半字、32位字),最低有效数据均占用最低地址位置。因此,对于从IN FIFO中读取的数据,在其进入CRYP处理器之前,必须对这些数据执行位、字节或半字交换操作(取决于要加密的数据类型)。在CRYP数据写入OUT FIFO之前,需要对其执行同样的交换操作。例如,对ASCII文本流执行字节交换操作。要处理的数据类型通过CRYP控制寄存器(CRYP_CR)中的DATATYPE位字段进行配置。
表1 数据类型
图4展示了根据不同的DATATYPE值,CRYP处理器是如何将IN FIFO中弹出的两个连续32位字构建成64位数据块M1...64的过程。同理,也可用该方法扩展构建用于AES加密算法的128位数据块(对于AES,块长度为四个32位字,但由于交换仅发生在字级别,因此它与此处描述的TDES的交换过程相同),本文不再赘述。
注意:IN FIFO和CRYP数据块之间,以及CRYP数据块和OUT FIFO之间执行相同的交换操作。
图4 根据DATATYPE构建64位块
3.初始化向量——CRYP_IV0...1(L/R)
初始化向量可视为两个64位数据项,因此,初始化向量在系统存储器中的数据格式和表示形式均不同于明文或密码数据,而且它们不受DATATYPE值的影响。初始化向量采用两个连续的32位字进行定义,即CRYP_IVL(左部分,记为位IV1...32)和CRYP_IVR(右部分,记为位IV33...64)。
以DES CBC算法为例,加密期间,CRYP_IV0(L/R)位会与一个64位数据块(即,数据块的M1...64位)进行异或运算,这里的64位数据块是根据DATATYPE值交换后从IN FIFO弹出的。当DEA3块的输出可用时,该输出值会复制到CRYP_IV0(L/R)向量,之后,这个新值与IN FIFO弹出的下一个64位数据块进行异或运算,以此类推。
在DES CBC解密期间,CRYP_IV0(L/R)位首先会与TDEA1块输出的64位数据块(即,M1...64位)进行异或运算,然后异或运算后的结果根据DATATYPE值进行交换并压入OUT FIFO。异或运算后的结果进行交换并压入OUT FIFO后,IN FIFO的输出会取代CRYP_IV0(L/R)值,然后IN FIFO执行弹出操作,随后可对新的64位数据块进行处理。
当CRYP_SR寄存器的BUSY位=1b时,针对CRYP_IV0...1(L/R)寄存器的任何写操作都会被忽略(CRYP_IV0...1(L/R)寄存器内容不会被修改),因此,在修改初始化向量之前,必须检查BUSY位是否等于0b。
4.CRYP忙碌状态
当输入FIFO中有充足的数据(至少有2个字可用于DES算法模式时)、输出FIFO中有充足的自由空间(至少有2个(DES/TDES)字位置),以及CRYP_CR寄存器中的位CRYPEN=1时,加密处理器会自动开始加密或解密过程(根据CRYP_CR寄存器中ALGODIR位的值)。
在此过程中,执行简易DES算法需16个AHB2时钟周期。在整个过程中,CRYP_SR寄存器的BUSY位始终置“1”。完成此过程后,CRYP内核会将两个(DES)字写入输出FIFO,并将BUSY位清零。在CBC、CTR模式下,还会更新初始化向量CRYP_IVx(L/R)R(x=0..3)。
当加密处理器繁忙时(CRYP_SR寄存器中的位BUSY=1b),会忽略针对密钥寄存器(CRYP_Kx(L/R)R,x=0..3)、初始化寄存器(CRYP_IVx(L/R)R,x=0..3)或CRYP_CR寄存器的位[9:2]的写操作,且不会修改这些寄存器,因此,不能在加密处理器处理数据块时修改其配置。不过,可以在BUSY=1时将CRYPEN位清零,这种情况下,只有完成正在进行的DES处理过程并将两个字的结果写入输出FIFO后才能将BUSY位清零。
注意:在DES模式下处理某个块时,如果输出FIFO已满并且输入FIFO至少含一个新块,则输入FIFO会弹出新块且BUSY位保持置1,直到有足够的空间可将这个新块存储到输出FIFO。
5.加密或解密执行步骤
--初始化
1) 初始化外设(在准备密钥之前必须输入密钥大小和密钥值,准备好密钥后,必须立即配置相应算法):
① 将对称密钥写入CRYP_KxL/R寄存器(需写入2到8个寄存器,具体取决于算法);
② 使用CRYP_CR寄存器中的DATATYPE位配置数据类型(1位、8位、16位或32位);
③ 使用CRYP_CR寄存器中的ALGOMODE位配置算法和链接(在ECB/CBC中为DES);
④ 使用CRYP_CR寄存器中的ALGODIR位配置方向(加密/解密);
2) 向CRYP_CR寄存器中的FFLUSH位写入1,刷新IN和OUT FIFO。
--DMA用于存储器数据传入和传出时的处理过程
1) 将DMA控制器配置为传输存储器中的输入数据,传输长度为消息的长度。当消息填充并非由外设进行管理时,消息长度必须为整个数量的数据块,数据传输均在突发模式下进行。DES中的突发长度为2个字,应将DMA配置为在完成输出数据传输时设置一个中断,以指示处理过程已结束;
2) 通过向CRYPEN位写入1来使能加密处理器,将CRYP_DMACR寄存器中的DIEN和DOEN位置1,以使能DMA请求;
3) 所有传输和处理过程均由DMA和加密处理器管理,DMA中断表示处理过程已完成,两个FIFO通常均为空,且BUSY=0;
--在中断期间通过CPU传输数据的处理过程
1) 将CRYP_IMSCR寄存器中的INIM和OUTIM位置1,以使能中断;
2) 将CRYP_CR寄存器中的CRYPEN位置1,以使能加密处理器;
3) 在中断中管理输入数据:将输入消息加载到IN FIFO,一次性可加载2个字或4个字,或者加载数据直到FIFO已满。当消息的最后一个字进入FIFO时,可通过将INIM位清零来禁止中断;
4) 在中断中管理输出数据:读取OUT FIFO中的输出消息。一次可读取1个块(2个字或4个字),或者读取数据直到FIFO为空。读取最后一个字后,INIM=0、BUSY=0且两个FIFO均为空(IFEM=1且OFNE=0)。将OUTIM位清零可禁止中断,而将CRYPEN位清零可禁止外设。
--不使用DMA也不使用中断时的处理过程
1) 将CRYP_CR寄存器中的CRYPEN位置1,以使能加密处理器;
2) 将首个块写入输入FIFO(2到8个字);
3) 重复以下步骤,直到处理完整个信息:
① 等待OFNE=1,然后读取输出FIFO(读取1个块,或FIFO为空为止);
② 等待IFNF=1,然后写入INFIFO(写入1个块,或FIFO已满为止;
处理过程结束时,BUSY=0且两个FIFO均为空(IFEM=1且OFNE=0),将CRYPEN位清零可禁止外设。
CRYP中断
CRYP可产生两个可单独屏蔽的中断源。这两个中断源共用同一个中断信号,且该中断信号是CRYP发出的唯一中断信号,用于驱动NVIC(嵌套向量中断控制器)。这一组合中断是两个单独屏蔽的中断源的或运算结果,如果下面列出的各个中断中的任何一个中断产生,则此组合中断即会产生。
通过更改CRYP_IMSCR寄存器中的屏蔽位,可单独使能或禁止各个中断源,将相应的屏蔽位置“1”以使能中断。
关于各个中断源的状态,通过CRYP_RISR寄存器可以读取原始中断状态,通过CRYP_MISR寄存器可以读取屏蔽中断状态。
--输出FIFO服务中断–OUTMIS
当输出FIFO中存在一个或多个(32位字)数据项时,即会产生输出FIFO服务中断。通过读取输出FIFO的数据,直到读完所有有效(32位)字,即可将此中断清除(即该中断的状态与OFNE(输出FIFO非空)标志一致)。
输出FIFO服务中断OUTMIS不是通过CRYP使能位使能,因此,如果输出FIFO非空,即使禁止CRYP之后也不会强制OUTMIS信号为低电平。
--输入FIFO服务中断–INMIS
当输入FIFO中少于四个字时,会产生输入FIFO服务中断,对输入FIFO执行写操作直到其中所含字不小于四字,这样即可将此中断清除。
输入FIFO服务中断INMIS通过CRYP使能位使能,因此,禁止CRYP之后,即使输入FIFO为空,INMIS信号也为低(无效)。
图5 CRYP中断映射图表
CRYP DMA接口
加密处理器可使用一个接口连接DMA控制器。DMA操作通过CRYP DMA控制寄存器CRYP_DMACR进行控制。
突发传输请求信号和单次传输请求信号并不相互排斥。这两种信号可同时产生。例如,当OUTFIFO中存在6个字时,会产生突发传输请求和单次传输请求。突发传输4个字之后,将只产生单次传输请求来传输余下的2个字。当数据流中待接收的剩余字数少于突发传输字数时,这一特性就非常有用。
在产生相关的DMA清除信号之前,仍会产生各个请求信号。禁止请求信号清除之后,可再次激活某个请求信号,具体取决于上述条件。如果已禁止CRYP外设并且已将DMA使能位清零(CRYP_DMACR寄存器中的DIEN位用于IN FIFO,DOEN位用于OUT FIFO),则会禁止所有请求信号。
注意:DMA控制器必须配置为执行不多余4字的突发传输。否则可能会丢失一些数据。为了在装满IN FIFO之前让DMA控制器清空OUT FIFO,OUT DMA通道的优先级应高于INDMA通道。
CRYP原理部分介绍到此,下面介绍具体使用情况。
CRYP应用实例
本节,我们将针对CRYP部分与DMA部分共同完成一个实验,首先需要在工程目录下新建一个CRYP文件夹。CRYP为加密处理器,本节例程通过DES128EBC算法进行验证,再使用软件Debug的方式查看加密与解密数据的正确与否。
打开本节实验工程可发现,相较其他工程,新增了几项相关文件:
① cks32f4xx_cryp.c
② cks32f4xx_cryp.h
③ cks32f4xx_cryp_des.c
④ cks32f4xx_cryp_tdes.c
⑤ cks32f4xx_cryp_aes.c
由于例程是通过CRYP加密处理器中的DES算法对数据进行加密/解密,且选用电子密码本(ECB)模式执行,因此,在例程中仅添加上述①②③三项即可,加密/解密流程详解见1.3.1小节,接下来介绍软件层面的应用。
代码中将实现数据加密/解密功能,取下列功能为例:
1) 软件复位
2) DES128 ECB
为缩短篇幅,不一一赘述所有算法形式,其余算法的使用方式可查阅相关参考手册与库文件,下面正式进入软件代码部分讲解。
1)软件复位功能
首先设置CRYP各个寄存器的软件复位值与偏移地址,如下所示,具体寄存器功能如手册所述。
uint32_t TABLE_RESETREG[][2] = { {0x0000, 0x00000000}, {0x0004, 0x00000003}, {0x0008, 0x00000000}, {0x000C, 0x00000000}, {0x0010, 0x00000000}, {0x0014, 0x00000000}, {0x0018, 0x00000001}, {0x001C, 0x00000000}, {0x0020, 0x00000000}, {0x0024, 0x00000000}, {0x0028, 0x00000000}, {0x002C, 0x00000000}, {0x0030, 0x00000000}, {0x0034, 0x00000000}, {0x0038, 0x00000000}, {0x003C, 0x00000000}, {0x0040, 0x00000000}, {0x0048, 0x00000000}, {0x004C, 0x00000000}, }; TestStatus Test1() { int i; for (i=0; i{ if(readl((uint8_t *)CRYP + TABLE_RESETREG[i][0]) != TABLE_RESETREG[i][1]) { return FAILED; } } return PASSED; }
通过代码判定基地址+偏移地址是否为CRYP相应地址,一致则正确,不一致则错误。
1) DES128 ECB
根据手册,首先设置以下向量组
① 设置密钥;
② 设置初始向量组;
③ 设置明文文本;
④ 设置密文文本;
下面进行代码讲解:
由上可知,实验开始前需要先设定DES-KEY密钥、初始向量IV_1、明文Plaintext等一系列数组。
由于我们添加了cks32f4xx_cryp_des.c,因此可直接调用明文加密函数,并发送加密后的密文。
uart2_fputc(3, DESkey, 8); uart2_fputc(3, IV_1, 16); uart2_fputc(3, Plaintext, AES_TEXT_SIZE); for (j=0; j<4; j++) { DataType = 0x40 * j; /* Encrypt the plaintext message*/ if(MYCRYP_DES_ECB(MODE_ENCRYPT, DESkey, Plaintext, AES_TEXT_SIZE, Encryptedtext, DataType) != SUCCESS) { return FAILED; } uart2_fputc(3, Encryptedtext, AES_TEXT_SIZE); /* Decrypt the plaintext message */ if(MYCRYP_DES_ECB(MODE_DECRYPT,DESkey, Encryptedtext,AES_TEXT_SIZE,Decryptedtext, DataType) != SUCCESS) { return FAILED; } for (i=0; i{ if (Decryptedtext[i] != Plaintext[i]) { return FAILED; } }
上述代码中的MYCRYP_DES_ECB()不仅可作为加密入口函数,同样可作为解密算法的入口函数,参数如下所示:
ErrorStatus MYCRYP_DES_ECB (uint8_t Mode, uint8_t Key[8], uint8_t *Input, uint32_t Ilength, uint8_t *Output, uint16_t DataType)
对于各个参数,可根据需求配置:
① Mode:根据需求选择加密(MODE_ENCRYPT)、解密(MODE_DECRYPT)
② Key[8]:本例成为DES128 ECB算法,所以选择DESkey
③ *Input:输入,根据功能设定,当功能为加密时,输入为明文;当输入为解密时,输入为密文
④ Ilength:输入的buffer长度,规定必须为8的倍数
⑤ *Output:输出,与第③条相反
⑥ DataType:默认值
由于加密后的数据可通过DMA的突发模式进行传输,因此也对DMA功能作简要介绍,如下所示,DMA配置与常规无异,仅在一句函数上需注意,入口函数如下所示:
void DES_Encrypt_DMA (uint32_t AlgoMode, uint8_t InitVectors[16], uint8_t *Key, uint8_t *Input, uint32_t Ilength, uint8_t *Output, uint16_t DataType, DMA_InitTypeDef *DMA_In_InitStructure, DMA_InitTypeDef *DMA_Out_InitStructure)
该函数用于CRYP加密处理器加密/解密的DMA传输,函数的各个参数根据使用需求决定:
① AlgoMode:根据选定的模式设置,由于例程是DES128 ECB算法,因此,该参数设定为CRYP_AlgoMode_DES_ECB
② InitVectors[16]:初始向量设定
③ *Key:秘钥方式,上文中已讲解,本次例程为DESkey
④ *Input:输入,上文已讲解
⑤ Ilength:输入的buffer长度
⑥ *Output:输出
⑦ DataType:默认值
与加密函数类似,本节的DMA函数同样分为加密和解密两个过程,函数相应更改*Input和*Output参数即可。
接下来讲解main.c函数,该函数相对不难。
在main.c中设定以下数组(具体数据如工程文件所示)
① DES密钥;
② 初始向量;
③ 明文/解密后的明文;
④ 加密计算后的密文;
Main.c函数如下所示:
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); uart_init(115200); NVIC_Config(); while(1) { CRYP_DeInit(); RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_CRYP, DISABLE); RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_CRYP, ENABLE); if(func[(0)]() == PASSED) { uart2_fputc(0, 0, 0); } else { uart2_fputc(0, 0, 0); } RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_CRYP, ENABLE); if(func[(1)]() == PASSED) { uart2_fputc(0, 0, 0); } else { CKS_EVAL_LEDToggle(LED1); CKS_EVAL_LEDToggle(LED2); } RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_CRYP, ENABLE); if(func[(2)]() == PASSED) { uart2_fputc(0, 0, 0); } else { CKS_EVAL_LEDToggle(LED1); CKS_EVAL_LEDToggle(LED2); }
需注意的是,在验证CRYP功能时,需要开启相应的总线时钟。具体的代码可详见工程。
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_CRYP, ENABLE);
以上即为CRYP加密处理器模块代码的大致讲解,具体代码详见相关工程。将代码下载到相应电路板后,通过软件Debug的方式进行验证,验证成功则跳转到相关的功能PASS位置。最后可得到明文数据(Plaintext),并将其与解密后的数据(Decrytedtext)相比对,比对正确则成功,实验结果如下图所示:
(a)明文数据
(b)解密后的数据
到此,CRYP加密处理器讲解完成,其他算法的使用详见参考手册与库文件。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !