Reputation: 91
Sorry for the very specific problem, but I am really going crazy here. I am trying to make a module to simply import when I need to sign something or verify a signature but I encountered a problem, the verificator simply returns true wether I enter signed data or anything else, here is the code:
RSA_Handler.py
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5
import pickle
def sign(data, exported_key):
key = RSA.importKey(exported_key)
signed_data = []
signed_data.append(data)
signed_data.append(PKCS1_v1_5.new(key).sign(SHA256.new(pickle.dumps(data))))
return signed_data
def verify(signed_data, exported_key):
data = signed_data[0]
signature = signed_data[1]
key = RSA.importKey(exported_key)
h = SHA256.new(pickle.dumps(data))
try:
PKCS1_v1_5.new(key).verify(h, signature)
return True
except(ValueError, TypeError):
return False
test01.py
from RSA_Handler import *
import pickle
import os
with open("keys.txt", "rb") as rb:
keys = rb.read()
signed = sign("hello", keys)
trueorfalse = verify(["this will return"," true whatever I enter"], keys)
print(trueorfalse)
Upvotes: 1
Views: 1343
Reputation: 49121
I can reproduce the problem (at least for the latest version of PyCryptodome, namely 3.9.8). It seems that the behavior depends on the padding type. In case of the module PKCS1_v1_5
, which is currently used in the posted code, the verification does not raise a ValueError
in case of an invalid signature, but returns the result as return value.
This means that your verify()
function always returns True
, because even in case of a mismatching signature neither a ValueError
is raised nor the returned value is evaluated.
To solve the issue, your verify()
function must be changed as follows:
def verify(signed_data, exported_key):
data = signed_data[0]
signature = signed_data[1]
key = RSA.importKey(exported_key)
h = SHA256.new(pickle.dumps(data))
return PKCS1_v1_5.new(key).verify(h, signature)
which can be tested with:
# Signing
key = RSA.generate(1024)
keyPriv = key.exportKey()
signed = sign(b'Some data', keyPriv)
# Verifying
#signed[0] = b'Some data' # Succeeds
signed[0] = b'Some other data' # Fails
keyPub = key.publickey().exportKey()
verified = verify(signed, keyPub)
print(verified)
For PSS padding, i.e. for the module pss
a ValueError
is raised in case of an invalid signature. I.e. if you switch to this padding by replacing
from Crypto.Signature import PKCS1_v1_5
with
from Crypto.Signature import pss
and also PKCS1_v1_5
with pss
in the rest of the code, the logic in your verify()
function can remain unchanged.
EDIT:
As explained in the answer from SquareRootOfTwentyThree, PKCS1_v1_5
is an outdated module and instead the module pkcs1_15
has to be used, which as expected generates a ValueError
in case of an invalid signature, according to the documentation, here.
Upvotes: 2
Reputation: 7766
You are importing the obsolete module PKCS1_v1_5
, which is not actually documented in in PyCryptodome. In your code, you must have instead:
from Crypto.Signature import import pkcs1_15
The PyCryptodome documentation (https://www.pycryptodome.org/en/latest/src/signature/pkcs1_v1_5.html) shows examples of the right way to verify PKCS#1 v1.5 signatures.
The old module you are using (that is, PKCS1_v1_5
) is there purely for backward compatibility with PyCrypto, where it behaves in the same way you are observing (i.e. without exceptions - which is not that great, the new module is better).
Upvotes: 0