def verify_rsa_signature(signature, signature_method, public_key, data): """ <Purpose> Determine whether the corresponding private key of 'public_key' produced 'signature'. verify_signature() will use the public key, signature method, and 'data' to complete the verification. >>> public, private = generate_rsa_public_and_private(2048) >>> data = b'The quick brown fox jumps over the lazy dog' >>> signature, method = create_rsa_signature(private, data) >>> verify_rsa_signature(signature, method, public, data) True >>> verify_rsa_signature(signature, method, public, b'bad_data') False <Arguments> signature: An RSASSA PSS signature, as a string. This is the signature returned by create_rsa_signature(). signature_method: A string that indicates the signature algorithm used to generate 'signature'. 'RSASSA-PSS' is currently supported. public_key: The RSA public key, a string in PEM format. data: Data used by tuf.keys.create_signature() to generate 'signature'. 'data' (a string) is needed here to verify 'signature'. <Exceptions> tuf.FormatError, if 'signature', 'signature_method', 'public_key', or 'data' are improperly formatted. tuf.UnknownMethodError, if the signing method used by 'signature' is not one supported by tuf.keys.create_signature(). tuf.CryptoError, if the private key cannot be decoded or its key type is unsupported. <Side Effects> pyca/cryptography's RSAPublicKey.verifier() called to do the actual verification. <Returns> Boolean. True if the signature is valid, False otherwise. """ I_TO_PRINT = TO_PRINT + uptane.YELLOW + '[verify_rsa_signature(signature, signature_method, public_key, data)]: ' + uptane.ENDCOLORS #TODO: Print to be deleted print( str('%s %s %s %s %s %s %s %s %s' % (I_TO_PRINT, 'Verifying RSA public_key:', public_key, 'has generate signature:', signature, 'signature_method:', signature_method, 'data:', data))) #TODO: Until here # Does 'public_key' have the correct format? # This check will ensure 'public_key' conforms to 'tuf.formats.PEMRSA_SCHEMA'. # Raise 'tuf.FormatError' if the check fails. tuf.formats.PEMRSA_SCHEMA.check_match(public_key) # Does 'signature_method' have the correct format? tuf.formats.NAME_SCHEMA.check_match(signature_method) # Does 'signature' have the correct format? tuf.formats.PYCACRYPTOSIGNATURE_SCHEMA.check_match(signature) # What about 'data'? tuf.formats.DATA_SCHEMA.check_match(data) # Verify whether the private key of 'public_key' produced 'signature'. # Before returning the 'valid_signature' Boolean result, ensure 'RSASSA-PSS' # was used as the signing method. valid_signature = False # Verify the expected 'signature_method' value. if signature_method != 'RSASSA-PSS': raise tuf.UnknownMethodError(signature_method) # Verify the RSASSA-PSS signature with pyca/cryptography. try: public_key_object = serialization.load_pem_public_key( public_key.encode('utf-8'), backend=default_backend()) # 'salt_length' is set to the digest size of the hashing algorithm (to # match the default size used by 'tuf.pycrypto_keys.py'). verifier = public_key_object.verifier( signature, padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=hashes.SHA256().digest_size), hashes.SHA256()) verifier.update(data) # verify() raises 'cryptograpahy.exceptions.InvalidSignature' if the # signature is invalid. try: verifier.verify() return True except cryptography.exceptions.InvalidSignature: return False # Raised by load_pem_public_key(). except ValueError: raise tuf.CryptoError('The PEM could not be decoded successfully.') # Raised by load_pem_public_key(). except cryptography.exceptions.UnsupportedAlgorithm: raise tuf.CryptoError('The private key type is not supported.')
def verify_signature(public_key, method, signature, data, use_pynacl=False): """ <Purpose> Determine whether the private key corresponding to 'public_key' produced 'signature'. verify_signature() will use the public key, the 'method' and 'sig', and 'data' arguments to complete the verification. >>> public, private = generate_public_and_private() >>> data = b'The quick brown fox jumps over the lazy dog' >>> signature, method = \ create_signature(public, private, data) >>> verify_signature(public, method, signature, data, use_pynacl=False) True >>> verify_signature(public, method, signature, data, use_pynacl=True) True >>> bad_data = b'The sly brown fox jumps over the lazy dog' >>> bad_signature, method = \ create_signature(public, private, bad_data) >>> verify_signature(public, method, bad_signature, data, use_pynacl=False) False <Arguments> public_key: The public key is a 32-byte string. method: 'ed25519' signature method generated by either the pure python implementation (i.e., 'tuf._vendor.ed25519.ed25519.py') or PyNacl (i.e., 'nacl'). signature: The signature is a 64-byte string. data: Data object used by tuf.ed25519_keys.create_signature() to generate 'signature'. 'data' is needed here to verify the signature. use_pynacl: True, if the ed25519 signature should be verified by PyNaCl. False, if the signature should be verified with the pure Python implementation of ed25519 (slower). <Exceptions> tuf.UnknownMethodError. Raised if the signing method used by 'signature' is not one supported by tuf.ed25519_keys.create_signature(). tuf.FormatError. Raised if the arguments are improperly formatted. <Side Effects> tuf._vendor.ed25519.ed25519.checkvalid() called to do the actual verification. nacl.signing.VerifyKey.verify() called if 'use_pynacl' is True. <Returns> Boolean. True if the signature is valid, False otherwise. """ # Does 'public_key' have the correct format? # This check will ensure 'public_key' conforms to # 'tuf.formats.ED25519PUBLIC_SCHEMA', which must have length 32 bytes. # Raise 'tuf.FormatError' if the check fails. tuf.formats.ED25519PUBLIC_SCHEMA.check_match(public_key) # Is 'method' properly formatted? tuf.formats.NAME_SCHEMA.check_match(method) # Is 'signature' properly formatted? tuf.formats.ED25519SIGNATURE_SCHEMA.check_match(signature) # Is 'use_pynacl' properly formatted? tuf.formats.BOOLEAN_SCHEMA.check_match(use_pynacl) # Verify 'signature'. Before returning the Boolean result, # ensure 'ed25519' was used as the signing method. # Raise 'tuf.UnsupportedLibraryError' if 'use_pynacl' is True but 'nacl' is # unavailable. public = public_key valid_signature = False if method in _SUPPORTED_ED25519_SIGNING_METHODS: if use_pynacl: try: nacl_verify_key = nacl.signing.VerifyKey(public) nacl_message = nacl_verify_key.verify(data, signature) valid_signature = True except NameError: # pragma: no cover message = 'The PyNaCl library and/or its dependencies unavailable.' raise tuf.UnsupportedLibraryError(message) except nacl.exceptions.BadSignatureError: pass # Verify 'ed25519' signature with the pure Python implementation. else: try: tuf._vendor.ed25519.ed25519.checkvalid(signature, data, public) valid_signature = True # The pure Python implementation raises 'Exception' if 'signature' is # invalid. except Exception as e: pass else: message = 'Unsupported ed25519 signing method: '+repr(method)+'.\n'+ \ 'Supported methods: '+repr(_SUPPORTED_ED25519_SIGNING_METHODS)+'.' raise tuf.UnknownMethodError(message) return valid_signature
def verify_rsa_signature(signature, signature_method, public_key, data): """ <Purpose> Determine whether the corresponding private key of 'public_key' produced 'signature'. verify_signature() will use the public key, signature method, and 'data' to complete the verification. >>> public, private = generate_rsa_public_and_private(2048) >>> data = b'The quick brown fox jumps over the lazy dog' >>> signature, method = create_rsa_signature(private, data) >>> verify_rsa_signature(signature, method, public, data) True >>> verify_rsa_signature(signature, method, public, b'bad_data') False <Arguments> signature: An RSASSA PSS signature as a string. This is the signature returned by create_rsa_signature(). signature_method: A string that indicates the signature algorithm used to generate 'signature'. 'RSASSA-PSS' is currently supported. public_key: The RSA public key, a string in PEM format. data: Data object used by tuf.keys.create_signature() to generate 'signature'. 'data' is needed here to verify the signature. <Exceptions> tuf.UnknownMethodError. Raised if the signing method used by 'signature' is not one supported by tuf.keys.create_signature(). tuf.FormatError. Raised if 'signature', 'signature_method', or 'public_key' is improperly formatted. <Side Effects> Crypto.Signature.PKCS1_PSS.verify() called to do the actual verification. <Returns> Boolean. True if the signature is valid, False otherwise. """ # Does 'public_key' have the correct format? # This check will ensure 'public_key' conforms to 'tuf.formats.PEMRSA_SCHEMA'. # Raise 'tuf.FormatError' if the check fails. tuf.formats.PEMRSA_SCHEMA.check_match(public_key) # Does 'signature_method' have the correct format? tuf.formats.NAME_SCHEMA.check_match(signature_method) # Does 'signature' have the correct format? tuf.formats.PYCRYPTOSIGNATURE_SCHEMA.check_match(signature) # Verify whether the private key of 'public_key' produced 'signature'. # Before returning the 'valid_signature' Boolean result, ensure 'RSASSA-PSS' # was used as the signing method. valid_signature = False # Verify the signature with PyCrypto if the signature method is valid, # otherwise raise 'tuf.UnknownMethodError'. if signature_method == 'RSASSA-PSS': try: rsa_key_object = Crypto.PublicKey.RSA.importKey(public_key) pkcs1_pss_verifier = Crypto.Signature.PKCS1_PSS.new(rsa_key_object) sha256_object = Crypto.Hash.SHA256.new(data) valid_signature = pkcs1_pss_verifier.verify( sha256_object, signature) except (ValueError, IndexError, TypeError) as e: message = 'The RSA signature could not be verified.' raise tuf.CryptoError(message) else: raise tuf.UnknownMethodError(signature_method) return valid_signature
if method == 'PyCrypto-PKCS#1 PSS': try: rsa_key_object = Crypto.PublicKey.RSA.importKey(public_key) pkcs1_pss_verifier = Crypto.Signature.PKCS1_PSS.new(rsa_key_object) sha256_object = Crypto.Hash.SHA256.new(data) # The metadata stores signatures in hex. Unhexlify and verify the # signature. signature = binascii.unhexlify(sig) valid_signature = pkcs1_pss_verifier.verify( sha256_object, signature) except (ValueError, IndexError, TypeError), e: message = 'The RSA signature could not be verified.' raise tuf.CryptoError(message) else: raise tuf.UnknownMethodError(method) return valid_signature def create_encrypted_pem(rsakey_dict, passphrase): """ <Purpose> Return a string in PEM format, where the private part of the RSA key is encrypted. The private part of the RSA key is encrypted by the Triple Data Encryption Algorithm (3DES) and Cipher-block chaining (CBC) for the mode of operation. Password-Based Key Derivation Function 1 (PBKF1) + MD5 is used to strengthen 'passphrase'. https://en.wikipedia.org/wiki/Triple_DES https://en.wikipedia.org/wiki/PBKDF2
def verify_signature(rsakey_dict, signature, data): """ <Purpose> Determine whether the private key belonging to 'rsakey_dict' produced 'signature'. verify_signature() will use the public key found in 'rsakey_dict', the 'method' and 'sig' objects contained in 'signature', and 'data' to complete the verification. Type-checking performed on both 'rsakey_dict' and 'signature'. <Arguments> rsakey_dict: A dictionary containing the RSA keys and other identifying information. 'rsakey_dict' has the form: {'keytype': 'rsa', 'keyid': keyid, 'keyval': {'public': '-----BEGIN RSA PUBLIC KEY----- ...', 'private': '-----BEGIN RSA PRIVATE KEY----- ...'}} The public and private keys are in PEM format and stored as strings. signature: The signature dictionary produced by tuf.rsa_key.create_signature(). 'signature' has the form: {'keyid': keyid, 'method': 'method', 'sig': sig}. Conformant to tuf.formats.SIGNATURE_SCHEMA. data: Data object used by tuf.rsa_key.create_signature() to generate 'signature'. 'data' is needed here to verify the signature. <Exceptions> tuf.UnknownMethodError. Raised if the signing method used by 'signature' is not one supported by tuf.rsa_key.create_signature(). tuf.FormatError. Raised if either 'rsakey_dict' or 'signature' do not match their respective tuf.formats schema. 'rsakey_dict' must conform to tuf.formats.RSAKEY_SCHEMA. 'signature' must conform to tuf.formats.SIGNATURE_SCHEMA. <Side Effects> evpy.signature_verify() called to do the actual verification. <Returns> Boolean. """ # Does 'rsakey_dict' have the correct format? # This check will ensure 'rsakey_dict' has the appropriate number # of objects and object types, and that all dict keys are properly named. # Raise 'tuf.FormatError' if the check fails. tuf.formats.RSAKEY_SCHEMA.check_match(rsakey_dict) # Does 'signature' have the correct format? tuf.formats.SIGNATURE_SCHEMA.check_match(signature) # Using the public key belonging to 'rsakey_dict' # (i.e., rsakey_dict['keyval']['public']), verify whether 'signature' # was produced by rsakey_dict's corresponding private key # rsakey_dict['keyval']['private']. Before returning the Boolean result, # ensure 'evp' was used as the signing method. method = signature['method'] sig = signature['sig'] public_key = rsakey_dict['keyval']['public'] if method != 'evp': raise tuf.UnknownMethodError(method) return evpy.signature.verify(data, binascii.unhexlify(sig), key=public_key)
nacl_message = nacl_verify_key.verify(data, sig) if nacl_message == data: valid_signature = True except nacl.signing.BadSignatureError: pass # Verify signature with 'ed25519-python' (i.e., pure Python implementation). else: try: ed25519.ed25519.checkvalid(sig, data, public) valid_signature = True # The pure Python implementation raises 'Exception' if 'signature' is # invalid. except Exception, e: pass else: message = 'Unsupported ed25519 signing method: '+repr(method)+'.\n'+ \ 'Supported methods: '+repr(_SUPPORTED_ED25519_SIGNING_METHODS)+'.' raise tuf.UnknownMethodError(message) return valid_signature if __name__ == '__main__': # The interactive sessions of the documentation strings can # be tested by running 'ed25519_key.py' as a standalone module. # python -B ed25519_key.py import doctest doctest.testmod()