赞
踩
AES-CMAC使用了高级加密标准作为组分。为了产生一个消息认证码,CMAC需要一个密钥,消息message及消息的长度length作为输入,输出是消息认证码。
AES-CMAC的核心是CBC-MAC。对于待加密消息M,应用CBC-MAC算法。在CMAC操作中有两种情况:
如果输入消息长度等于Block的整数倍,最后的Block M_n需要先于K1异或再进行处理;
如果输入的消息长度不等于Block的整数倍,最后的Block M_n需要补齐到一个Block的大小,与K2异或,再进行处理。上一次处理的结果将成为下一次处理的输入。
子密钥生成算法:
输入密钥K,输出子密钥K1与K2。过程如下:
①用密钥K对全零输入块加密得到L
②K1通过如下方式导出:
如果L的最高有效位为0,则K1:=L左移1位;否则,K1等于const_Rb与左移1位的L异或。
③K2通过如下方式导出:
如果K1的最高有效位为0,则K2:=K1左移1位;否则,K2等于const_Rb与左移1位的K1异或。
根据参考文献[1]javafr_RFC_4493给出的说明及测试实例,编写AES_CMAC类。在main()函数中加入取消注释宏定义AES_CMAC_TEST,进行AES-CMAC测试。
待测试消息是:
M= 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
密钥是:
K= 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
注意,测试中我们不是把M作为输入,而是截取其一部分作为输入消息,以测试AES_CMAC类处理不同长度的消息的正确性。测试结果如图:
对照参考文献[1]:
结果符合预期。
aes_cmac.h:
/************************************************************************/
/*AES_CMAC: Use AES-128
/*Author: chenweiliang
/*Version: 1.0
/*Reference: javafr_RFC_4493
/************************************************************************/
#pragma once
#include "aes.h"
class AES_CMAC
{
public:
//key: 128-bit key
AES_CMAC(const byte key[]);
virtual ~AES_CMAC();
static const byte const_Rb[16];
static const byte const_Zero[16];
//msg: message to be authenticated
//len: length of the message in bytes
//mac: message authentication code
void getCMAC(byte *msg, int len, byte *mac);
//Copy K1 to key1
void getK1(byte *key1);
//copy K2 to key2
void getK2(byte *key2);
protected:
private:
AES mAes_128;
//128-bit key
byte mK[16];
//128-bit first subkey
byte mK1[16];
//128-bit second subkey
byte mK2[16];
//Utils function
void leftShiftOneBit(byte *input_128,byte *output_128);
void xor128(const byte *a, const byte *b, byte *out);
void generateSubKey();
//lastb: last block of the intput message
//pad: last block after padding
//length: length of last block before padding
void padding(byte *lastb,byte *pad,int length);
};

aes_cmac.cpp:
/************************************************************************/
/*AES_CMAC: Use AES-128
/*Author: chenweiliang
/*Version: 1.0
/*Reference: javafr_RFC_4493
/************************************************************************/
#include "aes_cmac.h"
const byte AES_CMAC::const_Rb[16] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x87
};
const byte AES_CMAC::const_Zero[16] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
void AES_CMAC::leftShiftOneBit(byte *input_128, byte *output_128)
{
byte overflow = 0x00;
for (int i = 15; i >= 0; i--){
output_128[i] = input_128[i] << 1;
output_128[i] |= overflow;
overflow = (input_128[i] & 0x80) ? 0x01 : 0x00;
}
return;
}
void AES_CMAC::xor128(const byte *a, const byte *b, byte *out)
{
for (int i = 0; i < 16; i++){
out[i] = a[i] ^ b[i];
}
}
AES_CMAC::AES_CMAC(const byte key[])
{
for (int i = 0; i < 16; i++){
mK[i] = key[i];
}
mAes_128 = AES(mK,KEYLENGTH::KEY_LENGTH_16BYTES);
generateSubKey();
}
void AES_CMAC::generateSubKey()
{
//for output of AES-128 applied to 0^128
byte L[16];
//0^128
byte Z[16];
byte temp[16];
for (int i = 0; i < 16; i++){
Z[i] = 0;
}
mAes_128.encrypt(Z,L);
//If MSB(L)==0,then mK1=L<<1
if ((L[0] & 0x80) == 0){
leftShiftOneBit(L, mK1);
}
//mK1=(L<<1)xor(Rb)
else{
leftShiftOneBit(L, temp);
xor128(temp, const_Rb, mK1);
}
if ((mK1[0] & 0x80) == 0){
leftShiftOneBit(mK1, mK2);
}
else{
leftShiftOneBit(mK1, temp);
xor128(temp, const_Rb, mK2);
}
return;
}
void AES_CMAC::padding(byte *lastb, byte *pad, int length)
{
for (int i = 0; i < 16; i++){
if (i < length){
pad[i] = lastb[i];
}
else if (i == length){
pad[i] = 0x80;
}
else{
pad[i] = 0x00;
}
}
}
void AES_CMAC::getCMAC(byte *msg, int len, byte *mac)
{
byte X[16];
byte Y[16];
byte msgLast[16];
byte padded[16];
//the number of blocks to be processed
int n;
//the number of bytes of the last block
int r;
//denoting last block is complete or not
bool isComplete;
n = (len + 15) / 16;
if (n == 0){
n = 1;
isComplete = false;
}
else{
if ((len % 16) == 0){
isComplete = true;
}
else{
isComplete = false;
}
}
if (isComplete){
xor128(&msg[16*(n-1)], mK1, msgLast);
}
else{
padding(&msg[16*(n-1)], padded, len%16);
xor128(padded, mK2, msgLast);
}
for (int i = 0; i < 16; i++){
X[i] = 0;
}
for (int i = 0; i < n - 1; i++){
//Y=(X)xor(meg_i)
xor128(X, &msg[16 * i], Y);
//X=AES(key,Y)
mAes_128.encrypt(Y, X);
}
xor128(X, msgLast, Y);
mAes_128.encrypt(Y, X);
for (int i = 0; i < 16; i++){
mac[i] = X[i];
}
}
void AES_CMAC::getK1(byte *key1)
{
for (int i = 0; i < 16; i++){
key1[i] = mK1[i];
}
}
void AES_CMAC::getK2(byte *key2)
{
for (int i = 0; i < 16; i++){
key2[i] = mK2[i];
}
}
AES_CMAC::~AES_CMAC()
{
}

