首页 > 解决方案 > 长度大于56时sha256输出不正确

问题描述

我正在尝试学习sha256的每一步,所以我用python编写了一个代码,它使用二进制字符串而不是数学运算来完全理解它。

当输入少于 56 个字符时,代码可以正常工作,但当输入等于或大于 56 个字符时,输出不正确:

例如,当输入为: ba7816bf8f01cfea414140de5dae2223bda12ae1a5324sfdserew3ra

代替1caa150674ab1aed030dc69f9b86dbcbc412e6e1dd20344eeaa21687acae7789

我明白了8492782cc396d4454980c9b63f127c5730da7d838822f8f37b1c7705d2630b88

代码:

操作.py

  class Operations:
        def add(self, data1, data2):
              x = data1
              y = data2

              carry = 0
              result = ""

              for i in range(len(data1) -1, -1, -1):
                    r = carry
                    r += 1 if x[i] == '1' else 0
                    r += 1 if y[i] == '1' else 0
                    result = ('1' if r % 2 == 1 else '0') + result
                    carry = 0 if r < 2 else 1

              if carry != 0: result = '1' + result

              return result[-len(data1):]

        def xor(self, data1, data2):
              result = ""
              for i in range(len(data1)):
                    temp1 = data1[i]
                    temp2 = data2[i]
                    if (temp1 == "0" and temp2 == "0") or (temp1 == "1" and temp2 == "1"):
                          result += "0"
                    else:
                          result += "1"

              return result

        def shiftRight(self, data, turn):
              result = "0" * turn + data
              return result[:len(data)]

        def rotateRight(self, data, turn):
              result = None
              for i in range(turn):
                    if result:
                          temp = result[-1]
                          result = (temp + result)[:len(data)]
                    else:
                          temp = data[-1]
                          result = (temp + data)[:len(data)]

              return result

函数.py

  from operations import Operations

  class Functions(Operations):
        def sigma0(self, data): # Lowercase sigma
              temp1 = self.rotateRight(data, 7)
              temp2 = self.rotateRight(data, 18)
              temp3 = self.shiftRight(data, 3)
              result = self.xor(temp3, self.xor(temp1, temp2))
              return result

        def sigma1(self, data): # Lowercase sigma
              temp1 = self.rotateRight(data, 17)
              temp2 = self.rotateRight(data, 19)
              temp3 = self.shiftRight(data, 10)
              result = self.xor(temp3, self.xor(temp1, temp2))
              return result

        def gamma0(self, data): # Uppercase sigma
              temp1 = self.rotateRight(data, 2)
              temp2 = self.rotateRight(data, 13)
              temp3 = self.rotateRight(data, 22)
              result = self.xor(temp3, self.xor(temp1, temp2))
              return result

        def gamma1(self, data): # Uppercase sigma
              temp1 = self.rotateRight(data, 6)
              temp2 = self.rotateRight(data, 11)
              temp3 = self.rotateRight(data, 25)
              result = self.xor(temp3, self.xor(temp1, temp2))
              return result

        def choice(self, x, y, z):
              result = ""
              for i in range(len(x)):
                    result += y[i] if x[i] == "1" else z[i]

              return result

        def majority(self, x, y, z):
              result = ""
              for i in range(len(x)):
                    temp0 = 0
                    temp1 = 0

                    temp0 += 1 if x[i] == "0" else 0 
                    temp1 += 1 if x[i] == "1" else 0

                    temp0 += 1 if y[i] == "0" else 0                  
                    temp1 += 1 if y[i] == "1" else 0

                    temp0 += 1 if z[i] == "0" else 0
                    temp1 += 1 if z[i] == "1" else 0
                    
                    if temp0 > temp1:
                          result += "0"
                    else:
                          result += "1"

              return result

