AES-与基于AES-的CMAC.doc

上传人:聆听****声音 文档编号:1976536 上传时间:2023-05-02 格式:DOC 页数:15 大小:420KB
下载 相关 举报
AES-与基于AES-的CMAC.doc_第1页
第1页 / 共15页
AES-与基于AES-的CMAC.doc_第2页
第2页 / 共15页
AES-与基于AES-的CMAC.doc_第3页
第3页 / 共15页
AES-与基于AES-的CMAC.doc_第4页
第4页 / 共15页
AES-与基于AES-的CMAC.doc_第5页
第5页 / 共15页
AES-与基于AES-的CMAC.doc_第6页
第6页 / 共15页
AES-与基于AES-的CMAC.doc_第7页
第7页 / 共15页
AES-与基于AES-的CMAC.doc_第8页
第8页 / 共15页
AES-与基于AES-的CMAC.doc_第9页
第9页 / 共15页
AES-与基于AES-的CMAC.doc_第10页
第10页 / 共15页
AES-与基于AES-的CMAC.doc_第11页
第11页 / 共15页
AES-与基于AES-的CMAC.doc_第12页
第12页 / 共15页
AES-与基于AES-的CMAC.doc_第13页
第13页 / 共15页
AES-与基于AES-的CMAC.doc_第14页
第14页 / 共15页
AES-与基于AES-的CMAC.doc_第15页
第15页 / 共15页
亲,该文档总共15页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

AES-与基于AES-的CMAC.doc

《AES-与基于AES-的CMAC.doc》由会员分享,可在线阅读,更多相关《AES-与基于AES-的CMAC.doc(15页珍藏版)》请在冰点文库上搜索。

AES-与基于AES-的CMAC.doc

本科实验报告

课程名称:

信息与通信安全

姓名:

邓敏

实验:

实验一

系:

信电系

专业:

信息与通信工程

学号:

3110100978

指导教师:

谢磊

年月日

AES与基于AES的CMAC

一、实验目的

1、熟悉AES加解密过程,掌握其算法实现;

2、熟悉CMAC生成过程,掌握其算法实现。

二、实验任务

1、复习AES原理;

2、用C/C++编写AES算法并调试通过;

3、复习CMAC原理;

4、在实现AES基础上,用C/C++编写CMAC算法并调试通过。

三、实验原理

1.AES原理

AES加解密过程如下图所示,明文分组的长度为128位即16字节,秘钥长度可以为16,24或32字节(128,182或256位)。

根据秘钥的长度,算法被称为AES-128、AES-192、或AES-256,本次实验采用AES-128。

1.1AES加密过程

k0

k4

k8

k12

k1

k5

k9

k13

k2

k6

k10

k14

k3

k7

k11

k15

AES明文输入为一个128位分组,在代码实现中被描述为4x4的字节方阵,一般称其为state数组,并且按照如下方式填入到数组当中,原始密钥也为128为分组,并按同样的方式填入数组。

in0

in4

in8

in12

in1

in5

in9

in13

in2

in6

in10

in14

in3

in7

in11

in15

AES加密过程共进行十轮,前九轮由四个步骤组成,四个步骤依次为字节代替(SubBytes),行移位(ShiftRows),列混淆(MixColumns),轮密钥加(AddRoundKey),第十轮依次进行除列混淆的三个步骤。

1.1.1字节代替

AES定义了一个S盒,它是由16x16个字节组成的矩阵,包含了8位所能表示的256个数的一个置换,字节代替将输入字节的高四位作为行值,低四位作为列值,以这些行列值作为索引从S盒的对应位置取出元素作为输入。

1.1.2行移位变换

行移位变换完成基于行的循环移位操作,state的第0行不动,第1行循环左移1个字节,第2行循环左移2个字节,第3行循环左移3个字节。

1.1.3列混淆

列混淆变换的正向列混淆变换对每列独立地进行操作。

每列中的每个字节被映射为一个新值,此值由该列中的四个字节通过函数变换得到,这个变换可由下面基于state的矩阵乘法表示。

状态中单列的列混淆变换可表示为

1.1.4轮密钥加

轮密钥加变换用于将输入或中间态S的每一列与一个密钥字W[i]进行按位异或,其中,W[i]由原始密钥通过密钥扩展算法产生。