main函数:
/************************************************************************/
/*Main: Test AES,CMAC
/*Author: chenweiliang
/*Version: 1.0
/*Note: To test AES-128,please comment the macro definition
/* "#define AES_CMAC_TEST" and uncomment it for CMAC testing
/************************************************************************/
#include "aes.h"
#include "aes_cmac.h"
#ifndef AES_CMAC_TEST
#define AES_CMAC_TEST
#endif // !AES_CMAC_TEST
#include <string>
void print128(unsigned char state[16]){
for (int i = 0; i < 16; i++){
printf("%02hhx", state[i]);
if (i % 8 == 7){
printf(" ");
}
}
printf("\n");
}
void print512(unsigned char data[64]){
for (int i = 0; i < 64; i++){
printf("%02hhx", data[i]);
if (i % 8 == 7){
printf(" ");
}
if (i % 32 == 31){
printf("\n");
}
}
printf("\n");
}
void printn(unsigned char data[], int n)
{
for (int i = 0; i < n; i++){
printf("%02hhx", data[i]);
if (i % 8 == 7){
printf(" ");
}
if (i % 16 ==15&&i!=n-1){
printf("\n ");
}
else if (i == n - 1){
printf("\n");
}
}
}
using namespace std;
int main()
{
#ifdef AES_CMAC_TEST
unsigned char K1[16], K2[16], mac[16], TT[12];
unsigned char M[64] = {
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
};
unsigned char key[16] = {
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
};
AES_CMAC aes_cmac = AES_CMAC(key);
printf("AES-CMAC Test\n");
printf("-------------------------------------------------------------------\n");
printf("SubKeyGeneration\n");
printf("K ");
print128(key);
printf("K1 ");
aes_cmac.getK1(K1);
print128(K1);
printf("K2 ");
aes_cmac.getK2(K2);
print128(K2);
printf("-------------------------------------------------------------------\n");
printf("\n-------------------------------------------------------------------\n");
aes_cmac.getCMAC(M, 0, mac);
printf("Example 1: len=0\n");
printf("M <Empty String>\n");
printf("AES-CMAC: ");
print128(mac);
printf("-------------------------------------------------------------------\n");
aes_cmac.getCMAC(M, 16, mac);
printf("Example 2: len=16\n");
printf("M ");
printn(M, 16);
printf("AES-CMAC: ");
print128(mac);
printf("-------------------------------------------------------------------\n");
aes_cmac.getCMAC(M, 40, mac);
printf("Example 3: len=40\n");
printf("M ");
printn(M, 40);
printf("AES-CMAC: ");
print128(mac);
printf("-------------------------------------------------------------------\n");
aes_cmac.getCMAC(M, 64, mac);
printf("Example 4: len=64\n");
printf("M ");
printn(M, 64);
printf("AES-CMAC: ");
print128(mac);
printf("-------------------------------------------------------------------\n");
#else
unsigned char input[16] =
{
0x01, 0x23, 0x45, 0x67,
0x89, 0xab, 0xcd, 0xef,
0xfe, 0xdc, 0xba, 0x98,
0x76, 0x54, 0x32, 0x10
};
unsigned char key[] =
{
0x0f, 0x15, 0x71, 0xc9,
0x47, 0xd9, 0xe8, 0x59,
0x0c, 0xb7, 0xad, 0xd6,
0xaf, 0x7f, 0x67, 0x98
};
printf("AES Test\n");
AES aes = AES(key, KEYLENGTH::KEY_LENGTH_16BYTES);
printf("Key length: 128\n");
printf("key: ");
print128(key);
printf("Message: ");
print128(input);
byte out[16];
aes.encrypt(input, out);
printf("ciphertext: ");
print128(out);
aes.decrypt(out,out);
printf("plaintext: ");
print128(out);
#endif // AES_CMAC_TEST
return 0;
}

[1] javafr_RFC_4493
[2]AES加密学习笔记http://blog.csdn.net/whycadi/article/details/6917394
[3]AES加密算法http://www.cnblogs.com/mingcn/archive/2010/10/31/aes_c.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。