I am using the following code to create hash for a message:
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)
However, I need that the hash digest value i.e hash.digest()
to be in big-endian format.
Please note that I need to pass the whole hash
to the signer
. I can get the hash.digest() and convert it to big-endian, but then I need to construct a variable of type hash to pass to the signer.sig()
function.
How can I do that?
As mentioned in my comment, I'm not sure if it is really required to invert the hash.
But if so, you need an implementation that does not process the raw data, but the already hashed data (and does not hash anymore).
PyCryptodome does not support this, but the Cryptography library with the Prehashed
class does, s. here, 2nd snippet.
The following code performs a signing with PKCS#1 v1.5 and:
# 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())
with the output:
8c83cad897eda249fec9eba231061d585dafc99177267e3e71bb8a3fce07cc6663bf4df7af2e1c1945d2a6bb42eb25f042228b591fc18cda82d92caae844670c
8c83cad897eda249fec9eba231061d585dafc99177267e3e71bb8a3fce07cc6663bf4df7af2e1c1945d2a6bb42eb25f042228b591fc18cda82d92caae844670c
8c83cad897eda249fec9eba231061d585dafc99177267e3e71bb8a3fce07cc6663bf4df7af2e1c1945d2a6bb42eb25f042228b591fc18cda82d92caae844670c
550ba1cd3c968fa1e24b79a939edb6740b63d2ab021fe87f0639ce978d5127792661e83f4e8fdff8124a12fe208bd70bdca9db2b9c82306f2ed018ab06363c9e
Since the PKCS#1 v1.5 signature is deterministic, cases 1 to 3 produce the same signature.