python - 长度大于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())
解决方案
当输入少于 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
推荐阅读
- arrays - Vs 代码内部错误“架构 arm64 的未定义符号”
- java - 我在 android studio 中是上午 12:00 而不是下午 12:00 我该怎么办?
- google-apps-script - 用户如何登录,使用 Google Apps 脚本更新他们的任务
- flutter - 通过更改 AppBar 持久化 BottomNavigationBar
- markdown - 自定义 HTML 元素和 Markdown 解析
- python - 图像未从 Amazon S3 存储桶加载
- node.js - 谷歌翻译API中的UnhandledPromiseRejectionWarning与node.js
- flutter - 如何用墨水瓶在颤动中填充
- python - 在 PyQt5 中输入数学
- sql - 使用 SQL 查找具有重叠时间范围的记录