def verify_signature(data, signature, pubkey): """ Verify a signature. If the signature is valid, returns True. If the signature is invalid, raise an exception explaining why. """ # Data must be encoded as bytes if isinstance(data, str): data = data.encode() # Content signature implicitly adds a prefix to signed data data = b"Content-Signature:\x00" + data # fastecdsa expects ASCII armored keys, but ours is unarmored. Add the # armor before passing the key to the library. EC_PUBLIC_HEADER = "-----BEGIN PUBLIC KEY-----" EC_PUBLIC_FOOTER = "-----END PUBLIC KEY-----" verifying_pubkey = PEMEncoder.decode_public_key( "\n".join([EC_PUBLIC_HEADER, pubkey, EC_PUBLIC_FOOTER]) ) try: signature = base64.urlsafe_b64decode(signature) signature = ecdsa.util.sigdecode_string(signature, order=ecdsa.curves.NIST384p.order) except binascii.Error as e: if BASE64_WRONG_LENGTH_RE.match(e.args[0]): raise WrongSignatureSize("Base64 encoded signature was not a multiple of 4") else: raise except AssertionError as e: # The signature decoder has a clause like # assert len(signature) == 2*l, (len(signature), 2*l) # If the AssertionError is consistent with that signature, translate it # to a nicer error. Otherwise re-raise. if ( len(e.args) == 1 and isinstance(e.args[0], tuple) and len(e.args[0]) == 2 and isinstance(e.args[0][0], int) and isinstance(e.args[0][1], int) ): raise WrongSignatureSize() else: raise verified = fastecdsa.ecdsa.verify( signature, data, verifying_pubkey, curve=fastecdsa.curve.P384, hashfunc=hashlib.sha384 ) if not verified: raise SignatureDoesNotMatch() return True
def verify_signature(data, signature, pubkey): """ Verify a signature. If the signature is valid, returns True. If the signature is invalid, raise an exception explaining why. """ # Data must be encoded as bytes if isinstance(data, str): data = data.encode() # Content signature implicitly adds a prefix to signed data data = b"Content-Signature:\x00" + data # fastecdsa expects ASCII armored keys, but ours is unarmored. Add the # armor before passing the key to the library. EC_PUBLIC_HEADER = "-----BEGIN PUBLIC KEY-----" EC_PUBLIC_FOOTER = "-----END PUBLIC KEY-----" verifying_pubkey = PEMEncoder.decode_public_key("\n".join( [EC_PUBLIC_HEADER, pubkey, EC_PUBLIC_FOOTER])) try: signature = base64.urlsafe_b64decode(signature) signature = ecdsa.util.sigdecode_string( signature, order=ecdsa.curves.NIST384p.order) except binascii.Error as e: if BASE64_WRONG_LENGTH_RE.match(e.args[0]): raise WrongSignatureSize( "Base64 encoded signature was not a multiple of 4") else: raise except AssertionError as e: # The signature decoder has a clause like # assert len(signature) == 2*l, (len(signature), 2*l) # If the AssertionError is consistent with that signature, translate it # to a nicer error. Otherwise re-raise. if (len(e.args) == 1 and isinstance(e.args[0], tuple) and len(e.args[0]) == 2 and isinstance(e.args[0][0], int) and isinstance(e.args[0][1], int)): raise WrongSignatureSize() else: raise verified = fastecdsa.ecdsa.verify(signature, data, verifying_pubkey, curve=fastecdsa.curve.P384, hashfunc=hashlib.sha384) if not verified: raise SignatureDoesNotMatch() return True
def build_authorization_header(self): """Build authorization headers.""" if len(self.required_authorization_headers) > 0: self.authorization_parameters['headers'] = '{}'.format(' '.join([ header.lower() for header in self.required_authorization_headers ])) self.build_signing_string() signing_bytestring = self.signing_string.encode(self.encoding) if self.signing_algorithm == 'RSA': signer = RSA.import_key(self.private_key_string) if self.hashing_algorithm == 'SHA256': hash_obj = SHA256.new(signing_bytestring) elif self.hashing_algorithm == 'SHA512': hash_obj = SHA512.new(signing_bytestring) else: raise Exception("Invalid key type") signature = pkcs1_15.new(signer).sign(hash_obj) else: private_key, public_key = PEMEncoder.decode_private_key( self.private_key_string) if self.hashing_algorithm == 'SHA256': hash_function = hashlib.sha256 elif self.hashing_algorithm == 'SHA512': hash_function = hashlib.sha512 else: raise Exception("Invalid key type") if self.signing_algorithm.lower() == 'p256': r, s = ecdsa.sign(signing_bytestring, private_key, curve=curve.P256, hashfunc=hash_function) else: raise Exception("Invalid key type") signature = DEREncoder.encode_signature(r, s) base64_signature = base64.b64encode(signature).decode(self.encoding) self.authorization_parameters['signature'] = '{}'.format( base64_signature) authorization_rows = [] for key, value in self.authorization_parameters.items(): if isinstance(value, str): authorization_rows.append('{}="{}"'.format(key, value)) elif isinstance(value, int) or isinstance(value, float): authorization_rows.append('{}={}'.format(key, value)) elif isinstance(value, bool): if value is True: authorization_rows.append('{}=true') else: authorization_rows.append('{}=false') authorization_header = 'Signature {}'.format( ','.join(authorization_rows)) self.headers['Authorization'] = authorization_header
def verify_signature_pubkey(data, signature, pubkey): """ Verify a signature. If the signature is valid, returns True. If the signature is invalid, raise an exception explaining why. """ # Data must be encoded as bytes if isinstance(data, str): data = data.encode() # Content signature implicitly adds a prefix to signed data data = b"Content-Signature:\x00" + data # fastecdsa expects ASCII armored keys, but ours is unarmored. Add the # armor before passing the key to the library. EC_PUBLIC_HEADER = "-----BEGIN PUBLIC KEY-----" EC_PUBLIC_FOOTER = "-----END PUBLIC KEY-----" verifying_pubkey = PEMEncoder.decode_public_key("\n".join( [EC_PUBLIC_HEADER, pubkey, EC_PUBLIC_FOOTER])) try: signature = base64.urlsafe_b64decode(signature) signature = ecdsa.util.sigdecode_string( signature, order=ecdsa.curves.NIST384p.order) except binascii.Error as e: if BASE64_WRONG_LENGTH_RE.match(e.args[0]): raise WrongSignatureSize( "Base64 encoded signature was not a multiple of 4") else: raise except ecdsa.util.MalformedSignature: raise WrongSignatureSize() verified = fastecdsa.ecdsa.verify(signature, data, verifying_pubkey, curve=fastecdsa.curve.P384, hashfunc=hashlib.sha384) if not verified: raise SignatureDoesNotMatch() return True
def __validate_fastecdsa_signature(self, verification_string, signature, charset): """Return True if signature is valid, using FastEDSA algorithms.""" ecdsa_public_key = PEMEncoder.decode_public_key( self.inflated_public_key) # signature_length = len(signature) r, s = DEREncoder.decode_signature(signature) # r_bytes, s_bytes = signature[:signature_length // 2], signature[signature_length // 2:signature_length] # r, s = int.from_bytes(r_bytes, 'big', signed=False), int.from_bytes(s_bytes, 'big', signed=False) signing_algorithm = self.signing_algorithm.upper() if ('SHA-' in signing_algorithm): signing_algorithm = signing_algorithm.replace('SHA-', 'SHA') if ('P-' in signing_algorithm): signing_algorithm = signing_algorithm.replace('P-', 'P') if signing_algorithm == self.SIGNING_ALGORITHM_ECDSA_P256: curve_algorithm = curve.P256 elif signing_algorithm == self.SIGNING_ALGORITHM_ECDSA_P384: curve_algorithm = curve.P384 elif signing_algorithm == self.SIGNING_ALGORITHM_ECDSA_P521: curve_algorithm = curve.P2521 elif signing_algorithm == self.SIGNING_ALGORITHM_ECDSA_CURVE25519: curve_algorithm = curve.W25519 else: raise UnsupportedAlgorithmException(self.signing_algorithm) hashing_algorithm = self.hashing_algorithm.upper().replace('-', '') if hashing_algorithm == self.HASHING_ALGORITHM_SHA256: hash_function = hashlib.sha256 elif hashing_algorithm == self.HASHING_ALGORITHM_SHA512: hash_function = hashlib.sha512 else: raise UnsupportedAlgorithmException(self.hashing_algorithm) is_valid = False try: ecdsa.verify((r, s), signature, ecdsa_public_key, curve=curve_algorithm, hashfunc=hash_function) is_valid = True except ecdsa.EcdsaError: is_valid = False return is_valid
def import_verifying_key(pem_bytes: bytes) -> VerifyingKey: return PEMEncoder.decode_public_key(pem_bytes.decode(), curve.secp256k1)
def export_verifying_key(verifying_key: VerifyingKey) -> bytes: return PEMEncoder.encode_public_key(verifying_key).encode()