1.2AES解密过程

AES解密过程为加密过程的逆,同为十轮,四个步骤按一定顺序执行,四个步骤分别为逆向字节替代(InvSubBytes),逆向行移位(InvShiftRows),逆向列混淆(InvMixColumns),轮密钥加(AddRoundKey),其中轮密钥加与加密过程中的步骤相同。

1.2.1逆向字节替代

AES定义了一个逆S盒,其替代方法与加密过程相同

1.2.2逆向行移位

逆向行移位与行移位变换相反,逆行移位变换将态State的后三行按相反的方向进行移位操作,即第0行保持不变,第1行向右移1个字节,第2行向右移2个字节,第3行向右移3个字节。

1.2.2逆向列混淆

逆列混淆变换的处理方法与列混淆变换类似,每一列都通过与一个固定的多项相乘进行变换。

写为矩阵乘法的形式,逆列混淆变换按以下方式对列进行变换:

1.3AES秘钥扩展

AES加密解密过程中,每一轮都需要一个与输入分组具有相同长度的扩展密钥W[i]的参与。

由于外部输入的加密密钥长度有限,所以在算法中要用一个密钥扩展程序把外部密钥扩展成更长的比特串,以生成各轮的加密和解密密钥。

其一轮过程如下图所示,一共需要进行十次,由原密钥扩展出10个密钥,分别用于每轮加解密。

其中g函数为行移位,自己替代以及与轮常量异或。

2.CMAC原理

CMAC为基于密码的消息认证码,生成认证码的过程课分为两种。

首先,当消息长度是分组长度b的n倍时,在此我们选择b=128,可将消息换分为n组(M1,M2.......Mn)。

算法使用了k位的加密密钥K和n位的常数K1.对于AES,密钥长度k为128、192或256位,在此我们选择128位,CMAC按如下方式计算

其中,T为消息认证码,也成为tag;Tlen是T的位长度,是位串的X最左边的s位。

如果消息不是密文分组长度的整数倍时,则最后分组的右边(低有效位)填充一个1和若干0使得最后的分组长度为b。

除了使用一个不同的n位密钥K2代替K1外,和前面所述的一样进行CMAC运算。

两个n位的密钥由K位的加密密钥按如下方式导出:

其中乘法(*)在域GF(2^n)内进行。

四、AES模块代码实现

1、字节替代

state值由16进制表示,因此state[r][c]=16i+j,i为高四位,j为低4位,s盒为16x16矩阵,因此只需用state[r][c]=sbox[state[r][c]]即可完成字节替代。

其实现代码如下:

voidSubBytes(unsignedcharstate[4][4])

{

intr,c;

for(r=0;r<4;r++)

{

for(c=0;c<4;c++)

{

state[r][c]=sbox[state[r][c]];

}

}

}

2、行移位

代码实现时,一行一行的完成,因为第一行不变,因此行移位由r=1开始到r=3,定义一个中间数组变量存储移位后改行每列的值,变换可由t[c]=state[r][(c+r)%4]实现,例如当r=1,c=1,t[1]=state[2],r=1,c=3,t[3]=state[0],即完成了第一行的移位,然后再将t[c]赋值回state[r][c]即可。

模块代码实现如下:

voidShiftRows(unsignedcharstate[][4])

{

unsignedchart[4];

intr,c;

for(r=1;r<4;r++)

{

for(c=0;c<4;c++)

{

t[c]=state[r][(c+r)%4];

}

for(c=0;c<4;c++)

{

state[r][c]=t[c];

}

}

}

3、列混淆

列混淆实现时,一列一列的进行,由原理可知,每个列混淆之后的元素都与该列的四个元素有关,因此定义一个中间变量t[r]存储原state值防止之后给state赋值时将原值覆盖,由列混淆原理,可总结出state列混淆之后每个元素的值为state[r][c]=FFmul(0x02,t[r])^FFmul(0x03,t[(r+1)%4])^FFmul(0x01,t[(r+2)%4])^FFmul(0x01,t[(r+3)%4]),其中FFmul为定义在GF(2^8)上的乘法,其元算原理为将某值x乘以2其结果左移以为,若该值的最左边的位为1,那么在移位后还要异或(00011001),而x乘以3即为{x}*{03}={x}*{02}^{x},x乘以{0E}{09}{0D}{0B}也可按相同方式实现,因此可以写出FFmul代码。

