From 147bb4aab308113ef327ccfc924059b0cf1d54a3 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Sat, 6 Feb 2021 23:07:09 +0100 Subject: [PATCH] Fix GH500: nonce member of an XChaCha20 was not matching the original nonce --- Changelog.rst | 1 + lib/Crypto/Cipher/ChaCha20.py | 7 +++--- lib/Crypto/SelfTest/Cipher/test_ChaCha20.py | 27 +++++++++++++++++---- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Changelog.rst b/Changelog.rst index 30d4e3b38..2dd993215 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -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 ------------- diff --git a/lib/Crypto/Cipher/ChaCha20.py b/lib/Crypto/Cipher/ChaCha20.py index a8e66c023..9bd2252ce 100644 --- a/lib/Crypto/Cipher/ChaCha20.py +++ b/lib/Crypto/Cipher/ChaCha20.py @@ -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: @@ -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 ) @@ -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, diff --git a/lib/Crypto/SelfTest/Cipher/test_ChaCha20.py b/lib/Crypto/SelfTest/Cipher/test_ChaCha20.py index 2c8ce8cbd..2b8de2046 100644 --- a/lib/Crypto/SelfTest/Cipher/test_ChaCha20.py +++ b/lib/Crypto/SelfTest/Cipher/test_ChaCha20.py @@ -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""" @@ -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 @@ -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) @@ -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)