SHA-1加密实现
Copyright © 2018 Joyce_BY
All rights reserved.
Contact by [email protected]
实验原理
SHA-1接受一串二进制输入,加密后得到160bit的消息摘要,是一种hash加密。
算法的主要过程如下:
- 接收一串比特流,对其进行如下扩展:
- 在比特流尾部添加一个‘1’;
- 在新的比特流的尾部添加[0,512)个‘0’,使得最终bit数congruent to 448(mod 512);
- 最后在比特流尾部添加上64-bit的原消息长度。
- 初始化数值如下:
h = [0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0]
k = [0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6]
- 把扩展后的bit stream以每512bit分组作为一个chunk,对每个chunk进行如下操作:
a) 把此chunk分成16个32bit的word;
b) 将16个word扩展到80个word,如下:
word = leftrotate(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16],1)
c) 初始化a,b,c,d,e,分别等于h[0] - h[4];
d) 对word[i]做如下操作:
根据i算出f;
f = (b and c) or ((not b) and d), 0 ≤ i ≤ 19
f = b xor c xor d, 20 ≤ i ≤ 39
f = (b and c) or (b and d) or (c and d), 40 ≤ i ≤ 59
f = b xor c xor d, 60 ≤ i ≤ 79
算出新的a,b,c,d,e的值:
temp = (a leftrotate 5) + f + e + k[i/20] + w[i]
e = d,d = c,c = b leftrotate 30,b = a,a = temp
将新的a,b,c,d,e的值对应加到h[0]-h[4]得到新的h,作为下一个chunk的初始hash值。
- 最终将得到的h[0]-h[4]连接起来就是160bit的消息摘要。
hh = (h[0] << 128) | (h[1] << 96) | (h[2] << 64) | (h[3] << 32) | h[4]
主要算法
- 消息预处理
得到最初的消息长度;
把传入的str类型变量转换成字节存储在一个list中;
添加1,因为基于字节操作,也就是添加0x80;
加0直到list的长度在模64下与与-8同余;
将原始长度以8字节添加到末尾;
每64个字节为一个chunk,将其分为一个list;
最终返回一个含有n个列表,每个列表含64个字节的列表。
CODE
def preprocess(ss):
ml = len(ss)*8
li = []
for ch in ss:
li.append(ord(ch))
li.append(0x80)
if len(li) % 64 < 56:
li.extend([0]*(56 - len(li) % 64))
li.extend([0,0,0,0,0,0,0,ml])
ans = []
while li:
ans.append(li[:64])
li = li[64:]
return ans
- 处理消息块
初始化哈希值h和k值;
对每个chunk:
初始化临时哈希值a-e;
将每个chunk分为16个字;
由16个字扩展为80个字;
对每个字进行相关位运算,并重新计算临时哈希值;
将临时hash值加到hash值h中,得到下一个chunk的哈希值;
最后将得到的h连接起来形成最终的消息摘要。
注意事项:
- 这里leftrotate是一种循环位移,通过如下操作进行:
def leftrotate(a,num): #ok
word = (a << num) | (a >> (32-num)) & 0xFFFFFFFF
return word - 算法中用到的加法都是mod 2^32的,代码中只需要 &= 0xFFFFFFFF即可实现。
CODE
def processchunk(chunks):
h = [0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0]
k = [0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6]
for chunk in chunks:
w = []
while chunk:
temp = chunk[:4]
chunk = chunk[4:]
word = (temp[0] << 24) | (temp[1] << 16) | (temp[2] << 8) | temp[3]
w.append(word)
i = 16
while i < 80:
word = leftrotate(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16],1)
w.append(word)
i += 1
a = h[0]
b = h[1]
c = h[2]
d = h[3]
e = h[4]
for i in range(80):
if i >= 0 and i <= 19:
f = (b & c) | ((~b) & d)
t = (leftrotate(a,5) + e + w[i] + f + k[0]) & 0xFFFFFFFF
elif i >= 20 and i <= 39:
f = b ^ c ^ d
t = (leftrotate(a,5) + e + w[i] + f + k[1]) & 0xFFFFFFFF
elif i >= 40 and i <= 59:
f = (b & c) | (b & d) | (c & d)
t = (leftrotate(a,5) + e + w[i] + f + k[2]) & 0xFFFFFFFF
else:
f = b ^ c ^ d
t = (leftrotate(a,5) + e + w[i] + f + k[3]) & 0xFFFFFFFF
e = d
d = c
c = leftrotate(b,30)
b = a
a = t
h[0] = (h[0] + a) & 0xFFFFFFFF
h[1] = (h[1] + b) & 0xFFFFFFFF
h[2] = (h[2] + c) & 0xFFFFFFFF
h[3] = (h[3] + d) & 0xFFFFFFFF
h[4] = (h[4] + e) & 0xFFFFFFFF
hh = (h[0] << 128) | (h[1] << 96) | (h[2] << 64) | (h[3] << 32) | h[4]
return hh
- 主测试函数
def main():
ss = 'test'
hh = processchunk(preprocess(ss))
print(hex(hh)[2:])
上一篇: jquery制作弹窗提示窗口代码分享