voidMixColumns(unsignedcharstate[][4])

{

unsignedchart[4];

intr,c;

for(c=0;c<4;c++)

{

for(r=0;r<4;r++)

{

t[r]=state[r][c];

}

for(r=0;r<4;r++)

{

state[r][c]=FFmul(0x02,t[r])^FFmul(0x03,t[(r+1)%4])

^FFmul(0x01,t[(r+2)%4])^FFmul(0x01,t[(r+3)%4]);

}

}

}

unsignedcharFFmul(unsignedchara,unsignedcharb)

{

unsignedcharbw[4];

unsignedcharres=0;

inti;

bw[0]=b;

for(i=1;i<4;i++)

{

bw[i]=bw[i-1]<<1;

if(bw[i-1]&0x80)

{

bw[i]^=0x1b;

}

}

for(i=0;i<4;i++)

{

if((a>>i)&0x01)

{

res^=bw[i];

}

}

returnres;

}

4、轮密钥加

轮密钥加即将state值与相应的key值相异或后再赋回state,因此只需用state[r][c]^=k[r][c]即可实现。

模块代码实现如下:

voidAddRoundKey(unsignedcharstate[][4],unsignedchark[][4])

{

intr,c;

for(c=0;c<4;c++)

{

for(r=0;r<4;r++)

{

state[r][c]^=k[r][c];

}

}

}

5、逆字节替代

逆字节替代与字节替代代码实现基本相同,指需将s盒换位逆s盒Invsbox即可。

模块代码实现如下:

voidInvSubBytes(unsignedcharstate[][4])

{

intr,c;

for(r=0;r<4;r++)

{

for(c=0;c<4;c++)

{

state[r][c]=Invsbox[state[r][c]];

}

}

}

6、逆向行移位

逆向行移位代码实现与行移位代码实现也基本相同,行移位为向左移,而逆向行移位为向右移,可由t[c]=state[r][(c-r+4)%4]实现。

模块代码实现如下:

voidInvShiftRows(unsignedcharstate[][4])

{

unsignedchart[4];

intr,c;

for(r=1;r<4;r++)

{

for(c=0;c<4;c++)

{

t[c]=state[r][(c-r+4)%4];

}

for(c=0;c<4;c++)

{

state[r][c]=t[c];

}

}

}

7、逆向列混淆

逆向列混淆代码实现与列混淆基本相同,只需将相乘的矩阵变换一下即可,化成单列表示时,只需将各元素之前的系数改变即可,state[r][c]=FFmul(0x0e,t[r])^FFmul(0x0b,t[(r+1)%4])^FFmul(0x0d,t[(r+2)%4])^FFmul(0x09,t[(r+3)%4]),而FFmul模块之前已经介绍过了。

模块代码实现如下:

voidInvMixColumns(unsignedcharstate[][4])

{

unsignedchart[4];

intr,c;

for(c=0;c<4;c++)

{

for(r=0;r<4;r++)

{

t[r]=state[r][c];

}

for(r=0;r<4;r++)

{

state[r][c]=FFmul(0x0e,t[r])^FFmul(0x0b,t[(r+1)%4])

^FFmul(0x0d,t[(r+2)%4])^FFmul(0x09,t[(r+3)%4]);

}

}

}

8、密钥扩展

密钥扩展共生成11个轮密钥w[0]~w[10]。

A.w[0]为原始输入密钥,可由代码w[0][r][c]=key[r+c*4]实现;

B.之后各轮密钥由前一密钥生成,首先将前一轮密钥第四列进行g函数变换;

C.g函数可由如下步骤实现

a.将第四列四个元素循环左移一位;

b.将循环移位后所得数组进行s盒字节替代,这两步可由t[r]=sbox[temp[(r+1)%4]]实现;其中temp[]数组存储前一轮密钥第三列元素值,t[]数组为定义中间变量数组;

c将t[]与轮常量相异或,轮常量只有最高字节有值,其余为0,可由t[0]^=rc[i-1]实现;

