def test_split_two_signatures(): """ We make two random Signatures and concat them. Then split them and show that we got the proper result. """ sig1, sig2 = Signature(secure_random(65)), Signature(secure_random(65)) sigs_concatted = sig1 + sig2 two_signature_splitter = BytestringSplitter(Signature, Signature) rebuilt_sig1, rebuilt_sig2 = two_signature_splitter(sigs_concatted) assert (sig1, sig2) == (rebuilt_sig1, rebuilt_sig2)
def test_signature_rs_serialization(): privkey = UmbralPrivateKey.gen_key() message = b"attack at dawn" der_sig_bytes = ecdsa_sign(message, privkey) signature_from_der = Signature.from_bytes(der_sig_bytes, der_encoded=True) rs_sig_bytes = bytes(signature_from_der) assert len(rs_sig_bytes) == 64 signature_from_rs = Signature.from_bytes(rs_sig_bytes, der_encoded=False) assert signature_from_rs == signature_from_der assert signature_from_rs == der_sig_bytes assert signature_from_rs.verify(message, privkey.get_pubkey())
def test_split_signature_from_arbitrary_bytes(): how_many_bytes = 10 signature = Signature(secure_random(65)) some_bytes = secure_random(how_many_bytes) splitter = BytestringSplitter(Signature, (bytes, how_many_bytes)) rebuilt_signature, rebuilt_bytes = splitter(signature + some_bytes)
def verify_from(self, actor_whom_sender_claims_to_be: "Character", message: bytes, signature: Signature = None, decrypt=False, signature_is_on_cleartext=False) -> tuple: """ Inverse of encrypt_for. :param actor_that_sender_claims_to_be: A Character instance representing the actor whom the sender claims to be. We check the public key owned by this Character instance to verify. :param messages: The messages to be verified. :param decrypt: Whether or not to decrypt the messages. :param signature_is_on_cleartext: True if we expect the signature to be on the cleartext. Otherwise, we presume that the ciphertext is what is signed. :return: (Whether or not the signature is valid, the decrypted plaintext or NO_DECRYPTION_PERFORMED) """ if not signature and not signature_is_on_cleartext: raise ValueError("You need to either provide the Signature or decrypt and find it on the cleartext.") cleartext = NO_DECRYPTION_PERFORMED if signature_is_on_cleartext: if decrypt: cleartext = self._crypto_power.decrypt(message) signature, message = BytestringSplitter(Signature)(cleartext, return_remainder=True) else: raise ValueError( "Can't look for a signature on the cleartext if we're not decrypting.") actor = self._lookup_actor(actor_whom_sender_claims_to_be) return signature.verify(message, actor.seal), cleartext
def verify_from(self, actor_whom_sender_claims_to_be: "Character", message_kit: Union[MessageKit, bytes], signature: Signature=None, decrypt=False, signature_is_on_cleartext=False) -> tuple: """ Inverse of encrypt_for. :param actor_that_sender_claims_to_be: A Character instance representing the actor whom the sender claims to be. We check the public key owned by this Character instance to verify. :param messages: The messages to be verified. :param decrypt: Whether or not to decrypt the messages. :param signature_is_on_cleartext: True if we expect the signature to be on the cleartext. Otherwise, we presume that the ciphertext is what is signed. :return: Whether or not the signature is valid, the decrypted plaintext or NO_DECRYPTION_PERFORMED """ # TODO: In this flow we now essentially have two copies of the public key. See #174. # One from the actor (first arg) and one from the MessageKit. # Which do we use in which cases? # if not signature and not signature_is_on_cleartext: # TODO: Since a signature can now be in a MessageKit, this might not be accurate anymore. See #174. # raise ValueError("You need to either provide the Signature or \ # decrypt and find it on the cleartext.") cleartext = NO_DECRYPTION_PERFORMED if signature_is_on_cleartext: if decrypt: cleartext_with_sig = self.decrypt(message_kit) signature, cleartext = BytestringSplitter(Signature)(cleartext_with_sig, return_remainder=True) message_kit.signature = signature # TODO: Obviously this is the wrong way to do this. Let's make signature a property. else: raise ValueError( "Can't look for a signature on the cleartext if we're not \ decrypting.") message = cleartext alice_pubkey = message_kit.alice_pubkey else: # The signature is on the ciphertext. We might not even need to decrypt it. if decrypt: message = message_kit.ciphertext cleartext = self.decrypt(message_kit) else: message = bytes(message_kit) alice_pubkey = actor_whom_sender_claims_to_be.public_key(SigningPower) if signature: is_valid = signature.verify(message, alice_pubkey) else: # Meh, we didn't even get a signature. Not much we can do. is_valid = False return is_valid, cleartext
def test_trying_to_extract_too_many_bytes_raises_typeerror(): how_many_bytes = 10 too_many_bytes = 11 signature = Signature(secure_random(65)) some_bytes = secure_random(how_many_bytes) splitter = BytestringSplitter(Signature, (bytes, too_many_bytes)) with pytest.raises(ValueError): rebuilt_signature, rebuilt_bytes = splitter(signature + some_bytes, return_remainder=True)
def sign(self, message: bytes) -> bytes: """ Signs a hashed message and returns a signature. :param message: The message to sign :return: Signature in bytes """ signature_der_bytes = API.ecdsa_sign(message, self._privkey) return Signature.from_bytes(signature_der_bytes, der_encoded=True)
def sign(self, *messages): """ Signs a message and returns a signature with the keccak hash. :param Iterable messages: Messages to sign in an iterable of bytes :rtype: bytestring :return: Signature of message """ try: sig_keypair = self._power_ups[SigningPower] except KeyError as e: raise NoSigningPower(e) msg_digest = b"".join(API.keccak_digest(m) for m in messages) return Signature(sig_keypair.sign(msg_digest))
def test_signature_can_verify(): privkey = UmbralPrivateKey.gen_key() message = b"attack at dawn" der_sig_bytes = ecdsa_sign(message, privkey) signature = Signature.from_bytes(der_sig_bytes, der_encoded=True) assert signature.verify(message, privkey.get_pubkey())