Skip to content

Commit

Permalink
Fix GH500: nonce member of an XChaCha20 was not matching the original…
Browse files Browse the repository at this point in the history
… nonce
  • Loading branch information
Legrandin committed Feb 6, 2021
1 parent 19b8ad6 commit 147bb4a
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 8 deletions.
1 change: 1 addition & 0 deletions Changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Resolved issues
* GH#491: better exception message when ``Counter.new()`` is provided an integer
``initial_value`` than doesn't fit into ``nbits`` bits.
* GH#496: added missing ``block_size`` member for ECB cipher objects. Thanks to willem.
* GH#500: ``nonce`` member of an XChaCha20 cipher object was not matching the original nonce.

Other changes
-------------
Expand Down
7 changes: 4 additions & 3 deletions lib/Crypto/Cipher/ChaCha20.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ def __init__(self, key, nonce):
See also `new()` at the module level."""

self.nonce = _copy_bytes(None, None, nonce)

# XChaCha20 requires a key derivation with HChaCha20
# See 2.3 in https://tools.ietf.org/html/draft-arciszewski-xchacha-03
if len(nonce) == 24:
Expand All @@ -102,8 +104,7 @@ def __init__(self, key, nonce):
self._name = "XChaCha20"
else:
self._name = "ChaCha20"

self.nonce = _copy_bytes(None, None, nonce)
nonce = self.nonce

self._next = ( self.encrypt, self.decrypt )

Expand All @@ -112,7 +113,7 @@ def __init__(self, key, nonce):
self._state.address_of(),
c_uint8_ptr(key),
c_size_t(len(key)),
self.nonce,
nonce,
c_size_t(len(nonce)))
if result:
raise ValueError("Error %d instantiating a %s cipher" % (result,
Expand Down
27 changes: 22 additions & 5 deletions lib/Crypto/SelfTest/Cipher/test_ChaCha20.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ def test_default_nonce(self):
self.assertEquals(len(cipher1.nonce), 8)
self.assertNotEqual(cipher1.nonce, cipher2.nonce)

def test_nonce(self):
key = b'A' * 32

nonce1 = b'P' * 8
cipher1 = ChaCha20.new(key=key, nonce=nonce1)
self.assertEqual(nonce1, cipher1.nonce)

nonce2 = b'Q' * 12
cipher2 = ChaCha20.new(key=key, nonce=nonce2)
self.assertEqual(nonce2, cipher2.nonce)

def test_eiter_encrypt_or_decrypt(self):
"""Verify that a cipher cannot be used for both decrypting and encrypting"""

Expand Down Expand Up @@ -265,6 +276,12 @@ def test_hchacha20(self):

self.assertEqual(subkey, expected)

def test_nonce(self):
key = b'A' * 32
nonce = b'P' * 24
cipher = ChaCha20.new(key=key, nonce=nonce)
self.assertEqual(nonce, cipher.nonce)

def test_encrypt(self):
# Section A.3.2

Expand Down Expand Up @@ -464,7 +481,7 @@ def runTest(self):
res = cipher.encrypt(pt, output=output)
self.assertEqual(ct, output)
self.assertEqual(res, None)

cipher = ChaCha20.new(key=key, nonce=nonce)
res = cipher.decrypt(ct, output=output)
self.assertEqual(pt, output)
Expand All @@ -474,22 +491,22 @@ def runTest(self):
cipher = ChaCha20.new(key=key, nonce=nonce)
cipher.encrypt(pt, output=output)
self.assertEqual(ct, output)

cipher = ChaCha20.new(key=key, nonce=nonce)
cipher.decrypt(ct, output=output)
self.assertEqual(pt, output)

cipher = ChaCha20.new(key=key, nonce=nonce)
self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16)

cipher = ChaCha20.new(key=key, nonce=nonce)
self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16)

shorter_output = bytearray(7)

cipher = ChaCha20.new(key=key, nonce=nonce)
self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)

cipher = ChaCha20.new(key=key, nonce=nonce)
self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)

Expand Down

0 comments on commit 147bb4a

Please sign in to comment.