在 Python 中将散列摘要更改为大端

changing the hash digest to big-endian in Python

我正在使用以下代码为消息创建哈希:

from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_PSS

msg = b'\x15\x00\xea'
hash = SHA256.new(msg)
...
signer = PKCS1_PSS.new(privKey)
signature = signer.sign(hash)

但是,我需要散列摘要值,即 hash.digest() 为大端格式。 请注意,我需要将整个 hash 传递给 signer。我可以获得 hash.digest() 并将其转换为大端,但随后我需要构造一个散列类型的变量以传递给 signer.sig() 函数。 我该怎么做?

SHA-256 标准使用 32 位字,并且已经指定为大端。

如果你得到 32 位小端字节序,那么你可能需要重新排序其中的字节,但这不太可能。

如我的评论所述,我不确定是否真的需要反转哈希值。

但如果是这样,您需要一个不处理原始数据但处理已经散列的数据(并且不再散列)的实现。

PyCryptodome does not support this, but the Cryptography library with the Prehashed class does, s. here, 2nd snippet.

以下代码使用 PKCS#1 v1.5 执行签名并且:

  • 使用 PyCryptodome(隐式哈希)
  • 使用密码学(隐式哈希)
  • 使用密码学(使用预哈希 class 和显式哈希)
  • 使用密码学(使用预散列 class 和显式散列)并使用倒排散列
# Short key only for testing purposes!
pkcs8 = '''-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA2gdsVIRmg5IH0rG3
u3w+gHCZq5o4OMQIeomC1NTeHgxbkrfznv7TgWVzrHpr3HHK8IpLlG04/aBo6U5W
2umHQQIDAQABAkEAu7wulGvZFat1Xv+19BMcgl3yhCdsB70Mi+7CH98XTwjACk4T
+IYv4N53j16gce7U5fJxmGkdq83+xAyeyw8U0QIhAPIMhbtXlRS7XpkB66l5DvN1
XrKRWeB3RtvcUSf30RyFAiEA5ph7eWXbXWpIhdWMoe50yffF7pW+C5z07tzAIH6D
Ko0CIQCyveSTr917bdIxk2V/xNHxnx7LJuMEC5DcExorNanKMQIgUxHRQU1hNgjI
sXXZoKgfaHaa1jUZbmOPlNDvYYVRyS0CIB9ZZee2zubyRla4qN8PQxCJb7DiICmH
7nWP7CIvcQwB
-----END PRIVATE KEY-----'''
message = b'The quick brown fox jumps over the lazy dog'

# 1. PyCryptodome (implicit hashing)
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA

privateKey = RSA.import_key(pkcs8)
digest = SHA256.new(message)
signature = pkcs1_15.new(privateKey).sign(digest)
print(signature.hex())

# 2. Cryptography (implicit hashing)
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization

privateKey = serialization.load_pem_private_key(
    pkcs8.encode('utf8'),
    password=None,
)
digest = hashes.SHA256()
signature = privateKey.sign(
    message,
    padding.PKCS1v15(),
    digest
)
print(signature.hex())

# 3. Cryptography (explicit hashing)
from cryptography.hazmat.primitives.asymmetric import utils

digest = hashes.SHA256()
hasher = hashes.Hash(digest)
hasher.update(message)
hash = hasher.finalize()
signature = privateKey.sign(
     hash,
     padding.PKCS1v15(),     
     utils.Prehashed(digest) # The digest must still be specified because the digest ID is included in the signature.
)
print(signature.hex())

# 4. Cryptography (explicit hashing), inverse hash
hashBA  = bytearray(hash)
hashBA.reverse()
hashReversed = bytes(hashBA)
signature = privateKey.sign(
    hashReversed,
    padding.PKCS1v15(),     
    utils.Prehashed(digest) # The digest must still be specified because the digest ID is included in the signature.
)
print(signature.hex())

输出:

8c83cad897eda249fec9eba231061d585dafc99177267e3e71bb8a3fce07cc6663bf4df7af2e1c1945d2a6bb42eb25f042228b591fc18cda82d92caae844670c
8c83cad897eda249fec9eba231061d585dafc99177267e3e71bb8a3fce07cc6663bf4df7af2e1c1945d2a6bb42eb25f042228b591fc18cda82d92caae844670c
8c83cad897eda249fec9eba231061d585dafc99177267e3e71bb8a3fce07cc6663bf4df7af2e1c1945d2a6bb42eb25f042228b591fc18cda82d92caae844670c
550ba1cd3c968fa1e24b79a939edb6740b63d2ab021fe87f0639ce978d5127792661e83f4e8fdff8124a12fe208bd70bdca9db2b9c82306f2ed018ab06363c9e

由于 PKCS#1 v1.5 签名是确定性的,因此情况 1 到 3 会产生相同的签名。