《信息安全技术》实验报告
实验三 简单消息认证实验
1、实验目的
掌握消息摘要Hash算法的原理。
掌握消息认证的方法。
2、实验环境
硬件:ZXBee CC2530 节点板 2 块、USB 接口的 CC2530 仿真器,PC 机;
软件:Windows 7/Windows XP、IAR 集成开发环境、串口监控程序。
3、实验原理
假设所有发送及接收节点均工作在同一信号,每个节点均可监听到其他节点发送的数据。如何确信消息是来源声称的身份所发送的?同时,如何确保消息在传输过程中没有收到篡改?解决方法是采用消息认证机制。
4、实验步骤
1)本实验程序可在《指导书》4.4节程序上进行修改,可节约时间。信道编号不用更改。
2)增加下列三个函数和有关定义。
#define MD_LEN 5 //消息摘要长度,字节(40bit) //简化版的消息摘要,长度为5字节 #define BLOCK_SIZE 16 //Hash处理的块长度,字节(128bit) //简化版的SHA处理数据块大小,长度为16字节
//字节循环左移函数 uint8 crol(uint8 c, uint8 b) { uint8 left=c<<b; uint8 right=c>>(8-b); uint8 temp=left|right; return temp; }
//简化版的SHA函数 void HashTransfer(uint8 *yText, uint8 *MD) { uint8 A=MD[0],B=MD[1],C=MD[2],D=MD[3],E=MD[4]; uint8 TA,TB,TC,TD; int i;
for(i=0;i<20;i++) //只做20步,用一个逻辑函数 { TA=A;TB=B;TC=C;TD=D; A=crol(A,3)+(B&C)|(~B&D)+E+yText[i%MD_LEN]; B=TA; C=crol(TB,6); D=TC; E=TD; }
MD[0]=MD[0]^A; MD[1]=MD[1]^B; MD[2]=MD[2]^C; MD[3]=MD[3]^D; MD[4]=MD[4]^E; }
//消息摘要函数 void Hash(uint8 *Text, uint8 *MD, int TextLen) { int i; int leftLen=TextLen; uint8 yText[BLOCK_SIZE];
uint8 IV[MD_LEN]={'\x67','\xEF','\x98','\x10','\xC3'}; memcpy(MD, IV, MD_LEN); //初始化MD
//简化版的分块,不足一个分块大小的后面补0 for(i=0;i<(TextLen/BLOCK_SIZE+1);i++) { if(leftLen/BLOCK_SIZE!=0) { memcpy(yText, Text+i*BLOCK_SIZE, BLOCK_SIZE); } else { memcpy(yText, Text+i*BLOCK_SIZE, leftLen); memset(yText+leftLen, 0, BLOCK_SIZE-leftLen); }
//简化版SHA转换 HashTransfer(yText, MD);
leftLen=leftLen-BLOCK_SIZE; } } |
3)增加一个发送数据函数rfSendData()。发送节点每隔 1s发送一次数据。发送数据的格式为:
字段名称 |
消息内容长度 |
消息内容 |
HMAC |
长度(字节) |
1 |
2~256 |
5 |
代码:
/*发送数据函数 */ void rfSendData(void) { uint8 PlainText[] = { "No.15:GuangdongUniversity of Technology.\n" }; //待发送的数据 uint8 MD[MD_LEN]; uint8 pTxData[128]; //用来存放发送数据
Hash(PlainText, MD, sizeof PlainText); //产生消息摘要 pTxData[0]=sizeof PlainText; memcpy(pTxData+1, PlainText, sizeof PlainText); memcpy(pTxData+(sizeof PlainText)+1, MD, MD_LEN);
while(TRUE){ basicRfSendPacket(RECV_ADDR, pTxData, (sizeof PlainText)+6); //发送数据 halMcuWaitMs(1000); } } |
上面的PlainText[]数组中“No.15”改为各实验小组的组号。
4)修改接收数据函数rfRecvData()。接收节点不断接收各个发送节点发送的信息,并通过串口显示。
/* 接收数据函数 */ void rfRecvData(void) { uint8 pRxData[128]; //用来存放接收到的数据 int rlen; basicRfReceiveOn(); //打开接收器 uint8 Len; unsigned char Flag;
while (TRUE) { while(!basicRfPacketIsReady()); //等待直到数据准备好 rlen = basicRfReceive(pRxData, sizeof pRxData, NULL); //接收数据 if(rlen > 0) { //接收到数据 printf(pRxData); } } } |
注意:这个时候pRxData是不是字符串?里面是否含有非ASCII字符?为什么?
5)编写一个消息摘要认证函数MDCertify( )。其中省略号部分自己填充完成。
/* 消息认证函数 */ unsigned char MDCertify (uint8 *Msg, uint8 *MD, uint8 Len) { uint8 MDx[MD_LEN]; unsigned char ret; //认证的结果,1:正确,0:不正确
Hash(Msg, MDx, Len); //产生消息摘要
…… //比较MD和MDx
return ret; } |
6)修改接收数据函数rfRecvData(),添加如下代码。接收节点不断接收各个发送节点发送的信息,然后认证MAC,并通过串口显示认证结果。
printf(pRxData); Len= *pRxData; //获得消息内容的长度 Flag=MDCertify (pRxData+1, pRxData+1+Len, Len); //认证消息 if(Flag) printf("Correct!\n"); else printf("Incorrect!\n"); |
注意:(1)上面代码应该放在函数rfRecvData()的什么地方,请自行思考。
(2) 如果希望串口输出不要出现乱码(非ASCII字符),上面的代码应该如何修改?
7)上面的消息认证过程中没有使用任何密钥,请自行修改代码,在消息的前面增加一个字节作为秘密值。这个秘密值各个小组可自行设定。发送节点的参考代码:
uint8 secret=15; //秘密值可修改,如自己的组号 uint8 Text[(sizeof PlainText)+1]; Text[0]=secret; for(i=0;i<(sizeof PlainText);i++) Text[i+1]=PlainText[i];
Hash(Text, MD, (sizeof PlainText)+1); //产生消息摘要 |
此时,接收节点先不用更改,观察消息认证是否正确。
8)接收节点收到消息之后,同样需要在消息的前面增加一个字节的秘密值,然后才进行消息认证。修改消息摘要认证函数MDCertify( )。增加一个形参secret。
unsigned char MDCertify (uint8 *Msg, uint8 *MD, uint8 Len, uint8 secret); |
要求在消息认证函数里面,可以使用secret参数参与MD的计算。
5、实验结果
实验的结果注意观察下列情况,并对比(截图保存)。
1) 发送节点发送消息,接收节点接收后显示,对应步骤4。
2) 发送节点发送消息,接收节点接收后验证消息并显示,对应步骤6。
3) 发送节点使用秘密值计算MD,但接收节点没有使用秘密值或者不知道秘密值,对应步骤7。
4) 发送节点使用秘密值计算MD,接收节点使用相同的秘密值认证消息,对应步骤8。
对实验结果中出现乱码(非ASCII字符)的情形,要说明为什么出现?