D.t[r]与前一轮密钥第一列相异或得到该轮密钥第一列,由w[i][r][0]=w[i-1][r][0]^t[r]实现;

E.该轮第2~4列密钥由前一轮对应列密钥与该轮前一列密钥异或得到,可由w[i][r][j]=w[i-1][r][j]^w[i][r][j-1]实现。

for(r=0;r<4;r++)

{

for(c=0;c<4;c++)

{

w[0][r][c]=key[r+c*4];

}

}

for(i=1;i<=10;i++)

{

unsignedchart[4];

unsignedchartemp[4];

for(r=0;r<4;r++)

{

temp[r]=w[i-1][r][3];

}

for(r=0;r<4;r++)

{

t[r]=sbox[temp[(r+1)%4]];

}

t[0]^=rc[i-1];

for(r=0;r<4;r++)

{

w[i][r][0]=w[i-1][r][0]^t[r];

}

for(j=1;j<4;j++)

{

for(r=0;r<4;r++)

{

w[i][r][j]=w[i-1][r][j]^w[i][r][j-1];

}

}

}

9.加密

加密过程首先进行一轮轮密钥加,之后进行十轮的变换,每次变换分为字节替代,行移位,列混淆,轮密钥加,其中第十轮变换不进行列混淆。

代码实现如下:

AddRoundKey(state,w[0]);

for(i=1;i<=10;i++)

{

SubBytes(state);

ShiftRows(state);

if(i!

=10)MixColumns(state);

AddRoundKey(state,w[i]);

}

10.解密

解密过程首先进行一轮轮密钥加,之后进行十轮的变换,每次变换分为逆字节替代,逆向行移位,逆向列混淆,轮密钥加,其中第十轮变换不进行逆向列混淆。

代码实现如下:

AddRoundKey(state,w[10]);

for(i=9;i>=0;i--)

{

InvShiftRows(state);

InvSubBytes(state);

AddRoundKey(state,w[i]);

if(i)

{

InvMixColumns(state);

}

}

五、CMAC模块代码实现

1.K1、K2生成

由CMAC生成原理可知道K1、K2的生成过程

a.,用AES加密,由AES_128(key,Z,L)实现,L定义为输出;

b.K1=L*x,乘法定义在GF(2^n),即将L左移一位,若L最高位为1,则将L左移一位之后再与const_Rb(常量)异或,左移由函数leftshift_onebit(L,K1)实现,K1定义为输出。

c.K2=L*x^2=K1*x,因此将L换位K1,重复进行b中操作即可得到K2。

voidgenerate_subkey(unsignedchar*key,unsignedchar*K1,unsignedchar*K2)

{

unsignedcharL[16];

unsignedcharZ[16];

unsignedchartmp[16];

inti;

for(i=0;i<16;i++)Z[i]=0;

AES_128(key,Z,L);

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。

模块代码实现如下:

voidleftshift_onebit(unsignedchar*input,unsignedchar*output)

{

inti;

unsignedcharoverflow=0;

for(i=15;i>=0;i--)

{

output[i]=input[i]<<1;

output[i]|=overflow;

overflow=(input[i]&0x80)?

1:

0;

}

return;

}

2.消息末组确定

当消息长度不是分组长度整数倍时,最后一组消息分组需要进行一些变换,因此需要一个函数来确定最后一组消息分组,这个函数定义为padding(unsignedchar*lastb,unsignedchar*pad,intlength),其中lastb为消息分组后剩下不能成为一组的元素,length为lastb的元素个数,pad定义为输出,为最后一组消息分组。

当pad[j]中j

voidpadding(unsignedchar*lastb,unsignedchar*pad,intlength)

{

intj;

for(j=0;j<16;j++)

{

if(j

{

pad[j]=lastb[j];

}

elseif(j==length)

{

pad[j]=0x80;

}

else

{

pad[j]=0x00;

}

}

}

3.CMAC生成

CMAC有函数AES_CMAC(unsignedchar*key,unsignedchar*input,intlength,unsignedchar*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%16)确定最后分组,length%16即为未分组元素个数,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]实现。

voidAES_CMAC(unsignedchar*key,unsignedchar*input,intlength,unsignedchar*mac)

{

unsignedcharX[16],Y[16],M_last[1

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2