1. 程式人生 > >SHA-1加密實現

SHA-1加密實現

Copyright © 2018 Joyce_BY
All rights reserved.
Contact by [email protected]


實驗原理

SHA-1接受一串二進位制輸入,加密後得到160bit的訊息摘要,是一種hash加密。

演算法的主要過程如下:

  1. 接收一串位元流,對其進行如下擴充套件:
  1. 在位元流尾部新增一個‘1’;
  2. 在新的位元流的尾部新增[0,512)個‘0’,使得最終bit數congruent to 448(mod 512);
  3. 最後在位元流尾部新增上64-bit的原訊息長度。
  1. 初始化數值如下:

h = [0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0]
k = [0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6]

  1. 把擴充套件後的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值。

  1. 最終將得到的h[0]-h[4]連線起來就是160bit的訊息摘要。

hh = (h[0] << 128) | (h[1] << 96) | (h[2] << 64) | (h[3] << 32) | h[4]

 

主要演算法

  1. 訊息預處理
    得到最初的訊息長度;
    把傳入的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
  1. 處理訊息塊
    初始化雜湊值h和k值;
    對每個chunk:
    初始化臨時雜湊值a-e;
    將每個chunk分為16個字;
    由16個字擴充套件為80個字;
    對每個字進行相關位運算,並重新計算臨時雜湊值;
    將臨時hash值加到hash值h中,得到下一個chunk的雜湊值;
    最後將得到的h連線起來形成最終的訊息摘要。

注意事項:

  1. 這裡leftrotate是一種迴圈位移,通過如下操作進行:
    def leftrotate(a,num): #ok
    word = (a << num) | (a >> (32-num)) & 0xFFFFFFFF
    return word
  2. 演算法中用到的加法都是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
  1. 主測試函式
def main(): 
    ss = 'test'
    hh = processchunk(preprocess(ss))
    print(hex(hh)[2:])