一种生成消息摘要的方法
技术领域
本发明涉及密钥算法领域,特别涉及一种生成消息摘要的方法。
背景技术
在现有信息加密技术中,常见的信息保护手段大致可以分为保密和认证两大类。目前的认证技术有对用户的认证和对消息的认证两种方式,用户认证用于鉴别用户的身份是否是合法用户;消息认证就是验证所收到的消息确实是来自真正的发送方且未被修改的消息,也可以验证消息的顺序和及时性。消息认证实际上是对消息本身产生一个冗余的信息-MAC(Message Authentication Code,消息认证码),消息认证码是利用密钥对要认证的消息产生新的数据块,并对数据块加密生成的。它对于要保护的信息来说是唯一和一一对应的。因此可以有效地保护消息的完整性,以及实现发送方消息的不可抵赖和不能伪造。消息认证码的安全性取决于两点:1)采用的加密算法生成数字签名;2)待加密数据块的生成方法。用消息认证码实现消息认证可通过消息摘要方案来实现。消息摘要通常是利用目前广泛应用的单向散列函数来生成。
安全哈希算法(SHA,Secure Hash Algorithm)主要适用于数字签名标准(DSS,DigitalSignature Standard)里面定义的数字签名算法(DSA,Digital Signature Algorithm)。其SHA1算法就是一种目前广泛应用的单向散列函数,对于长度小于264位的消息,SHA1会产生一个160位即20字节的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。
SHA1有如下特性:不可以从消息摘要中复原信息;两个不同的消息不会产生同样的消息摘要。SHA1始终把消息当成一个位(bit)字符串来处理。本文中,一个“字”(Word)是32位,而一个“字节”(Byte)是8位。比如,字符串“abc”可以被转换成一个位字符串:01100001 01100010 01100011,它也可以被表示成16进制字符串:0x616263。
SHA1中循环左移位操作符Sn(X),其中,X是一个字,n是一个整数,0<=n<=32,Sn(X)=(X<<n)OR(X>>32-n)。
X<<n定义如下:抛弃最左边的n位数字,将其余各个位依次向左移动n位,然后用0填补右边的n位(最后结果还是32位)。
X>>n是抛弃右边的n位,将其余各个位依次向右移动n位,然后在左边的n位填0。
在SHA1算法中,必须把原始消息(字符串,文件等)转换成位字符串。SHA1算法只接受位作为输入,假设对字符串“abc”产生消息摘要。首先,将它转换成位字符串如下:
01100001 01100010 01100011
—————————————
‘a’=97‘b’=98‘c’=99
这个位字符串的长度为24位,需要5个步骤来计算SHA1:
1)补位消息必须进行补位,以使其长度在对512取模以后的余数是448。也就是说,(补位后的消息长度)%512=448,即使长度已经满足对512取模后余数是448,补位也必须要进行。补位是这样进行的:先补一个1,然后再补0,直到长度满足对512取模后余数是448,总而言之;补位是至少补一位,最多补512位,还是以前面的“abc”为例显示补位的过程:
原始信息:01100001 01100010 01100011
补位第一步:01100001 01100010 01100011 1 首先补一个“1”
补位第二步:01100001 01100010 01100011 10...0 然后补423个“0”
可以把最后补位完成后的数据用16进制写成下面的样子
61626380 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000
现在,数据的长度是448,可以进行下一步操作;
2)补长度
所谓的补长度是将原始数据的长度补到已经进行了补位操作的消息后面,通常用一个64位的数据来表示原始消息的长度,如果消息长度不大于264,那么第一个字就是0,在进行了补长度的操作以后,整个消息就变成下面这样了(16进制格式):
61626380 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000018
如果原始的消息长度超过了512,需要将它补成512的倍数,然后把整个消息分成多个长度为512位的数据块(16个字的数据块M1,M2,...,Mn),分别处理每一个数据块Mn,从而得到消息摘要;
3)使用的常量
一系列的常量字K(0),K(1),......,K(79),如果以16进制给出,它们如下:
Kt=0x5A827999(0<=t<=19)
Kt=0x6ED9EBA1(20<=t<=39)
Kt=0x8F1BBCDC(40<=t<=59)
Kt=0xCA62C1D6(60<=t<=79);
4)需要使用的函数
在SHA1中需要一系列的函数,每个函数ft(0<=t<=79)都操作32位字B,C,D并且产生32位字作为输出,ft(B,C,D)可以如下定义:
ft(B,C,D)=(B AND C)or((NOT B)AND D)(0<=t<=19)
ft(B,C,D)=B XOR C XOR D (20<=t<=39)
ft(B,C,D)=(B AND C)or(B AND D)or(C AND D)(40<=t<=59)
ft(B,C,D)=B XOR C XOR D (60<=t<=79);
5)计算消息摘要
必须使用进行了补位和补长度后的消息来计算消息摘要,计算需要两个缓冲区,每个都由5个32位的字组成,还需要80个容量为32位字的缓冲区,第一个5个字的缓冲区被标识为A,B,C,D,E。第二个5个字的缓冲区被标识为H0,H1,H2,H3,H4。80个字的缓冲区被标识为W0,W1,...,W79,另外还需要一个一个字的临时缓冲区Temp,为了产生消息摘要,前面定义的16个字的数据块M1,M2,...,Mn会依次进行处理,处理每个数据块Mi包含下述5个步骤。在处理每个数据块之前,缓冲区{Hi}被初始化为下面的值(16进制):
H0=0x67452301;H1=0xEFCDAB89;H2=0x98BADCFE;H3=0x10325476;H4=0xC3D2E1F0,
现在开始处理M1,M2,...,Mn。为了处理Mi,需要进行下面的步骤:
(1).将Mi分成16个字W0,W1,...,W15,W0是最左边的字;
(2).对于t=16到79令Wt=S1(Wt-3 XOR Wt-8 XOR Wt-14 XOR Wt-16);
(3).令A=H0,B=H1,C=H2,D=H3,E=H4;
(4).对于t=0到79,执行下面的循环;
Temp=S5(A)+ft(B,C,D)+E+Wt+Kt;
E=D;D=C;C=S30(B);B=A;A=Temp;
(5).令H0=H0+A,H1=H1+B,H2=H2+C,H3=H3+D,H4=H4+E。
在处理完所有的Mn后,消息摘要是一个160位的字符串,以下面的顺序标识H0 H1 H2H3 H4。
标准的SHA1算法的特点是需要80个容量为32位字的缓冲区,还需要为消息的补位补长度分配缓冲区,这造成了RAM资源的浪费,密钥生成设备的不断低成本化是产品的趋势所在,由于密钥生成设备中的RAM区通常很小(256字节以内),这会导致无法有足够的RAM资源来满足SHA1算法运算。
发明内容
为了降低生成消息摘要的过程中占用的存储空间,本发明实施例提供了一种生成消息摘要的方法。所述技术方案如下:
一种生成消息摘要的方法,所述方法包括:
步骤A1:用预先规定的常量分别初始化字变量1、字变量2、字变量3、字变量4和字变量5;根据预设的消息块长度对原始消息进行补位和补长度处理,得到新消息,将所述新消息划分为多个消息块,每个消息块的长度为所述预设的消息块长度,计算所述消息块的总块数、所述新消息的补位总长度;初始化当前消息块号为0;
步骤A2:判断当前消息块号是否小于消息块的总块数,如果是,执行步骤A3,否则,执行步骤A7;
步骤A3:根据所述当前消息块在所述新消息中的位置初始化中间量缓冲区,将所述中间量缓冲区中按字节规则存放的数据转换为按字规则存放的数据,从而得到16字中间量;
步骤A4:将所述字变量1、字变量2、字变量3、字变量4和字变量5分别赋给预先设定的字变量6、字变量7、字变量8、字变量9和字变量10,令计数变量等于0;
步骤A5:对于计数变量取值0到79,循环计算中间量、字变量6、字变量7、字变量8、字变量9和字变量10;其中,所述计数变量的初始值为0,每循环计算一次,所述计数变量加1;每循环一次,根据当前中间量按照预设规则修改所述字变量6、字变量7、字变量8、字变量9和字变量10;所述中间量分如下两步计算:
1)如果所述计数变量取值0到15,把所述中间量缓冲区中计数变量对应的中间量作为当前中间量;
2)如果所述计数变量取值16到79,将所述中间量缓冲区中缓存的16个中间量依次从0至15编号,提取所述16个中间量中第0、2、8、13个编号对应的中间量,运用预先规定的算法计算当前中间量,并根据所述当前中间量更新所述中间量缓冲区中的中间量;
步骤A6:所述计数变量等于80时,根据如下公式:
字变量1=字变量1+字变量6,
字变量2=字变量2+字变量7,
字变量3=字变量3+字变量8,
字变量4=字变量4+字变量9,
字变量5=字变量5+字变量10;
计算当前字变量1、字变量2、字变量3、字变量4和字变量5;当前消息块号加1;执行步骤A2;
步骤A7:每个消息块都处理完毕,将当前的字变量1、字变量2、字变量3、字变量4和字变量5作为消息摘要。
所述步骤A1中的预先规定的常量为0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0。
所述步骤A1中的计算所述消息块的总块数、所述新消息的补位总长度包括:
所述消息块的总块数等于所述新消息的长度的六十四分之一;
将所述新消息的长度减去所述原始消息的长度,得到的结果再减去8后的值作为所述新消息的补位总长度。
所述步骤A3包括:
步骤A31:如果当前消息块位于所述新消息中的原始消息部分,则用所述当前消息块按字节顺序初始化所述中间量缓冲区,然后执行步骤A34;
步骤A32:如果所述当前消息块中位于所述新消息中的原始消息部分的长度大于1,且小于64字节,则用所述当前消息块中的原始消息部分按字节顺序初始化中间量缓冲区,所述中间量缓冲区没有初始化的单元按消息补位、补长度规则进行补位及补长度,若只补位就完成中间量缓冲区的剩余单元的初始化,然后执行步骤A34,否则,在补位后再补长度来完成中间量缓冲区的剩余单元的初始化,然后后执行步骤A34;
步骤A33:如果所述当前消息块位于所述新消息中的补位或补长度部分,按消息补位、补长度规则初始化中间量缓冲区,然后执行步骤A34;
步骤A34:把中间量缓冲区中按字节规则存放的数据转换成按字规则存放的数据,从而得到16字中间量。
所述步骤A5中的运用预先规定的算法计算当前中间量,并根据所述当前中间量更新所述中间量缓冲区中的中间量的步骤包括:
对提取出的第0、2、8、13个编号对应的中间量进行异或运算,对异或运算的结果做循环左移1位运算,将移位后的结果作为当前中间量;
把所述中间量缓冲区中第1至15号中间量依次赋值给第0至14号中间量,然后将第15号中间量保存所述当前中间量。
本发明实施例提供的技术方案的有益效果是:
本发明通过在使用中间量时再进行计算,不仅把标准SHA1算法运算所需的80个容量为32位字中间量缓冲区减少到仅需16个字的中间量缓冲区,节省了256字节的RAM资源,而且,用这16个字中间量缓冲区临时缓存运算所需的消息的补位及补长度数据,避免了这些数据单独占用一块RAM资源,又可节省72字节的RAM资源。因此,本发明解决了现有技术中SHA1算法无法在资源(存储空间)有限的场合上应用的难题。例如,本发明可以广泛应用于RAM资源小、成本低的密钥生成设备中,降低对设备的要求,提高了设备应用的竞争力。
附图说明
图1是本发明实施例提供的生成消息摘要的方法的流程图。
具体实施方式
为使本发明的目的、技术方案和优点更加清楚,下面将结合附图对本发明实施方式作进一步地详细描述。
本发明实施例通过改进现有技术中的SHA1算法,应用改进后的SHA1算法生成消息摘要,并将该算法生成的消息摘要作为信息交互过程中的认证密钥,既保证了信息交互的安全性,又降低了生成消息摘要过程中所占用的存储空间,降低了对设备的要求。
为使本发明的目的、技术方案和优点更加清楚,以USB接口的一次性密码生成设备为例,来具体说明该设备中采用改进后SHA1算法生成消息摘要的过程。在本实施例中,USB接口的一次性密码生成设备简称USB Key,首先需要进行如下初始化过程:
SHA1算法有两个输入,分别是原始消息Message和原始消息长度MessageLen,而输出是20字节消息摘要,本实施例将消息摘要放在字变量1、字变量2、字变量3、字变量4和字变量5中,其中,字变量1、字变量2、字变量3、字变量4和字变量5分别用H0、H1、H2、H3、H4表示;同时,本发明中需要用到16字的中间量缓冲区W,32位字的字变量6、字变量7、字变量8、字变量9和字变量10,其中,字变量6、字变量7、字变量8、字变量9和字变量10分别用A、B、C、D、E表示,一个字节的当前消息块号CurBlock,消息总块数N,消息补位总长度X、一个32位字临时缓冲区Temp,以及用于循环计数的单字节计数变量t、i;中间量Wt是一个符号,表示一个32位的字,t是下标,t可变;
本发明实施例提供的生成消息摘要的方法,原始消息以字节为单位,参见图1,使用上述初始化后的USB Key,该方法具体包括:
步骤101:用预先规定常量初始化H0,H1,H2,H3,H4;根据预设的消息块长度对原始消息进行补位和补长度处理,得到新消息,将新消息划分为多个消息块,每个消息块的长度为预设的消息块长度,例如64字节,计算消息块的总块数N、新消息的补位总长度X;初始化当前消息块号i为0;
本实施例采用的预先规定的常数分别为0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0,将这五个常量分别赋给H0,H1,H2,H3,H4;根据需要也可以采用其它常量实现。
计算消息块的总块数N、新消息的补位总长度X时可以采用如下方法实现:
如果(MessageLen&0x3F)<56,则
N=(MessageLen&0xc0+64)/64;
X=(MessageLen&0xc0+64)-MessageLen-8;
如果(MessageLen&0x3F)>=56,则
N=(MessageLen&0xc0+128)/64;
X=(MessageLen&0xc0+128)-MessageLen-8;
步骤102:判断当前消息块号i算法小于消息块的总块数N,则执行步骤103,否则,执行步骤107;
步骤103:根据当前消息块在新消息中的位置初始化中间量缓冲区,将中间量缓冲区中按字节规则存放的数据转换为按字规则存放的数据,从而得到16字中间量;
根据当前消息块在新消息中的位置的不同,初始化中间量缓冲区W的方法也不同,简单描述如下:
1)如果MessageLen-CurBlock*64≥64,即原始消息中存在当前64字节的消息块,则用地址(Message+CurBlock*64)开始的64字节消息块初始化中间量缓冲区;
例如:若原始消息为65字节的消息,因每个消息块的长度为64字节,则按补位、补长度规则需要通过补位、补长度将原始消息补成128字节的新消息,新消息将会被划分为两个消息块,对应消息块号0对应的消息块,有65-0×64=65≥64字节,此时,若正在处理消息块0,则用消息块0初始化中间量缓冲区;
2)如果0<MessageLen-CurBlock*64<64,即当前消息块中有一部分为原始消息中的部分,一部分为新消息中的补位部分,则用地址(Message+CurBlock*64)开始的(MessageLen-CurBlock*64)字节消息块初始化中间量缓冲区;若只补位就完成中间量缓冲区的剩余单元的初始化(这在消息补位总长度X>56,即消息补位多于448位时会发生,剩余的补位数据及补长度数据下次处理),则只进行补位初始化操作,否则,在补位后再补长度来完成中间量缓冲区的剩余单元的初始化;
例如:若原始消息为65字节的消息,因每个消息块的长度为64字节,则按补位、补长度规则需要通过补位、补长度将原始消息补成128字节的新消息,新消息将会被划分为两个消息块,对应消息块号1对应的消息块,有65-1×64=1<64字节,此时,若正在处理消息块1,则先用消息块1中的1个数据来初始化中间量缓冲区,然后用补位数据0x80及连续54个0,8字节补长度数据(0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x08),共63个字节数据来完成中间量缓冲区的剩余单元的初始化;
3)如果MessageLen<=CurBlock*64,这种情况下消息补位大于448位,原始消息中不存在当前消息块,故要用按消息补位、补长度规则所生成的数据来初始化中间量缓冲区;
例如:若原始消息为120字节的消息,因每个消息块的长度为64字节,则按补位、补长度规则需要通过补位、补长度将原始消息补成192字节的新消息,新消息将会被划分为三个消息块,消息块0全由原始消息组成,而消息块1由部分原始消息及部分补位数据组成,消息块2则全部由部分补位及补长度数据组成。此时,若正在处理消息块2,则需用连续56个字节0,8字节补长度数据(0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0),共64个字节数据来完成中间量缓冲区的剩余单元的初始化;
4)中间量缓冲区经过上述初始化后,把中间量缓冲区中按字节规则存放的数据按字规则存放的数据,从而得到16字中间量;
步骤104:把H0、H1、H2、H3、H4分别赋给A、B、C、D、E;即令A=H0;B=H1;C=H2;D=H3;E=H4,t=0;
步骤105:对于t取值0到79,循环计算Wt,A、B、C、D、E;Wt的计算分如下两步:
1)如果t取值0到15,则Temp=Wt;
2)如果t取值16到79,令Temp=S1(W13^W8^W2^W0);
根据Wi=Wi+1,得到新的15个字W0~W14;W15=Temp;
然后,根据下列算式得到A、B、C、D、E,更新计数值t:
Temp=S5(A)+ft(B,C,D)+E+Temp+Kt;
E=D;D=C;C=S30(B);B=A;A=Temp;
t=t+1;
步骤106:t等于80时,根据如下公式:
令H0=H0+A,H1=H1+B,H2=H2+C,H3=H3+D,H4=H4+E;令i=i+1;
计算H0、H1、H2、H3、H4;当前的i,执行步骤102;
步骤107:所有消息块都已处理完毕,将当前的H0、H1、H2、H3、H4作为消息摘要。
上述方法把补位、补长度的消息划分为若干消息块依次处理,补位及补长度过程中使用的数据不单独分配RAM资源,仅在需要时即时进行计算,并初始化中间量缓冲区;其中,中间量缓冲区是处理一个消息块所用到的一个16个字的中间量缓冲区,当前中间量根据该中间量缓冲区中的16个字计算而来,每计算一个中间量,16个中间量缓冲区就依次按字移动,实现中间量缓冲区中数据的动态更新,并根据更新后的中间量缓冲区计算消息摘要。
下面给出了用改进的SHA1对247字节内短消息(补位长度小于等于56字节)求消息摘要的程序代码,用来参考。
//说明:该函数针对用短消息初始化16字缓冲区W;短消息的补位长度小于等于56字节。
//参数:1)W--16字缓冲区W
// 2)Message--消息缓冲区
// 3)MessageLen--消息长度
// 4)CurBlock-当前块索引
void InitBufW(unsigned int*W,unsigned char *Message,
unsigned char MessageLen,unsigned char CurBlock)
{
unsigned char len,temp;
unsigned char *ptr;
unsigned int ww;
temp=MessageLen-CurBlock*64;
if(temp>=64) len=64;
else len=temp;
ptr=Message+CurBlock*64;
memcpy((unsigned char*)W,ptr,len);
if(len<56)
{
/*补消息位*/
ptr=(unsigned char*)W;
ptr=ptr+len;
*ptr++=0x80;
memset(ptr,0,55-len);
/*补消息长度*/
ptr=ptr+55-len;
*ptr++=MessageLen>>56;
*ptr++=MessageLen>>48;
*ptr++=MessageLen>>40;
*ptr++=MessageLen>>32;
*ptr++=MessageLen>>24;
*ptr++=MessageLen>>16;
*ptr++=MessageLen>>8;
*ptr++=MessageLen;
}
/*数据类型转换*/
ptr=(unsigned char*)W;
for(len=0;len<16;len++)
{ ww=(((unsigned int)*(ptr+4*len)<<24) |
(((unsigned int)*(ptr+4*len+1))<<16) |
(((unsigned int)*(ptr+4*len+2))<<8) |
((unsigned int)*(ptr+4*len+3));
pBufW[len]=ww;
}
}
下面代码是关于如何得到t=0至t=79时Wt,并计算对应的A,B,C,D,E
for(t=0;t<80;t++)
{
if(t<16) //读取t<16时的Wt(即Temp)
{
Temp=W[t];
}
else //计算16=<t<=79时的Wt(即Temp)
{ Temp=rotl(1,(W[13]^W[8]^W[2]^W[0]));
for(j=0;j<15;j++) //更新16字缓冲区W
{ W[j]=W[j+1];}
W[j]=Temp;
}
Temp=rotl(5,A)+ft(t,B,C,D)+E+Temp+K(t);;
E=D;
D=C;
C=rotl(30,B); //字B循环左移30位
B=A;
A=Temp;
} //for(...)
采用本发明实施例提供的生成消息摘要的方法来计算消息摘要,运算中使用的中间量缓冲区的大小为16个字,中间量的初始化在步骤103中完成,用这16个字中间量缓冲区临时缓存运算所需的消息的补位及补长度数据,避免了这些数据在密钥生成设备内部单独占用一块RAM资源,可节省72字节的RAM资源;当前中间量的计算和中间量缓冲区的数据更新是在步骤105中完成,比原有的SHA1算法所需的80个容量为32位字中间量缓冲区少用64个32位字的中间量缓冲区,从而节省了256字节的RAM资源。
以上对本发明所提供的一种密钥生成设备中的生成消息摘要的方法进行了详细介绍,本文中应用了具体个例对本发明的原理及实施方式进行了阐述,以上实施例的说明只是用于帮助理解本发明的方法及其核心思想;同时,对于本领域的一般技术人员,依据本发明的思想,在具体实施方式及应用范围上均会有改变之处,综上所述,本说明书内容不应理解为对本发明的限制。