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:])