【密码学】SHA-1加密原理及其Java实现
简介
安全哈希算法(Secure Hash Algorithm)主要适⽤于数字签名标准(DSS,Digital Signature Standard)⾥⾯定义的数字签名算法(DSA,Digital Signature Algorithm)
对于长度⼩于2^64位的消息,SHA1会产⽣⼀个160位的消息摘要。当接收到消息的时候,这个消息摘要可以⽤来验证数据的完整性。在传输的过程中,数据很可能会发⽣变化,那么这时候就会产⽣不同的消息摘要
SHA1有如下特性:
不可以从消息摘要中复原信息java源代码加密
两个不同的消息不会产⽣同样的消息摘要
发展历史
SHA-1算法的原理基于MD4和MD5消息摘要算法的设计原理,但是具有更保守的设计。
SHA-1是美国政府Capstone项⽬的⼀部分。该算法的原始规范于1993年以美国政府标准机构NIST(国家标准与技术研究所)的标题《Secure Hash Standard》出版。这个版本通常称为SHA-0。它在出版后不久被国家安全局撤回,并在1995年由SHA-1取代。
SHA-1与SHA-0的不同之处仅在于,其压缩功能的消息调度中单个按位旋转。根据国家安全局的说法,这是为了纠正原始算法中的缺陷,增强了其加密安全性,但没有提供任何进⼀步的解释。不过确实有公开技术能攻击SHA-0。
应⽤
密码体系
SHA-1构成了许多⼴泛使⽤的安全应⽤和协议的⼀部分,包括TLS和SSL,PGP,SSH,S / MIME和IPsec。这些应⽤程序也可以使⽤MD5(MD5和SHA-1均来⾃MD4)。
分布式版本控制系统(如Git,Mercurial和Monotone)也使⽤SHA-1散列来识别修订,并检测数据损坏或篡改。该算法也被⽤于任天堂的Wii游戏控制台,以便在引导时进⾏签名验证,但在固件的第⼀次实验中,存在允许攻击者绕过系统的安全性⽅案的⼀个重要缺陷。
SHA-1和SHA-2是法律要求在某些美国政府应⽤中使⽤的哈希算法,包括在其他加密算法和协议中使
⽤,⽤于保护敏感的未分类信息。FIPS PUB 180-1还⿎励私营和商业组织采⽤和使⽤SHA-1。SHA-1正在从⼤多数政府⽤途中退休,美国国家标准技术研究所表⽰:“联邦机构应尽快停⽌使⽤SHA-1应⽤程序,这些应⽤程序需要抗冲突,并且必须在2010年之后使⽤SHA-2系列的哈希功能进⾏这些应⽤。”,虽然后来放松了。
⾸先推动安全散列算法出版的是已合并的数位签名标准。
SHA 散列函数已被做为 SHACAL 分组密码算法的基础。
数据完整
Git和Mercurial等版本控制系统使⽤SHA-1不是为了安全,⽽是确保数据没有因意外的损坏⽽改变。 Linus Torvald说,关于Git:
如果您有磁盘损坏,如果您有DRAM损坏,如果您有任何问题,Git会注意到它们。这不是⼀个问题,是否是⼀个保证。你可以让⼈恶意破坏,但他们不会成功。没有⼈能够破解SHA-1,但关键是SHA-1,就Git来说,甚⾄不是⼀个安全功能。它纯粹是⼀致性检查。
安全部件在别的地⽅,所以很多⼈都认为,由于Git使⽤SHA-1,SHA-1⽤于加密安全的东西,他们认为,这是⼀个巨⼤的安全功能。它与安全⽆关,只是你可以得到的最好的哈希。
我保证,如果您将数据放在Git中,您可以信任五年后,从硬盘转换为DVD到任何新技术,并将其复制的五年之后,您可以验证你收到的数据是你输⼊的完全相同的数据。
我关⼼的⼀个原因是内核,我们在BitKeeper的⼀个⽹站上有⼀个突破,⼈们试图破坏内核源代码存储库。然⽽,Git不需要SHA-1的第⼆个preimage抵抗作为⼀个安全功能,因为它总是喜欢保持对象的最早版本的情况下发⽣冲突,防⽌攻击者偷偷覆盖⽂件。
SHA加密原理
位串和整数的定义
下⾯有关位串和整数的术语将被使⽤:
1. ⼀个⼗六进制数是集合{0, 1, … , 9, A, … , F}中的元素,表⽰4-bit⼆进制串。例如:7 = 0111, A = 1010。
2. ⼀个字表⽰32-bit⼆进制串,或者是8个⼗六进制数。把⼀个字转换成⼆进制串,等价于把每⼀个⼗六进制数转换成4-bit⼆进制串。
3. 0和2 ^ 32 - 1之间的整数可以表⽰为⼀个字。整数的最低有效四位是由最右边的⼗六进制数字表⽰。⽰例:整数291 = 2^8 + 2^5
+ 2^1 + 2^0 = 256 + 32 + 2 + 1由⼗六进制字00000123表⽰。如果z是整数,0 <= z < 2^64,则z =(2^32)x + y其中0 <= x < 2^32和0 <= y < 2^32。 由于x和y可以表⽰为字X和Y,z可以表⽰为⼀对单词(X,Y)。
4. block=512-bit⼆进制串。⼀个block可以表⽰成16个字。
对字的操作
下⾯的逻辑运算符将被⽤于字操作:
1. 按位逻辑运算:
X AND Y = X和Y的逻辑“和”
X OR Y = X和Y的逻辑“或”
X XOR Y = X和Y的逻辑“异或”
NOT X = X的逻辑“补”
Example:
01101100101110011101001001111011
XOR 01100101110000010110100110110111
--------------------------------
=00001001011110001011101111001100
2. 操作X + Y定义如下:字X和Y表⽰整数x和y,其中0 <= x < 2^32和0 <= y < 2^32。对于正整数n和m,令n mod m是将n除以m的
余数。计算z =(x + y)mod 2^32。 那么0 <= z < 2^32。将z转换为字Z,并定义Z = X + Y.
3. 循环左移运算S ^ n(X),其中X是⼀个字,n是0 <= n <32的整数,由如下定义:S^n(X)=(X << n)OR(X >> 32-n)。其中
X << n:舍弃X的最左n位,然后将结果填充到右边的n个零(结果仍然是32位)。X >> n是丢弃X的最右n位,然后在左边填充n个零。因此,S^n(X)等价于X向左移动n个位置的循环移位。
消息填充
SHA-1⽤于计算作为输⼊的消息或数据⽂件的消息摘要。消息或数据⽂件应该被认为是⼀个位字符串。消息的长度是消息中的位数(空消息的长度为0)。如果消息中的位数是8的倍数,为了紧凑,可以以⼗六进制表⽰消息。
消息填充的⽬的是使填充消息的总长度为512的倍数。当计算消息摘要时,SHA-1顺序处理512位的块。作为总结,随后是“1”后⾯跟着填充的“0”,64位的消息长度附加到消息的末尾以产⽣长度为512 * n的填充消息。 然后填充的消息由SHA-1处理为n个512位块。
要求输⼊到SHA-1的消息长度为L < 2^64,消息填充步骤如下:
1. 先填充⼀个“1”。
Example:
原始消息为:
01010000
填充过后为:
010100001
2. 再填充“0”。“0”的个数由原始消息长度决定。最后64-bit⽤原始消息的长度填充。
Example:
原始字符串⽤⼆进制表⽰为:
0110000101100010011000110110010001100101.
经过第⼀步后:
01100001011000100110001101100100011001011.
如果 L = 40, 现在填充的位有41个并且还有407个"0"被填充,使得总共填充448位。现在填充后的结果⽤⼗六进制表⽰为:
61626364658000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
0000000000000000
3. 获取原始消息长度L的⼆进制表⽰。如果L < 2^32,那么第⼀个字都是零。然后将这两个字追加到填充的消息中。
Example:
假设原始消息如2所⽰。那么L = 40(注意,L在任何填充之前计算)。40的⼗六进制为00000000 000
00028。因此,最后填充的消息是⼗六进制:
61626364 65800000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000028
对于某些n > 0,填充消息将包含16 * n个字。填充后的消息被认为是消息的n个块中的M(1),M(2),是消息的第⼀个字符(或⽐特)。
函数和常量
在SHA-1中使⽤⼀系列逻辑函数f(0),f(1),…,f(79)。 每个f(t),0 <= t <= 79,对三个32-bit字的B,C,D进⾏操作,并
产⽣32-bit字作为输出。 f(t; B,C,D)定义如下:对于B,C,D,
f(t;B,C,D) = (B AND C) OR ((NOT B) AND D)        ( 0 <= t <= 19)
f(t;B,C,D) = B XOR C XOR D                        (20 <= t <= 39)
f(t;B,C,D) = (B AND C) OR (B AND D) OR (C AND D)  (40 <= t <= 59)
f(t;B,C,D) = B XOR C XOR D                        (60 <= t <= 79)
⽤户SHA-1的常量K(0),K(1),…,K(79)。⽤⼗六进制表⽰为:
K(t) = 5A827999        ( 0 <= t <= 19)
K(t) = 6ED9EBA1        (20 <= t <= 39)
K(t) = 8F1BBCDC        (40 <= t <= 59)
K(t) = CA62C1D6        (60 <= t <= 79)
计算消息摘要
下⾯给出了两种产⽣消息摘要的⽅法。虽然使⽤⽅法2节省了64位32位存储字,但由于步骤(c)中{W [t]}的地址计算的复杂性增加,可能会延长执⾏时间。
⽅法⼀:消息摘要使⽤如前所述填充的消息进⾏计算。使⽤两个缓冲区来描述计算,每个缓冲区由五个32位字组成,⼋个32位字序列。第⼀个5字缓冲区的字被标记为A,B,C,D,E。第⼆个5字缓冲区的字被标记为H0,H1,H2,H3,H4。80字序列的字被标记为
W(0),W(1),…,W(79)。还使⽤单个字缓冲器TEMP。为了⽣成消息摘要,按顺序处理在前⾯定义的16字块
M(1),M(2),…,M(n)。每个M(i)的处理涉及80个步骤。
H常量⽤⼗六进制表⽰为:
H0 = 67452301
H1 = EFCDAB89
H2 = 98BADCFE
H3 = 10325476
H4 = C3D2E1F0.
现在M(1), M(2), ... , M(n)已经有了。为了产⽣M(i),有如下步骤:
a. Divide M(i) into 16 words W(0), W(1), ... , W(15), where W(0) is the left-most word.
b. For t = 16 to 79 let
W(t) = S^1(W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16)).
c. Let A = H0, B = H1, C = H2, D = H3, E = H4.
d. For t = 0 to 79 do
TEMP = S^5(A) + f(t;B,C,D) + E + W(t) + K(t);
E = D;  D = C;  C = S^30(B);  B = A; A = TEMP;
e. Let H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E.
产⽣M(n)之后,消息摘要就是160-bit串由5字H0 H1 H2 H3 H4表⽰
⽅法⼆:上述⽅法假设序列W(0),…,W(79)被实现为80个32-bit字的数组。从执⾏时间的最⼩
化的观点来看,这是有效的,因为步骤(b)中的W(t-3),…,W(t-16)的地址容易被计算。如果空间是⾮常重要的,另⼀种⽅法是将{W(t)}视为圆环队列,这可以使⽤⼗六进制数组来实现32位字W [0],… W [15]。在这种情况下,⽤⼗六进制表⽰MASK = 0000000F。那么M(i)的处理如下:
a. Divide M(i) into 16 words W[0], ... , W[15], where W[0] is the left-most word.
b. Let A = H0, B = H1, C = H2, D = H3, E = H4.
c. For t = 0 to 79 do
s = t AND MASK;
if (t >= 16) W[s] = S^1(W[(s + 13) AND MASK] XOR W[(s + 8) AND MASK] XOR W[(s + 2) AND MASK] XOR W[s]);
TEMP = S^5(A) + f(t;B,C,D) + E + W[s] + K(t);
E = D; D = C; C = S^30(B); B = A; A = TEMP;
d. Let H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E.
伪代码
SHA-1算法的伪代码如下:
Note 1: 所有变量都是⽆符号的32-bit,并且都在模2^32下做运算,除了
ml,消息长度,64-bit
hh,消息摘要,160-bit
Note 2: 所有定量都是⼤端存储
每⼀个字的重要字节都存储在最左边
Initialize variables:
h0 = 0x67452301

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。