为什么我的哈希函数不输出动态值?

2024-05-14 00:22:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我是这个领域的新手,正在尝试学习如何编写加密哈希函数

为了获得一些实践经验,我尝试更新Python3.6及以上版本的PySHA2算法(原始版本在Python2.5+上不起作用,作者说他不会解决这个问题)。我不打算在任何工作中使用这个算法,只是为了知识而对它进行编码

我已经做到了这一点:

import copy
import struct

_initial_hashes = [0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
                   0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179]
_round_constants = [0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
                    0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
                    0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
                    0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
                    0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
                    0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
                    0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
                    0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
                    0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
                    0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
                    0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
                    0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
                    0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
                    0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
                    0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
                    0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
                    0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
                    0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
                    0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
                    0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817]


def _rit_rot(on: int, by: int) -> int:
    """
    helper function for right rotation as it isn't done by a simple bitwise operation (xor is done by '^')
    :param on: value to be rotated
    :param by: value by which to rotate
    :return: right rotated 'on'
    """
    return ((on >> by) | (on << (64 - by))) & 0xFFFFFFFFFFFFFFFF


def hash_main(chunk):
    global _initial_hashes, _round_constants
    # start the hashing process
    # to begin, create a place to store the 80 words that we'll make
    words = [0] * 80

    # first 16 words will be saved without any changes
    words[:16] = struct.unpack('!16Q', chunk)

    # extend these 16 words into the remaining 64 words of 'message schedule array'
    for i in range(16, 80):
        part_1 = _rit_rot(words[i - 15], 1) ^ _rit_rot(words[i - 15], 8) ^ (words[i - 15] >> 7)
        part_2 = _rit_rot(words[i - 2], 19) ^ _rit_rot(words[i - 2], 61) ^ (words[i - 2] >> 6)
        words[i] = (words[i - 16] + part_1 + words[i - 7] + part_2) & 0xFFFFFFFFFFFFFFFF

        # create the working variables
        a, b, c, d, e, f, g, h = _initial_hashes

        # start the compression function
        for z in range(80):
            var_1 = _rit_rot(a, 28) ^ _rit_rot(a, 34) ^ _rit_rot(a, 39)
            var_2 = _rit_rot(e, 14) ^ _rit_rot(e, 18) ^ _rit_rot(e, 41)
            var_3 = (a & b) ^ (a & c) ^ (b & c)
            var_4 = (e & f) ^ ((~e) & g)
            temp_1 = var_1 + var_3
            temp_2 = h + var_2 + var_4 + _round_constants[z] + words[z]

            # remix the hashes
            h = g
            g = f
            f = e
            e = (d + temp_2) & 0xFFFFFFFFFFFFFFFF
            d = c
            c = b
            b = a
            a = (temp_1 + temp_2) & 0xFFFFFFFFFFFFFFFF

            # add this chunk to initial hashes
            _initial_hashes = [(x + y) & 0xFFFFFFFFFFFFFFFF for x, y in zip(_initial_hashes,
                                                                            [a, b, c, d, e, f, g, h])]


def _sha_backend_update(text_copy, _buffer, _counter):
    """
    backend function that hashes given string
    """
    global _initial_hashes, _round_constants
    # create variables for cycling
    _buffer += text_copy
    _counter += len(text_copy)

    # assert the variables are correct
    if not text_copy:
        return
    if type(text_copy) is not str:
        raise TypeError("Invalid Object! Please enter a valid string for hashing!")

    # break the buffer into 128-bit chunks
    while len(_buffer) >= 128:
        chunk = _buffer[:128].encode()[1:]
        hash_main(chunk)
        _buffer = _buffer[128:]


