这几天终于搞定了AES硬件加密工具的使用,几种简单的加密模式也都实验通过了,比较麻烦的一种是CCM模式的加密,它是CTR加密模式和CMAC认证算法的混合使用。本文先介绍CCM模式的原理与基本实现,然后结合OpenSSL的加密库,了解一下具体过程,最后,在AES硬件加密引擎上实现。
CCM介绍
CCM是CTR加密模式和CMAC认证算法的混合使用,常用在需要同时加密和认证的领域,比如WiFi安全中的WPE协议,它就使用了AES-CCM模式。
CCM首先使用CBC-MAC模式来认证传输帧,然后使用CTR模式来加密帧。在这里,用于加密的初始化向量IV构成结构如下:
sequence counter表示在一个帧中16个字节块的数目. Flags域结构如下:
Bit7设置为0,Adata为1的话,表示此帧有额外的认证数据,为0则表示没有额外的认证数据。M为认证域长度经过转换后的结果.L固定为1. 在不同的安全模式下,初始化向量中的Flags值不同。从上表可以看出,只要有MIC的存在,那么Adata就必须为1.
首先引入两个CCM模式下的两个参数:
L : 长度域,取值为2~8, OpenSSL中缺省为8
M : tag的长度,可选范围为4,6,8,10,12,14,16.OpenSSL中缺省为12
接下来,将详细描述如何在硬件加密模块上实现CCM模式的认证和加密。
在硬件AES加密引擎上面,没有完整的实现CCM模式的加密,需要软硬件一起配合,才能实现CCM模式。
在CCM模式下CBC-MAC
对于待加密数据中的前数据块,采用CBC-MAC模式加密生成认证域,对于最后一个数据块,需要改为使用CBC模式加密。当最后一个数据块载入AES硬件加密引擎后,从AES读出的就是消息的MAC校验码。
在CCM模式下CTR
以下是认证执行的步骤。
1. 载入加密密钥
2. 载入全0的初始化向量
3. 构建一个16个字节的数组B,其第一个元素B[0]需要有如下的构造。
其中,Flag的值和安全级别有关系,具体关系间下表。
其他内容元素按规则来填充。
4. 按照16字节加密块来划分,第一个块填充初始化向量,第二个块填充Adata相关内容,第三个块(或者更多块)填充明文内容
5. 先按照CBC_MAC模式加密前N-1个块,最后一个数据块使用CBC模式来加密.当认证域长度为16时,CBC_MAC加密后的内容是不变的,如果不为16,则高M字节内容保持不变,其余字节变为0.
6. 等待加密完成后,从结果中,读出Mval个字节到Cstate就可以了。
函数头说明:
void Test_SSP_CCM_Auth (uint8 Mval, // 认证域字节长度 [0,4,8,16]
uint8 *N, // N 指向13字节的随机数
uint8 *M, // M 指向明文的指针
uint16 len_m, // len_m 明文长度
uint8 *A, // A 指向Adata的指针
uint16 len_a, // len_a 数据长度
uint8 *AesKey, //AesKey 指向密钥的指针
uint8 *Cstate) //输出Cstate 缓存
加密步骤:
CCM模式下的加密,需要使用前面生产的Cstate值,具体使用步骤如下:
加密也需要初始化向量,其构成如下:
当在OFB模式,将认证域加密生产U时,CTR的值必须为0,当在CTR模式,CTR的值必须不为0
1. 创建A块,并按照规则来填充A[0],当做后的IV
2. 创建T块,将Cstate的前Mval填充到T中。
3.分配缓存,用于填充输入明文,不足16字节的补0.
4. 以OFB模式,将明文T加密输出到Cstate[也叫做U]。当认证域长度为16时,上传缓存内容保持不变,如果不为16,则上传内容的高M位保持不变,其余字节变为0.结果为U.
5. 以CTR模式,将IV最高字节设置为1,重新载入IV,然后加密明文缓存块
6. 最后的结果,是输出的密文块加上U,都是16字节对齐的。
void Test_SSP_CCM_Encrypt (uint8 Mval, //认证域字节长度 [0,4,8,16]
uint8 *N, //指向13个字节的随机数指针
uint8 *M, //指向待加密明文 (明文输出也在这里,多加16个字节的空间)
uint16 len_m, //待加密明文长度
uint8 *AesKey, //AekKey密钥指针
uint8 *Cstate) //明文的认证域内容
从目前浅显的理解上来看,CCM的认证和加密好像是相互独立设置的,从逻辑上,一段明文进来,先通过认证,产生一个tag,在后续加密时使用此Tag和IV生成一个新的校验U.原负载明文填充满后,通过CTR模式来加密数据,在密文的后面附上新的校验码U,这样,就完成了校验和加密的过程。
---------------今天就先介绍到这里,还有解密过程和代码没贴上来,周一来了再贴-----------------------
-------------------周一来了,整理剩下的代码---------------------------------------------------
解密的过程和加密的相反,先解密,再解认证。
void Test_SSP_CCM_Decrypt (uint8 Mval, //认证域长度
uint8 *N, //随机数
uint8 *C, //待解密密文指针
uint16 len_c, //待解密密文长度
uint8 *AesKey, //解密密钥
uint8 *Cstate) //认证域内容
解密流程:
1. 先利用随机数,构造A向量
2. 从待解密密文中提取最后Mval字节(补全16个字节)到U向量中
3. 通过OFB模式,来将U解密成T
4. 通过CTR模式,将密文解密成明文
5. 最后,将T附加在明文后
鉴权的过程是利用上述解密出来的明文,全场为len_c,认证域长度位为Mval,位置在字节的尾端,鉴权就是把解密的明文,通过(len_c-Mval)长度鉴权计算,把得到的结果和解密输出的结果进行对比,如果相同,则鉴权成功,否则,鉴权失败。
参考资料:openssl学习之ccm,gcm 模式