pynacl icon indicating copy to clipboard operation
pynacl copied to clipboard

Signature verification failure when using URLSafeBase64Encoder

Open kiwih opened this issue 5 years ago • 1 comments

I have been experimenting with pynacl (1.3.0) using python3 (3.5.2) Using the examples on https://pynacl.readthedocs.io/en/stable/signing/, I construct this minimum example:

import nacl.encoding
import nacl.signing

message = b"Attack at Dawn"

# Generate a new random signing key
signing_key = nacl.signing.SigningKey.generate()

# Sign a message with the signing key
signed = signing_key.sign(message, encoder=nacl.encoding.HexEncoder)

# Obtain the verify key for a given signing key
verify_key = signing_key.verify_key

# Check the validity of a message's signature
# The message and the signature can either be passed separately or
# concatenated together.  These are supposed to be equivalent:
verify_key.verify(signed, encoder=nacl.encoding.HexEncoder) #this line verifies
verify_key.verify(signed.message, signed.signature, encoder=nacl.encoding.HexEncoder) #this line also verifies, since they are the same

print("All is well")

This works fine. However, if we change the encoding type to URLSafeBase64Encoder, as in the following minimum example

import nacl.encoding
import nacl.signing

message = b"Attack at Dawn"

# Generate a new random signing key
signing_key = nacl.signing.SigningKey.generate()

# Sign a message with the signing key
signed = signing_key.sign(message, encoder=nacl.encoding.URLSafeBase64Encoder)

# Obtain the verify key for a given signing key
verify_key = signing_key.verify_key

# Check the validity of a message's signature
# The message and the signature can either be passed separately or
# concatenated together.  These are supposed to be equivalent:
verify_key.verify(signed, encoder=nacl.encoding.URLSafeBase64Encoder) #this line verifies
verify_key.verify(signed.message, signed.signature, encoder=nacl.encoding.URLSafeBase64Encoder) #THIS LINE DOES NOT VERIFY

print("All is well")

I get the following trace

Traceback (most recent call last):
  File "testing_nacl.py", line 19, in <module>
    verify_key.verify(signed.message, signed.signature, encoder=nacl.encoding.URLSafeBase64Encoder) #THIS LINE DOES NOT VERIFY
  File "/home/username/.local/lib/python3.5/site-packages/nacl/signing.py", line 112, in verify
    return nacl.bindings.crypto_sign_open(smessage, self._key)
  File "/home/username/.local/lib/python3.5/site-packages/nacl/bindings/crypto_sign.py", line 111, in crypto_sign_open
    raise exc.BadSignatureError("Signature was forged or corrupt")
nacl.exceptions.BadSignatureError: Signature was forged or corrupt

I think there is a bug with the URLSafeBase64Encoder in this case.

kiwih avatar May 02 '19 23:05 kiwih

This kind of weirdness is the reason why we are discussing, about removing support from the encoding= parameter since @alex comment in https://github.com/pyca/pynacl/pull/504#issuecomment-454233998 and my later #523 PR.

lmctv avatar May 07 '19 20:05 lmctv