def sha_backend_digest(text_to_hash: str, _buffer: str, _counter: int,
                       _output_size: int, hex_output: bool = False):
    # initialize variables
    variable_x = _counter & 0x7F
    length = str(struct.pack('!Q', _counter << 3))

    # set the thresholds
    if variable_x < 112:
        padding_len = 111 - variable_x
    else:
        padding_len = 239 - variable_x

    # make a copy of the text_to_hash before starting hashing
    text_copy = copy.deepcopy(text_to_hash)
    m = '\x80' + ('\x00' * (padding_len + 8)) + length

    # run the update function
    _sha_backend_update(text_copy, _buffer, _counter)

    # return the hash value
    return_val = [hex(stuff) for stuff in _initial_hashes[:_output_size]]

    if hex_output is True:
        return_val = [int(stuff, base=16) for stuff in return_val]
        return return_val

    return ''.join(return_val)


def sha_512(text_to_hash: str, hex_digest: bool = False) -> str:
    """
    frontend function for SHA512 hashing
    :return: hashed string
    """
    # before anything, check if the input is correct
    if not text_to_hash:
        return ""
    if type(text_to_hash) is not str:
        raise TypeError("Invalid content! Please provide content in correct format for hashing!")

    # initialize default variables
    _buffer = ''
    _counter = 0
    _output_size = 8

    # start the backend function
    return sha_backend_digest(text_to_hash, _buffer, _counter, _output_size, hex_output=hex_digest)


message = "This is a string to be hashed"
from hashlib import sha512
print("hashlib gives: ", sha512(message.encode()).hexdigest())
print("I give: ", sha_512(message))

很明显,我不理解这个算法中的很多东西,并且从原始代码中复制了很多部分(而且,我知道用一个函数编写所有内容不是一个好的做法,但我发现在尝试理解某些内容时会更容易)

但我现在最大的问题是它不起作用无论我向函数提供什么输入消息,它都会给出相同的输出:

0x6a09e667f3bcc9080xbb67ae8584caa73b0x3c6ef372fe94f82b0xa54ff53a5f1d36f1
0x510e527fade682d10x9b05688c2b3e6c1f0x1f83d9abfb41bd6b0x5be0cd19137e2179 

我在底部编写了一段代码,将其与python的hashlib模块进行比较

我在这方面哪里出了问题,如何解决

编辑:如评论中所述,我尝试输入一个更长的message字符串,代码似乎正常工作(但它仍然提供比hashlib更长的输出):

message = "This is a string to be hashed. I'll try to make this string as long as possible by adding" \
          "as much information to it as I can, in the hopes that this string would somehow become longer than" \
          "128 bits and my code can run properly. Hopefully, this is already longer than 128 bits, so lets see" \
          "how it works..."

hash: 0x6fcc0f346f2577800x334bd9b6c1178a970x90964a3f45f7b5bb0xc14033d12f6607e60xb598bea0a8b0ac1e0x116b0e134691ab540x73d88e77e5b862ba0x89181da7462c5574

message = "This is a string to be hashed. I'll try to make this string as long as possible by adding" \
          "as much information to it as I can, in the hopes that this string would somehow become longer than"

hash: 0x166e40ab03bc98750xe81fe34168b6994f0xe56b81bd5972b5560x8789265c3a56b30b0x2c810d652ea7b1550xa23ca2704602a8240x12ffb1ec8f3dd6d10x88c29f84cbef8988

Tags: thetotextforstringbyreturnas
1条回答
网友
1楼 · 发布于 2024-05-14 00:22:11

你总是需要用便笺簿来记录信息。填充和添加长度始终是SHA-2过程的最后一步。目前,您没有执行最后一步(完成)

以下是我的最后两条评论,为您指出了正确的方向:

So generally you try and take one 128 byte block from the binary message, update the hash state using the information in that block, then move to the next one until you have a partial or 0 byte block. That block you need to pad & add size indication (in bits) and process. If you've not enough space for the padding / size indication then you need yet another block consisting entirely of padding and the size indication. If you read carefully, then you always process at least one block.

Hmm, it is already in sha_backend_digest (the 0x80 followed by zero bytes and the length which is input size * 8 (_counter << 3).

但当然,你需要做到这一点,而不是跳过任何一步

相关问题 更多 >