From a7c355cccf850375327c4cc4ef990bc1dfa1e461 Mon Sep 17 00:00:00 2001 From: blag Date: Sun, 13 Jan 2019 03:12:49 -0800 Subject: [PATCH 1/4] Decode smessage before concatenating it with the signature --- src/nacl/signing.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/nacl/signing.py b/src/nacl/signing.py index b99a99015..497fd3352 100644 --- a/src/nacl/signing.py +++ b/src/nacl/signing.py @@ -104,10 +104,10 @@ def verify(self, smessage, signature=None, encoder=encoding.RawEncoder): if signature is not None: # If we were given the message and signature separately, combine # them. - smessage = signature + smessage - - # Decode the signed message - smessage = encoder.decode(smessage) + smessage = signature + encoder.decode(smessage) + else: + # Decode the signed message + smessage = encoder.decode(smessage) return nacl.bindings.crypto_sign_open(smessage, self._key) From e37decd3e0cffa4fa56f43d8931495c4139812dc Mon Sep 17 00:00:00 2001 From: blag Date: Sun, 13 Jan 2019 03:13:26 -0800 Subject: [PATCH 2/4] Tweak existing test and add two more --- tests/test_signing.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/tests/test_signing.py b/tests/test_signing.py index 676d11b72..4304afb92 100644 --- a/tests/test_signing.py +++ b/tests/test_signing.py @@ -21,7 +21,7 @@ from utils import assert_equal, assert_not_equal, read_crypto_test_vectors from nacl.bindings import crypto_sign_PUBLICKEYBYTES, crypto_sign_SEEDBYTES -from nacl.encoding import HexEncoder +from nacl.encoding import Base64Encoder, HexEncoder from nacl.exceptions import BadSignatureError from nacl.signing import SignedMessage, SigningKey, VerifyKey @@ -149,7 +149,8 @@ def test_valid_signed_message( key.verify(signed, encoder=HexEncoder), ) == message assert binascii.hexlify( - key.verify(message, signature, encoder=HexEncoder), + key.verify(message, HexEncoder.decode(signature), + encoder=HexEncoder), ) == message def test_invalid_signed_message(self): @@ -167,6 +168,38 @@ def test_invalid_signed_message(self): forged = SignedMessage(signature + message) skey.verify_key.verify(forged) + def test_base64_smessage_with_detached_sig_matches_with_attached_sig(self): + sk = SigningKey.generate() + vk = sk.verify_key + + smsg = sk.sign(b"Hello World in base64", encoder=Base64Encoder) + + msg = smsg.message + b64sig = smsg.signature + + sig = Base64Encoder.decode(b64sig) + + assert vk.verify(msg, sig, encoder=Base64Encoder) == \ + vk.verify(smsg, encoder=Base64Encoder) + + assert Base64Encoder.decode(msg) == b"Hello World in base64" + + def test_hex_smessage_with_detached_sig_matches_with_attached_sig(self): + sk = SigningKey.generate() + vk = sk.verify_key + + smsg = sk.sign(b"Hello World in hex", encoder=HexEncoder) + + msg = smsg.message + hexsig = smsg.signature + + sig = HexEncoder.decode(hexsig) + + assert vk.verify(msg, sig, encoder=HexEncoder) == \ + vk.verify(smsg, encoder=HexEncoder) + + assert HexEncoder.decode(msg) == b"Hello World in hex" + def test_key_conversion(self): keypair_seed = (b"421151a459faeade3d247115f94aedae" b"42318124095afabe4d1451a559faedee") From 6f5a558629e6a7a1299b1a6072f4ec15b229acb3 Mon Sep 17 00:00:00 2001 From: blag Date: Sun, 13 Jan 2019 03:14:39 -0800 Subject: [PATCH 3/4] Document that VerifyKey.verify requires that signature be already decoded to raw bytes --- docs/signing.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/signing.rst b/docs/signing.rst index 92183acf0..ea3ec4a2a 100644 --- a/docs/signing.rst +++ b/docs/signing.rst @@ -47,10 +47,11 @@ Verifier's perspective (:class:`~nacl.signing.VerifyKey`) encoder=nacl.encoding.HexEncoder) # Check the validity of a message's signature - # The message and the signature can either be passed separately or - # concatenated together. These are equivalent: + # The message and the signature can either be passed together, or + # separately if the signature is decoded to raw bytes. + # These are equivalent: verify_key.verify(signed) - verify_key.verify(signed.message, signed.signature) + verify_key.verify(signed.message, HexEncoder.decode(signed.signature)) # Alter the signed message text forged = signed[:-1] + bytes([int(signed[-1]) ^ 1]) From fd966de29a80a7fa760456744b4ec2c395fd1318 Mon Sep 17 00:00:00 2001 From: blag Date: Sun, 13 Jan 2019 19:38:42 -0800 Subject: [PATCH 4/4] Fix example, and add examples with HexEncoder and Base64Encoder --- docs/signing.rst | 128 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 120 insertions(+), 8 deletions(-) diff --git a/docs/signing.rst b/docs/signing.rst index ea3ec4a2a..a7c847e3e 100644 --- a/docs/signing.rst +++ b/docs/signing.rst @@ -17,15 +17,16 @@ use it to validate that your messages are actually authentic. Example ------- +Signing and verifying a message without encoding the key or message + Signer's perspective (:class:`~nacl.signing.SigningKey`) .. testcode:: - import nacl.encoding - import nacl.signing + from nacl.signing import SigningKey # Generate a new random signing key - signing_key = nacl.signing.SigningKey.generate() + signing_key = SigningKey.generate() # Sign a message with the signing key signed = signing_key.sign(b"Attack at Dawn") @@ -34,24 +35,23 @@ Signer's perspective (:class:`~nacl.signing.SigningKey`) verify_key = signing_key.verify_key # Serialize the verify key to send it to a third party - verify_key_hex = verify_key.encode(encoder=nacl.encoding.HexEncoder) + verify_key_bytes = verify_key.encode() Verifier's perspective (:class:`~nacl.signing.VerifyKey`) .. testcode:: - import nacl.signing + from nacl.signing import VerifyKey # Create a VerifyKey object from a hex serialized public key - verify_key = nacl.signing.VerifyKey(verify_key_hex, - encoder=nacl.encoding.HexEncoder) + verify_key = VerifyKey(verify_key_bytes) # Check the validity of a message's signature # The message and the signature can either be passed together, or # separately if the signature is decoded to raw bytes. # These are equivalent: verify_key.verify(signed) - verify_key.verify(signed.message, HexEncoder.decode(signed.signature)) + verify_key.verify(signed.message, signed.signature) # Alter the signed message text forged = signed[:-1] + bytes([int(signed[-1]) ^ 1]) @@ -66,6 +66,118 @@ Verifier's perspective (:class:`~nacl.signing.VerifyKey`) nacl.exceptions.BadSignatureError: Signature was forged or corrupt +Example +------- + +Signing and verifying a message encoded with HexEncoder + +Signer's perspective (:class:`~nacl.signing.SigningKey`) + +.. testcode:: + + from nacl.encoding import HexEncoder + from nacl.signing import SigningKey + + # Generate a new random signing key + signing_key = SigningKey.generate() + + # Sign a message with the signing key + signed_hex = signing_key.sign(b"Attack at Dawn", encoder=HexEncoder) + + # Obtain the verify key for a given signing key + verify_key = signing_key.verify_key + + # Serialize the verify key to send it to a third party + verify_key_hex = verify_key.encode(encoder=HexEncoder) + +Verifier's perspective (:class:`~nacl.signing.VerifyKey`) + +.. testcode:: + + from nacl.encoding import HexEncoder + from nacl.signing import VerifyKey + + # Create a VerifyKey object from a hex serialized public key + verify_key = VerifyKey(verify_key_hex, encoder=HexEncoder) + + # Check the validity of a message's signature + # The message and the signature can either be passed together, or + # separately if the signature is decoded to raw bytes. + # These are equivalent: + verify_key.verify(signed_hex, encoder=HexEncoder) + signature_bytes = HexEncoder.decode(signed_hex.signature) + verify_key.verify(signed_hex.message, signature_bytes, + encoder=HexEncoder) + + # Alter the signed message text + forged = signed_hex[:-1] + bytes([int(signed_hex[-1]) ^ 1]) + # Will raise nacl.exceptions.BadSignatureError, since the signature check + # is failing + verify_key.verify(forged) + +.. testoutput:: + + Traceback (most recent call last): + ... + nacl.exceptions.BadSignatureError: Signature was forged or corrupt + + +Example +------- + +Signing and verifying a message encoded with Base64Encoder + +Signer's perspective (:class:`~nacl.signing.SigningKey`) + +.. testcode:: + + from nacl.encoding import Base64Encoder + from nacl.signing import SigningKey + + # Generate a new random signing key + signing_key = SigningKey.generate() + + # Sign a message with the signing key + signed_b64 = signing_key.sign(b"Attack at Dawn", encoder=Base64Encoder) + + # Obtain the verify key for a given signing key + verify_key = signing_key.verify_key + + # Serialize the verify key to send it to a third party + verify_key_b64 = verify_key.encode(encoder=Base64Encoder) + +Verifier's perspective (:class:`~nacl.signing.VerifyKey`) + +.. testcode:: + + from nacl.encoding import Base64Encoder + from nacl.signing import VerifyKey + + # Create a VerifyKey object from a base64 serialized public key + verify_key = VerifyKey(verify_key_b64, encoder=Base64Encoder) + + # Check the validity of a message's signature + # The message and the signature can either be passed together, or + # separately if the signature is decoded to raw bytes. + # These are equivalent: + verify_key.verify(signed_b64, encoder=Base64Encoder) + signature_bytes = Base64Encoder.decode(signed_b64.signature) + verify_key.verify(signed_b64.message, signature_bytes, + encoder=Base64Encoder) + + # Alter the signed message text + forged = signed_b64[:-1] + bytes([int(signed_b64[-1]) ^ 1]) + # Will raise nacl.exceptions.BadSignatureError, since the signature check + # is failing + verify_key.verify(forged) + +.. testoutput:: + + Traceback (most recent call last): + ... + nacl.exceptions.BadSignatureError: Signature was forged or corrupt + + Reference ---------