主文件

  from math import ceil
  from copy import copy
  from functions import Functions

  _k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
        0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
        0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
        0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
        0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
        0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
        0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
        0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
        0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]

  _h = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
        0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]

  class SHA256(Functions):
        blocks = []

        def __init__(self):
              global _k, _h            
              _k = [f'{i:b}'.zfill(32) for i in _k]
              _h = [f'{i:b}'.zfill(32) for i in _h]

        def message_to_blocks(self, message):
              chunk = 56
              data = [format(ord(x), 'b').zfill(8) for x in message]

              for i in range(ceil(len(data) / chunk)):
                    self.blocks.append(data[chunk * i:chunk * (i + 1)])

                    self.blocks[i] = ''.join(self.blocks[i])
                    length = f'{len(self.blocks[i]):b}'
                    self.blocks[i] += '1'
                    self.blocks[i] = self.blocks[i].ljust(512, '0')

                    # add length to last 64 bit
                    self.blocks[i] = self.blocks[i][:-len(length)]
                    self.blocks[i] += length

        def message_schedule(self, data):
              schedule = []
              n = 32
              # first 16 words
              schedule = [(data[i:i+n]) for i in range(0, len(data), n)]
              # generate the rest
              for i in range(16, 64):
                    temp1 = self.sigma1(schedule[-2])
                    temp2 = self.sigma0(schedule[-15])
                    result = self.add(temp1, self.add(schedule[-7], self.add(temp2, schedule[-16])))
                    schedule.append(result)

              return schedule

        def compress(self):
              for block in self.blocks:
                    temp_h = copy(_h)
                    _w = self.message_schedule(block)
                    for i in range(64):
                          T1 = [self.gamma1(_h[4]), self.choice(_h[4], _h[5], _h[6]), _h[7], _k[i], _w[i]]
                          T1 = self.add(T1[0], self.add(T1[1], self.add(T1[2], self.add(T1[3], T1[4]))))

                          T2 = [self.gamma0(_h[0]), self.majority(_h[0], _h[1], _h[2])]
                          T2 = self.add(T2[0], T2[1])
                          
                          # shift all constants down
                          _h[7] = _h[6] # h
                          _h[6] = _h[5] # g
                          _h[5] = _h[4] # f
                          _h[4] = _h[3] # e
                          _h[3] = _h[2] # d
                          _h[2] = _h[1] # c
                          _h[1] = _h[0] # b

                          # compress
                          _h[0] = self.add(T1, T2)
                          _h[4] = self.add(_h[4], T1)

                    # add with initial values
                    _h[0] = self.add(_h[0], temp_h[0])
                    _h[1] = self.add(_h[1], temp_h[1])
                    _h[2] = self.add(_h[2], temp_h[2])
                    _h[3] = self.add(_h[3], temp_h[3])
                    _h[4] = self.add(_h[4], temp_h[4])
                    _h[5] = self.add(_h[5], temp_h[5])
                    _h[6] = self.add(_h[6], temp_h[6])
                    _h[7] = self.add(_h[7], temp_h[7])

              return self.digest(_h)

        def digest(self, hashes):
              final_hash = ""
              for hash in hashes:
                    t = hex(int(hash, 2))
                    final_hash += t[2:]

              return final_hash

  a = SHA256()
  a.message_to_blocks("ba7816bf8f01cfea414140de5dae2223bda12ae1a5324sfdserew3ra")
  print(a.compress())

标签: pythonhashsha256

解决方案


当输入少于 56 个字符时,代码工作正常,但当输入等于或大于 56 个字符时,输出不正确

问题出在这部分:

length = f'{len(self.blocks[i]):b}'
self.blocks[i] += '1'
self.blocks[i] = self.blocks[i].ljust(512, '0')
# add length to last 64 bit
self.blocks[i] = self.blocks[i][:-len(length)]
self.blocks[i] += length

错误在于零填充的计算方式与不具有 64 位宽度的长度相结合。实际上,您的代码用零填充最后一个消息块,因此它将具有 512 位长度,然后用未填充的二进制长度 ( 111000000) 替换最后 n 位,但在零填充的情况下,这将无法正常工作小于 64 位。

结果是代码将总消息输入处理为:

01100010011000010011011100111000 00110001001101100110001001100110 00111000011001100011000000110001 01100011011001100110010101100001 00110100001100010011010000110001 00110100001100000110010001100101 00110101011001000110000101100101 00110010001100100011001000110011 01100010011001000110000100110001 00110010011000010110010100110001 01100001001101010011001100110010 00110100011100110110011001100100 01110011011001010111001001100101 01110111001100110111001001100001 10000000000000000000000000000000 00000000000000000000000111000000

代替:

01100010011000010011011100111000 00110001001101100110001001100110 00111000011001100011000000110001 01100011011001100110010101100001 00110100001100010011010000110001 00110100001100000110010001100101 00110101011001000110000101100101 00110010001100100011001000110011 01100010011001000110000100110001 00110010011000010110010100110001 01100001001101010011001100110010 00110100011100110110011001100100 01110011011001010111001001100101 01110111001100110111001001100001 10000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000111000000


推荐阅读