AESCMAC实验报告材料 信息与通信安全系统.docx
《AESCMAC实验报告材料 信息与通信安全系统.docx》由会员分享,可在线阅读,更多相关《AESCMAC实验报告材料 信息与通信安全系统.docx(62页珍藏版)》请在冰豆网上搜索。
AESCMAC实验报告材料信息与通信安全系统
本科实验报告
课程名称:
信息与通信安全
姓名:
选择课题:
C/C++实现加解密算法及其应用(实验一)
系:
信电系
专业:
信息与通信工程
学号:
指导教师:
年月日
1.实验容与要求
(1).复习AES原理。
(2).用C/C++编写AES算法并调试通过。
(3).复习CMAC原理。
(4).在实现AES基础上,用C/C++编写CMAC算法并调试通过。
(5).回答下列思考题。
ØAES解密算法和AES的逆算法之间有什么不同?
ØCMAC与HMAC相比,有什么优点?
2.实验原理
2.1AES原理
2.1.1AES总体结构
下图展示了AES加密过程的总体结构。
明文分组长度为128位即16字节密钥长度可以为16,24或32字节(在本次设计中选择16字节)。
加密和解密算法是输入是一个128位的分组。
在FIPSPUB197中,这个分组被描述为4*4的字节方阵。
这个分组被复制到state数组,饼子啊加密或解密的各个阶段被修改。
同样,密钥也被描述为字节的方阵,并被扩展为44字的密钥字序列。
密码由N轮组成,其中轮数依赖于密钥长度,16字节密钥是10轮,前N-1轮由4个不同的变换组成:
字节代替,行位移,列混淆,轮密钥加。
最后一轮包含三个变换,而在第一轮的前面有一个起始的单变换(轮密钥加),可视为第0轮。
每一个变换输入一个活多个4*4的矩阵,并输出一个4*4的矩阵,最后一轮输出为密文。
同样,密钥扩展函数为N+1轮密钥,它们是互不相同的4*4矩阵。
每一个轮密钥作为每轮的轮密钥加变换的一种输入。
2.1.2AES详细结构
1)
AES算法未使用Feisel结构,而是在每一轮都使用代替和混淆将整个数据分组作为一个单一的矩阵处理。
2)输入的密钥被扩展为44个32位字所组成的数组w[i],每轮由四个不同的字作为该轮的轮密钥。
3)由四个不同的阶段组成,包括一个置换和三个代替。
字节代替:
用一个S盒完成分组的字节到字节的代替。
行位移:
一个简单的置换。
列混淆:
利用GF(2^8)上的算术特性的一个代替。
轮密钥加:
当前分组和扩展秘钥的一部分进行按位异或。
(一)字节代替变换
如上图,字节代替变换是一个简单的查表操作。
AES定义了一个S盒,它由16*16个字节组成的矩阵,包含了8位所能表示的256个数的一个置换。
State中的每个字节按照如下的方式映射为一个新的字节,把改字节的搞4位作为行值,低四位作为列值,以这些行列值作为索引从S盒的对应位置取出元素作为输出。
而其逆向操作则是有对应的逆S盒可进行查表。
(二)行移位变换
如上图,其正向行移位变换中,state的第一行保持不变,把state的第二行循环左移一个字节,state的第三行循环左移两个字节,state的第四行循环左移四个字节。
例如:
逆向行移位变换将state中的后三行执行相反方向的一位操作即可。
(三)列混淆变换
如上图,列混淆的正向变换是对每列单独进行操作。
每列中的每个字节被映射为一个新值,此值由该列中的4个字通过函数变换得到。
这个变换可有下面基于state的矩阵乘法表示:
乘积矩阵中的每个元素军事一行和一列中对应元素的乘积之和。
这里的乘法和假发都是定义在GF(2^n)上的。
状态中单列的列混淆变换可表示为:
其中一个例子如下:
(四)轮密钥加变换
如上图,在轮密钥加变换中,128位的state按位与128位的轮秘钥XOR。
该操作可以视为state的一列中的四个字节与轮秘钥的一个字进行列间的操作,例如:
(五)AES密钥扩展
AES密钥扩展算法的输入值是一个4个字,输出值是一个由44个字组成的移位线性数组。
输入密钥字节被复制到扩展密钥数组的前4个字。
然后每次用四个字填充扩展密钥数组余下的部分。
在扩展数组中,每一个新增的字w[i]的值依赖于w[i-1]和w[i-4]。
在4个情形中,三个使用了异或。
对w数组中下标为4的倍数的的元素采用了更复杂的函数来计算:
(1)字循环的功能时使一个字中的四个字节的循环左移一个字节,即将输入字[B0,B1,B2,B3]变成为[B1,B2,B3,B0].
(2)字代替利用S盒对输入字中的每个字节进行字节代替。
(3)步骤1和步骤2的结果再与轮常量Rcon[j]相异或。
1.1CMAC原理
基于密码的消息认证码(CMAC)对于AES,3DES适用,它使用三个密钥:
一个密钥长为K,用在密文分组的每一步,两个长度为n的密钥,其中k是密钥长度,n为密文分组长度。
并且两个n位的密钥可以从加密密钥导出,而不是单独提供。
首先,当消息长度是分组长度b的n倍时,我们考虑CMAC的运算情况。
对AES,b=128,对于3DES,b=64.这个消息被划分为n组,(M1,M2…,Mn)。
算法使用了k比特的加密密钥K和n比特的常数K1。
对于AES,密钥长度k为128,192和256比特,对于3DES,密钥长度为112或168比特。
CMAC按如下方式计算:
其中:
T——消息认证码,也称为tag
Tlen——T的比特长度
MSBs(X)——比特串X最左边的s位
如果消息不是密文分组长度的整数倍,则最后分组的右边(低有效位)填充一个1和若干个0,使得最后的分组长度为b。
除了使用一个不同的n比特密钥K2代替K1外,与前面所述一样进行CMAC运算。
两个n比特的密钥由k比特的加密密钥按如下方式导出:
其中乘法(·)是在域GF(2^n)进行,X和X^2是该域的一次和二次多项式。
因此X的二元表示为n-2个0,后跟10,X^2的二元表示为n-3个0,后跟100。
对于AES,已获批准的分组长度为X^128+X^7+X^2+X+2.。
当消息长度是分组长度的整数倍:
当消息长度不是分组长度的整数倍:
2.实验环境
装有C_Free的笔记本
4.代码实现
首先是实现AES的各个子模块,在验证其正确以后,再进行CMAC的认证算法的实现。
4.1字节代替变换
#include
staticunsignedcharSbox[256]=
{//AES的S盒
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
};
staticunsignedcharInvSbox[256]=
{//AES的逆S盒
0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
};
//字节代替变换
voidSub_Byte(unsignedcharstate[4][4])
{
inti,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
state[i][j]=Sbox[state[i][j]];
}
//逆向字节代替
voidInv_Sub_Byte(unsignedcharstate[4][4])
{
inti,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
state[i][j]=InvSbox[state[i][j]];
}
intmain()
{
unsignedcharstate[4][4]={
{0xea,0x04,0x65,0x85},
{0x83,0x45,0x5d,0x96},
{0x5c,0x33,0x98,0xb0},
{0xf0,0x2d,0xad,0xc5}
};
inti,j;
//正向替换
Sub_Byte(state);
printf("正向代替结果:
\n");
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
printf("%x",state[i][j]);
printf("\n");
}
printf("\n");
//反向替换
Inv_Sub_Byte(state);
printf("反向代替结果:
\n");
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
printf("%x",state[i][j]);
printf("\n");
}
}
其测试结果如下,可见该功能可实现是正确的。
4.2行移位变换
#include
//行移位
voidRow_Shift(unsignedcharstate[4][4])
{
inti;
unsignedchartemp;
//第一行保持不变,第二行左移一位
temp=state[1][0];
for(i=0;i<3;i++)
state[1][i]=state[1][i+1];
state[1][3]=temp;
//第三行左移2位
temp=state[2][0];
state[2][0]=state[2][2];
state[2][2]=temp;
temp=state[2][1];
state[2][1]=state[2][3];
state[2][3]=temp;
//第四行左移3位
temp=state[3][3];
for(i=3;i>0;i--)
state[3][i]=state[3][i-1];
state[3][0]=temp;
}
//逆向行移位
voidInv_Row_Shift(unsignedcharstate[4][4])
{
inti;
unsignedchartemp;
//第一行保持不变,第二行右移一位
temp=state[1][3];
for(i=3;i>0;i--)
state[1][i]=state[1][i-1];
state[1][0]=temp;
//第三行右移二位
temp=state[2][0];
state[2][0]=state[2][2];
state[2][2]=temp;
temp=state[2][1];
state[2][1]=state[2][3];
state[2][3]=temp;
//第四行右移三位
temp=state[3][0];
for(i=0;i<3;i++)
state[3][i]=state[3][i+1];
state[3][3]=temp;
}
intmain()
{
inti,j;
unsignedcharstate[4][4]={
{0x87,0xf2,0x4d,0x97},
{0xec,0x6e,0x4c,0x90},
{0x4a,0xc3,0x46,0xe7},
{0x8c,0xd8,0x95,0xa6}
};
Row_Shift(state);
printf("正向行移位变换:
\n");
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
printf("%02x",state[i][j]);
printf("\n");
}
printf("\n");
Inv_Row_Shift(state);
printf("反向向行移位变换:
\n");
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
printf("%02x",state[i][j]);
printf("\n");
}
}
测试结果如下
通过比较,可知结果正确,因此该子模块实现。
4.3列混淆变换
#include
//乘法处理部分
unsignedcharx_time2(unsignedcharstate)//乘2处理
{
unsignedchartemp;
if(state>=0x80)
temp=(state<<1)^0x1b;//判断b7=1?
else
temp=(state<<1);
returntemp;
}
unsignedcharx_time3(unsignedcharstate)//乘3处理
{
state=state^x_time2(state);
returnstate;
}
unsignedcharx_time4(unsignedcharstate)//乘4处理
{
state=x_time2(x_time2(state));
returnstate;
}
unsignedcharx_time8(unsignedcharstate)//乘8处理
{
state=x_time2(x_time2(x_time2(state)));
returnstate;
}
unsignedcharx_time9(unsignedcharstate)//乘9处理
{
state=state^x_time8(state);
returnstate;
}
unsignedcharx_timeB(unsignedcharstate)//乘B处理
{
state=state^x_time2(state)^x_time8(state);
returnstate;
}
unsignedcharx_timeD(unsignedcharstate)//乘D处理
{
state=state^x_time4(state)^x_time8(state);
returnstate;
}
unsignedcharx_timeE(unsignedcharstate)//乘E处理
{
state=x_time2(state)^x_time4(state)^x_time8(state);
returnstate;
}
voidMixColumns(unsignedcharstate[4][4])
{
inti,j;
unsignedcharstate_1[4][4];
for(i=0;i<4;i++)
for(j=0;j<4;j++)
state_1[i][j]=state[i][j];
for(j=0;j<4;j++)
{
state[0][j]=x_time2(state_1[0][j])^x_time3(state_1[1][j])^state_1[2][j]^state_1[3][j];
state[1][j]=state_1[0][j]^x_time2(state_1[1][j])^x_time3(state_1[2][j])^state_1[3][j];
state[2][j]=state_1[0][j]^state_1[1][j]^x_time2(state_1[2][j])^x_time3(state_1[3][j]);
state[3][j]=x_time3(state_1[0][j])^state_1[1][j]^state_1[2][j]^x_time2(state_1[3][j]);
}
}
//逆向列混淆
voidInv_MixColumns(unsignedcharstate[4][4])
{
inti,j;
unsignedcharstate_1[4][4];
for(i=0;i<4;i++)
for(j=0;j<4;j++)
state_1[i][j]=state[i][j];
for(j=0;j<4;j++)
{
state[0][