if ( (L[0] & 0x80) == 0 ) {
leftshift_onebit(L,K1); } else { leftshift_onebit(L,tmp); xor_128(tmp,const_Rb,K1); }
if ( (K1[0] & 0x80) == 0 ) {
leftshift_onebit(K1,K2); } else {
leftshift_onebit(K1,tmp); xor_128(tmp,const_Rb,K2); }
return; }
K1、K2生成时运用了左移一位函数,因为input,为16为数组,因此左移时应考虑溢出,当前一数组元素最高位为1时,则此时数组元素应在左移的同时加1,因此定义overflow,当前一元素最高位为1时,即input[i] & 0x80=1,则overflow=1,否则为0,当前元素先左移一位 output[i] = input[i] << 1,而后加上前一元素确定的overflow,output[i] |= overflow。模块代码实现如下:
void leftshift_onebit(unsigned char *input,unsigned char *output) {
int i;
unsigned char overflow = 0; for ( i=15; i>=0; i-- ) {
output[i] = input[i] << 1; output[i] |= overflow;
overflow = (input[i] & 0x80)?1:0; }
return; }
2.消息末组确定
当消息长度不是分组长度整数倍时,最后一组消息分组需要进行一些变换,因此需要一个函数来确定最后一组消息分组,这个函数定义为padding ( unsigned char *lastb, unsigned char *pad, int length ),其中lastb为消息分组后剩下不能成为一组的元素,length为lastb的
元素个数,pad定义为输出,为最后一组消息分组。当pad[j]中j int j; for ( j=0; j<16; j++ ) { if ( j < length ) { pad[j] = lastb[j]; } else if ( j == length ) { pad[j] = 0x80; } else { pad[j] = 0x00; } } } 3.CMAC生成 CMAC有函数AES_CMAC ( unsigned char *key, unsigned char *input, int length, unsigned char *mac )生成,key为密钥,input为消息输入,length为消息长度,而mac则为生成的CMAC,在此算法中,将消息分组长度设置为16. a.生成K1,K2,由generate_subkey(key,K1,K2)实现; b.确定分组长度,由n = (length+15) / 16实现,当length<16时,n=1; c.确定消息长度是否为分组长度的整数倍,定义flag,当flag=1时,是整数倍,否则不是,当length=0时,即输入消息为0时,定义分组数n=1,flag=0; d.当flag=1,即消息长度为分组长度整数倍时,定义M_last为最后分组&input[16*(n-1)] 与K1异或,由函数xor_128(&input[16*(n-1)],K1,M_last)实现,注意&的使用; e.当flag=0时,先由padding(&input[16*(n-1)],padded,length)确定最后分组,length即为未分组元素个数,padded为最后分组,M_last为最后分组padded与K2异或,由函数xor_128(padded,K2,M_last)实现; f.定义中间变量X为AES加密输出,第一组运算时为M1直接与K加密,其后为前一组加密输出X与Mi异或后再与K进行AES加密,因此第一次时定义X=0x00,则前n-1轮可由 xor_128(X,&input[16*i],Y),AES_128(key,Y,X)两步实现; g.最后一步加密与之前都不一样,用第n-1轮加密输出X与M_last异或,再与K进行AES加密,其中M_last先前已定义,因此最后一步运算为xor_128(X,M_last,Y),AES_128(key,Y,X) h.最后一步运算为MSB(Tlen),其中Tlen为输出CMAC即T的长度,在此我们都定义为16,而MSB运算即为截取X最左边的Tlen=16位,可由mac[i] = X[i]实现。 void AES_CMAC ( unsigned char *key, unsigned char *input, int length, unsigned char *mac ) { unsigned char X[16],Y[16], M_last[16], padded[16]; unsigned char K1[16], K2[16]; int n, i, flag; generate_subkey(key,K1,K2); n = (length+15) / 16; if ( n == 0 ) { n = 1; flag = 0; } else { if ( (length) == 0 ) { flag = 1; } else { flag = 0; } } if ( flag ) { xor_128(&input[16*(n-1)],K1,M_last); } else { padding(&input[16*(n-1)],padded,length); xor_128(padded,K2,M_last); } for ( i=0; i<16; i++ ) X[i] = 0; for ( i=0; i xor_128(X,&input[16*i],Y); AES_128(key,Y,X); } xor_128(X,M_last,Y); AES_128(key,Y,X); for ( i=0; i<16; i++ ) { mac[i] = X[i]; } } 五、实验结果 1.AES实验结果: 在VC中运行工程,输入课本中一个已知密文的例子,其中明文、密钥、密文如下 input=0123456789abcdeffedcba9876543210 key=0f1571c947d9e8590cb7add6af7f6798 output=ff0b844a0853bf7c6934ab4364148fb9 VC运行结果如图所示,实验结果与理论值相等,因此可知实现了AES的加解密。 2.CMAC实验结果: 定义输入函数为M[64],进行CMAC验证时,截取M[64]的长度各不相同,消息长度分别选择为0(输入消息为0),40(消息长度不为分组长度16的整数倍),64(消息长度为分组长度16的整数倍),得到如下结果。 六、思考题 1.AES 解密算法和AES 的逆算法之间有什么不同? a.字节替代时,所用替代盒不同,加密sbox,解密用Invsbox; b.行移位方向不同,加密为各行分别左移0~3位,解密为各行右移0~3位; c.列混淆所用矩阵不同,两个矩阵互为逆; d.轮密钥加各轮使用密钥不同,加密时从w[0]用到w[10],为解密时从w[10]用到w[0]; e.对应轮运算顺序不同,加密每轮运算分别为字节替代、行移位、列混淆、轮密钥加,而解密时为逆向行移位、逆向字节替代、轮密钥加、逆向列混淆。 2.CMAC 与HMAC 相比,有什么优点? a.CMAC可处理长度不为分组长度整数倍的消息; b.HMAC的安全性依赖于嵌入Hash函数的强度;