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

猜你喜欢

转载自blog.csdn.net/qq_35649764/article/details/83859132
今日推荐