1
votes

I am signing SHA512 hash with RSA and save it to file. The hash is the same on both python and javascript, but signature can not be verified. Python code:

from Cryptodome.Hash import SHA512
from Cryptodome.PublicKey import RSA
from Cryptodome.Signature import pkcs1_15

hash = SHA512.new(someByteArray)
#This is equal to digest generated in JavaScript
hashDigest = hashPDF.hexdigest()
pk = RSA.importKey(privateKey)
signature=pkcs1_15.new(pk).sign(hashPDF)
#Write signature to file
with open("storage/{0}.sig".format(hashDigest), 'wb+') as f:
        f.write(signature)

#Then JavaScript request occurs return content of saved signature in base64

from base64 import b64encode
from flask import jsonify
with open("storage/{0}.sig".format(pdfHashDigest), "rb") as f:
        sign = b64encode(f.read())
return jsonify({"sign":sign.decode("utf-8")})

JavaScript:

var hash=await crypto.subtle.digest('SHA-512', Uint8Array.from(atob(someBase64content), c => c.charCodeAt(0)))
//This is equal to python hashDigest
var hashDigest = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
var cryptoKey=await crypto.subtle.importKey('spki', this.pemToArrayBuffer(publicKey), {name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-512'}, false, ["verify"])
//Always false
var result=await crypto.subtle.verify("RSASSA-PKCS1-v1_5", cryptoKey, Uint8Array.from(atob(signature), c => c.charCodeAt(0)), hash)

I tried different ways to convert base64 signature into ArrayBuffer to use in Web Crypto API: rfc4648.js, new TextEncoder(), custom conversions to Uint8Array, but result is always false. Also i tried to verify signature using forge (https://github.com/digitalbazaar/forge) but result is also false.

Where am i getting wrong? I tried to compare byte values of hash, which goes to input of signing functions, but actually it is Crypto.Hash object on python.

1

1 Answers

1
votes

The sign/verify implementation in the Python-code doesn't perform hashing automatically, i.e. the user must explicitly hash the data before signing. During verification, the user must therefore verify the signature against the hash of the data.

The sign/verify implementation in the JavaScript-code performs hashing automatically, i.e. the user must not hash the data before signing. During verification, the user must therefore verify the signature against the data (and not against the hash of the data). The hash algorithm is specified in the key i.e. in generateKey/importKey using {hash: 'hash-algorithm'}.

The error in the posted JavaScript-code is caused by verifying the signature against the hash of the data. This is wrong. The signature must be checked against the data, i.e. in the JavaScript-code the following lines:

var hash=await crypto.subtle.digest('SHA-512', Uint8Array.from(atob(someBase64content), c => c.charCodeAt(0)))
...
var result=await crypto.subtle.verify("RSASSA-PKCS1-v1_5", cryptoKey, Uint8Array.from(atob(signature), c => c.charCodeAt(0)), hash)

must be replaced by

var data=Uint8Array.from(atob(someBase64content), c => c.charCodeAt(0));
...
var result=await crypto.subtle.verify("RSASSA-PKCS1-v1_5", cryptoKey, Uint8Array.from(atob(signature), c => c.charCodeAt(0)), data)

Try to perform the verification with this change.