summaryrefslogtreecommitdiffstats
path: root/lib/Crypto/SelfTest/Cipher
diff options
context:
space:
mode:
authorxiubuzhe <xiubuzhe@sina.com>2023-10-08 20:59:00 +0800
committerxiubuzhe <xiubuzhe@sina.com>2023-10-08 20:59:00 +0800
commit1dac2263372df2b85db5d029a45721fa158a5c9d (patch)
tree0365f9c57df04178a726d7584ca6a6b955a7ce6a /lib/Crypto/SelfTest/Cipher
parentb494be364bb39e1de128ada7dc576a729d99907e (diff)
downloadsunhpc-1dac2263372df2b85db5d029a45721fa158a5c9d.tar.gz
sunhpc-1dac2263372df2b85db5d029a45721fa158a5c9d.tar.bz2
sunhpc-1dac2263372df2b85db5d029a45721fa158a5c9d.zip
first add files
Diffstat (limited to 'lib/Crypto/SelfTest/Cipher')
-rw-r--r--lib/Crypto/SelfTest/Cipher/__init__.py60
-rw-r--r--lib/Crypto/SelfTest/Cipher/common.py510
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_AES.py1351
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_ARC2.py167
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_ARC4.py466
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_Blowfish.py160
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_CAST.py101
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_CBC.py556
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_CCM.py936
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_CFB.py411
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_CTR.py472
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_ChaCha20.py529
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py770
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_DES.py374
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_DES3.py195
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_EAX.py773
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_GCM.py951
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_OCB.py742
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_OFB.py238
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_OpenPGP.py218
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_SIV.py552
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_Salsa20.py367
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_pkcs1_15.py283
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py506
24 files changed, 11688 insertions, 0 deletions
diff --git a/lib/Crypto/SelfTest/Cipher/__init__.py b/lib/Crypto/SelfTest/Cipher/__init__.py
new file mode 100644
index 0000000..05fc139
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/__init__.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Cipher/__init__.py: Self-test for cipher modules
+#
+# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+"""Self-test for cipher modules"""
+
+__revision__ = "$Id$"
+
+def get_tests(config={}):
+ tests = []
+ from Crypto.SelfTest.Cipher import test_AES; tests += test_AES.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_ARC2; tests += test_ARC2.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_ARC4; tests += test_ARC4.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_Blowfish; tests += test_Blowfish.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_CAST; tests += test_CAST.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_DES3; tests += test_DES3.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_DES; tests += test_DES.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_Salsa20; tests += test_Salsa20.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_ChaCha20; tests += test_ChaCha20.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_ChaCha20_Poly1305; tests += test_ChaCha20_Poly1305.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_pkcs1_15; tests += test_pkcs1_15.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_pkcs1_oaep; tests += test_pkcs1_oaep.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_OCB; tests += test_OCB.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_CBC; tests += test_CBC.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_CFB; tests += test_CFB.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_OpenPGP; tests += test_OpenPGP.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_OFB; tests += test_OFB.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_CTR; tests += test_CTR.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_CCM; tests += test_CCM.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_EAX; tests += test_EAX.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_GCM; tests += test_GCM.get_tests(config=config)
+ from Crypto.SelfTest.Cipher import test_SIV; tests += test_SIV.get_tests(config=config)
+ return tests
+
+if __name__ == '__main__':
+ import unittest
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
+
+# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/SelfTest/Cipher/common.py b/lib/Crypto/SelfTest/Cipher/common.py
new file mode 100644
index 0000000..c5bc755
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/common.py
@@ -0,0 +1,510 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Hash/common.py: Common code for Crypto.SelfTest.Hash
+#
+# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+"""Self-testing for PyCrypto hash modules"""
+
+import unittest
+from binascii import a2b_hex, b2a_hex, hexlify
+
+from Crypto.Util.py3compat import b
+from Crypto.Util.strxor import strxor_c
+
+class _NoDefault: pass # sentinel object
+def _extract(d, k, default=_NoDefault):
+ """Get an item from a dictionary, and remove it from the dictionary."""
+ try:
+ retval = d[k]
+ except KeyError:
+ if default is _NoDefault:
+ raise
+ return default
+ del d[k]
+ return retval
+
+# Generic cipher test case
+class CipherSelfTest(unittest.TestCase):
+
+ def __init__(self, module, params):
+ unittest.TestCase.__init__(self)
+ self.module = module
+
+ # Extract the parameters
+ params = params.copy()
+ self.description = _extract(params, 'description')
+ self.key = b(_extract(params, 'key'))
+ self.plaintext = b(_extract(params, 'plaintext'))
+ self.ciphertext = b(_extract(params, 'ciphertext'))
+ self.module_name = _extract(params, 'module_name', None)
+ self.assoc_data = _extract(params, 'assoc_data', None)
+ self.mac = _extract(params, 'mac', None)
+ if self.assoc_data:
+ self.mac = b(self.mac)
+
+ mode = _extract(params, 'mode', None)
+ self.mode_name = str(mode)
+
+ if mode is not None:
+ # Block cipher
+ self.mode = getattr(self.module, "MODE_" + mode)
+
+ self.iv = _extract(params, 'iv', None)
+ if self.iv is None:
+ self.iv = _extract(params, 'nonce', None)
+ if self.iv is not None:
+ self.iv = b(self.iv)
+
+ else:
+ # Stream cipher
+ self.mode = None
+ self.iv = _extract(params, 'iv', None)
+ if self.iv is not None:
+ self.iv = b(self.iv)
+
+ self.extra_params = params
+
+ def shortDescription(self):
+ return self.description
+
+ def _new(self):
+ params = self.extra_params.copy()
+ key = a2b_hex(self.key)
+
+ old_style = []
+ if self.mode is not None:
+ old_style = [ self.mode ]
+ if self.iv is not None:
+ old_style += [ a2b_hex(self.iv) ]
+
+ return self.module.new(key, *old_style, **params)
+
+ def isMode(self, name):
+ if not hasattr(self.module, "MODE_"+name):
+ return False
+ return self.mode == getattr(self.module, "MODE_"+name)
+
+ def runTest(self):
+ plaintext = a2b_hex(self.plaintext)
+ ciphertext = a2b_hex(self.ciphertext)
+ assoc_data = []
+ if self.assoc_data:
+ assoc_data = [ a2b_hex(b(x)) for x in self.assoc_data]
+
+ ct = None
+ pt = None
+
+ #
+ # Repeat the same encryption or decryption twice and verify
+ # that the result is always the same
+ #
+ for i in range(2):
+ cipher = self._new()
+ decipher = self._new()
+
+ # Only AEAD modes
+ for comp in assoc_data:
+ cipher.update(comp)
+ decipher.update(comp)
+
+ ctX = b2a_hex(cipher.encrypt(plaintext))
+ ptX = b2a_hex(decipher.decrypt(ciphertext))
+
+ if ct:
+ self.assertEqual(ct, ctX)
+ self.assertEqual(pt, ptX)
+ ct, pt = ctX, ptX
+
+ self.assertEqual(self.ciphertext, ct) # encrypt
+ self.assertEqual(self.plaintext, pt) # decrypt
+
+ if self.mac:
+ mac = b2a_hex(cipher.digest())
+ self.assertEqual(self.mac, mac)
+ decipher.verify(a2b_hex(self.mac))
+
+class CipherStreamingSelfTest(CipherSelfTest):
+
+ def shortDescription(self):
+ desc = self.module_name
+ if self.mode is not None:
+ desc += " in %s mode" % (self.mode_name,)
+ return "%s should behave like a stream cipher" % (desc,)
+
+ def runTest(self):
+ plaintext = a2b_hex(self.plaintext)
+ ciphertext = a2b_hex(self.ciphertext)
+
+ # The cipher should work like a stream cipher
+
+ # Test counter mode encryption, 3 bytes at a time
+ ct3 = []
+ cipher = self._new()
+ for i in range(0, len(plaintext), 3):
+ ct3.append(cipher.encrypt(plaintext[i:i+3]))
+ ct3 = b2a_hex(b("").join(ct3))
+ self.assertEqual(self.ciphertext, ct3) # encryption (3 bytes at a time)
+
+ # Test counter mode decryption, 3 bytes at a time
+ pt3 = []
+ cipher = self._new()
+ for i in range(0, len(ciphertext), 3):
+ pt3.append(cipher.encrypt(ciphertext[i:i+3]))
+ # PY3K: This is meant to be text, do not change to bytes (data)
+ pt3 = b2a_hex(b("").join(pt3))
+ self.assertEqual(self.plaintext, pt3) # decryption (3 bytes at a time)
+
+
+class RoundtripTest(unittest.TestCase):
+ def __init__(self, module, params):
+ from Crypto import Random
+ unittest.TestCase.__init__(self)
+ self.module = module
+ self.iv = Random.get_random_bytes(module.block_size)
+ self.key = b(params['key'])
+ self.plaintext = 100 * b(params['plaintext'])
+ self.module_name = params.get('module_name', None)
+
+ def shortDescription(self):
+ return """%s .decrypt() output of .encrypt() should not be garbled""" % (self.module_name,)
+
+ def runTest(self):
+
+ ## ECB mode
+ mode = self.module.MODE_ECB
+ encryption_cipher = self.module.new(a2b_hex(self.key), mode)
+ ciphertext = encryption_cipher.encrypt(self.plaintext)
+ decryption_cipher = self.module.new(a2b_hex(self.key), mode)
+ decrypted_plaintext = decryption_cipher.decrypt(ciphertext)
+ self.assertEqual(self.plaintext, decrypted_plaintext)
+
+
+class IVLengthTest(unittest.TestCase):
+ def __init__(self, module, params):
+ unittest.TestCase.__init__(self)
+ self.module = module
+ self.key = b(params['key'])
+
+ def shortDescription(self):
+ return "Check that all modes except MODE_ECB and MODE_CTR require an IV of the proper length"
+
+ def runTest(self):
+ self.assertRaises(TypeError, self.module.new, a2b_hex(self.key),
+ self.module.MODE_ECB, b(""))
+
+ def _dummy_counter(self):
+ return "\0" * self.module.block_size
+
+
+class NoDefaultECBTest(unittest.TestCase):
+ def __init__(self, module, params):
+ unittest.TestCase.__init__(self)
+ self.module = module
+ self.key = b(params['key'])
+
+ def runTest(self):
+ self.assertRaises(TypeError, self.module.new, a2b_hex(self.key))
+
+
+class BlockSizeTest(unittest.TestCase):
+ def __init__(self, module, params):
+ unittest.TestCase.__init__(self)
+ self.module = module
+ self.key = a2b_hex(b(params['key']))
+
+ def runTest(self):
+ cipher = self.module.new(self.key, self.module.MODE_ECB)
+ self.assertEqual(cipher.block_size, self.module.block_size)
+
+
+class ByteArrayTest(unittest.TestCase):
+ """Verify we can use bytearray's for encrypting and decrypting"""
+
+ def __init__(self, module, params):
+ unittest.TestCase.__init__(self)
+ self.module = module
+
+ # Extract the parameters
+ params = params.copy()
+ self.description = _extract(params, 'description')
+ self.key = b(_extract(params, 'key'))
+ self.plaintext = b(_extract(params, 'plaintext'))
+ self.ciphertext = b(_extract(params, 'ciphertext'))
+ self.module_name = _extract(params, 'module_name', None)
+ self.assoc_data = _extract(params, 'assoc_data', None)
+ self.mac = _extract(params, 'mac', None)
+ if self.assoc_data:
+ self.mac = b(self.mac)
+
+ mode = _extract(params, 'mode', None)
+ self.mode_name = str(mode)
+
+ if mode is not None:
+ # Block cipher
+ self.mode = getattr(self.module, "MODE_" + mode)
+
+ self.iv = _extract(params, 'iv', None)
+ if self.iv is None:
+ self.iv = _extract(params, 'nonce', None)
+ if self.iv is not None:
+ self.iv = b(self.iv)
+ else:
+ # Stream cipher
+ self.mode = None
+ self.iv = _extract(params, 'iv', None)
+ if self.iv is not None:
+ self.iv = b(self.iv)
+
+ self.extra_params = params
+
+ def _new(self):
+ params = self.extra_params.copy()
+ key = a2b_hex(self.key)
+
+ old_style = []
+ if self.mode is not None:
+ old_style = [ self.mode ]
+ if self.iv is not None:
+ old_style += [ a2b_hex(self.iv) ]
+
+ return self.module.new(key, *old_style, **params)
+
+ def runTest(self):
+
+ plaintext = a2b_hex(self.plaintext)
+ ciphertext = a2b_hex(self.ciphertext)
+ assoc_data = []
+ if self.assoc_data:
+ assoc_data = [ bytearray(a2b_hex(b(x))) for x in self.assoc_data]
+
+ cipher = self._new()
+ decipher = self._new()
+
+ # Only AEAD modes
+ for comp in assoc_data:
+ cipher.update(comp)
+ decipher.update(comp)
+
+ ct = b2a_hex(cipher.encrypt(bytearray(plaintext)))
+ pt = b2a_hex(decipher.decrypt(bytearray(ciphertext)))
+
+ self.assertEqual(self.ciphertext, ct) # encrypt
+ self.assertEqual(self.plaintext, pt) # decrypt
+
+ if self.mac:
+ mac = b2a_hex(cipher.digest())
+ self.assertEqual(self.mac, mac)
+ decipher.verify(bytearray(a2b_hex(self.mac)))
+
+
+class MemoryviewTest(unittest.TestCase):
+ """Verify we can use memoryviews for encrypting and decrypting"""
+
+ def __init__(self, module, params):
+ unittest.TestCase.__init__(self)
+ self.module = module
+
+ # Extract the parameters
+ params = params.copy()
+ self.description = _extract(params, 'description')
+ self.key = b(_extract(params, 'key'))
+ self.plaintext = b(_extract(params, 'plaintext'))
+ self.ciphertext = b(_extract(params, 'ciphertext'))
+ self.module_name = _extract(params, 'module_name', None)
+ self.assoc_data = _extract(params, 'assoc_data', None)
+ self.mac = _extract(params, 'mac', None)
+ if self.assoc_data:
+ self.mac = b(self.mac)
+
+ mode = _extract(params, 'mode', None)
+ self.mode_name = str(mode)
+
+ if mode is not None:
+ # Block cipher
+ self.mode = getattr(self.module, "MODE_" + mode)
+
+ self.iv = _extract(params, 'iv', None)
+ if self.iv is None:
+ self.iv = _extract(params, 'nonce', None)
+ if self.iv is not None:
+ self.iv = b(self.iv)
+ else:
+ # Stream cipher
+ self.mode = None
+ self.iv = _extract(params, 'iv', None)
+ if self.iv is not None:
+ self.iv = b(self.iv)
+
+ self.extra_params = params
+
+ def _new(self):
+ params = self.extra_params.copy()
+ key = a2b_hex(self.key)
+
+ old_style = []
+ if self.mode is not None:
+ old_style = [ self.mode ]
+ if self.iv is not None:
+ old_style += [ a2b_hex(self.iv) ]
+
+ return self.module.new(key, *old_style, **params)
+
+ def runTest(self):
+
+ plaintext = a2b_hex(self.plaintext)
+ ciphertext = a2b_hex(self.ciphertext)
+ assoc_data = []
+ if self.assoc_data:
+ assoc_data = [ memoryview(a2b_hex(b(x))) for x in self.assoc_data]
+
+ cipher = self._new()
+ decipher = self._new()
+
+ # Only AEAD modes
+ for comp in assoc_data:
+ cipher.update(comp)
+ decipher.update(comp)
+
+ ct = b2a_hex(cipher.encrypt(memoryview(plaintext)))
+ pt = b2a_hex(decipher.decrypt(memoryview(ciphertext)))
+
+ self.assertEqual(self.ciphertext, ct) # encrypt
+ self.assertEqual(self.plaintext, pt) # decrypt
+
+ if self.mac:
+ mac = b2a_hex(cipher.digest())
+ self.assertEqual(self.mac, mac)
+ decipher.verify(memoryview(a2b_hex(self.mac)))
+
+
+def make_block_tests(module, module_name, test_data, additional_params=dict()):
+ tests = []
+ extra_tests_added = False
+ for i in range(len(test_data)):
+ row = test_data[i]
+
+ # Build the "params" dictionary with
+ # - plaintext
+ # - ciphertext
+ # - key
+ # - mode (default is ECB)
+ # - (optionally) description
+ # - (optionally) any other parameter that this cipher mode requires
+ params = {}
+ if len(row) == 3:
+ (params['plaintext'], params['ciphertext'], params['key']) = row
+ elif len(row) == 4:
+ (params['plaintext'], params['ciphertext'], params['key'], params['description']) = row
+ elif len(row) == 5:
+ (params['plaintext'], params['ciphertext'], params['key'], params['description'], extra_params) = row
+ params.update(extra_params)
+ else:
+ raise AssertionError("Unsupported tuple size %d" % (len(row),))
+
+ if not "mode" in params:
+ params["mode"] = "ECB"
+
+ # Build the display-name for the test
+ p2 = params.copy()
+ p_key = _extract(p2, 'key')
+ p_plaintext = _extract(p2, 'plaintext')
+ p_ciphertext = _extract(p2, 'ciphertext')
+ p_mode = _extract(p2, 'mode')
+ p_description = _extract(p2, 'description', None)
+
+ if p_description is not None:
+ description = p_description
+ elif p_mode == 'ECB' and not p2:
+ description = "p=%s, k=%s" % (p_plaintext, p_key)
+ else:
+ description = "p=%s, k=%s, %r" % (p_plaintext, p_key, p2)
+ name = "%s #%d: %s" % (module_name, i+1, description)
+ params['description'] = name
+ params['module_name'] = module_name
+ params.update(additional_params)
+
+ # Add extra test(s) to the test suite before the current test
+ if not extra_tests_added:
+ tests += [
+ RoundtripTest(module, params),
+ IVLengthTest(module, params),
+ NoDefaultECBTest(module, params),
+ ByteArrayTest(module, params),
+ BlockSizeTest(module, params),
+ ]
+ extra_tests_added = True
+
+ # Add the current test to the test suite
+ tests.append(CipherSelfTest(module, params))
+
+ return tests
+
+def make_stream_tests(module, module_name, test_data):
+ tests = []
+ extra_tests_added = False
+ for i in range(len(test_data)):
+ row = test_data[i]
+
+ # Build the "params" dictionary
+ params = {}
+ if len(row) == 3:
+ (params['plaintext'], params['ciphertext'], params['key']) = row
+ elif len(row) == 4:
+ (params['plaintext'], params['ciphertext'], params['key'], params['description']) = row
+ elif len(row) == 5:
+ (params['plaintext'], params['ciphertext'], params['key'], params['description'], extra_params) = row
+ params.update(extra_params)
+ else:
+ raise AssertionError("Unsupported tuple size %d" % (len(row),))
+
+ # Build the display-name for the test
+ p2 = params.copy()
+ p_key = _extract(p2, 'key')
+ p_plaintext = _extract(p2, 'plaintext')
+ p_ciphertext = _extract(p2, 'ciphertext')
+ p_description = _extract(p2, 'description', None)
+
+ if p_description is not None:
+ description = p_description
+ elif not p2:
+ description = "p=%s, k=%s" % (p_plaintext, p_key)
+ else:
+ description = "p=%s, k=%s, %r" % (p_plaintext, p_key, p2)
+ name = "%s #%d: %s" % (module_name, i+1, description)
+ params['description'] = name
+ params['module_name'] = module_name
+
+ # Add extra test(s) to the test suite before the current test
+ if not extra_tests_added:
+ tests += [
+ ByteArrayTest(module, params),
+ ]
+
+ tests.append(MemoryviewTest(module, params))
+ extra_tests_added = True
+
+ # Add the test to the test suite
+ tests.append(CipherSelfTest(module, params))
+ tests.append(CipherStreamingSelfTest(module, params))
+ return tests
+
+# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/SelfTest/Cipher/test_AES.py b/lib/Crypto/SelfTest/Cipher/test_AES.py
new file mode 100644
index 0000000..116deec
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_AES.py
@@ -0,0 +1,1351 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Cipher/AES.py: Self-test for the AES cipher
+#
+# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+"""Self-test suite for Crypto.Cipher.AES"""
+
+from __future__ import print_function
+
+import unittest
+from Crypto.Hash import SHA256
+from Crypto.Cipher import AES
+from Crypto.Util.py3compat import *
+from binascii import hexlify
+
+# This is a list of (plaintext, ciphertext, key[, description[, params]]) tuples.
+test_data = [
+ # FIPS PUB 197 test vectors
+ # http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+ ('00112233445566778899aabbccddeeff', '69c4e0d86a7b0430d8cdb78070b4c55a',
+ '000102030405060708090a0b0c0d0e0f', 'FIPS 197 C.1 (AES-128)'),
+
+ ('00112233445566778899aabbccddeeff', 'dda97ca4864cdfe06eaf70a0ec0d7191',
+ '000102030405060708090a0b0c0d0e0f1011121314151617',
+ 'FIPS 197 C.2 (AES-192)'),
+
+ ('00112233445566778899aabbccddeeff', '8ea2b7ca516745bfeafc49904b496089',
+ '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
+ 'FIPS 197 C.3 (AES-256)'),
+
+ # Rijndael128 test vectors
+ # Downloaded 2008-09-13 from
+ # http://www.iaik.tugraz.at/Research/krypto/AES/old/~rijmen/rijndael/testvalues.tar.gz
+
+ # ecb_tbl.txt, KEYSIZE=128
+ ('506812a45f08c889b97f5980038b8359', 'd8f532538289ef7d06b506a4fd5be9c9',
+ '00010203050607080a0b0c0d0f101112',
+ 'ecb-tbl-128: I=1'),
+ ('5c6d71ca30de8b8b00549984d2ec7d4b', '59ab30f4d4ee6e4ff9907ef65b1fb68c',
+ '14151617191a1b1c1e1f202123242526',
+ 'ecb-tbl-128: I=2'),
+ ('53f3f4c64f8616e4e7c56199f48f21f6', 'bf1ed2fcb2af3fd41443b56d85025cb1',
+ '28292a2b2d2e2f30323334353738393a',
+ 'ecb-tbl-128: I=3'),
+ ('a1eb65a3487165fb0f1c27ff9959f703', '7316632d5c32233edcb0780560eae8b2',
+ '3c3d3e3f41424344464748494b4c4d4e',
+ 'ecb-tbl-128: I=4'),
+ ('3553ecf0b1739558b08e350a98a39bfa', '408c073e3e2538072b72625e68b8364b',
+ '50515253555657585a5b5c5d5f606162',
+ 'ecb-tbl-128: I=5'),
+ ('67429969490b9711ae2b01dc497afde8', 'e1f94dfa776597beaca262f2f6366fea',
+ '64656667696a6b6c6e6f707173747576',
+ 'ecb-tbl-128: I=6'),
+ ('93385c1f2aec8bed192f5a8e161dd508', 'f29e986c6a1c27d7b29ffd7ee92b75f1',
+ '78797a7b7d7e7f80828384858788898a',
+ 'ecb-tbl-128: I=7'),
+ ('b5bf946be19beb8db3983b5f4c6e8ddb', '131c886a57f8c2e713aba6955e2b55b5',
+ '8c8d8e8f91929394969798999b9c9d9e',
+ 'ecb-tbl-128: I=8'),
+ ('41321ee10e21bd907227c4450ff42324', 'd2ab7662df9b8c740210e5eeb61c199d',
+ 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2',
+ 'ecb-tbl-128: I=9'),
+ ('00a82f59c91c8486d12c0a80124f6089', '14c10554b2859c484cab5869bbe7c470',
+ 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6',
+ 'ecb-tbl-128: I=10'),
+ ('7ce0fd076754691b4bbd9faf8a1372fe', 'db4d498f0a49cf55445d502c1f9ab3b5',
+ 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9da',
+ 'ecb-tbl-128: I=11'),
+ ('23605a8243d07764541bc5ad355b3129', '6d96fef7d66590a77a77bb2056667f7f',
+ 'dcdddedfe1e2e3e4e6e7e8e9ebecedee',
+ 'ecb-tbl-128: I=12'),
+ ('12a8cfa23ea764fd876232b4e842bc44', '316fb68edba736c53e78477bf913725c',
+ 'f0f1f2f3f5f6f7f8fafbfcfdfe010002',
+ 'ecb-tbl-128: I=13'),
+ ('bcaf32415e8308b3723e5fdd853ccc80', '6936f2b93af8397fd3a771fc011c8c37',
+ '04050607090a0b0c0e0f101113141516',
+ 'ecb-tbl-128: I=14'),
+ ('89afae685d801ad747ace91fc49adde0', 'f3f92f7a9c59179c1fcc2c2ba0b082cd',
+ '2c2d2e2f31323334363738393b3c3d3e',
+ 'ecb-tbl-128: I=15'),
+ ('f521d07b484357c4a69e76124a634216', '6a95ea659ee3889158e7a9152ff04ebc',
+ '40414243454647484a4b4c4d4f505152',
+ 'ecb-tbl-128: I=16'),
+ ('3e23b3bc065bcc152407e23896d77783', '1959338344e945670678a5d432c90b93',
+ '54555657595a5b5c5e5f606163646566',
+ 'ecb-tbl-128: I=17'),
+ ('79f0fba002be1744670e7e99290d8f52', 'e49bddd2369b83ee66e6c75a1161b394',
+ '68696a6b6d6e6f70727374757778797a',
+ 'ecb-tbl-128: I=18'),
+ ('da23fe9d5bd63e1d72e3dafbe21a6c2a', 'd3388f19057ff704b70784164a74867d',
+ '7c7d7e7f81828384868788898b8c8d8e',
+ 'ecb-tbl-128: I=19'),
+ ('e3f5698ba90b6a022efd7db2c7e6c823', '23aa03e2d5e4cd24f3217e596480d1e1',
+ 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6',
+ 'ecb-tbl-128: I=20'),
+ ('bdc2691d4f1b73d2700679c3bcbf9c6e', 'c84113d68b666ab2a50a8bdb222e91b9',
+ 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2',
+ 'ecb-tbl-128: I=21'),
+ ('ba74e02093217ee1ba1b42bd5624349a', 'ac02403981cd4340b507963db65cb7b6',
+ '08090a0b0d0e0f10121314151718191a',
+ 'ecb-tbl-128: I=22'),
+ ('b5c593b5851c57fbf8b3f57715e8f680', '8d1299236223359474011f6bf5088414',
+ '6c6d6e6f71727374767778797b7c7d7e',
+ 'ecb-tbl-128: I=23'),
+ ('3da9bd9cec072381788f9387c3bbf4ee', '5a1d6ab8605505f7977e55b9a54d9b90',
+ '80818283858687888a8b8c8d8f909192',
+ 'ecb-tbl-128: I=24'),
+ ('4197f3051121702ab65d316b3c637374', '72e9c2d519cf555e4208805aabe3b258',
+ '94959697999a9b9c9e9fa0a1a3a4a5a6',
+ 'ecb-tbl-128: I=25'),
+ ('9f46c62ec4f6ee3f6e8c62554bc48ab7', 'a8f3e81c4a23a39ef4d745dffe026e80',
+ 'a8a9aaabadaeafb0b2b3b4b5b7b8b9ba',
+ 'ecb-tbl-128: I=26'),
+ ('0220673fe9e699a4ebc8e0dbeb6979c8', '546f646449d31458f9eb4ef5483aee6c',
+ 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdce',
+ 'ecb-tbl-128: I=27'),
+ ('b2b99171337ded9bc8c2c23ff6f18867', '4dbe4bc84ac797c0ee4efb7f1a07401c',
+ 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2',
+ 'ecb-tbl-128: I=28'),
+ ('a7facf4e301e984e5efeefd645b23505', '25e10bfb411bbd4d625ac8795c8ca3b3',
+ 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6',
+ 'ecb-tbl-128: I=29'),
+ ('f7c762e4a9819160fd7acfb6c4eedcdd', '315637405054ec803614e43def177579',
+ 'f8f9fafbfdfefe00020304050708090a',
+ 'ecb-tbl-128: I=30'),
+ ('9b64fc21ea08709f4915436faa70f1be', '60c5bc8a1410247295c6386c59e572a8',
+ '0c0d0e0f11121314161718191b1c1d1e',
+ 'ecb-tbl-128: I=31'),
+ ('52af2c3de07ee6777f55a4abfc100b3f', '01366fc8ca52dfe055d6a00a76471ba6',
+ '20212223252627282a2b2c2d2f303132',
+ 'ecb-tbl-128: I=32'),
+ ('2fca001224386c57aa3f968cbe2c816f', 'ecc46595516ec612449c3f581e7d42ff',
+ '34353637393a3b3c3e3f404143444546',
+ 'ecb-tbl-128: I=33'),
+ ('4149c73658a4a9c564342755ee2c132f', '6b7ffe4c602a154b06ee9c7dab5331c9',
+ '48494a4b4d4e4f50525354555758595a',
+ 'ecb-tbl-128: I=34'),
+ ('af60005a00a1772f7c07a48a923c23d2', '7da234c14039a240dd02dd0fbf84eb67',
+ '5c5d5e5f61626364666768696b6c6d6e',
+ 'ecb-tbl-128: I=35'),
+ ('6fccbc28363759914b6f0280afaf20c6', 'c7dc217d9e3604ffe7e91f080ecd5a3a',
+ '70717273757677787a7b7c7d7f808182',
+ 'ecb-tbl-128: I=36'),
+ ('7d82a43ddf4fefa2fc5947499884d386', '37785901863f5c81260ea41e7580cda5',
+ '84858687898a8b8c8e8f909193949596',
+ 'ecb-tbl-128: I=37'),
+ ('5d5a990eaab9093afe4ce254dfa49ef9', 'a07b9338e92ed105e6ad720fccce9fe4',
+ '98999a9b9d9e9fa0a2a3a4a5a7a8a9aa',
+ 'ecb-tbl-128: I=38'),
+ ('4cd1e2fd3f4434b553aae453f0ed1a02', 'ae0fb9722418cc21a7da816bbc61322c',
+ 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbe',
+ 'ecb-tbl-128: I=39'),
+ ('5a2c9a9641d4299125fa1b9363104b5e', 'c826a193080ff91ffb21f71d3373c877',
+ 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2',
+ 'ecb-tbl-128: I=40'),
+ ('b517fe34c0fa217d341740bfd4fe8dd4', '1181b11b0e494e8d8b0aa6b1d5ac2c48',
+ 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6',
+ 'ecb-tbl-128: I=41'),
+ ('014baf2278a69d331d5180103643e99a', '6743c3d1519ab4f2cd9a78ab09a511bd',
+ 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fa',
+ 'ecb-tbl-128: I=42'),
+ ('b529bd8164f20d0aa443d4932116841c', 'dc55c076d52bacdf2eefd952946a439d',
+ 'fcfdfeff01020304060708090b0c0d0e',
+ 'ecb-tbl-128: I=43'),
+ ('2e596dcbb2f33d4216a1176d5bd1e456', '711b17b590ffc72b5c8e342b601e8003',
+ '10111213151617181a1b1c1d1f202122',
+ 'ecb-tbl-128: I=44'),
+ ('7274a1ea2b7ee2424e9a0e4673689143', '19983bb0950783a537e1339f4aa21c75',
+ '24252627292a2b2c2e2f303133343536',
+ 'ecb-tbl-128: I=45'),
+ ('ae20020bd4f13e9d90140bee3b5d26af', '3ba7762e15554169c0f4fa39164c410c',
+ '38393a3b3d3e3f40424344454748494a',
+ 'ecb-tbl-128: I=46'),
+ ('baac065da7ac26e855e79c8849d75a02', 'a0564c41245afca7af8aa2e0e588ea89',
+ '4c4d4e4f51525354565758595b5c5d5e',
+ 'ecb-tbl-128: I=47'),
+ ('7c917d8d1d45fab9e2540e28832540cc', '5e36a42a2e099f54ae85ecd92e2381ed',
+ '60616263656667686a6b6c6d6f707172',
+ 'ecb-tbl-128: I=48'),
+ ('bde6f89e16daadb0e847a2a614566a91', '770036f878cd0f6ca2268172f106f2fe',
+ '74757677797a7b7c7e7f808183848586',
+ 'ecb-tbl-128: I=49'),
+ ('c9de163725f1f5be44ebb1db51d07fbc', '7e4e03908b716116443ccf7c94e7c259',
+ '88898a8b8d8e8f90929394959798999a',
+ 'ecb-tbl-128: I=50'),
+ ('3af57a58f0c07dffa669572b521e2b92', '482735a48c30613a242dd494c7f9185d',
+ '9c9d9e9fa1a2a3a4a6a7a8a9abacadae',
+ 'ecb-tbl-128: I=51'),
+ ('3d5ebac306dde4604f1b4fbbbfcdae55', 'b4c0f6c9d4d7079addf9369fc081061d',
+ 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2',
+ 'ecb-tbl-128: I=52'),
+ ('c2dfa91bceb76a1183c995020ac0b556', 'd5810fe0509ac53edcd74f89962e6270',
+ 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6',
+ 'ecb-tbl-128: I=53'),
+ ('c70f54305885e9a0746d01ec56c8596b', '03f17a16b3f91848269ecdd38ebb2165',
+ 'd8d9dadbdddedfe0e2e3e4e5e7e8e9ea',
+ 'ecb-tbl-128: I=54'),
+ ('c4f81b610e98012ce000182050c0c2b2', 'da1248c3180348bad4a93b4d9856c9df',
+ 'ecedeeeff1f2f3f4f6f7f8f9fbfcfdfe',
+ 'ecb-tbl-128: I=55'),
+ ('eaab86b1d02a95d7404eff67489f97d4', '3d10d7b63f3452c06cdf6cce18be0c2c',
+ '00010203050607080a0b0c0d0f101112',
+ 'ecb-tbl-128: I=56'),
+ ('7c55bdb40b88870b52bec3738de82886', '4ab823e7477dfddc0e6789018fcb6258',
+ '14151617191a1b1c1e1f202123242526',
+ 'ecb-tbl-128: I=57'),
+ ('ba6eaa88371ff0a3bd875e3f2a975ce0', 'e6478ba56a77e70cfdaa5c843abde30e',
+ '28292a2b2d2e2f30323334353738393a',
+ 'ecb-tbl-128: I=58'),
+ ('08059130c4c24bd30cf0575e4e0373dc', '1673064895fbeaf7f09c5429ff75772d',
+ '3c3d3e3f41424344464748494b4c4d4e',
+ 'ecb-tbl-128: I=59'),
+ ('9a8eab004ef53093dfcf96f57e7eda82', '4488033ae9f2efd0ca9383bfca1a94e9',
+ '50515253555657585a5b5c5d5f606162',
+ 'ecb-tbl-128: I=60'),
+ ('0745b589e2400c25f117b1d796c28129', '978f3b8c8f9d6f46626cac3c0bcb9217',
+ '64656667696a6b6c6e6f707173747576',
+ 'ecb-tbl-128: I=61'),
+ ('2f1777781216cec3f044f134b1b92bbe', 'e08c8a7e582e15e5527f1d9e2eecb236',
+ '78797a7b7d7e7f80828384858788898a',
+ 'ecb-tbl-128: I=62'),
+ ('353a779ffc541b3a3805d90ce17580fc', 'cec155b76ac5ffda4cf4f9ca91e49a7a',
+ '8c8d8e8f91929394969798999b9c9d9e',
+ 'ecb-tbl-128: I=63'),
+ ('1a1eae4415cefcf08c4ac1c8f68bea8f', 'd5ac7165763225dd2a38cdc6862c29ad',
+ 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2',
+ 'ecb-tbl-128: I=64'),
+ ('e6e7e4e5b0b3b2b5d4d5aaab16111013', '03680fe19f7ce7275452020be70e8204',
+ 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6',
+ 'ecb-tbl-128: I=65'),
+ ('f8f9fafbfbf8f9e677767170efe0e1e2', '461df740c9781c388e94bb861ceb54f6',
+ 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9da',
+ 'ecb-tbl-128: I=66'),
+ ('63626160a1a2a3a445444b4a75727370', '451bd60367f96483042742219786a074',
+ 'dcdddedfe1e2e3e4e6e7e8e9ebecedee',
+ 'ecb-tbl-128: I=67'),
+ ('717073720605040b2d2c2b2a05fafbf9', 'e4dfa42671a02e57ef173b85c0ea9f2b',
+ 'f0f1f2f3f5f6f7f8fafbfcfdfe010002',
+ 'ecb-tbl-128: I=68'),
+ ('78797a7beae9e8ef3736292891969794', 'ed11b89e76274282227d854700a78b9e',
+ '04050607090a0b0c0e0f101113141516',
+ 'ecb-tbl-128: I=69'),
+ ('838281803231300fdddcdbdaa0afaead', '433946eaa51ea47af33895f2b90b3b75',
+ '18191a1b1d1e1f20222324252728292a',
+ 'ecb-tbl-128: I=70'),
+ ('18191a1bbfbcbdba75747b7a7f78797a', '6bc6d616a5d7d0284a5910ab35022528',
+ '2c2d2e2f31323334363738393b3c3d3e',
+ 'ecb-tbl-128: I=71'),
+ ('848586879b989996a3a2a5a4849b9a99', 'd2a920ecfe919d354b5f49eae9719c98',
+ '40414243454647484a4b4c4d4f505152',
+ 'ecb-tbl-128: I=72'),
+ ('0001020322212027cacbf4f551565754', '3a061b17f6a92885efbd0676985b373d',
+ '54555657595a5b5c5e5f606163646566',
+ 'ecb-tbl-128: I=73'),
+ ('cecfcccdafacadb2515057564a454447', 'fadeec16e33ea2f4688499d157e20d8f',
+ '68696a6b6d6e6f70727374757778797a',
+ 'ecb-tbl-128: I=74'),
+ ('92939091cdcecfc813121d1c80878685', '5cdefede59601aa3c3cda36fa6b1fa13',
+ '7c7d7e7f81828384868788898b8c8d8e',
+ 'ecb-tbl-128: I=75'),
+ ('d2d3d0d16f6c6d6259585f5ed1eeefec', '9574b00039844d92ebba7ee8719265f8',
+ '90919293959697989a9b9c9d9fa0a1a2',
+ 'ecb-tbl-128: I=76'),
+ ('acadaeaf878485820f0e1110d5d2d3d0', '9a9cf33758671787e5006928188643fa',
+ 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6',
+ 'ecb-tbl-128: I=77'),
+ ('9091929364676619e6e7e0e1757a7b78', '2cddd634c846ba66bb46cbfea4a674f9',
+ 'b8b9babbbdbebfc0c2c3c4c5c7c8c9ca',
+ 'ecb-tbl-128: I=78'),
+ ('babbb8b98a89888f74757a7b92959497', 'd28bae029393c3e7e26e9fafbbb4b98f',
+ 'cccdcecfd1d2d3d4d6d7d8d9dbdcddde',
+ 'ecb-tbl-128: I=79'),
+ ('8d8c8f8e6e6d6c633b3a3d3ccad5d4d7', 'ec27529b1bee0a9ab6a0d73ebc82e9b7',
+ 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2',
+ 'ecb-tbl-128: I=80'),
+ ('86878485010203040808f7f767606162', '3cb25c09472aff6ee7e2b47ccd7ccb17',
+ 'f4f5f6f7f9fafbfcfefe010103040506',
+ 'ecb-tbl-128: I=81'),
+ ('8e8f8c8d656667788a8b8c8d010e0f0c', 'dee33103a7283370d725e44ca38f8fe5',
+ '08090a0b0d0e0f10121314151718191a',
+ 'ecb-tbl-128: I=82'),
+ ('c8c9cacb858687807a7b7475e7e0e1e2', '27f9bcd1aac64bffc11e7815702c1a69',
+ '1c1d1e1f21222324262728292b2c2d2e',
+ 'ecb-tbl-128: I=83'),
+ ('6d6c6f6e5053525d8c8d8a8badd2d3d0', '5df534ffad4ed0749a9988e9849d0021',
+ '30313233353637383a3b3c3d3f404142',
+ 'ecb-tbl-128: I=84'),
+ ('28292a2b393a3b3c0607181903040506', 'a48bee75db04fb60ca2b80f752a8421b',
+ '44454647494a4b4c4e4f505153545556',
+ 'ecb-tbl-128: I=85'),
+ ('a5a4a7a6b0b3b28ddbdadddcbdb2b3b0', '024c8cf70bc86ee5ce03678cb7af45f9',
+ '58595a5b5d5e5f60626364656768696a',
+ 'ecb-tbl-128: I=86'),
+ ('323330316467666130313e3f2c2b2a29', '3c19ac0f8a3a3862ce577831301e166b',
+ '6c6d6e6f71727374767778797b7c7d7e',
+ 'ecb-tbl-128: I=87'),
+ ('27262524080b0a05171611100b141516', 'c5e355b796a57421d59ca6be82e73bca',
+ '80818283858687888a8b8c8d8f909192',
+ 'ecb-tbl-128: I=88'),
+ ('040506074142434435340b0aa3a4a5a6', 'd94033276417abfb05a69d15b6e386e2',
+ '94959697999a9b9c9e9fa0a1a3a4a5a6',
+ 'ecb-tbl-128: I=89'),
+ ('242526271112130c61606766bdb2b3b0', '24b36559ea3a9b9b958fe6da3e5b8d85',
+ 'a8a9aaabadaeafb0b2b3b4b5b7b8b9ba',
+ 'ecb-tbl-128: I=90'),
+ ('4b4a4948252627209e9f9091cec9c8cb', '20fd4feaa0e8bf0cce7861d74ef4cb72',
+ 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdce',
+ 'ecb-tbl-128: I=91'),
+ ('68696a6b6665646b9f9e9998d9e6e7e4', '350e20d5174277b9ec314c501570a11d',
+ 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2',
+ 'ecb-tbl-128: I=92'),
+ ('34353637c5c6c7c0f0f1eeef7c7b7a79', '87a29d61b7c604d238fe73045a7efd57',
+ 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6',
+ 'ecb-tbl-128: I=93'),
+ ('32333031c2c1c13f0d0c0b0a050a0b08', '2c3164c1cc7d0064816bdc0faa362c52',
+ 'f8f9fafbfdfefe00020304050708090a',
+ 'ecb-tbl-128: I=94'),
+ ('cdcccfcebebdbcbbabaaa5a4181f1e1d', '195fe5e8a05a2ed594f6e4400eee10b3',
+ '0c0d0e0f11121314161718191b1c1d1e',
+ 'ecb-tbl-128: I=95'),
+ ('212023223635343ba0a1a6a7445b5a59', 'e4663df19b9a21a5a284c2bd7f905025',
+ '20212223252627282a2b2c2d2f303132',
+ 'ecb-tbl-128: I=96'),
+ ('0e0f0c0da8abaaad2f2e515002050407', '21b88714cfb4e2a933bd281a2c4743fd',
+ '34353637393a3b3c3e3f404143444546',
+ 'ecb-tbl-128: I=97'),
+ ('070605042a2928378e8f8889bdb2b3b0', 'cbfc3980d704fd0fc54378ab84e17870',
+ '48494a4b4d4e4f50525354555758595a',
+ 'ecb-tbl-128: I=98'),
+ ('cbcac9c893909196a9a8a7a6a5a2a3a0', 'bc5144baa48bdeb8b63e22e03da418ef',
+ '5c5d5e5f61626364666768696b6c6d6e',
+ 'ecb-tbl-128: I=99'),
+ ('80818283c1c2c3cc9c9d9a9b0cf3f2f1', '5a1dbaef1ee2984b8395da3bdffa3ccc',
+ '70717273757677787a7b7c7d7f808182',
+ 'ecb-tbl-128: I=100'),
+ ('1213101125262720fafbe4e5b1b6b7b4', 'f0b11cd0729dfcc80cec903d97159574',
+ '84858687898a8b8c8e8f909193949596',
+ 'ecb-tbl-128: I=101'),
+ ('7f7e7d7c3033320d97969190222d2c2f', '9f95314acfddc6d1914b7f19a9cc8209',
+ '98999a9b9d9e9fa0a2a3a4a5a7a8a9aa',
+ 'ecb-tbl-128: I=102'),
+ ('4e4f4c4d484b4a4d81808f8e53545556', '595736f6f0f70914a94e9e007f022519',
+ 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbe',
+ 'ecb-tbl-128: I=103'),
+ ('dcdddedfb0b3b2bd15141312a1bebfbc', '1f19f57892cae586fcdfb4c694deb183',
+ 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2',
+ 'ecb-tbl-128: I=104'),
+ ('93929190282b2a2dc4c5fafb92959497', '540700ee1f6f3dab0b3eddf6caee1ef5',
+ 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6',
+ 'ecb-tbl-128: I=105'),
+ ('f5f4f7f6c4c7c6d9373631307e717073', '14a342a91019a331687a2254e6626ca2',
+ 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fa',
+ 'ecb-tbl-128: I=106'),
+ ('93929190b6b5b4b364656a6b05020300', '7b25f3c3b2eea18d743ef283140f29ff',
+ 'fcfdfeff01020304060708090b0c0d0e',
+ 'ecb-tbl-128: I=107'),
+ ('babbb8b90d0e0f00a4a5a2a3043b3a39', '46c2587d66e5e6fa7f7ca6411ad28047',
+ '10111213151617181a1b1c1d1f202122',
+ 'ecb-tbl-128: I=108'),
+ ('d8d9dadb7f7c7d7a10110e0f787f7e7d', '09470e72229d954ed5ee73886dfeeba9',
+ '24252627292a2b2c2e2f303133343536',
+ 'ecb-tbl-128: I=109'),
+ ('fefffcfdefeced923b3a3d3c6768696a', 'd77c03de92d4d0d79ef8d4824ef365eb',
+ '38393a3b3d3e3f40424344454748494a',
+ 'ecb-tbl-128: I=110'),
+ ('d6d7d4d58a89888f96979899a5a2a3a0', '1d190219f290e0f1715d152d41a23593',
+ '4c4d4e4f51525354565758595b5c5d5e',
+ 'ecb-tbl-128: I=111'),
+ ('18191a1ba8abaaa5303136379b848586', 'a2cd332ce3a0818769616292e87f757b',
+ '60616263656667686a6b6c6d6f707172',
+ 'ecb-tbl-128: I=112'),
+ ('6b6a6968a4a7a6a1d6d72829b0b7b6b5', 'd54afa6ce60fbf9341a3690e21385102',
+ '74757677797a7b7c7e7f808183848586',
+ 'ecb-tbl-128: I=113'),
+ ('000102038a89889755545352a6a9a8ab', '06e5c364ded628a3f5e05e613e356f46',
+ '88898a8b8d8e8f90929394959798999a',
+ 'ecb-tbl-128: I=114'),
+ ('2d2c2f2eb3b0b1b6b6b7b8b9f2f5f4f7', 'eae63c0e62556dac85d221099896355a',
+ '9c9d9e9fa1a2a3a4a6a7a8a9abacadae',
+ 'ecb-tbl-128: I=115'),
+ ('979695943536373856575051e09f9e9d', '1fed060e2c6fc93ee764403a889985a2',
+ 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2',
+ 'ecb-tbl-128: I=116'),
+ ('a4a5a6a7989b9a9db1b0afae7a7d7c7f', 'c25235c1a30fdec1c7cb5c5737b2a588',
+ 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6',
+ 'ecb-tbl-128: I=117'),
+ ('c1c0c3c2686b6a55a8a9aeafeae5e4e7', '796dbef95147d4d30873ad8b7b92efc0',
+ 'd8d9dadbdddedfe0e2e3e4e5e7e8e9ea',
+ 'ecb-tbl-128: I=118'),
+ ('c1c0c3c2141716118c8d828364636261', 'cbcf0fb34d98d0bd5c22ce37211a46bf',
+ 'ecedeeeff1f2f3f4f6f7f8f9fbfcfdfe',
+ 'ecb-tbl-128: I=119'),
+ ('93929190cccfcec196979091e0fffefd', '94b44da6466126cafa7c7fd09063fc24',
+ '00010203050607080a0b0c0d0f101112',
+ 'ecb-tbl-128: I=120'),
+ ('b4b5b6b7f9fafbfc25241b1a6e69686b', 'd78c5b5ebf9b4dbda6ae506c5074c8fe',
+ '14151617191a1b1c1e1f202123242526',
+ 'ecb-tbl-128: I=121'),
+ ('868784850704051ac7c6c1c08788898a', '6c27444c27204b043812cf8cf95f9769',
+ '28292a2b2d2e2f30323334353738393a',
+ 'ecb-tbl-128: I=122'),
+ ('f4f5f6f7aaa9a8affdfcf3f277707172', 'be94524ee5a2aa50bba8b75f4c0aebcf',
+ '3c3d3e3f41424344464748494b4c4d4e',
+ 'ecb-tbl-128: I=123'),
+ ('d3d2d1d00605040bc3c2c5c43e010003', 'a0aeaae91ba9f31f51aeb3588cf3a39e',
+ '50515253555657585a5b5c5d5f606162',
+ 'ecb-tbl-128: I=124'),
+ ('73727170424140476a6b74750d0a0b08', '275297779c28266ef9fe4c6a13c08488',
+ '64656667696a6b6c6e6f707173747576',
+ 'ecb-tbl-128: I=125'),
+ ('c2c3c0c10a0908f754555253a1aeafac', '86523d92bb8672cb01cf4a77fd725882',
+ '78797a7b7d7e7f80828384858788898a',
+ 'ecb-tbl-128: I=126'),
+ ('6d6c6f6ef8fbfafd82838c8df8fffefd', '4b8327640e9f33322a04dd96fcbf9a36',
+ '8c8d8e8f91929394969798999b9c9d9e',
+ 'ecb-tbl-128: I=127'),
+ ('f5f4f7f684878689a6a7a0a1d2cdcccf', 'ce52af650d088ca559425223f4d32694',
+ 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2',
+ 'ecb-tbl-128: I=128'),
+
+ # ecb_tbl.txt, KEYSIZE=192
+ ('2d33eef2c0430a8a9ebf45e809c40bb6', 'dff4945e0336df4c1c56bc700eff837f',
+ '00010203050607080a0b0c0d0f10111214151617191a1b1c',
+ 'ecb-tbl-192: I=1'),
+ ('6aa375d1fa155a61fb72353e0a5a8756', 'b6fddef4752765e347d5d2dc196d1252',
+ '1e1f20212324252628292a2b2d2e2f30323334353738393a',
+ 'ecb-tbl-192: I=2'),
+ ('bc3736518b9490dcb8ed60eb26758ed4', 'd23684e3d963b3afcf1a114aca90cbd6',
+ '3c3d3e3f41424344464748494b4c4d4e5051525355565758',
+ 'ecb-tbl-192: I=3'),
+ ('aa214402b46cffb9f761ec11263a311e', '3a7ac027753e2a18c2ceab9e17c11fd0',
+ '5a5b5c5d5f60616264656667696a6b6c6e6f707173747576',
+ 'ecb-tbl-192: I=4'),
+ ('02aea86e572eeab66b2c3af5e9a46fd6', '8f6786bd007528ba26603c1601cdd0d8',
+ '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394',
+ 'ecb-tbl-192: I=5'),
+ ('e2aef6acc33b965c4fa1f91c75ff6f36', 'd17d073b01e71502e28b47ab551168b3',
+ '969798999b9c9d9ea0a1a2a3a5a6a7a8aaabacadafb0b1b2',
+ 'ecb-tbl-192: I=6'),
+ ('0659df46427162b9434865dd9499f91d', 'a469da517119fab95876f41d06d40ffa',
+ 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6c8c9cacbcdcecfd0',
+ 'ecb-tbl-192: I=7'),
+ ('49a44239c748feb456f59c276a5658df', '6091aa3b695c11f5c0b6ad26d3d862ff',
+ 'd2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee',
+ 'ecb-tbl-192: I=8'),
+ ('66208f6e9d04525bdedb2733b6a6be37', '70f9e67f9f8df1294131662dc6e69364',
+ 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c',
+ 'ecb-tbl-192: I=9'),
+ ('3393f8dfc729c97f5480b950bc9666b0', 'd154dcafad8b207fa5cbc95e9996b559',
+ '0e0f10111314151618191a1b1d1e1f20222324252728292a',
+ 'ecb-tbl-192: I=10'),
+ ('606834c8ce063f3234cf1145325dbd71', '4934d541e8b46fa339c805a7aeb9e5da',
+ '2c2d2e2f31323334363738393b3c3d3e4041424345464748',
+ 'ecb-tbl-192: I=11'),
+ ('fec1c04f529bbd17d8cecfcc4718b17f', '62564c738f3efe186e1a127a0c4d3c61',
+ '4a4b4c4d4f50515254555657595a5b5c5e5f606163646566',
+ 'ecb-tbl-192: I=12'),
+ ('32df99b431ed5dc5acf8caf6dc6ce475', '07805aa043986eb23693e23bef8f3438',
+ '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384',
+ 'ecb-tbl-192: I=13'),
+ ('7fdc2b746f3f665296943b83710d1f82', 'df0b4931038bade848dee3b4b85aa44b',
+ '868788898b8c8d8e90919293959697989a9b9c9d9fa0a1a2',
+ 'ecb-tbl-192: I=14'),
+ ('8fba1510a3c5b87e2eaa3f7a91455ca2', '592d5fded76582e4143c65099309477c',
+ 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6b8b9babbbdbebfc0',
+ 'ecb-tbl-192: I=15'),
+ ('2c9b468b1c2eed92578d41b0716b223b', 'c9b8d6545580d3dfbcdd09b954ed4e92',
+ 'c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde',
+ 'ecb-tbl-192: I=16'),
+ ('0a2bbf0efc6bc0034f8a03433fca1b1a', '5dccd5d6eb7c1b42acb008201df707a0',
+ 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfc',
+ 'ecb-tbl-192: I=17'),
+ ('25260e1f31f4104d387222e70632504b', 'a2a91682ffeb6ed1d34340946829e6f9',
+ 'fefe01010304050608090a0b0d0e0f10121314151718191a',
+ 'ecb-tbl-192: I=18'),
+ ('c527d25a49f08a5228d338642ae65137', 'e45d185b797000348d9267960a68435d',
+ '1c1d1e1f21222324262728292b2c2d2e3031323335363738',
+ 'ecb-tbl-192: I=19'),
+ ('3b49fc081432f5890d0e3d87e884a69e', '45e060dae5901cda8089e10d4f4c246b',
+ '3a3b3c3d3f40414244454647494a4b4c4e4f505153545556',
+ 'ecb-tbl-192: I=20'),
+ ('d173f9ed1e57597e166931df2754a083', 'f6951afacc0079a369c71fdcff45df50',
+ '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374',
+ 'ecb-tbl-192: I=21'),
+ ('8c2b7cafa5afe7f13562daeae1adede0', '9e95e00f351d5b3ac3d0e22e626ddad6',
+ '767778797b7c7d7e80818283858687888a8b8c8d8f909192',
+ 'ecb-tbl-192: I=22'),
+ ('aaf4ec8c1a815aeb826cab741339532c', '9cb566ff26d92dad083b51fdc18c173c',
+ '94959697999a9b9c9e9fa0a1a3a4a5a6a8a9aaabadaeafb0',
+ 'ecb-tbl-192: I=23'),
+ ('40be8c5d9108e663f38f1a2395279ecf', 'c9c82766176a9b228eb9a974a010b4fb',
+ 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebec',
+ 'ecb-tbl-192: I=24'),
+ ('0c8ad9bc32d43e04716753aa4cfbe351', 'd8e26aa02945881d5137f1c1e1386e88',
+ '2a2b2c2d2f30313234353637393a3b3c3e3f404143444546',
+ 'ecb-tbl-192: I=25'),
+ ('1407b1d5f87d63357c8dc7ebbaebbfee', 'c0e024ccd68ff5ffa4d139c355a77c55',
+ '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364',
+ 'ecb-tbl-192: I=26'),
+ ('e62734d1ae3378c4549e939e6f123416', '0b18b3d16f491619da338640df391d43',
+ '84858687898a8b8c8e8f90919394959698999a9b9d9e9fa0',
+ 'ecb-tbl-192: I=27'),
+ ('5a752cff2a176db1a1de77f2d2cdee41', 'dbe09ac8f66027bf20cb6e434f252efc',
+ 'a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe',
+ 'ecb-tbl-192: I=28'),
+ ('a9c8c3a4eabedc80c64730ddd018cd88', '6d04e5e43c5b9cbe05feb9606b6480fe',
+ 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdc',
+ 'ecb-tbl-192: I=29'),
+ ('ee9b3dbbdb86180072130834d305999a', 'dd1d6553b96be526d9fee0fbd7176866',
+ '1a1b1c1d1f20212224252627292a2b2c2e2f303133343536',
+ 'ecb-tbl-192: I=30'),
+ ('a7fa8c3586b8ebde7568ead6f634a879', '0260ca7e3f979fd015b0dd4690e16d2a',
+ '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354',
+ 'ecb-tbl-192: I=31'),
+ ('37e0f4a87f127d45ac936fe7ad88c10a', '9893734de10edcc8a67c3b110b8b8cc6',
+ '929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae',
+ 'ecb-tbl-192: I=32'),
+ ('3f77d8b5d92bac148e4e46f697a535c5', '93b30b750516b2d18808d710c2ee84ef',
+ '464748494b4c4d4e50515253555657585a5b5c5d5f606162',
+ 'ecb-tbl-192: I=33'),
+ ('d25ebb686c40f7e2c4da1014936571ca', '16f65fa47be3cb5e6dfe7c6c37016c0e',
+ '828384858788898a8c8d8e8f91929394969798999b9c9d9e',
+ 'ecb-tbl-192: I=34'),
+ ('4f1c769d1e5b0552c7eca84dea26a549', 'f3847210d5391e2360608e5acb560581',
+ 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbc',
+ 'ecb-tbl-192: I=35'),
+ ('8548e2f882d7584d0fafc54372b6633a', '8754462cd223366d0753913e6af2643d',
+ 'bebfc0c1c3c4c5c6c8c9cacbcdcecfd0d2d3d4d5d7d8d9da',
+ 'ecb-tbl-192: I=36'),
+ ('87d7a336cb476f177cd2a51af2a62cdf', '1ea20617468d1b806a1fd58145462017',
+ 'dcdddedfe1e2e3e4e6e7e8e9ebecedeef0f1f2f3f5f6f7f8',
+ 'ecb-tbl-192: I=37'),
+ ('03b1feac668c4e485c1065dfc22b44ee', '3b155d927355d737c6be9dda60136e2e',
+ 'fafbfcfdfe01000204050607090a0b0c0e0f101113141516',
+ 'ecb-tbl-192: I=38'),
+ ('bda15e66819fa72d653a6866aa287962', '26144f7b66daa91b6333dbd3850502b3',
+ '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334',
+ 'ecb-tbl-192: I=39'),
+ ('4d0c7a0d2505b80bf8b62ceb12467f0a', 'e4f9a4ab52ced8134c649bf319ebcc90',
+ '363738393b3c3d3e40414243454647484a4b4c4d4f505152',
+ 'ecb-tbl-192: I=40'),
+ ('626d34c9429b37211330986466b94e5f', 'b9ddd29ac6128a6cab121e34a4c62b36',
+ '54555657595a5b5c5e5f60616364656668696a6b6d6e6f70',
+ 'ecb-tbl-192: I=41'),
+ ('333c3e6bf00656b088a17e5ff0e7f60a', '6fcddad898f2ce4eff51294f5eaaf5c9',
+ '727374757778797a7c7d7e7f81828384868788898b8c8d8e',
+ 'ecb-tbl-192: I=42'),
+ ('687ed0cdc0d2a2bc8c466d05ef9d2891', 'c9a6fe2bf4028080bea6f7fc417bd7e3',
+ '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabac',
+ 'ecb-tbl-192: I=43'),
+ ('487830e78cc56c1693e64b2a6660c7b6', '6a2026846d8609d60f298a9c0673127f',
+ 'aeafb0b1b3b4b5b6b8b9babbbdbebfc0c2c3c4c5c7c8c9ca',
+ 'ecb-tbl-192: I=44'),
+ ('7a48d6b7b52b29392aa2072a32b66160', '2cb25c005e26efea44336c4c97a4240b',
+ 'cccdcecfd1d2d3d4d6d7d8d9dbdcdddee0e1e2e3e5e6e7e8',
+ 'ecb-tbl-192: I=45'),
+ ('907320e64c8c5314d10f8d7a11c8618d', '496967ab8680ddd73d09a0e4c7dcc8aa',
+ 'eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506',
+ 'ecb-tbl-192: I=46'),
+ ('b561f2ca2d6e65a4a98341f3ed9ff533', 'd5af94de93487d1f3a8c577cb84a66a4',
+ '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324',
+ 'ecb-tbl-192: I=47'),
+ ('df769380d212792d026f049e2e3e48ef', '84bdac569cae2828705f267cc8376e90',
+ '262728292b2c2d2e30313233353637383a3b3c3d3f404142',
+ 'ecb-tbl-192: I=48'),
+ ('79f374bc445bdabf8fccb8843d6054c6', 'f7401dda5ad5ab712b7eb5d10c6f99b6',
+ '44454647494a4b4c4e4f50515354555658595a5b5d5e5f60',
+ 'ecb-tbl-192: I=49'),
+ ('4e02f1242fa56b05c68dbae8fe44c9d6', '1c9d54318539ebd4c3b5b7e37bf119f0',
+ '626364656768696a6c6d6e6f71727374767778797b7c7d7e',
+ 'ecb-tbl-192: I=50'),
+ ('cf73c93cbff57ac635a6f4ad2a4a1545', 'aca572d65fb2764cffd4a6eca090ea0d',
+ '80818283858687888a8b8c8d8f90919294959697999a9b9c',
+ 'ecb-tbl-192: I=51'),
+ ('9923548e2875750725b886566784c625', '36d9c627b8c2a886a10ccb36eae3dfbb',
+ '9e9fa0a1a3a4a5a6a8a9aaabadaeafb0b2b3b4b5b7b8b9ba',
+ 'ecb-tbl-192: I=52'),
+ ('4888336b723a022c9545320f836a4207', '010edbf5981e143a81d646e597a4a568',
+ 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdced0d1d2d3d5d6d7d8',
+ 'ecb-tbl-192: I=53'),
+ ('f84d9a5561b0608b1160dee000c41ba8', '8db44d538dc20cc2f40f3067fd298e60',
+ 'dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6',
+ 'ecb-tbl-192: I=54'),
+ ('c23192a0418e30a19b45ae3e3625bf22', '930eb53bc71e6ac4b82972bdcd5aafb3',
+ 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314',
+ 'ecb-tbl-192: I=55'),
+ ('b84e0690b28b0025381ad82a15e501a7', '6c42a81edcbc9517ccd89c30c95597b4',
+ '161718191b1c1d1e20212223252627282a2b2c2d2f303132',
+ 'ecb-tbl-192: I=56'),
+ ('acef5e5c108876c4f06269f865b8f0b0', 'da389847ad06df19d76ee119c71e1dd3',
+ '34353637393a3b3c3e3f40414344454648494a4b4d4e4f50',
+ 'ecb-tbl-192: I=57'),
+ ('0f1b3603e0f5ddea4548246153a5e064', 'e018fdae13d3118f9a5d1a647a3f0462',
+ '525354555758595a5c5d5e5f61626364666768696b6c6d6e',
+ 'ecb-tbl-192: I=58'),
+ ('fbb63893450d42b58c6d88cd3c1809e3', '2aa65db36264239d3846180fabdfad20',
+ '70717273757677787a7b7c7d7f80818284858687898a8b8c',
+ 'ecb-tbl-192: I=59'),
+ ('4bef736df150259dae0c91354e8a5f92', '1472163e9a4f780f1ceb44b07ecf4fdb',
+ '8e8f90919394959698999a9b9d9e9fa0a2a3a4a5a7a8a9aa',
+ 'ecb-tbl-192: I=60'),
+ ('7d2d46242056ef13d3c3fc93c128f4c7', 'c8273fdc8f3a9f72e91097614b62397c',
+ 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbec0c1c2c3c5c6c7c8',
+ 'ecb-tbl-192: I=61'),
+ ('e9c1ba2df415657a256edb33934680fd', '66c8427dcd733aaf7b3470cb7d976e3f',
+ 'cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6',
+ 'ecb-tbl-192: I=62'),
+ ('e23ee277b0aa0a1dfb81f7527c3514f1', '146131cb17f1424d4f8da91e6f80c1d0',
+ 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304',
+ 'ecb-tbl-192: I=63'),
+ ('3e7445b0b63caaf75e4a911e12106b4c', '2610d0ad83659081ae085266a88770dc',
+ '060708090b0c0d0e10111213151617181a1b1c1d1f202122',
+ 'ecb-tbl-192: I=64'),
+ ('767774752023222544455a5be6e1e0e3', '38a2b5a974b0575c5d733917fb0d4570',
+ '24252627292a2b2c2e2f30313334353638393a3b3d3e3f40',
+ 'ecb-tbl-192: I=65'),
+ ('72737475717e7f7ce9e8ebea696a6b6c', 'e21d401ebc60de20d6c486e4f39a588b',
+ '424344454748494a4c4d4e4f51525354565758595b5c5d5e',
+ 'ecb-tbl-192: I=66'),
+ ('dfdedddc25262728c9c8cfcef1eeefec', 'e51d5f88c670b079c0ca1f0c2c4405a2',
+ '60616263656667686a6b6c6d6f70717274757677797a7b7c',
+ 'ecb-tbl-192: I=67'),
+ ('fffe0100707776755f5e5d5c7675746b', '246a94788a642fb3d1b823c8762380c8',
+ '7e7f80818384858688898a8b8d8e8f90929394959798999a',
+ 'ecb-tbl-192: I=68'),
+ ('e0e1e2e3424140479f9e9190292e2f2c', 'b80c391c5c41a4c3b30c68e0e3d7550f',
+ '9c9d9e9fa1a2a3a4a6a7a8a9abacadaeb0b1b2b3b5b6b7b8',
+ 'ecb-tbl-192: I=69'),
+ ('2120272690efeeed3b3a39384e4d4c4b', 'b77c4754fc64eb9a1154a9af0bb1f21c',
+ 'babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6',
+ 'ecb-tbl-192: I=70'),
+ ('ecedeeef5350516ea1a0a7a6a3acadae', 'fb554de520d159a06bf219fc7f34a02f',
+ 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4',
+ 'ecb-tbl-192: I=71'),
+ ('32333c3d25222320e9e8ebeacecdccc3', 'a89fba152d76b4927beed160ddb76c57',
+ 'f6f7f8f9fbfcfdfe00010203050607080a0b0c0d0f101112',
+ 'ecb-tbl-192: I=72'),
+ ('40414243626160678a8bb4b511161714', '5676eab4a98d2e8473b3f3d46424247c',
+ '14151617191a1b1c1e1f20212324252628292a2b2d2e2f30',
+ 'ecb-tbl-192: I=73'),
+ ('94959293f5fafbf81f1e1d1c7c7f7e79', '4e8f068bd7ede52a639036ec86c33568',
+ '323334353738393a3c3d3e3f41424344464748494b4c4d4e',
+ 'ecb-tbl-192: I=74'),
+ ('bebfbcbd191a1b14cfcec9c8546b6a69', 'f0193c4d7aff1791ee4c07eb4a1824fc',
+ '50515253555657585a5b5c5d5f60616264656667696a6b6c',
+ 'ecb-tbl-192: I=75'),
+ ('2c2d3233898e8f8cbbbab9b8333031ce', 'ac8686eeca9ba761afe82d67b928c33f',
+ '6e6f70717374757678797a7b7d7e7f80828384858788898a',
+ 'ecb-tbl-192: I=76'),
+ ('84858687bfbcbdba37363938fdfafbf8', '5faf8573e33b145b6a369cd3606ab2c9',
+ '8c8d8e8f91929394969798999b9c9d9ea0a1a2a3a5a6a7a8',
+ 'ecb-tbl-192: I=77'),
+ ('828384857669686b909192930b08090e', '31587e9944ab1c16b844ecad0df2e7da',
+ 'aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6',
+ 'ecb-tbl-192: I=78'),
+ ('bebfbcbd9695948b707176779e919093', 'd017fecd91148aba37f6f3068aa67d8a',
+ 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4',
+ 'ecb-tbl-192: I=79'),
+ ('8b8a85846067666521202322d0d3d2dd', '788ef2f021a73cba2794b616078a8500',
+ 'e6e7e8e9ebecedeef0f1f2f3f5f6f7f8fafbfcfdfe010002',
+ 'ecb-tbl-192: I=80'),
+ ('76777475f1f2f3f4f8f9e6e777707172', '5d1ef20dced6bcbc12131ac7c54788aa',
+ '04050607090a0b0c0e0f10111314151618191a1b1d1e1f20',
+ 'ecb-tbl-192: I=81'),
+ ('a4a5a2a34f404142b4b5b6b727242522', 'b3c8cf961faf9ea05fdde6d1e4d8f663',
+ '222324252728292a2c2d2e2f31323334363738393b3c3d3e',
+ 'ecb-tbl-192: I=82'),
+ ('94959697e1e2e3ec16171011839c9d9e', '143075c70605861c7fac6526199e459f',
+ '40414243454647484a4b4c4d4f50515254555657595a5b5c',
+ 'ecb-tbl-192: I=83'),
+ ('03023d3c06010003dedfdcddfffcfde2', 'a5ae12eade9a87268d898bfc8fc0252a',
+ '5e5f60616364656668696a6b6d6e6f70727374757778797a',
+ 'ecb-tbl-192: I=84'),
+ ('10111213f1f2f3f4cecfc0c1dbdcddde', '0924f7cf2e877a4819f5244a360dcea9',
+ '7c7d7e7f81828384868788898b8c8d8e9091929395969798',
+ 'ecb-tbl-192: I=85'),
+ ('67666160724d4c4f1d1c1f1e73707176', '3d9e9635afcc3e291cc7ab3f27d1c99a',
+ '9a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6',
+ 'ecb-tbl-192: I=86'),
+ ('e6e7e4e5a8abaad584858283909f9e9d', '9d80feebf87510e2b8fb98bb54fd788c',
+ 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4',
+ 'ecb-tbl-192: I=87'),
+ ('71707f7e565150537d7c7f7e6162636c', '5f9d1a082a1a37985f174002eca01309',
+ 'd6d7d8d9dbdcdddee0e1e2e3e5e6e7e8eaebecedeff0f1f2',
+ 'ecb-tbl-192: I=88'),
+ ('64656667212223245555aaaa03040506', 'a390ebb1d1403930184a44b4876646e4',
+ 'f4f5f6f7f9fafbfcfefe01010304050608090a0b0d0e0f10',
+ 'ecb-tbl-192: I=89'),
+ ('9e9f9899aba4a5a6cfcecdcc2b28292e', '700fe918981c3195bb6c4bcb46b74e29',
+ '121314151718191a1c1d1e1f21222324262728292b2c2d2e',
+ 'ecb-tbl-192: I=90'),
+ ('c7c6c5c4d1d2d3dc626364653a454447', '907984406f7bf2d17fb1eb15b673d747',
+ '30313233353637383a3b3c3d3f40414244454647494a4b4c',
+ 'ecb-tbl-192: I=91'),
+ ('f6f7e8e9e0e7e6e51d1c1f1e5b585966', 'c32a956dcfc875c2ac7c7cc8b8cc26e1',
+ '4e4f50515354555658595a5b5d5e5f60626364656768696a',
+ 'ecb-tbl-192: I=92'),
+ ('bcbdbebf5d5e5f5868696667f4f3f2f1', '02646e2ebfa9b820cf8424e9b9b6eb51',
+ '6c6d6e6f71727374767778797b7c7d7e8081828385868788',
+ 'ecb-tbl-192: I=93'),
+ ('40414647b0afaead9b9a99989b98999e', '621fda3a5bbd54c6d3c685816bd4ead8',
+ '8a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6',
+ 'ecb-tbl-192: I=94'),
+ ('69686b6a0201001f0f0e0908b4bbbab9', 'd4e216040426dfaf18b152469bc5ac2f',
+ 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4',
+ 'ecb-tbl-192: I=95'),
+ ('c7c6c9c8d8dfdedd5a5b5859bebdbcb3', '9d0635b9d33b6cdbd71f5d246ea17cc8',
+ 'c6c7c8c9cbcccdced0d1d2d3d5d6d7d8dadbdcdddfe0e1e2',
+ 'ecb-tbl-192: I=96'),
+ ('dedfdcdd787b7a7dfffee1e0b2b5b4b7', '10abad1bd9bae5448808765583a2cc1a',
+ 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6f8f9fafbfdfefe00',
+ 'ecb-tbl-192: I=97'),
+ ('4d4c4b4a606f6e6dd0d1d2d3fbf8f9fe', '6891889e16544e355ff65a793c39c9a8',
+ '020304050708090a0c0d0e0f11121314161718191b1c1d1e',
+ 'ecb-tbl-192: I=98'),
+ ('b7b6b5b4d7d4d5dae5e4e3e2e1fefffc', 'cc735582e68072c163cd9ddf46b91279',
+ '20212223252627282a2b2c2d2f30313234353637393a3b3c',
+ 'ecb-tbl-192: I=99'),
+ ('cecfb0b1f7f0f1f2aeafacad3e3d3c23', 'c5c68b9aeeb7f878df578efa562f9574',
+ '3e3f40414344454648494a4b4d4e4f50525354555758595a',
+ 'ecb-tbl-192: I=100'),
+ ('cacbc8c9cdcecfc812131c1d494e4f4c', '5f4764395a667a47d73452955d0d2ce8',
+ '5c5d5e5f61626364666768696b6c6d6e7071727375767778',
+ 'ecb-tbl-192: I=101'),
+ ('9d9c9b9ad22d2c2fb1b0b3b20c0f0e09', '701448331f66106cefddf1eb8267c357',
+ '7a7b7c7d7f80818284858687898a8b8c8e8f909193949596',
+ 'ecb-tbl-192: I=102'),
+ ('7a7b787964676659959493924f404142', 'cb3ee56d2e14b4e1941666f13379d657',
+ '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4',
+ 'ecb-tbl-192: I=103'),
+ ('aaaba4a5cec9c8cb1f1e1d1caba8a9a6', '9fe16efd18ab6e1981191851fedb0764',
+ 'b6b7b8b9bbbcbdbec0c1c2c3c5c6c7c8cacbcccdcfd0d1d2',
+ 'ecb-tbl-192: I=104'),
+ ('93929190282b2a2dc4c5fafb92959497', '3dc9ba24e1b223589b147adceb4c8e48',
+ 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6e8e9eaebedeeeff0',
+ 'ecb-tbl-192: I=105'),
+ ('efeee9e8ded1d0d339383b3a888b8a8d', '1c333032682e7d4de5e5afc05c3e483c',
+ 'f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e',
+ 'ecb-tbl-192: I=106'),
+ ('7f7e7d7ca2a1a0af78797e7f112e2f2c', 'd593cc99a95afef7e92038e05a59d00a',
+ '10111213151617181a1b1c1d1f20212224252627292a2b2c',
+ 'ecb-tbl-192: I=107'),
+ ('84859a9b2b2c2d2e868784852625245b', '51e7f96f53b4353923452c222134e1ec',
+ '2e2f30313334353638393a3b3d3e3f40424344454748494a',
+ 'ecb-tbl-192: I=108'),
+ ('b0b1b2b3070405026869666710171615', '4075b357a1a2b473400c3b25f32f81a4',
+ '4c4d4e4f51525354565758595b5c5d5e6061626365666768',
+ 'ecb-tbl-192: I=109'),
+ ('acadaaabbda2a3a00d0c0f0e595a5b5c', '302e341a3ebcd74f0d55f61714570284',
+ '6a6b6c6d6f70717274757677797a7b7c7e7f808183848586',
+ 'ecb-tbl-192: I=110'),
+ ('121310115655544b5253545569666764', '57abdd8231280da01c5042b78cf76522',
+ '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4',
+ 'ecb-tbl-192: I=111'),
+ ('dedfd0d166616063eaebe8e94142434c', '17f9ea7eea17ac1adf0e190fef799e92',
+ 'a6a7a8a9abacadaeb0b1b2b3b5b6b7b8babbbcbdbfc0c1c2',
+ 'ecb-tbl-192: I=112'),
+ ('dbdad9d81417161166677879e0e7e6e5', '2e1bdd563dd87ee5c338dd6d098d0a7a',
+ 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6d8d9dadbdddedfe0',
+ 'ecb-tbl-192: I=113'),
+ ('6a6b6c6de0efeeed2b2a2928c0c3c2c5', 'eb869996e6f8bfb2bfdd9e0c4504dbb2',
+ 'e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe',
+ 'ecb-tbl-192: I=114'),
+ ('b1b0b3b21714151a1a1b1c1d5649484b', 'c2e01549e9decf317468b3e018c61ba8',
+ '00010203050607080a0b0c0d0f10111214151617191a1b1c',
+ 'ecb-tbl-192: I=115'),
+ ('39380706a3a4a5a6c4c5c6c77271706f', '8da875d033c01dd463b244a1770f4a22',
+ '1e1f20212324252628292a2b2d2e2f30323334353738393a',
+ 'ecb-tbl-192: I=116'),
+ ('5c5d5e5f1013121539383736e2e5e4e7', '8ba0dcf3a186844f026d022f8839d696',
+ '3c3d3e3f41424344464748494b4c4d4e5051525355565758',
+ 'ecb-tbl-192: I=117'),
+ ('43424544ead5d4d72e2f2c2d64676661', 'e9691ff9a6cc6970e51670a0fd5b88c1',
+ '5a5b5c5d5f60616264656667696a6b6c6e6f707173747576',
+ 'ecb-tbl-192: I=118'),
+ ('55545756989b9a65f8f9feff18171615', 'f2baec06faeed30f88ee63ba081a6e5b',
+ '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394',
+ 'ecb-tbl-192: I=119'),
+ ('05040b0a525554573c3d3e3f4a494847', '9c39d4c459ae5753394d6094adc21e78',
+ '969798999b9c9d9ea0a1a2a3a5a6a7a8aaabacadafb0b1b2',
+ 'ecb-tbl-192: I=120'),
+ ('14151617595a5b5c8584fbfa8e89888b', '6345b532a11904502ea43ba99c6bd2b2',
+ 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6c8c9cacbcdcecfd0',
+ 'ecb-tbl-192: I=121'),
+ ('7c7d7a7bfdf2f3f029282b2a51525354', '5ffae3061a95172e4070cedce1e428c8',
+ 'd2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee',
+ 'ecb-tbl-192: I=122'),
+ ('38393a3b1e1d1c1341404746c23d3c3e', '0a4566be4cdf9adce5dec865b5ab34cd',
+ 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c',
+ 'ecb-tbl-192: I=123'),
+ ('8d8c939240474645818083827c7f7e41', 'ca17fcce79b7404f2559b22928f126fb',
+ '0e0f10111314151618191a1b1d1e1f20222324252728292a',
+ 'ecb-tbl-192: I=124'),
+ ('3b3a39381a19181f32333c3d45424340', '97ca39b849ed73a6470a97c821d82f58',
+ '2c2d2e2f31323334363738393b3c3d3e4041424345464748',
+ 'ecb-tbl-192: I=125'),
+ ('f0f1f6f738272625828380817f7c7d7a', '8198cb06bc684c6d3e9b7989428dcf7a',
+ '4a4b4c4d4f50515254555657595a5b5c5e5f606163646566',
+ 'ecb-tbl-192: I=126'),
+ ('89888b8a0407061966676061141b1a19', 'f53c464c705ee0f28d9a4c59374928bd',
+ '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384',
+ 'ecb-tbl-192: I=127'),
+ ('d3d2dddcaaadacaf9c9d9e9fe8ebeae5', '9adb3d4cca559bb98c3e2ed73dbf1154',
+ '868788898b8c8d8e90919293959697989a9b9c9d9fa0a1a2',
+ 'ecb-tbl-192: I=128'),
+
+ # ecb_tbl.txt, KEYSIZE=256
+ ('834eadfccac7e1b30664b1aba44815ab', '1946dabf6a03a2a2c3d0b05080aed6fc',
+ '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526',
+ 'ecb-tbl-256: I=1'),
+ ('d9dc4dba3021b05d67c0518f72b62bf1', '5ed301d747d3cc715445ebdec62f2fb4',
+ '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e',
+ 'ecb-tbl-256: I=2'),
+ ('a291d86301a4a739f7392173aa3c604c', '6585c8f43d13a6beab6419fc5935b9d0',
+ '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576',
+ 'ecb-tbl-256: I=3'),
+ ('4264b2696498de4df79788a9f83e9390', '2a5b56a596680fcc0e05f5e0f151ecae',
+ '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e',
+ 'ecb-tbl-256: I=4'),
+ ('ee9932b3721804d5a83ef5949245b6f6', 'f5d6ff414fd2c6181494d20c37f2b8c4',
+ 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6',
+ 'ecb-tbl-256: I=5'),
+ ('e6248f55c5fdcbca9cbbb01c88a2ea77', '85399c01f59fffb5204f19f8482f00b8',
+ 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee',
+ 'ecb-tbl-256: I=6'),
+ ('b8358e41b9dff65fd461d55a99266247', '92097b4c88a041ddf98144bc8d22e8e7',
+ 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516',
+ 'ecb-tbl-256: I=7'),
+ ('f0e2d72260af58e21e015ab3a4c0d906', '89bd5b73b356ab412aef9f76cea2d65c',
+ '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e',
+ 'ecb-tbl-256: I=8'),
+ ('475b8b823ce8893db3c44a9f2a379ff7', '2536969093c55ff9454692f2fac2f530',
+ '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566',
+ 'ecb-tbl-256: I=9'),
+ ('688f5281945812862f5f3076cf80412f', '07fc76a872843f3f6e0081ee9396d637',
+ '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e',
+ 'ecb-tbl-256: I=10'),
+ ('08d1d2bc750af553365d35e75afaceaa', 'e38ba8ec2aa741358dcc93e8f141c491',
+ '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6',
+ 'ecb-tbl-256: I=11'),
+ ('8707121f47cc3efceca5f9a8474950a1', 'd028ee23e4a89075d0b03e868d7d3a42',
+ 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde',
+ 'ecb-tbl-256: I=12'),
+ ('e51aa0b135dba566939c3b6359a980c5', '8cd9423dfc459e547155c5d1d522e540',
+ 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506',
+ 'ecb-tbl-256: I=13'),
+ ('069a007fc76a459f98baf917fedf9521', '080e9517eb1677719acf728086040ae3',
+ '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e',
+ 'ecb-tbl-256: I=14'),
+ ('726165c1723fbcf6c026d7d00b091027', '7c1700211a3991fc0ecded0ab3e576b0',
+ '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556',
+ 'ecb-tbl-256: I=15'),
+ ('d7c544de91d55cfcde1f84ca382200ce', 'dabcbcc855839251db51e224fbe87435',
+ '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e',
+ 'ecb-tbl-256: I=16'),
+ ('fed3c9a161b9b5b2bd611b41dc9da357', '68d56fad0406947a4dd27a7448c10f1d',
+ '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6',
+ 'ecb-tbl-256: I=17'),
+ ('4f634cdc6551043409f30b635832cf82', 'da9a11479844d1ffee24bbf3719a9925',
+ 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce',
+ 'ecb-tbl-256: I=18'),
+ ('109ce98db0dfb36734d9f3394711b4e6', '5e4ba572f8d23e738da9b05ba24b8d81',
+ 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6',
+ 'ecb-tbl-256: I=19'),
+ ('4ea6dfaba2d8a02ffdffa89835987242', 'a115a2065d667e3f0b883837a6e903f8',
+ '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596',
+ 'ecb-tbl-256: I=20'),
+ ('5ae094f54af58e6e3cdbf976dac6d9ef', '3e9e90dc33eac2437d86ad30b137e66e',
+ '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe',
+ 'ecb-tbl-256: I=21'),
+ ('764d8e8e0f29926dbe5122e66354fdbe', '01ce82d8fbcdae824cb3c48e495c3692',
+ 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6',
+ 'ecb-tbl-256: I=22'),
+ ('3f0418f888cdf29a982bf6b75410d6a9', '0c9cff163ce936faaf083cfd3dea3117',
+ 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e',
+ 'ecb-tbl-256: I=23'),
+ ('e4a3e7cb12cdd56aa4a75197a9530220', '5131ba9bd48f2bba85560680df504b52',
+ '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536',
+ 'ecb-tbl-256: I=24'),
+ ('211677684aac1ec1a160f44c4ebf3f26', '9dc503bbf09823aec8a977a5ad26ccb2',
+ '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e',
+ 'ecb-tbl-256: I=25'),
+ ('d21e439ff749ac8f18d6d4b105e03895', '9a6db0c0862e506a9e397225884041d7',
+ '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586',
+ 'ecb-tbl-256: I=26'),
+ ('d9f6ff44646c4725bd4c0103ff5552a7', '430bf9570804185e1ab6365fc6a6860c',
+ '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae',
+ 'ecb-tbl-256: I=27'),
+ ('0b1256c2a00b976250cfc5b0c37ed382', '3525ebc02f4886e6a5a3762813e8ce8a',
+ 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6',
+ 'ecb-tbl-256: I=28'),
+ ('b056447ffc6dc4523a36cc2e972a3a79', '07fa265c763779cce224c7bad671027b',
+ 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe',
+ 'ecb-tbl-256: I=29'),
+ ('5e25ca78f0de55802524d38da3fe4456', 'e8b72b4e8be243438c9fff1f0e205872',
+ '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526',
+ 'ecb-tbl-256: I=30'),
+ ('a5bcf4728fa5eaad8567c0dc24675f83', '109d4f999a0e11ace1f05e6b22cbcb50',
+ '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e',
+ 'ecb-tbl-256: I=31'),
+ ('814e59f97ed84646b78b2ca022e9ca43', '45a5e8d4c3ed58403ff08d68a0cc4029',
+ '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576',
+ 'ecb-tbl-256: I=32'),
+ ('15478beec58f4775c7a7f5d4395514d7', '196865964db3d417b6bd4d586bcb7634',
+ '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e',
+ 'ecb-tbl-256: I=33'),
+ ('253548ffca461c67c8cbc78cd59f4756', '60436ad45ac7d30d99195f815d98d2ae',
+ 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6',
+ 'ecb-tbl-256: I=34'),
+ ('fd7ad8d73b9b0f8cc41600640f503d65', 'bb07a23f0b61014b197620c185e2cd75',
+ 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee',
+ 'ecb-tbl-256: I=35'),
+ ('06199de52c6cbf8af954cd65830bcd56', '5bc0b2850129c854423aff0751fe343b',
+ 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516',
+ 'ecb-tbl-256: I=36'),
+ ('f17c4ffe48e44c61bd891e257e725794', '7541a78f96738e6417d2a24bd2beca40',
+ '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e',
+ 'ecb-tbl-256: I=37'),
+ ('9a5b4a402a3e8a59be6bf5cd8154f029', 'b0a303054412882e464591f1546c5b9e',
+ '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566',
+ 'ecb-tbl-256: I=38'),
+ ('79bd40b91a7e07dc939d441782ae6b17', '778c06d8a355eeee214fcea14b4e0eef',
+ '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e',
+ 'ecb-tbl-256: I=39'),
+ ('d8ceaaf8976e5fbe1012d8c84f323799', '09614206d15cbace63227d06db6beebb',
+ '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6',
+ 'ecb-tbl-256: I=40'),
+ ('3316e2751e2e388b083da23dd6ac3fbe', '41b97fb20e427a9fdbbb358d9262255d',
+ 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde',
+ 'ecb-tbl-256: I=41'),
+ ('8b7cfbe37de7dca793521819242c5816', 'c1940f703d845f957652c2d64abd7adf',
+ 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506',
+ 'ecb-tbl-256: I=42'),
+ ('f23f033c0eebf8ec55752662fd58ce68', 'd2d44fcdae5332343366db297efcf21b',
+ '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e',
+ 'ecb-tbl-256: I=43'),
+ ('59eb34f6c8bdbacc5fc6ad73a59a1301', 'ea8196b79dbe167b6aa9896e287eed2b',
+ '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556',
+ 'ecb-tbl-256: I=44'),
+ ('dcde8b6bd5cf7cc22d9505e3ce81261a', 'd6b0b0c4ba6c7dbe5ed467a1e3f06c2d',
+ '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e',
+ 'ecb-tbl-256: I=45'),
+ ('e33cf7e524fed781e7042ff9f4b35dc7', 'ec51eb295250c22c2fb01816fb72bcae',
+ '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6',
+ 'ecb-tbl-256: I=46'),
+ ('27963c8facdf73062867d164df6d064c', 'aded6630a07ce9c7408a155d3bd0d36f',
+ 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce',
+ 'ecb-tbl-256: I=47'),
+ ('77b1ce386b551b995f2f2a1da994eef8', '697c9245b9937f32f5d1c82319f0363a',
+ 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6',
+ 'ecb-tbl-256: I=48'),
+ ('f083388b013679efcf0bb9b15d52ae5c', 'aad5ad50c6262aaec30541a1b7b5b19c',
+ 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e',
+ 'ecb-tbl-256: I=49'),
+ ('c5009e0dab55db0abdb636f2600290c8', '7d34b893855341ec625bd6875ac18c0d',
+ '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546',
+ 'ecb-tbl-256: I=50'),
+ ('7804881e26cd532d8514d3683f00f1b9', '7ef05105440f83862f5d780e88f02b41',
+ '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e',
+ 'ecb-tbl-256: I=51'),
+ ('46cddcd73d1eb53e675ca012870a92a3', 'c377c06403382061af2c9c93a8e70df6',
+ '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596',
+ 'ecb-tbl-256: I=52'),
+ ('a9fb44062bb07fe130a8e8299eacb1ab', '1dbdb3ffdc052dacc83318853abc6de5',
+ '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe',
+ 'ecb-tbl-256: I=53'),
+ ('2b6ff8d7a5cc3a28a22d5a6f221af26b', '69a6eab00432517d0bf483c91c0963c7',
+ 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6',
+ 'ecb-tbl-256: I=54'),
+ ('1a9527c29b8add4b0e3e656dbb2af8b4', '0797f41dc217c80446e1d514bd6ab197',
+ 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e',
+ 'ecb-tbl-256: I=55'),
+ ('7f99cf2c75244df015eb4b0c1050aeae', '9dfd76575902a637c01343c58e011a03',
+ '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536',
+ 'ecb-tbl-256: I=56'),
+ ('e84ff85b0d9454071909c1381646c4ed', 'acf4328ae78f34b9fa9b459747cc2658',
+ '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e',
+ 'ecb-tbl-256: I=57'),
+ ('89afd40f99521280d5399b12404f6db4', 'b0479aea12bac4fe2384cf98995150c6',
+ '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586',
+ 'ecb-tbl-256: I=58'),
+ ('a09ef32dbc5119a35ab7fa38656f0329', '9dd52789efe3ffb99f33b3da5030109a',
+ '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae',
+ 'ecb-tbl-256: I=59'),
+ ('61773457f068c376c7829b93e696e716', 'abbb755e4621ef8f1214c19f649fb9fd',
+ 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6',
+ 'ecb-tbl-256: I=60'),
+ ('a34f0cae726cce41dd498747d891b967', 'da27fb8174357bce2bed0e7354f380f9',
+ 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe',
+ 'ecb-tbl-256: I=61'),
+ ('856f59496c7388ee2d2b1a27b7697847', 'c59a0663f0993838f6e5856593bdc5ef',
+ '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526',
+ 'ecb-tbl-256: I=62'),
+ ('cb090c593ef7720bd95908fb93b49df4', 'ed60b264b5213e831607a99c0ce5e57e',
+ '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e',
+ 'ecb-tbl-256: I=63'),
+ ('a0ac75cd2f1923d460fc4d457ad95baf', 'e50548746846f3eb77b8c520640884ed',
+ '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576',
+ 'ecb-tbl-256: I=64'),
+ ('2a2b282974777689e8e9eeef525d5c5f', '28282cc7d21d6a2923641e52d188ef0c',
+ '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e',
+ 'ecb-tbl-256: I=65'),
+ ('909192939390919e0f0e09089788898a', '0dfa5b02abb18e5a815305216d6d4f8e',
+ 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6',
+ 'ecb-tbl-256: I=66'),
+ ('777675748d8e8f907170777649464744', '7359635c0eecefe31d673395fb46fb99',
+ 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee',
+ 'ecb-tbl-256: I=67'),
+ ('717073720605040b2d2c2b2a05fafbf9', '73c679f7d5aef2745c9737bb4c47fb36',
+ 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516',
+ 'ecb-tbl-256: I=68'),
+ ('64656667fefdfcc31b1a1d1ca5aaaba8', 'b192bd472a4d2eafb786e97458967626',
+ '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e',
+ 'ecb-tbl-256: I=69'),
+ ('dbdad9d86a696867b5b4b3b2c8d7d6d5', '0ec327f6c8a2b147598ca3fde61dc6a4',
+ '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566',
+ 'ecb-tbl-256: I=70'),
+ ('5c5d5e5fe3e0e1fe31303736333c3d3e', 'fc418eb3c41b859b38d4b6f646629729',
+ '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e',
+ 'ecb-tbl-256: I=71'),
+ ('545556574b48494673727574546b6a69', '30249e5ac282b1c981ea64b609f3a154',
+ '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6',
+ 'ecb-tbl-256: I=72'),
+ ('ecedeeefc6c5c4bb56575051f5fafbf8', '5e6e08646d12150776bb43c2d78a9703',
+ 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde',
+ 'ecb-tbl-256: I=73'),
+ ('464744452724252ac9c8cfced2cdcccf', 'faeb3d5de652cd3447dceb343f30394a',
+ 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506',
+ 'ecb-tbl-256: I=74'),
+ ('e6e7e4e54142435c878681801c131211', 'a8e88706823f6993ef80d05c1c7b2cf0',
+ '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e',
+ 'ecb-tbl-256: I=75'),
+ ('72737071cfcccdc2f9f8fffe710e0f0c', '8ced86677e6e00a1a1b15968f2d3cce6',
+ '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556',
+ 'ecb-tbl-256: I=76'),
+ ('505152537370714ec3c2c5c4010e0f0c', '9fc7c23858be03bdebb84e90db6786a9',
+ '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e',
+ 'ecb-tbl-256: I=77'),
+ ('a8a9aaab5c5f5e51aeafa8a93d222320', 'b4fbd65b33f70d8cf7f1111ac4649c36',
+ '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6',
+ 'ecb-tbl-256: I=78'),
+ ('dedfdcddf6f5f4eb10111617fef1f0f3', 'c5c32d5ed03c4b53cc8c1bd0ef0dbbf6',
+ 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce',
+ 'ecb-tbl-256: I=79'),
+ ('bdbcbfbe5e5d5c530b0a0d0cfac5c4c7', 'd1a7f03b773e5c212464b63709c6a891',
+ 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6',
+ 'ecb-tbl-256: I=80'),
+ ('8a8b8889050606f8f4f5f2f3636c6d6e', '6b7161d8745947ac6950438ea138d028',
+ 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e',
+ 'ecb-tbl-256: I=81'),
+ ('a6a7a4a54d4e4f40b2b3b4b539262724', 'fd47a9f7e366ee7a09bc508b00460661',
+ '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546',
+ 'ecb-tbl-256: I=82'),
+ ('9c9d9e9fe9eaebf40e0f08099b949596', '00d40b003dc3a0d9310b659b98c7e416',
+ '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e',
+ 'ecb-tbl-256: I=83'),
+ ('2d2c2f2e1013121dcccdcacbed121310', 'eea4c79dcc8e2bda691f20ac48be0717',
+ '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596',
+ 'ecb-tbl-256: I=84'),
+ ('f4f5f6f7edeeefd0eaebecedf7f8f9fa', 'e78f43b11c204403e5751f89d05a2509',
+ '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe',
+ 'ecb-tbl-256: I=85'),
+ ('3d3c3f3e282b2a2573727574150a0b08', 'd0f0e3d1f1244bb979931e38dd1786ef',
+ 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6',
+ 'ecb-tbl-256: I=86'),
+ ('b6b7b4b5f8fbfae5b4b5b2b3a0afaead', '042e639dc4e1e4dde7b75b749ea6f765',
+ 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e',
+ 'ecb-tbl-256: I=87'),
+ ('b7b6b5b4989b9a95878681809ba4a5a6', 'bc032fdd0efe29503a980a7d07ab46a8',
+ '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536',
+ 'ecb-tbl-256: I=88'),
+ ('a8a9aaabe5e6e798e9e8efee4748494a', '0c93ac949c0da6446effb86183b6c910',
+ '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e',
+ 'ecb-tbl-256: I=89'),
+ ('ecedeeefd9dadbd4b9b8bfbe657a7b78', 'e0d343e14da75c917b4a5cec4810d7c2',
+ '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586',
+ 'ecb-tbl-256: I=90'),
+ ('7f7e7d7c696a6b74cacbcccd929d9c9f', '0eafb821748408279b937b626792e619',
+ '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae',
+ 'ecb-tbl-256: I=91'),
+ ('08090a0b0605040bfffef9f8b9c6c7c4', 'fa1ac6e02d23b106a1fef18b274a553f',
+ 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6',
+ 'ecb-tbl-256: I=92'),
+ ('08090a0bf1f2f3ccfcfdfafb68676665', '0dadfe019cd12368075507df33c1a1e9',
+ 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe',
+ 'ecb-tbl-256: I=93'),
+ ('cacbc8c93a393837050403020d121310', '3a0879b414465d9ffbaf86b33a63a1b9',
+ '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526',
+ 'ecb-tbl-256: I=94'),
+ ('e9e8ebea8281809f8f8e8988343b3a39', '62199fadc76d0be1805d3ba0b7d914bf',
+ '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e',
+ 'ecb-tbl-256: I=95'),
+ ('515053524645444bd0d1d6d7340b0a09', '1b06d6c5d333e742730130cf78e719b4',
+ '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576',
+ 'ecb-tbl-256: I=96'),
+ ('42434041ecefee1193929594c6c9c8cb', 'f1f848824c32e9dcdcbf21580f069329',
+ '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e',
+ 'ecb-tbl-256: I=97'),
+ ('efeeedecc2c1c0cf76777071455a5b58', '1a09050cbd684f784d8e965e0782f28a',
+ 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6',
+ 'ecb-tbl-256: I=98'),
+ ('5f5e5d5c3f3c3d221d1c1b1a19161714', '79c2969e7ded2ba7d088f3f320692360',
+ 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee',
+ 'ecb-tbl-256: I=99'),
+ ('000102034142434c1c1d1a1b8d727371', '091a658a2f7444c16accb669450c7b63',
+ 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516',
+ 'ecb-tbl-256: I=100'),
+ ('8e8f8c8db1b2b38c56575051050a0b08', '97c1e3a72cca65fa977d5ed0e8a7bbfc',
+ '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e',
+ 'ecb-tbl-256: I=101'),
+ ('a7a6a5a4e8ebeae57f7e7978cad5d4d7', '70c430c6db9a17828937305a2df91a2a',
+ '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566',
+ 'ecb-tbl-256: I=102'),
+ ('8a8b888994979689454443429f909192', '629553457fbe2479098571c7c903fde8',
+ '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e',
+ 'ecb-tbl-256: I=103'),
+ ('8c8d8e8fe0e3e2ed45444342f1cecfcc', 'a25b25a61f612669e7d91265c7d476ba',
+ '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6',
+ 'ecb-tbl-256: I=104'),
+ ('fffefdfc4c4f4e31d8d9dedfb6b9b8bb', 'eb7e4e49b8ae0f024570dda293254fed',
+ 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde',
+ 'ecb-tbl-256: I=105'),
+ ('fdfcfffecccfcec12f2e29286679787b', '38fe15d61cca84516e924adce5014f67',
+ 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506',
+ 'ecb-tbl-256: I=106'),
+ ('67666564bab9b8a77071767719161714', '3ad208492249108c9f3ebeb167ad0583',
+ '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e',
+ 'ecb-tbl-256: I=107'),
+ ('9a9b98992d2e2f2084858283245b5a59', '299ba9f9bf5ab05c3580fc26edd1ed12',
+ '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556',
+ 'ecb-tbl-256: I=108'),
+ ('a4a5a6a70b0809365c5d5a5b2c232221', '19dc705b857a60fb07717b2ea5717781',
+ '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e',
+ 'ecb-tbl-256: I=109'),
+ ('464744455754555af3f2f5f4afb0b1b2', 'ffc8aeb885b5efcad06b6dbebf92e76b',
+ '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6',
+ 'ecb-tbl-256: I=110'),
+ ('323330317675746b7273747549464744', 'f58900c5e0b385253ff2546250a0142b',
+ 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce',
+ 'ecb-tbl-256: I=111'),
+ ('a8a9aaab181b1a15808186872b141516', '2ee67b56280bc462429cee6e3370cbc1',
+ 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6',
+ 'ecb-tbl-256: I=112'),
+ ('e7e6e5e4202323ddaaabacad343b3a39', '20db650a9c8e9a84ab4d25f7edc8f03f',
+ 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e',
+ 'ecb-tbl-256: I=113'),
+ ('a8a9aaab2221202fedecebea1e010003', '3c36da169525cf818843805f25b78ae5',
+ '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546',
+ 'ecb-tbl-256: I=114'),
+ ('f9f8fbfa5f5c5d42424344450e010003', '9a781d960db9e45e37779042fea51922',
+ '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e',
+ 'ecb-tbl-256: I=115'),
+ ('57565554f5f6f7f89697909120dfdedd', '6560395ec269c672a3c288226efdba77',
+ '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596',
+ 'ecb-tbl-256: I=116'),
+ ('f8f9fafbcccfcef1dddcdbda0e010003', '8c772b7a189ac544453d5916ebb27b9a',
+ '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe',
+ 'ecb-tbl-256: I=117'),
+ ('d9d8dbda7073727d80818687c2dddcdf', '77ca5468cc48e843d05f78eed9d6578f',
+ 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6',
+ 'ecb-tbl-256: I=118'),
+ ('c5c4c7c6080b0a1588898e8f68676665', '72cdcc71dc82c60d4429c9e2d8195baa',
+ 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e',
+ 'ecb-tbl-256: I=119'),
+ ('83828180dcdfded186878081f0cfcecd', '8080d68ce60e94b40b5b8b69eeb35afa',
+ '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536',
+ 'ecb-tbl-256: I=120'),
+ ('98999a9bdddedfa079787f7e0a050407', '44222d3cde299c04369d58ac0eba1e8e',
+ '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e',
+ 'ecb-tbl-256: I=121'),
+ ('cecfcccd4f4c4d429f9e9998dfc0c1c2', '9b8721b0a8dfc691c5bc5885dbfcb27a',
+ '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586',
+ 'ecb-tbl-256: I=122'),
+ ('404142436665647b29282f2eaba4a5a6', '0dc015ce9a3a3414b5e62ec643384183',
+ '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae',
+ 'ecb-tbl-256: I=123'),
+ ('33323130e6e5e4eb23222524dea1a0a3', '705715448a8da412025ce38345c2a148',
+ 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6',
+ 'ecb-tbl-256: I=124'),
+ ('cfcecdccf6f5f4cbe6e7e0e199969794', 'c32b5b0b6fbae165266c569f4b6ecf0b',
+ 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe',
+ 'ecb-tbl-256: I=125'),
+ ('babbb8b97271707fdcdddadb29363734', '4dca6c75192a01ddca9476af2a521e87',
+ '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526',
+ 'ecb-tbl-256: I=126'),
+ ('c9c8cbca4447465926272021545b5a59', '058691e627ecbc36ac07b6db423bd698',
+ '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e',
+ 'ecb-tbl-256: I=127'),
+ ('050407067477767956575051221d1c1f', '7444527095838fe080fc2bcdd30847eb',
+ '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576',
+ 'ecb-tbl-256: I=128'),
+
+ # FIPS PUB 800-38A test vectors, 2001 edition. Annex F.
+
+ ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+
+ '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710',
+ '3ad77bb40d7a3660a89ecaf32466ef97'+'f5d3d58503b9699de785895a96fdbaaf'+
+ '43b1cd7f598ece23881b00e3ed030688'+'7b0c785e27e8ad3f8223207104725dd4',
+ '2b7e151628aed2a6abf7158809cf4f3c',
+ 'NIST 800-38A, F.1.1, ECB and AES-128'),
+
+ ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+
+ '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710',
+ 'bd334f1d6e45f25ff712a214571fa5cc'+'974104846d0ad3ad7734ecb3ecee4eef'+
+ 'ef7afd2270e2e60adce0ba2face6444e'+'9a4b41ba738d6c72fb16691603c18e0e',
+ '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b',
+ 'NIST 800-38A, F.1.3, ECB and AES-192'),
+
+ ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+
+ '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710',
+ 'f3eed1bdb5d2a03c064b5a7e3db181f8'+'591ccb10d410ed26dc5ba74a31362870'+
+ 'b6ed21b99ca6f4f9f153e7b1beafed1d'+'23304b7a39f9f3ff067d8d8f9e24ecc7',
+ '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4',
+ 'NIST 800-38A, F.1.3, ECB and AES-256'),
+
+]
+
+test_data_8_lanes = []
+for td in test_data:
+ test_data_8_lanes.append((td[0] * 8, td[1] * 8, td[2], td[3]))
+test_data += test_data_8_lanes
+
+class TestMultipleBlocks(unittest.TestCase):
+
+ def __init__(self, use_aesni):
+ unittest.TestCase.__init__(self)
+ self.use_aesni = use_aesni
+
+ def runTest(self):
+ # Encrypt data which is 8*2+4 bytes long, so as to trigger (for the
+ # AESNI variant) both the path that parallelizes 8 lanes and the one
+ # that processes data serially
+
+ tvs = [
+ (b'a' * 16, 'c0b27011eb15bf144d2fc9fae80ea16d4c231cb230416c5fac02e6835ad9d7d0'),
+ (b'a' * 24, 'df8435ce361a78c535b41dcb57da952abbf9ee5954dc6fbcd75fd00fa626915d'),
+ (b'a' * 32, '211402de6c80db1f92ba255881178e1f70783b8cfd3b37808205e48b80486cd8')
+ ]
+
+ for key, expected in tvs:
+
+ cipher = AES.new(key, AES.MODE_ECB, use_aesni=self.use_aesni)
+ h = SHA256.new()
+
+ pt = b"".join([ tobytes('{0:016x}'.format(x)) for x in range(20) ])
+ ct = cipher.encrypt(pt)
+ self.assertEqual(SHA256.new(ct).hexdigest(), expected)
+
+
+class TestIncompleteBlocks(unittest.TestCase):
+
+ def __init__(self, use_aesni):
+ unittest.TestCase.__init__(self)
+ self.use_aesni = use_aesni
+
+ def runTest(self):
+ # Encrypt data with length not multiple of 16 bytes
+
+ cipher = AES.new(b'4'*16, AES.MODE_ECB, use_aesni=self.use_aesni)
+
+ for msg_len in range(1, 16):
+ self.assertRaises(ValueError, cipher.encrypt, b'1' * msg_len)
+ self.assertRaises(ValueError, cipher.encrypt, b'1' * (msg_len+16))
+ self.assertRaises(ValueError, cipher.decrypt, b'1' * msg_len)
+ self.assertRaises(ValueError, cipher.decrypt, b'1' * (msg_len+16))
+
+ self.assertEqual(cipher.encrypt(b''), b'')
+ self.assertEqual(cipher.decrypt(b''), b'')
+
+
+class TestOutput(unittest.TestCase):
+
+ def __init__(self, use_aesni):
+ unittest.TestCase.__init__(self)
+ self.use_aesni = use_aesni
+
+ def runTest(self):
+ # Encrypt/Decrypt data and test output parameter
+
+ cipher = AES.new(b'4'*16, AES.MODE_ECB, use_aesni=self.use_aesni)
+
+ pt = b'5' * 16
+ ct = cipher.encrypt(pt)
+
+ output = bytearray(16)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ output = memoryview(bytearray(16))
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16)
+
+ shorter_output = bytearray(15)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+def get_tests(config={}):
+ from Crypto.Util import _cpu_features
+ from .common import make_block_tests
+
+ tests = make_block_tests(AES, "AES", test_data, {'use_aesni': False})
+ tests += [ TestMultipleBlocks(False) ]
+ tests += [ TestIncompleteBlocks(False) ]
+ if _cpu_features.have_aes_ni():
+ # Run tests with AES-NI instructions if they are available.
+ tests += make_block_tests(AES, "AESNI", test_data, {'use_aesni': True})
+ tests += [ TestMultipleBlocks(True) ]
+ tests += [ TestIncompleteBlocks(True) ]
+ tests += [ TestOutput(True) ]
+ else:
+ print("Skipping AESNI tests")
+ return tests
+
+if __name__ == '__main__':
+ import unittest
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
+
+# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/SelfTest/Cipher/test_ARC2.py b/lib/Crypto/SelfTest/Cipher/test_ARC2.py
new file mode 100644
index 0000000..fd9448c
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_ARC2.py
@@ -0,0 +1,167 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Cipher/ARC2.py: Self-test for the Alleged-RC2 cipher
+#
+# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+"""Self-test suite for Crypto.Cipher.ARC2"""
+
+import unittest
+
+from Crypto.Util.py3compat import b, bchr
+
+from Crypto.Cipher import ARC2
+
+# This is a list of (plaintext, ciphertext, key[, description[, extra_params]]) tuples.
+test_data = [
+ # Test vectors from RFC 2268
+
+ # 63-bit effective key length
+ ('0000000000000000', 'ebb773f993278eff', '0000000000000000',
+ 'RFC2268-1', dict(effective_keylen=63)),
+
+ # 64-bit effective key length
+ ('ffffffffffffffff', '278b27e42e2f0d49', 'ffffffffffffffff',
+ 'RFC2268-2', dict(effective_keylen=64)),
+ ('1000000000000001', '30649edf9be7d2c2', '3000000000000000',
+ 'RFC2268-3', dict(effective_keylen=64)),
+ #('0000000000000000', '61a8a244adacccf0', '88',
+ # 'RFC2268-4', dict(effective_keylen=64)),
+ ('0000000000000000', '6ccf4308974c267f', '88bca90e90875a',
+ 'RFC2268-5', dict(effective_keylen=64)),
+ ('0000000000000000', '1a807d272bbe5db1', '88bca90e90875a7f0f79c384627bafb2',
+ 'RFC2268-6', dict(effective_keylen=64)),
+
+ # 128-bit effective key length
+ ('0000000000000000', '2269552ab0f85ca6', '88bca90e90875a7f0f79c384627bafb2',
+ "RFC2268-7", dict(effective_keylen=128)),
+ ('0000000000000000', '5b78d3a43dfff1f1',
+ '88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e',
+ "RFC2268-8", dict(effective_keylen=129)),
+
+ # Test vectors from PyCrypto 2.0.1's testdata.py
+ # 1024-bit effective key length
+ ('0000000000000000', '624fb3e887419e48', '5068696c6970476c617373',
+ 'PCTv201-0'),
+ ('ffffffffffffffff', '79cadef44c4a5a85', '5068696c6970476c617373',
+ 'PCTv201-1'),
+ ('0001020304050607', '90411525b34e4c2c', '5068696c6970476c617373',
+ 'PCTv201-2'),
+ ('0011223344556677', '078656aaba61cbfb', '5068696c6970476c617373',
+ 'PCTv201-3'),
+ ('0000000000000000', 'd7bcc5dbb4d6e56a', 'ffffffffffffffff',
+ 'PCTv201-4'),
+ ('ffffffffffffffff', '7259018ec557b357', 'ffffffffffffffff',
+ 'PCTv201-5'),
+ ('0001020304050607', '93d20a497f2ccb62', 'ffffffffffffffff',
+ 'PCTv201-6'),
+ ('0011223344556677', 'cb15a7f819c0014d', 'ffffffffffffffff',
+ 'PCTv201-7'),
+ ('0000000000000000', '63ac98cdf3843a7a', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553',
+ 'PCTv201-8'),
+ ('ffffffffffffffff', '3fb49e2fa12371dd', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553',
+ 'PCTv201-9'),
+ ('0001020304050607', '46414781ab387d5f', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553',
+ 'PCTv201-10'),
+ ('0011223344556677', 'be09dc81feaca271', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553',
+ 'PCTv201-11'),
+ ('0000000000000000', 'e64221e608be30ab', '53e5ffe553',
+ 'PCTv201-12'),
+ ('ffffffffffffffff', '862bc60fdcd4d9a9', '53e5ffe553',
+ 'PCTv201-13'),
+ ('0001020304050607', '6a34da50fa5e47de', '53e5ffe553',
+ 'PCTv201-14'),
+ ('0011223344556677', '584644c34503122c', '53e5ffe553',
+ 'PCTv201-15'),
+]
+
+class BufferOverflowTest(unittest.TestCase):
+ # Test a buffer overflow found in older versions of PyCrypto
+
+ def runTest(self):
+ """ARC2 with keylength > 128"""
+ key = b("x") * 16384
+ self.assertRaises(ValueError, ARC2.new, key, ARC2.MODE_ECB)
+
+class KeyLength(unittest.TestCase):
+
+ def runTest(self):
+ ARC2.new(b'\x00' * 16, ARC2.MODE_ECB, effective_keylen=40)
+ self.assertRaises(ValueError, ARC2.new, bchr(0) * 4, ARC2.MODE_ECB)
+ self.assertRaises(ValueError, ARC2.new, bchr(0) * 129, ARC2.MODE_ECB)
+
+ self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB,
+ effective_keylen=39)
+ self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB,
+ effective_keylen=1025)
+
+
+class TestOutput(unittest.TestCase):
+
+ def runTest(self):
+ # Encrypt/Decrypt data and test output parameter
+
+ cipher = ARC2.new(b'4'*16, ARC2.MODE_ECB)
+
+ pt = b'5' * 16
+ ct = cipher.encrypt(pt)
+
+ output = bytearray(16)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ output = memoryview(bytearray(16))
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16)
+
+ shorter_output = bytearray(7)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+def get_tests(config={}):
+ from Crypto.Cipher import ARC2
+ from .common import make_block_tests
+
+ tests = make_block_tests(ARC2, "ARC2", test_data)
+ tests.append(BufferOverflowTest())
+ tests.append(KeyLength())
+ tests += [TestOutput()]
+
+ return tests
+
+if __name__ == '__main__':
+ import unittest
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
+
+# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/SelfTest/Cipher/test_ARC4.py b/lib/Crypto/SelfTest/Cipher/test_ARC4.py
new file mode 100644
index 0000000..1b9a7d8
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_ARC4.py
@@ -0,0 +1,466 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Cipher/ARC4.py: Self-test for the Alleged-RC4 cipher
+#
+# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+"""Self-test suite for Crypto.Cipher.ARC4"""
+
+__revision__ = "$Id$"
+
+from Crypto.Util.py3compat import *
+from Crypto.SelfTest.st_common import *
+from binascii import unhexlify
+
+from Crypto.Cipher import ARC4
+
+# This is a list of (plaintext, ciphertext, key[, description]) tuples.
+test_data = [
+ # Test vectors from Eric Rescorla's message with the subject
+ # "RC4 compatibility testing", sent to the cipherpunks mailing list on
+ # September 13, 1994.
+ # http://cypherpunks.venona.com/date/1994/09/msg00420.html
+
+ ('0123456789abcdef', '75b7878099e0c596', '0123456789abcdef',
+ 'Test vector 0'),
+
+ ('0000000000000000', '7494c2e7104b0879', '0123456789abcdef',
+ 'Test vector 1'),
+
+ ('0000000000000000', 'de188941a3375d3a', '0000000000000000',
+ 'Test vector 2'),
+
+ #('00000000000000000000', 'd6a141a7ec3c38dfbd61', 'ef012345',
+ # 'Test vector 3'),
+
+ ('01' * 512,
+ '7595c3e6114a09780c4ad452338e1ffd9a1be9498f813d76533449b6778dcad8'
+ + 'c78a8d2ba9ac66085d0e53d59c26c2d1c490c1ebbe0ce66d1b6b1b13b6b919b8'
+ + '47c25a91447a95e75e4ef16779cde8bf0a95850e32af9689444fd377108f98fd'
+ + 'cbd4e726567500990bcc7e0ca3c4aaa304a387d20f3b8fbbcd42a1bd311d7a43'
+ + '03dda5ab078896ae80c18b0af66dff319616eb784e495ad2ce90d7f772a81747'
+ + 'b65f62093b1e0db9e5ba532fafec47508323e671327df9444432cb7367cec82f'
+ + '5d44c0d00b67d650a075cd4b70dedd77eb9b10231b6b5b741347396d62897421'
+ + 'd43df9b42e446e358e9c11a9b2184ecbef0cd8e7a877ef968f1390ec9b3d35a5'
+ + '585cb009290e2fcde7b5ec66d9084be44055a619d9dd7fc3166f9487f7cb2729'
+ + '12426445998514c15d53a18c864ce3a2b7555793988126520eacf2e3066e230c'
+ + '91bee4dd5304f5fd0405b35bd99c73135d3d9bc335ee049ef69b3867bf2d7bd1'
+ + 'eaa595d8bfc0066ff8d31509eb0c6caa006c807a623ef84c3d33c195d23ee320'
+ + 'c40de0558157c822d4b8c569d849aed59d4e0fd7f379586b4b7ff684ed6a189f'
+ + '7486d49b9c4bad9ba24b96abf924372c8a8fffb10d55354900a77a3db5f205e1'
+ + 'b99fcd8660863a159ad4abe40fa48934163ddde542a6585540fd683cbfd8c00f'
+ + '12129a284deacc4cdefe58be7137541c047126c8d49e2755ab181ab7e940b0c0',
+ '0123456789abcdef',
+ "Test vector 4"),
+]
+
+class RFC6229_Tests(unittest.TestCase):
+ # Test vectors from RFC 6229. Each test vector is a tuple with two items:
+ # the ARC4 key and a dictionary. The dictionary has keystream offsets as keys
+ # and the 16-byte keystream starting at the relevant offset as value.
+ rfc6229_data = [
+ # Page 3
+ (
+ '0102030405',
+ {
+ 0: 'b2 39 63 05 f0 3d c0 27 cc c3 52 4a 0a 11 18 a8',
+ 16: '69 82 94 4f 18 fc 82 d5 89 c4 03 a4 7a 0d 09 19',
+ 240: '28 cb 11 32 c9 6c e2 86 42 1d ca ad b8 b6 9e ae',
+ 256: '1c fc f6 2b 03 ed db 64 1d 77 df cf 7f 8d 8c 93',
+ 496: '42 b7 d0 cd d9 18 a8 a3 3d d5 17 81 c8 1f 40 41',
+ 512: '64 59 84 44 32 a7 da 92 3c fb 3e b4 98 06 61 f6',
+ 752: 'ec 10 32 7b de 2b ee fd 18 f9 27 76 80 45 7e 22',
+ 768: 'eb 62 63 8d 4f 0b a1 fe 9f ca 20 e0 5b f8 ff 2b',
+ 1008:'45 12 90 48 e6 a0 ed 0b 56 b4 90 33 8f 07 8d a5',
+ 1024:'30 ab bc c7 c2 0b 01 60 9f 23 ee 2d 5f 6b b7 df',
+ 1520:'32 94 f7 44 d8 f9 79 05 07 e7 0f 62 e5 bb ce ea',
+ 1536:'d8 72 9d b4 18 82 25 9b ee 4f 82 53 25 f5 a1 30',
+ 2032:'1e b1 4a 0c 13 b3 bf 47 fa 2a 0b a9 3a d4 5b 8b',
+ 2048:'cc 58 2f 8b a9 f2 65 e2 b1 be 91 12 e9 75 d2 d7',
+ 3056:'f2 e3 0f 9b d1 02 ec bf 75 aa ad e9 bc 35 c4 3c',
+ 3072:'ec 0e 11 c4 79 dc 32 9d c8 da 79 68 fe 96 56 81',
+ 4080:'06 83 26 a2 11 84 16 d2 1f 9d 04 b2 cd 1c a0 50',
+ 4096:'ff 25 b5 89 95 99 67 07 e5 1f bd f0 8b 34 d8 75'
+ }
+ ),
+ # Page 4
+ (
+ '01020304050607',
+ {
+ 0: '29 3f 02 d4 7f 37 c9 b6 33 f2 af 52 85 fe b4 6b',
+ 16: 'e6 20 f1 39 0d 19 bd 84 e2 e0 fd 75 20 31 af c1',
+ 240: '91 4f 02 53 1c 92 18 81 0d f6 0f 67 e3 38 15 4c',
+ 256: 'd0 fd b5 83 07 3c e8 5a b8 39 17 74 0e c0 11 d5',
+ 496: '75 f8 14 11 e8 71 cf fa 70 b9 0c 74 c5 92 e4 54',
+ 512: '0b b8 72 02 93 8d ad 60 9e 87 a5 a1 b0 79 e5 e4',
+ 752: 'c2 91 12 46 b6 12 e7 e7 b9 03 df ed a1 da d8 66',
+ 768: '32 82 8f 91 50 2b 62 91 36 8d e8 08 1d e3 6f c2',
+ 1008:'f3 b9 a7 e3 b2 97 bf 9a d8 04 51 2f 90 63 ef f1',
+ 1024:'8e cb 67 a9 ba 1f 55 a5 a0 67 e2 b0 26 a3 67 6f',
+ 1520:'d2 aa 90 2b d4 2d 0d 7c fd 34 0c d4 58 10 52 9f',
+ 1536:'78 b2 72 c9 6e 42 ea b4 c6 0b d9 14 e3 9d 06 e3',
+ 2032:'f4 33 2f d3 1a 07 93 96 ee 3c ee 3f 2a 4f f0 49',
+ 2048:'05 45 97 81 d4 1f da 7f 30 c1 be 7e 12 46 c6 23',
+ 3056:'ad fd 38 68 b8 e5 14 85 d5 e6 10 01 7e 3d d6 09',
+ 3072:'ad 26 58 1c 0c 5b e4 5f 4c ea 01 db 2f 38 05 d5',
+ 4080:'f3 17 2c ef fc 3b 3d 99 7c 85 cc d5 af 1a 95 0c',
+ 4096:'e7 4b 0b 97 31 22 7f d3 7c 0e c0 8a 47 dd d8 b8'
+ }
+ ),
+ (
+ '0102030405060708',
+ {
+ 0: '97 ab 8a 1b f0 af b9 61 32 f2 f6 72 58 da 15 a8',
+ 16: '82 63 ef db 45 c4 a1 86 84 ef 87 e6 b1 9e 5b 09',
+ 240: '96 36 eb c9 84 19 26 f4 f7 d1 f3 62 bd df 6e 18',
+ 256: 'd0 a9 90 ff 2c 05 fe f5 b9 03 73 c9 ff 4b 87 0a',
+ 496: '73 23 9f 1d b7 f4 1d 80 b6 43 c0 c5 25 18 ec 63',
+ 512: '16 3b 31 99 23 a6 bd b4 52 7c 62 61 26 70 3c 0f',
+ 752: '49 d6 c8 af 0f 97 14 4a 87 df 21 d9 14 72 f9 66',
+ 768: '44 17 3a 10 3b 66 16 c5 d5 ad 1c ee 40 c8 63 d0',
+ 1008:'27 3c 9c 4b 27 f3 22 e4 e7 16 ef 53 a4 7d e7 a4',
+ 1024:'c6 d0 e7 b2 26 25 9f a9 02 34 90 b2 61 67 ad 1d',
+ 1520:'1f e8 98 67 13 f0 7c 3d 9a e1 c1 63 ff 8c f9 d3',
+ 1536:'83 69 e1 a9 65 61 0b e8 87 fb d0 c7 91 62 aa fb',
+ 2032:'0a 01 27 ab b4 44 84 b9 fb ef 5a bc ae 1b 57 9f',
+ 2048:'c2 cd ad c6 40 2e 8e e8 66 e1 f3 7b db 47 e4 2c',
+ 3056:'26 b5 1e a3 7d f8 e1 d6 f7 6f c3 b6 6a 74 29 b3',
+ 3072:'bc 76 83 20 5d 4f 44 3d c1 f2 9d da 33 15 c8 7b',
+ 4080:'d5 fa 5a 34 69 d2 9a aa f8 3d 23 58 9d b8 c8 5b',
+ 4096:'3f b4 6e 2c 8f 0f 06 8e dc e8 cd cd 7d fc 58 62'
+ }
+ ),
+ # Page 5
+ (
+ '0102030405060708090a',
+ {
+ 0: 'ed e3 b0 46 43 e5 86 cc 90 7d c2 18 51 70 99 02',
+ 16: '03 51 6b a7 8f 41 3b eb 22 3a a5 d4 d2 df 67 11',
+ 240: '3c fd 6c b5 8e e0 fd de 64 01 76 ad 00 00 04 4d',
+ 256: '48 53 2b 21 fb 60 79 c9 11 4c 0f fd 9c 04 a1 ad',
+ 496: '3e 8c ea 98 01 71 09 97 90 84 b1 ef 92 f9 9d 86',
+ 512: 'e2 0f b4 9b db 33 7e e4 8b 8d 8d c0 f4 af ef fe',
+ 752: '5c 25 21 ea cd 79 66 f1 5e 05 65 44 be a0 d3 15',
+ 768: 'e0 67 a7 03 19 31 a2 46 a6 c3 87 5d 2f 67 8a cb',
+ 1008:'a6 4f 70 af 88 ae 56 b6 f8 75 81 c0 e2 3e 6b 08',
+ 1024:'f4 49 03 1d e3 12 81 4e c6 f3 19 29 1f 4a 05 16',
+ 1520:'bd ae 85 92 4b 3c b1 d0 a2 e3 3a 30 c6 d7 95 99',
+ 1536:'8a 0f ed db ac 86 5a 09 bc d1 27 fb 56 2e d6 0a',
+ 2032:'b5 5a 0a 5b 51 a1 2a 8b e3 48 99 c3 e0 47 51 1a',
+ 2048:'d9 a0 9c ea 3c e7 5f e3 96 98 07 03 17 a7 13 39',
+ 3056:'55 22 25 ed 11 77 f4 45 84 ac 8c fa 6c 4e b5 fc',
+ 3072:'7e 82 cb ab fc 95 38 1b 08 09 98 44 21 29 c2 f8',
+ 4080:'1f 13 5e d1 4c e6 0a 91 36 9d 23 22 be f2 5e 3c',
+ 4096:'08 b6 be 45 12 4a 43 e2 eb 77 95 3f 84 dc 85 53'
+ }
+ ),
+ (
+ '0102030405060708090a0b0c0d0e0f10',
+ {
+ 0: '9a c7 cc 9a 60 9d 1e f7 b2 93 28 99 cd e4 1b 97',
+ 16: '52 48 c4 95 90 14 12 6a 6e 8a 84 f1 1d 1a 9e 1c',
+ 240: '06 59 02 e4 b6 20 f6 cc 36 c8 58 9f 66 43 2f 2b',
+ 256: 'd3 9d 56 6b c6 bc e3 01 07 68 15 15 49 f3 87 3f',
+ 496: 'b6 d1 e6 c4 a5 e4 77 1c ad 79 53 8d f2 95 fb 11',
+ 512: 'c6 8c 1d 5c 55 9a 97 41 23 df 1d bc 52 a4 3b 89',
+ 752: 'c5 ec f8 8d e8 97 fd 57 fe d3 01 70 1b 82 a2 59',
+ 768: 'ec cb e1 3d e1 fc c9 1c 11 a0 b2 6c 0b c8 fa 4d',
+ 1008:'e7 a7 25 74 f8 78 2a e2 6a ab cf 9e bc d6 60 65',
+ 1024:'bd f0 32 4e 60 83 dc c6 d3 ce dd 3c a8 c5 3c 16',
+ 1520:'b4 01 10 c4 19 0b 56 22 a9 61 16 b0 01 7e d2 97',
+ 1536:'ff a0 b5 14 64 7e c0 4f 63 06 b8 92 ae 66 11 81',
+ 2032:'d0 3d 1b c0 3c d3 3d 70 df f9 fa 5d 71 96 3e bd',
+ 2048:'8a 44 12 64 11 ea a7 8b d5 1e 8d 87 a8 87 9b f5',
+ 3056:'fa be b7 60 28 ad e2 d0 e4 87 22 e4 6c 46 15 a3',
+ 3072:'c0 5d 88 ab d5 03 57 f9 35 a6 3c 59 ee 53 76 23',
+ 4080:'ff 38 26 5c 16 42 c1 ab e8 d3 c2 fe 5e 57 2b f8',
+ 4096:'a3 6a 4c 30 1a e8 ac 13 61 0c cb c1 22 56 ca cc'
+ }
+ ),
+ # Page 6
+ (
+ '0102030405060708090a0b0c0d0e0f101112131415161718',
+ {
+ 0: '05 95 e5 7f e5 f0 bb 3c 70 6e da c8 a4 b2 db 11',
+ 16: 'df de 31 34 4a 1a f7 69 c7 4f 07 0a ee 9e 23 26',
+ 240: 'b0 6b 9b 1e 19 5d 13 d8 f4 a7 99 5c 45 53 ac 05',
+ 256: '6b d2 37 8e c3 41 c9 a4 2f 37 ba 79 f8 8a 32 ff',
+ 496: 'e7 0b ce 1d f7 64 5a db 5d 2c 41 30 21 5c 35 22',
+ 512: '9a 57 30 c7 fc b4 c9 af 51 ff da 89 c7 f1 ad 22',
+ 752: '04 85 05 5f d4 f6 f0 d9 63 ef 5a b9 a5 47 69 82',
+ 768: '59 1f c6 6b cd a1 0e 45 2b 03 d4 55 1f 6b 62 ac',
+ 1008:'27 53 cc 83 98 8a fa 3e 16 88 a1 d3 b4 2c 9a 02',
+ 1024:'93 61 0d 52 3d 1d 3f 00 62 b3 c2 a3 bb c7 c7 f0',
+ 1520:'96 c2 48 61 0a ad ed fe af 89 78 c0 3d e8 20 5a',
+ 1536:'0e 31 7b 3d 1c 73 b9 e9 a4 68 8f 29 6d 13 3a 19',
+ 2032:'bd f0 e6 c3 cc a5 b5 b9 d5 33 b6 9c 56 ad a1 20',
+ 2048:'88 a2 18 b6 e2 ec e1 e6 24 6d 44 c7 59 d1 9b 10',
+ 3056:'68 66 39 7e 95 c1 40 53 4f 94 26 34 21 00 6e 40',
+ 3072:'32 cb 0a 1e 95 42 c6 b3 b8 b3 98 ab c3 b0 f1 d5',
+ 4080:'29 a0 b8 ae d5 4a 13 23 24 c6 2e 42 3f 54 b4 c8',
+ 4096:'3c b0 f3 b5 02 0a 98 b8 2a f9 fe 15 44 84 a1 68'
+ }
+ ),
+ (
+ '0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20',
+ {
+ 0: 'ea a6 bd 25 88 0b f9 3d 3f 5d 1e 4c a2 61 1d 91',
+ 16: 'cf a4 5c 9f 7e 71 4b 54 bd fa 80 02 7c b1 43 80',
+ 240: '11 4a e3 44 de d7 1b 35 f2 e6 0f eb ad 72 7f d8',
+ 256: '02 e1 e7 05 6b 0f 62 39 00 49 64 22 94 3e 97 b6',
+ 496: '91 cb 93 c7 87 96 4e 10 d9 52 7d 99 9c 6f 93 6b',
+ 512: '49 b1 8b 42 f8 e8 36 7c be b5 ef 10 4b a1 c7 cd',
+ 752: '87 08 4b 3b a7 00 ba de 95 56 10 67 27 45 b3 74',
+ 768: 'e7 a7 b9 e9 ec 54 0d 5f f4 3b db 12 79 2d 1b 35',
+ 1008:'c7 99 b5 96 73 8f 6b 01 8c 76 c7 4b 17 59 bd 90',
+ 1024:'7f ec 5b fd 9f 9b 89 ce 65 48 30 90 92 d7 e9 58',
+ 1520:'40 f2 50 b2 6d 1f 09 6a 4a fd 4c 34 0a 58 88 15',
+ 1536:'3e 34 13 5c 79 db 01 02 00 76 76 51 cf 26 30 73',
+ 2032:'f6 56 ab cc f8 8d d8 27 02 7b 2c e9 17 d4 64 ec',
+ 2048:'18 b6 25 03 bf bc 07 7f ba bb 98 f2 0d 98 ab 34',
+ 3056:'8a ed 95 ee 5b 0d cb fb ef 4e b2 1d 3a 3f 52 f9',
+ 3072:'62 5a 1a b0 0e e3 9a 53 27 34 6b dd b0 1a 9c 18',
+ 4080:'a1 3a 7c 79 c7 e1 19 b5 ab 02 96 ab 28 c3 00 b9',
+ 4096:'f3 e4 c0 a2 e0 2d 1d 01 f7 f0 a7 46 18 af 2b 48'
+ }
+ ),
+ # Page 7
+ (
+ '833222772a',
+ {
+ 0: '80 ad 97 bd c9 73 df 8a 2e 87 9e 92 a4 97 ef da',
+ 16: '20 f0 60 c2 f2 e5 12 65 01 d3 d4 fe a1 0d 5f c0',
+ 240: 'fa a1 48 e9 90 46 18 1f ec 6b 20 85 f3 b2 0e d9',
+ 256: 'f0 da f5 ba b3 d5 96 83 98 57 84 6f 73 fb fe 5a',
+ 496: '1c 7e 2f c4 63 92 32 fe 29 75 84 b2 96 99 6b c8',
+ 512: '3d b9 b2 49 40 6c c8 ed ff ac 55 cc d3 22 ba 12',
+ 752: 'e4 f9 f7 e0 06 61 54 bb d1 25 b7 45 56 9b c8 97',
+ 768: '75 d5 ef 26 2b 44 c4 1a 9c f6 3a e1 45 68 e1 b9',
+ 1008:'6d a4 53 db f8 1e 82 33 4a 3d 88 66 cb 50 a1 e3',
+ 1024:'78 28 d0 74 11 9c ab 5c 22 b2 94 d7 a9 bf a0 bb',
+ 1520:'ad b8 9c ea 9a 15 fb e6 17 29 5b d0 4b 8c a0 5c',
+ 1536:'62 51 d8 7f d4 aa ae 9a 7e 4a d5 c2 17 d3 f3 00',
+ 2032:'e7 11 9b d6 dd 9b 22 af e8 f8 95 85 43 28 81 e2',
+ 2048:'78 5b 60 fd 7e c4 e9 fc b6 54 5f 35 0d 66 0f ab',
+ 3056:'af ec c0 37 fd b7 b0 83 8e b3 d7 0b cd 26 83 82',
+ 3072:'db c1 a7 b4 9d 57 35 8c c9 fa 6d 61 d7 3b 7c f0',
+ 4080:'63 49 d1 26 a3 7a fc ba 89 79 4f 98 04 91 4f dc',
+ 4096:'bf 42 c3 01 8c 2f 7c 66 bf de 52 49 75 76 81 15'
+ }
+ ),
+ (
+ '1910833222772a',
+ {
+ 0: 'bc 92 22 db d3 27 4d 8f c6 6d 14 cc bd a6 69 0b',
+ 16: '7a e6 27 41 0c 9a 2b e6 93 df 5b b7 48 5a 63 e3',
+ 240: '3f 09 31 aa 03 de fb 30 0f 06 01 03 82 6f 2a 64',
+ 256: 'be aa 9e c8 d5 9b b6 81 29 f3 02 7c 96 36 11 81',
+ 496: '74 e0 4d b4 6d 28 64 8d 7d ee 8a 00 64 b0 6c fe',
+ 512: '9b 5e 81 c6 2f e0 23 c5 5b e4 2f 87 bb f9 32 b8',
+ 752: 'ce 17 8f c1 82 6e fe cb c1 82 f5 79 99 a4 61 40',
+ 768: '8b df 55 cd 55 06 1c 06 db a6 be 11 de 4a 57 8a',
+ 1008:'62 6f 5f 4d ce 65 25 01 f3 08 7d 39 c9 2c c3 49',
+ 1024:'42 da ac 6a 8f 9a b9 a7 fd 13 7c 60 37 82 56 82',
+ 1520:'cc 03 fd b7 91 92 a2 07 31 2f 53 f5 d4 dc 33 d9',
+ 1536:'f7 0f 14 12 2a 1c 98 a3 15 5d 28 b8 a0 a8 a4 1d',
+ 2032:'2a 3a 30 7a b2 70 8a 9c 00 fe 0b 42 f9 c2 d6 a1',
+ 2048:'86 26 17 62 7d 22 61 ea b0 b1 24 65 97 ca 0a e9',
+ 3056:'55 f8 77 ce 4f 2e 1d db bf 8e 13 e2 cd e0 fd c8',
+ 3072:'1b 15 56 cb 93 5f 17 33 37 70 5f bb 5d 50 1f c1',
+ 4080:'ec d0 e9 66 02 be 7f 8d 50 92 81 6c cc f2 c2 e9',
+ 4096:'02 78 81 fa b4 99 3a 1c 26 20 24 a9 4f ff 3f 61'
+ }
+ ),
+ # Page 8
+ (
+ '641910833222772a',
+ {
+ 0: 'bb f6 09 de 94 13 17 2d 07 66 0c b6 80 71 69 26',
+ 16: '46 10 1a 6d ab 43 11 5d 6c 52 2b 4f e9 36 04 a9',
+ 240: 'cb e1 ff f2 1c 96 f3 ee f6 1e 8f e0 54 2c bd f0',
+ 256: '34 79 38 bf fa 40 09 c5 12 cf b4 03 4b 0d d1 a7',
+ 496: '78 67 a7 86 d0 0a 71 47 90 4d 76 dd f1 e5 20 e3',
+ 512: '8d 3e 9e 1c ae fc cc b3 fb f8 d1 8f 64 12 0b 32',
+ 752: '94 23 37 f8 fd 76 f0 fa e8 c5 2d 79 54 81 06 72',
+ 768: 'b8 54 8c 10 f5 16 67 f6 e6 0e 18 2f a1 9b 30 f7',
+ 1008:'02 11 c7 c6 19 0c 9e fd 12 37 c3 4c 8f 2e 06 c4',
+ 1024:'bd a6 4f 65 27 6d 2a ac b8 f9 02 12 20 3a 80 8e',
+ 1520:'bd 38 20 f7 32 ff b5 3e c1 93 e7 9d 33 e2 7c 73',
+ 1536:'d0 16 86 16 86 19 07 d4 82 e3 6c da c8 cf 57 49',
+ 2032:'97 b0 f0 f2 24 b2 d2 31 71 14 80 8f b0 3a f7 a0',
+ 2048:'e5 96 16 e4 69 78 79 39 a0 63 ce ea 9a f9 56 d1',
+ 3056:'c4 7e 0d c1 66 09 19 c1 11 01 20 8f 9e 69 aa 1f',
+ 3072:'5a e4 f1 28 96 b8 37 9a 2a ad 89 b5 b5 53 d6 b0',
+ 4080:'6b 6b 09 8d 0c 29 3b c2 99 3d 80 bf 05 18 b6 d9',
+ 4096:'81 70 cc 3c cd 92 a6 98 62 1b 93 9d d3 8f e7 b9'
+ }
+ ),
+ (
+ '8b37641910833222772a',
+ {
+ 0: 'ab 65 c2 6e dd b2 87 60 0d b2 fd a1 0d 1e 60 5c',
+ 16: 'bb 75 90 10 c2 96 58 f2 c7 2d 93 a2 d1 6d 29 30',
+ 240: 'b9 01 e8 03 6e d1 c3 83 cd 3c 4c 4d d0 a6 ab 05',
+ 256: '3d 25 ce 49 22 92 4c 55 f0 64 94 33 53 d7 8a 6c',
+ 496: '12 c1 aa 44 bb f8 7e 75 e6 11 f6 9b 2c 38 f4 9b',
+ 512: '28 f2 b3 43 4b 65 c0 98 77 47 00 44 c6 ea 17 0d',
+ 752: 'bd 9e f8 22 de 52 88 19 61 34 cf 8a f7 83 93 04',
+ 768: '67 55 9c 23 f0 52 15 84 70 a2 96 f7 25 73 5a 32',
+ 1008:'8b ab 26 fb c2 c1 2b 0f 13 e2 ab 18 5e ab f2 41',
+ 1024:'31 18 5a 6d 69 6f 0c fa 9b 42 80 8b 38 e1 32 a2',
+ 1520:'56 4d 3d ae 18 3c 52 34 c8 af 1e 51 06 1c 44 b5',
+ 1536:'3c 07 78 a7 b5 f7 2d 3c 23 a3 13 5c 7d 67 b9 f4',
+ 2032:'f3 43 69 89 0f cf 16 fb 51 7d ca ae 44 63 b2 dd',
+ 2048:'02 f3 1c 81 e8 20 07 31 b8 99 b0 28 e7 91 bf a7',
+ 3056:'72 da 64 62 83 22 8c 14 30 08 53 70 17 95 61 6f',
+ 3072:'4e 0a 8c 6f 79 34 a7 88 e2 26 5e 81 d6 d0 c8 f4',
+ 4080:'43 8d d5 ea fe a0 11 1b 6f 36 b4 b9 38 da 2a 68',
+ 4096:'5f 6b fc 73 81 58 74 d9 71 00 f0 86 97 93 57 d8'
+ }
+ ),
+ # Page 9
+ (
+ 'ebb46227c6cc8b37641910833222772a',
+ {
+ 0: '72 0c 94 b6 3e df 44 e1 31 d9 50 ca 21 1a 5a 30',
+ 16: 'c3 66 fd ea cf 9c a8 04 36 be 7c 35 84 24 d2 0b',
+ 240: 'b3 39 4a 40 aa bf 75 cb a4 22 82 ef 25 a0 05 9f',
+ 256: '48 47 d8 1d a4 94 2d bc 24 9d ef c4 8c 92 2b 9f',
+ 496: '08 12 8c 46 9f 27 53 42 ad da 20 2b 2b 58 da 95',
+ 512: '97 0d ac ef 40 ad 98 72 3b ac 5d 69 55 b8 17 61',
+ 752: '3c b8 99 93 b0 7b 0c ed 93 de 13 d2 a1 10 13 ac',
+ 768: 'ef 2d 67 6f 15 45 c2 c1 3d c6 80 a0 2f 4a db fe',
+ 1008:'b6 05 95 51 4f 24 bc 9f e5 22 a6 ca d7 39 36 44',
+ 1024:'b5 15 a8 c5 01 17 54 f5 90 03 05 8b db 81 51 4e',
+ 1520:'3c 70 04 7e 8c bc 03 8e 3b 98 20 db 60 1d a4 95',
+ 1536:'11 75 da 6e e7 56 de 46 a5 3e 2b 07 56 60 b7 70',
+ 2032:'00 a5 42 bb a0 21 11 cc 2c 65 b3 8e bd ba 58 7e',
+ 2048:'58 65 fd bb 5b 48 06 41 04 e8 30 b3 80 f2 ae de',
+ 3056:'34 b2 1a d2 ad 44 e9 99 db 2d 7f 08 63 f0 d9 b6',
+ 3072:'84 a9 21 8f c3 6e 8a 5f 2c cf be ae 53 a2 7d 25',
+ 4080:'a2 22 1a 11 b8 33 cc b4 98 a5 95 40 f0 54 5f 4a',
+ 4096:'5b be b4 78 7d 59 e5 37 3f db ea 6c 6f 75 c2 9b'
+ }
+ ),
+ (
+ 'c109163908ebe51debb46227c6cc8b37641910833222772a',
+ {
+ 0: '54 b6 4e 6b 5a 20 b5 e2 ec 84 59 3d c7 98 9d a7',
+ 16: 'c1 35 ee e2 37 a8 54 65 ff 97 dc 03 92 4f 45 ce',
+ 240: 'cf cc 92 2f b4 a1 4a b4 5d 61 75 aa bb f2 d2 01',
+ 256: '83 7b 87 e2 a4 46 ad 0e f7 98 ac d0 2b 94 12 4f',
+ 496: '17 a6 db d6 64 92 6a 06 36 b3 f4 c3 7a 4f 46 94',
+ 512: '4a 5f 9f 26 ae ee d4 d4 a2 5f 63 2d 30 52 33 d9',
+ 752: '80 a3 d0 1e f0 0c 8e 9a 42 09 c1 7f 4e eb 35 8c',
+ 768: 'd1 5e 7d 5f fa aa bc 02 07 bf 20 0a 11 77 93 a2',
+ 1008:'34 96 82 bf 58 8e aa 52 d0 aa 15 60 34 6a ea fa',
+ 1024:'f5 85 4c db 76 c8 89 e3 ad 63 35 4e 5f 72 75 e3',
+ 1520:'53 2c 7c ec cb 39 df 32 36 31 84 05 a4 b1 27 9c',
+ 1536:'ba ef e6 d9 ce b6 51 84 22 60 e0 d1 e0 5e 3b 90',
+ 2032:'e8 2d 8c 6d b5 4e 3c 63 3f 58 1c 95 2b a0 42 07',
+ 2048:'4b 16 e5 0a bd 38 1b d7 09 00 a9 cd 9a 62 cb 23',
+ 3056:'36 82 ee 33 bd 14 8b d9 f5 86 56 cd 8f 30 d9 fb',
+ 3072:'1e 5a 0b 84 75 04 5d 9b 20 b2 62 86 24 ed fd 9e',
+ 4080:'63 ed d6 84 fb 82 62 82 fe 52 8f 9c 0e 92 37 bc',
+ 4096:'e4 dd 2e 98 d6 96 0f ae 0b 43 54 54 56 74 33 91'
+ }
+ ),
+ # Page 10
+ (
+ '1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a',
+ {
+ 0: 'dd 5b cb 00 18 e9 22 d4 94 75 9d 7c 39 5d 02 d3',
+ 16: 'c8 44 6f 8f 77 ab f7 37 68 53 53 eb 89 a1 c9 eb',
+ 240: 'af 3e 30 f9 c0 95 04 59 38 15 15 75 c3 fb 90 98',
+ 256: 'f8 cb 62 74 db 99 b8 0b 1d 20 12 a9 8e d4 8f 0e',
+ 496: '25 c3 00 5a 1c b8 5d e0 76 25 98 39 ab 71 98 ab',
+ 512: '9d cb c1 83 e8 cb 99 4b 72 7b 75 be 31 80 76 9c',
+ 752: 'a1 d3 07 8d fa 91 69 50 3e d9 d4 49 1d ee 4e b2',
+ 768: '85 14 a5 49 58 58 09 6f 59 6e 4b cd 66 b1 06 65',
+ 1008:'5f 40 d5 9e c1 b0 3b 33 73 8e fa 60 b2 25 5d 31',
+ 1024:'34 77 c7 f7 64 a4 1b ac ef f9 0b f1 4f 92 b7 cc',
+ 1520:'ac 4e 95 36 8d 99 b9 eb 78 b8 da 8f 81 ff a7 95',
+ 1536:'8c 3c 13 f8 c2 38 8b b7 3f 38 57 6e 65 b7 c4 46',
+ 2032:'13 c4 b9 c1 df b6 65 79 ed dd 8a 28 0b 9f 73 16',
+ 2048:'dd d2 78 20 55 01 26 69 8e fa ad c6 4b 64 f6 6e',
+ 3056:'f0 8f 2e 66 d2 8e d1 43 f3 a2 37 cf 9d e7 35 59',
+ 3072:'9e a3 6c 52 55 31 b8 80 ba 12 43 34 f5 7b 0b 70',
+ 4080:'d5 a3 9e 3d fc c5 02 80 ba c4 a6 b5 aa 0d ca 7d',
+ 4096:'37 0b 1c 1f e6 55 91 6d 97 fd 0d 47 ca 1d 72 b8'
+ }
+ )
+ ]
+
+ def test_keystream(self):
+ for tv in self.rfc6229_data:
+ key = unhexlify(b((tv[0])))
+ cipher = ARC4.new(key)
+ count = 0
+ for offset in range(0,4096+1,16):
+ ct = cipher.encrypt(b('\x00')*16)
+ expected = tv[1].get(offset)
+ if expected:
+ expected = unhexlify(b(expected.replace(" ",'')))
+ self.assertEqual(ct, expected)
+ count += 1
+ self.assertEqual(count, len(tv[1]))
+
+class Drop_Tests(unittest.TestCase):
+ key = b('\xAA')*16
+ data = b('\x00')*5000
+
+ def setUp(self):
+ self.cipher = ARC4.new(self.key)
+
+ def test_drop256_encrypt(self):
+ cipher_drop = ARC4.new(self.key, 256)
+ ct_drop = cipher_drop.encrypt(self.data[:16])
+ ct = self.cipher.encrypt(self.data)[256:256+16]
+ self.assertEqual(ct_drop, ct)
+
+ def test_drop256_decrypt(self):
+ cipher_drop = ARC4.new(self.key, 256)
+ pt_drop = cipher_drop.decrypt(self.data[:16])
+ pt = self.cipher.decrypt(self.data)[256:256+16]
+ self.assertEqual(pt_drop, pt)
+
+
+class KeyLength(unittest.TestCase):
+
+ def runTest(self):
+ self.assertRaises(ValueError, ARC4.new, bchr(0) * 4)
+ self.assertRaises(ValueError, ARC4.new, bchr(0) * 257)
+
+
+def get_tests(config={}):
+ from .common import make_stream_tests
+ tests = make_stream_tests(ARC4, "ARC4", test_data)
+ tests += list_test_cases(RFC6229_Tests)
+ tests += list_test_cases(Drop_Tests)
+ tests.append(KeyLength())
+ return tests
+
+if __name__ == '__main__':
+ import unittest
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
+
+# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/SelfTest/Cipher/test_Blowfish.py b/lib/Crypto/SelfTest/Cipher/test_Blowfish.py
new file mode 100644
index 0000000..4ce3a41
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_Blowfish.py
@@ -0,0 +1,160 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Cipher/test_Blowfish.py: Self-test for the Blowfish cipher
+#
+# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+"""Self-test suite for Crypto.Cipher.Blowfish"""
+
+import unittest
+
+from Crypto.Util.py3compat import bchr
+
+from Crypto.Cipher import Blowfish
+
+# This is a list of (plaintext, ciphertext, key) tuples.
+test_data = [
+ # Test vectors from http://www.schneier.com/code/vectors.txt
+ ('0000000000000000', '4ef997456198dd78', '0000000000000000'),
+ ('ffffffffffffffff', '51866fd5b85ecb8a', 'ffffffffffffffff'),
+ ('1000000000000001', '7d856f9a613063f2', '3000000000000000'),
+ ('1111111111111111', '2466dd878b963c9d', '1111111111111111'),
+ ('1111111111111111', '61f9c3802281b096', '0123456789abcdef'),
+ ('0123456789abcdef', '7d0cc630afda1ec7', '1111111111111111'),
+ ('0000000000000000', '4ef997456198dd78', '0000000000000000'),
+ ('0123456789abcdef', '0aceab0fc6a0a28d', 'fedcba9876543210'),
+ ('01a1d6d039776742', '59c68245eb05282b', '7ca110454a1a6e57'),
+ ('5cd54ca83def57da', 'b1b8cc0b250f09a0', '0131d9619dc1376e'),
+ ('0248d43806f67172', '1730e5778bea1da4', '07a1133e4a0b2686'),
+ ('51454b582ddf440a', 'a25e7856cf2651eb', '3849674c2602319e'),
+ ('42fd443059577fa2', '353882b109ce8f1a', '04b915ba43feb5b6'),
+ ('059b5e0851cf143a', '48f4d0884c379918', '0113b970fd34f2ce'),
+ ('0756d8e0774761d2', '432193b78951fc98', '0170f175468fb5e6'),
+ ('762514b829bf486a', '13f04154d69d1ae5', '43297fad38e373fe'),
+ ('3bdd119049372802', '2eedda93ffd39c79', '07a7137045da2a16'),
+ ('26955f6835af609a', 'd887e0393c2da6e3', '04689104c2fd3b2f'),
+ ('164d5e404f275232', '5f99d04f5b163969', '37d06bb516cb7546'),
+ ('6b056e18759f5cca', '4a057a3b24d3977b', '1f08260d1ac2465e'),
+ ('004bd6ef09176062', '452031c1e4fada8e', '584023641aba6176'),
+ ('480d39006ee762f2', '7555ae39f59b87bd', '025816164629b007'),
+ ('437540c8698f3cfa', '53c55f9cb49fc019', '49793ebc79b3258f'),
+ ('072d43a077075292', '7a8e7bfa937e89a3', '4fb05e1515ab73a7'),
+ ('02fe55778117f12a', 'cf9c5d7a4986adb5', '49e95d6d4ca229bf'),
+ ('1d9d5c5018f728c2', 'd1abb290658bc778', '018310dc409b26d6'),
+ ('305532286d6f295a', '55cb3774d13ef201', '1c587f1c13924fef'),
+ ('0123456789abcdef', 'fa34ec4847b268b2', '0101010101010101'),
+ ('0123456789abcdef', 'a790795108ea3cae', '1f1f1f1f0e0e0e0e'),
+ ('0123456789abcdef', 'c39e072d9fac631d', 'e0fee0fef1fef1fe'),
+ ('ffffffffffffffff', '014933e0cdaff6e4', '0000000000000000'),
+ ('0000000000000000', 'f21e9a77b71c49bc', 'ffffffffffffffff'),
+ ('0000000000000000', '245946885754369a', '0123456789abcdef'),
+ ('ffffffffffffffff', '6b5c5a9c5d9e0a5a', 'fedcba9876543210'),
+ #('fedcba9876543210', 'f9ad597c49db005e', 'f0'),
+ #('fedcba9876543210', 'e91d21c1d961a6d6', 'f0e1'),
+ #('fedcba9876543210', 'e9c2b70a1bc65cf3', 'f0e1d2'),
+ ('fedcba9876543210', 'be1e639408640f05', 'f0e1d2c3'),
+ ('fedcba9876543210', 'b39e44481bdb1e6e', 'f0e1d2c3b4'),
+ ('fedcba9876543210', '9457aa83b1928c0d', 'f0e1d2c3b4a5'),
+ ('fedcba9876543210', '8bb77032f960629d', 'f0e1d2c3b4a596'),
+ ('fedcba9876543210', 'e87a244e2cc85e82', 'f0e1d2c3b4a59687'),
+ ('fedcba9876543210', '15750e7a4f4ec577', 'f0e1d2c3b4a5968778'),
+ ('fedcba9876543210', '122ba70b3ab64ae0', 'f0e1d2c3b4a596877869'),
+ ('fedcba9876543210', '3a833c9affc537f6', 'f0e1d2c3b4a5968778695a'),
+ ('fedcba9876543210', '9409da87a90f6bf2', 'f0e1d2c3b4a5968778695a4b'),
+ ('fedcba9876543210', '884f80625060b8b4', 'f0e1d2c3b4a5968778695a4b3c'),
+ ('fedcba9876543210', '1f85031c19e11968', 'f0e1d2c3b4a5968778695a4b3c2d'),
+ ('fedcba9876543210', '79d9373a714ca34f', 'f0e1d2c3b4a5968778695a4b3c2d1e'),
+ ('fedcba9876543210', '93142887ee3be15c',
+ 'f0e1d2c3b4a5968778695a4b3c2d1e0f'),
+ ('fedcba9876543210', '03429e838ce2d14b',
+ 'f0e1d2c3b4a5968778695a4b3c2d1e0f00'),
+ ('fedcba9876543210', 'a4299e27469ff67b',
+ 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011'),
+ ('fedcba9876543210', 'afd5aed1c1bc96a8',
+ 'f0e1d2c3b4a5968778695a4b3c2d1e0f001122'),
+ ('fedcba9876543210', '10851c0e3858da9f',
+ 'f0e1d2c3b4a5968778695a4b3c2d1e0f00112233'),
+ ('fedcba9876543210', 'e6f51ed79b9db21f',
+ 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344'),
+ ('fedcba9876543210', '64a6e14afd36b46f',
+ 'f0e1d2c3b4a5968778695a4b3c2d1e0f001122334455'),
+ ('fedcba9876543210', '80c7d7d45a5479ad',
+ 'f0e1d2c3b4a5968778695a4b3c2d1e0f00112233445566'),
+ ('fedcba9876543210', '05044b62fa52d080',
+ 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344556677'),
+]
+
+
+class KeyLength(unittest.TestCase):
+
+ def runTest(self):
+ self.assertRaises(ValueError, Blowfish.new, bchr(0) * 3,
+ Blowfish.MODE_ECB)
+ self.assertRaises(ValueError, Blowfish.new, bchr(0) * 57,
+ Blowfish.MODE_ECB)
+
+
+class TestOutput(unittest.TestCase):
+
+ def runTest(self):
+ # Encrypt/Decrypt data and test output parameter
+
+ cipher = Blowfish.new(b'4'*16, Blowfish.MODE_ECB)
+
+ pt = b'5' * 16
+ ct = cipher.encrypt(pt)
+
+ output = bytearray(16)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ output = memoryview(bytearray(16))
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16)
+
+ shorter_output = bytearray(7)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+def get_tests(config={}):
+ from .common import make_block_tests
+ tests = make_block_tests(Blowfish, "Blowfish", test_data)
+ tests.append(KeyLength())
+ tests += [TestOutput()]
+ return tests
+
+
+if __name__ == '__main__':
+ import unittest
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_CAST.py b/lib/Crypto/SelfTest/Cipher/test_CAST.py
new file mode 100644
index 0000000..ff13bd4
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_CAST.py
@@ -0,0 +1,101 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Cipher/CAST.py: Self-test for the CAST-128 (CAST5) cipher
+#
+# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+"""Self-test suite for Crypto.Cipher.CAST"""
+
+import unittest
+
+from Crypto.Util.py3compat import bchr
+
+from Crypto.Cipher import CAST
+
+# This is a list of (plaintext, ciphertext, key) tuples.
+test_data = [
+ # Test vectors from RFC 2144, B.1
+ ('0123456789abcdef', '238b4fe5847e44b2',
+ '0123456712345678234567893456789a',
+ '128-bit key'),
+
+ ('0123456789abcdef', 'eb6a711a2c02271b',
+ '01234567123456782345',
+ '80-bit key'),
+
+ ('0123456789abcdef', '7ac816d16e9b302e',
+ '0123456712',
+ '40-bit key'),
+]
+
+
+class KeyLength(unittest.TestCase):
+
+ def runTest(self):
+ self.assertRaises(ValueError, CAST.new, bchr(0) * 4, CAST.MODE_ECB)
+ self.assertRaises(ValueError, CAST.new, bchr(0) * 17, CAST.MODE_ECB)
+
+
+class TestOutput(unittest.TestCase):
+
+ def runTest(self):
+ # Encrypt/Decrypt data and test output parameter
+
+ cipher = CAST.new(b'4'*16, CAST.MODE_ECB)
+
+ pt = b'5' * 16
+ ct = cipher.encrypt(pt)
+
+ output = bytearray(16)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ output = memoryview(bytearray(16))
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16)
+
+ shorter_output = bytearray(7)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+def get_tests(config={}):
+ from .common import make_block_tests
+
+ tests = make_block_tests(CAST, "CAST", test_data)
+ tests.append(KeyLength())
+ tests.append(TestOutput())
+ return tests
+
+if __name__ == '__main__':
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_CBC.py b/lib/Crypto/SelfTest/Cipher/test_CBC.py
new file mode 100644
index 0000000..374fb5a
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_CBC.py
@@ -0,0 +1,556 @@
+# ===================================================================
+#
+# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+import unittest
+from binascii import unhexlify
+
+from Crypto.SelfTest.loader import load_test_vectors
+from Crypto.SelfTest.st_common import list_test_cases
+from Crypto.Util.py3compat import tobytes, is_string
+from Crypto.Cipher import AES, DES3, DES
+from Crypto.Hash import SHAKE128
+
+
+def get_tag_random(tag, length):
+ return SHAKE128.new(data=tobytes(tag)).read(length)
+
+class BlockChainingTests(unittest.TestCase):
+
+ key_128 = get_tag_random("key_128", 16)
+ key_192 = get_tag_random("key_192", 24)
+ iv_128 = get_tag_random("iv_128", 16)
+ iv_64 = get_tag_random("iv_64", 8)
+ data_128 = get_tag_random("data_128", 16)
+
+ def test_loopback_128(self):
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ pt = get_tag_random("plaintext", 16 * 100)
+ ct = cipher.encrypt(pt)
+
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def test_loopback_64(self):
+ cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64)
+ pt = get_tag_random("plaintext", 8 * 100)
+ ct = cipher.encrypt(pt)
+
+ cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def test_iv(self):
+ # If not passed, the iv is created randomly
+ cipher = AES.new(self.key_128, self.aes_mode)
+ iv1 = cipher.iv
+ cipher = AES.new(self.key_128, self.aes_mode)
+ iv2 = cipher.iv
+ self.assertNotEqual(iv1, iv2)
+ self.assertEqual(len(iv1), 16)
+
+ # IV can be passed in uppercase or lowercase
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ ct = cipher.encrypt(self.data_128)
+
+ cipher = AES.new(self.key_128, self.aes_mode, iv=self.iv_128)
+ self.assertEqual(ct, cipher.encrypt(self.data_128))
+
+ cipher = AES.new(self.key_128, self.aes_mode, IV=self.iv_128)
+ self.assertEqual(ct, cipher.encrypt(self.data_128))
+
+ def test_iv_must_be_bytes(self):
+ self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode,
+ iv = u'test1234567890-*')
+
+ def test_only_one_iv(self):
+ # Only one IV/iv keyword allowed
+ self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode,
+ iv=self.iv_128, IV=self.iv_128)
+
+ def test_iv_with_matching_length(self):
+ self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode,
+ b"")
+ self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode,
+ self.iv_128[:15])
+ self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode,
+ self.iv_128 + b"0")
+
+ def test_block_size_128(self):
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ self.assertEqual(cipher.block_size, AES.block_size)
+
+ def test_block_size_64(self):
+ cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64)
+ self.assertEqual(cipher.block_size, DES3.block_size)
+
+ def test_unaligned_data_128(self):
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ for wrong_length in range(1,16):
+ self.assertRaises(ValueError, cipher.encrypt, b"5" * wrong_length)
+
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ for wrong_length in range(1,16):
+ self.assertRaises(ValueError, cipher.decrypt, b"5" * wrong_length)
+
+ def test_unaligned_data_64(self):
+ cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64)
+ for wrong_length in range(1,8):
+ self.assertRaises(ValueError, cipher.encrypt, b"5" * wrong_length)
+
+ cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64)
+ for wrong_length in range(1,8):
+ self.assertRaises(ValueError, cipher.decrypt, b"5" * wrong_length)
+
+ def test_IV_iv_attributes(self):
+ data = get_tag_random("data", 16 * 100)
+ for func in "encrypt", "decrypt":
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ getattr(cipher, func)(data)
+ self.assertEqual(cipher.iv, self.iv_128)
+ self.assertEqual(cipher.IV, self.iv_128)
+
+ def test_unknown_parameters(self):
+ self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode,
+ self.iv_128, 7)
+ self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode,
+ iv=self.iv_128, unknown=7)
+ # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module)
+ AES.new(self.key_128, self.aes_mode, iv=self.iv_128, use_aesni=False)
+
+ def test_null_encryption_decryption(self):
+ for func in "encrypt", "decrypt":
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ result = getattr(cipher, func)(b"")
+ self.assertEqual(result, b"")
+
+ def test_either_encrypt_or_decrypt(self):
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ cipher.encrypt(b"")
+ self.assertRaises(TypeError, cipher.decrypt, b"")
+
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ cipher.decrypt(b"")
+ self.assertRaises(TypeError, cipher.encrypt, b"")
+
+ def test_data_must_be_bytes(self):
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*')
+
+ cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*')
+
+ def test_bytearray(self):
+ data = b"1" * 128
+ data_ba = bytearray(data)
+
+ # Encrypt
+ key_ba = bytearray(self.key_128)
+ iv_ba = bytearray(self.iv_128)
+
+ cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ ref1 = cipher1.encrypt(data)
+
+ cipher2 = AES.new(key_ba, self.aes_mode, iv_ba)
+ key_ba[:3] = b'\xFF\xFF\xFF'
+ iv_ba[:3] = b'\xFF\xFF\xFF'
+ ref2 = cipher2.encrypt(data_ba)
+
+ self.assertEqual(ref1, ref2)
+ self.assertEqual(cipher1.iv, cipher2.iv)
+
+ # Decrypt
+ key_ba = bytearray(self.key_128)
+ iv_ba = bytearray(self.iv_128)
+
+ cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ ref3 = cipher3.decrypt(data)
+
+ cipher4 = AES.new(key_ba, self.aes_mode, iv_ba)
+ key_ba[:3] = b'\xFF\xFF\xFF'
+ iv_ba[:3] = b'\xFF\xFF\xFF'
+ ref4 = cipher4.decrypt(data_ba)
+
+ self.assertEqual(ref3, ref4)
+
+ def test_memoryview(self):
+ data = b"1" * 128
+ data_mv = memoryview(bytearray(data))
+
+ # Encrypt
+ key_mv = memoryview(bytearray(self.key_128))
+ iv_mv = memoryview(bytearray(self.iv_128))
+
+ cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ ref1 = cipher1.encrypt(data)
+
+ cipher2 = AES.new(key_mv, self.aes_mode, iv_mv)
+ key_mv[:3] = b'\xFF\xFF\xFF'
+ iv_mv[:3] = b'\xFF\xFF\xFF'
+ ref2 = cipher2.encrypt(data_mv)
+
+ self.assertEqual(ref1, ref2)
+ self.assertEqual(cipher1.iv, cipher2.iv)
+
+ # Decrypt
+ key_mv = memoryview(bytearray(self.key_128))
+ iv_mv = memoryview(bytearray(self.iv_128))
+
+ cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128)
+ ref3 = cipher3.decrypt(data)
+
+ cipher4 = AES.new(key_mv, self.aes_mode, iv_mv)
+ key_mv[:3] = b'\xFF\xFF\xFF'
+ iv_mv[:3] = b'\xFF\xFF\xFF'
+ ref4 = cipher4.decrypt(data_mv)
+
+ self.assertEqual(ref3, ref4)
+
+ def test_output_param(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ ct = cipher.encrypt(pt)
+
+ output = bytearray(128)
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+
+ def test_output_param_same_buffer(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ ct = cipher.encrypt(pt)
+
+ pt_ba = bytearray(pt)
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ res = cipher.encrypt(pt_ba, output=pt_ba)
+ self.assertEqual(ct, pt_ba)
+ self.assertEqual(res, None)
+
+ ct_ba = bytearray(ct)
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ res = cipher.decrypt(ct_ba, output=ct_ba)
+ self.assertEqual(pt, ct_ba)
+ self.assertEqual(res, None)
+
+
+ def test_output_param_memoryview(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ ct = cipher.encrypt(pt)
+
+ output = memoryview(bytearray(128))
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ def test_output_param_neg(self):
+ LEN_PT = 128
+
+ pt = b'5' * LEN_PT
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ ct = cipher.encrypt(pt)
+
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT)
+
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT)
+
+ shorter_output = bytearray(LEN_PT - 1)
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+ cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+class CbcTests(BlockChainingTests):
+ aes_mode = AES.MODE_CBC
+ des3_mode = DES3.MODE_CBC
+
+
+class NistBlockChainingVectors(unittest.TestCase):
+
+ def _do_kat_aes_test(self, file_name):
+
+ test_vectors = load_test_vectors(("Cipher", "AES"),
+ file_name,
+ "AES CBC KAT",
+ { "count" : lambda x: int(x) } )
+ if test_vectors is None:
+ return
+
+ direction = None
+ for tv in test_vectors:
+
+ # The test vector file contains some directive lines
+ if is_string(tv):
+ direction = tv
+ continue
+
+ self.description = tv.desc
+
+ cipher = AES.new(tv.key, self.aes_mode, tv.iv)
+ if direction == "[ENCRYPT]":
+ self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext)
+ elif direction == "[DECRYPT]":
+ self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext)
+ else:
+ assert False
+
+ # See Section 6.4.2 in AESAVS
+ def _do_mct_aes_test(self, file_name):
+
+ test_vectors = load_test_vectors(("Cipher", "AES"),
+ file_name,
+ "AES CBC Montecarlo",
+ { "count" : lambda x: int(x) } )
+ if test_vectors is None:
+ return
+
+ direction = None
+ for tv in test_vectors:
+
+ # The test vector file contains some directive lines
+ if is_string(tv):
+ direction = tv
+ continue
+
+ self.description = tv.desc
+ cipher = AES.new(tv.key, self.aes_mode, tv.iv)
+
+ if direction == '[ENCRYPT]':
+ cts = [ tv.iv ]
+ for count in range(1000):
+ cts.append(cipher.encrypt(tv.plaintext))
+ tv.plaintext = cts[-2]
+ self.assertEqual(cts[-1], tv.ciphertext)
+ elif direction == '[DECRYPT]':
+ pts = [ tv.iv]
+ for count in range(1000):
+ pts.append(cipher.decrypt(tv.ciphertext))
+ tv.ciphertext = pts[-2]
+ self.assertEqual(pts[-1], tv.plaintext)
+ else:
+ assert False
+
+ def _do_tdes_test(self, file_name):
+
+ test_vectors = load_test_vectors(("Cipher", "TDES"),
+ file_name,
+ "TDES CBC KAT",
+ { "count" : lambda x: int(x) } )
+ if test_vectors is None:
+ return
+
+ direction = None
+ for tv in test_vectors:
+
+ # The test vector file contains some directive lines
+ if is_string(tv):
+ direction = tv
+ continue
+
+ self.description = tv.desc
+ if hasattr(tv, "keys"):
+ cipher = DES.new(tv.keys, self.des_mode, tv.iv)
+ else:
+ if tv.key1 != tv.key3:
+ key = tv.key1 + tv.key2 + tv.key3 # Option 3
+ else:
+ key = tv.key1 + tv.key2 # Option 2
+ cipher = DES3.new(key, self.des3_mode, tv.iv)
+
+ if direction == "[ENCRYPT]":
+ self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext)
+ elif direction == "[DECRYPT]":
+ self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext)
+ else:
+ assert False
+
+
+class NistCbcVectors(NistBlockChainingVectors):
+ aes_mode = AES.MODE_CBC
+ des_mode = DES.MODE_CBC
+ des3_mode = DES3.MODE_CBC
+
+
+# Create one test method per file
+nist_aes_kat_mmt_files = (
+ # KAT
+ "CBCGFSbox128.rsp",
+ "CBCGFSbox192.rsp",
+ "CBCGFSbox256.rsp",
+ "CBCKeySbox128.rsp",
+ "CBCKeySbox192.rsp",
+ "CBCKeySbox256.rsp",
+ "CBCVarKey128.rsp",
+ "CBCVarKey192.rsp",
+ "CBCVarKey256.rsp",
+ "CBCVarTxt128.rsp",
+ "CBCVarTxt192.rsp",
+ "CBCVarTxt256.rsp",
+ # MMT
+ "CBCMMT128.rsp",
+ "CBCMMT192.rsp",
+ "CBCMMT256.rsp",
+ )
+nist_aes_mct_files = (
+ "CBCMCT128.rsp",
+ "CBCMCT192.rsp",
+ "CBCMCT256.rsp",
+ )
+
+for file_name in nist_aes_kat_mmt_files:
+ def new_func(self, file_name=file_name):
+ self._do_kat_aes_test(file_name)
+ setattr(NistCbcVectors, "test_AES_" + file_name, new_func)
+
+for file_name in nist_aes_mct_files:
+ def new_func(self, file_name=file_name):
+ self._do_mct_aes_test(file_name)
+ setattr(NistCbcVectors, "test_AES_" + file_name, new_func)
+del file_name, new_func
+
+nist_tdes_files = (
+ "TCBCMMT2.rsp", # 2TDES
+ "TCBCMMT3.rsp", # 3TDES
+ "TCBCinvperm.rsp", # Single DES
+ "TCBCpermop.rsp",
+ "TCBCsubtab.rsp",
+ "TCBCvarkey.rsp",
+ "TCBCvartext.rsp",
+ )
+
+for file_name in nist_tdes_files:
+ def new_func(self, file_name=file_name):
+ self._do_tdes_test(file_name)
+ setattr(NistCbcVectors, "test_TDES_" + file_name, new_func)
+
+# END OF NIST CBC TEST VECTORS
+
+
+class SP800TestVectors(unittest.TestCase):
+ """Class exercising the CBC test vectors found in Section F.2
+ of NIST SP 800-3A"""
+
+ def test_aes_128(self):
+ key = '2b7e151628aed2a6abf7158809cf4f3c'
+ iv = '000102030405060708090a0b0c0d0e0f'
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ ciphertext = '7649abac8119b246cee98e9b12e9197d' +\
+ '5086cb9b507219ee95db113a917678b2' +\
+ '73bed6b8e3c1743b7116e69e22229516' +\
+ '3ff1caa1681fac09120eca307586e1a7'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CBC, iv)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CBC, iv)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ def test_aes_192(self):
+ key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'
+ iv = '000102030405060708090a0b0c0d0e0f'
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ ciphertext = '4f021db243bc633d7178183a9fa071e8' +\
+ 'b4d9ada9ad7dedf4e5e738763f69145a' +\
+ '571b242012fb7ae07fa9baac3df102e0' +\
+ '08b0e27988598881d920a9e64f5615cd'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CBC, iv)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CBC, iv)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ def test_aes_256(self):
+ key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'
+ iv = '000102030405060708090a0b0c0d0e0f'
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ ciphertext = 'f58c4c04d6e5f1ba779eabfb5f7bfbd6' +\
+ '9cfc4e967edb808d679f777bc6702c7d' +\
+ '39f23369a9d9bacfa530e26304231461' +\
+ 'b2eb05e2c39be9fcda6c19078c6a9d1b'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CBC, iv)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CBC, iv)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+
+def get_tests(config={}):
+ tests = []
+ tests += list_test_cases(CbcTests)
+ if config.get('slow_tests'):
+ tests += list_test_cases(NistCbcVectors)
+ tests += list_test_cases(SP800TestVectors)
+ return tests
+
+
+if __name__ == '__main__':
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_CCM.py b/lib/Crypto/SelfTest/Cipher/test_CCM.py
new file mode 100644
index 0000000..e8ebc0b
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_CCM.py
@@ -0,0 +1,936 @@
+# ===================================================================
+#
+# Copyright (c) 2015, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+import unittest
+from binascii import unhexlify
+
+from Crypto.SelfTest.st_common import list_test_cases
+from Crypto.SelfTest.loader import load_test_vectors_wycheproof
+from Crypto.Util.py3compat import tobytes, bchr
+from Crypto.Cipher import AES
+from Crypto.Hash import SHAKE128
+
+from Crypto.Util.strxor import strxor
+
+
+def get_tag_random(tag, length):
+ return SHAKE128.new(data=tobytes(tag)).read(length)
+
+
+class CcmTests(unittest.TestCase):
+
+ key_128 = get_tag_random("key_128", 16)
+ nonce_96 = get_tag_random("nonce_128", 12)
+ data = get_tag_random("data", 128)
+
+ def test_loopback_128(self):
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ pt = get_tag_random("plaintext", 16 * 100)
+ ct = cipher.encrypt(pt)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def test_nonce(self):
+ # If not passed, the nonce is created randomly
+ cipher = AES.new(self.key_128, AES.MODE_CCM)
+ nonce1 = cipher.nonce
+ cipher = AES.new(self.key_128, AES.MODE_CCM)
+ nonce2 = cipher.nonce
+ self.assertEqual(len(nonce1), 11)
+ self.assertNotEqual(nonce1, nonce2)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, self.nonce_96)
+ ct = cipher.encrypt(self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ self.assertEqual(ct, cipher.encrypt(self.data))
+
+ def test_nonce_must_be_bytes(self):
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM,
+ nonce=u'test12345678')
+
+ def test_nonce_length(self):
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM,
+ nonce=b"")
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM,
+ nonce=bchr(1) * 6)
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM,
+ nonce=bchr(1) * 14)
+ for x in range(7, 13 + 1):
+ AES.new(self.key_128, AES.MODE_CCM, nonce=bchr(1) * x)
+
+ def test_block_size(self):
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ self.assertEqual(cipher.block_size, AES.block_size)
+
+ def test_nonce_attribute(self):
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ self.assertEqual(cipher.nonce, self.nonce_96)
+
+ # By default, a 11 bytes long nonce is randomly generated
+ nonce1 = AES.new(self.key_128, AES.MODE_CCM).nonce
+ nonce2 = AES.new(self.key_128, AES.MODE_CCM).nonce
+ self.assertEqual(len(nonce1), 11)
+ self.assertNotEqual(nonce1, nonce2)
+
+ def test_unknown_parameters(self):
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM,
+ self.nonce_96, 7)
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM,
+ nonce=self.nonce_96, unknown=7)
+
+ # But some are only known by the base cipher
+ # (e.g. use_aesni consumed by the AES module)
+ AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ use_aesni=False)
+
+ def test_null_encryption_decryption(self):
+ for func in "encrypt", "decrypt":
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ result = getattr(cipher, func)(b"")
+ self.assertEqual(result, b"")
+
+ def test_either_encrypt_or_decrypt(self):
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.encrypt(b"")
+ self.assertRaises(TypeError, cipher.decrypt, b"")
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.decrypt(b"")
+ self.assertRaises(TypeError, cipher.encrypt, b"")
+
+ def test_data_must_be_bytes(self):
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*')
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*')
+
+ def test_mac_len(self):
+ # Invalid MAC length
+ for mac_len in range(3, 17 + 1, 2):
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM,
+ nonce=self.nonce_96, mac_len=mac_len)
+
+ # Valid MAC length
+ for mac_len in range(4, 16 + 1, 2):
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ mac_len=mac_len)
+ _, mac = cipher.encrypt_and_digest(self.data)
+ self.assertEqual(len(mac), mac_len)
+
+ # Default MAC length
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ _, mac = cipher.encrypt_and_digest(self.data)
+ self.assertEqual(len(mac), 16)
+
+ def test_invalid_mac(self):
+ from Crypto.Util.strxor import strxor_c
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ ct, mac = cipher.encrypt_and_digest(self.data)
+
+ invalid_mac = strxor_c(mac, 0x01)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.decrypt_and_verify, ct,
+ invalid_mac)
+
+ def test_hex_mac(self):
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ mac_hex = cipher.hexdigest()
+ self.assertEqual(cipher.digest(), unhexlify(mac_hex))
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.hexverify(mac_hex)
+
+ def test_longer_assoc_data_than_declared(self):
+ # More than zero
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ assoc_len=0)
+ self.assertRaises(ValueError, cipher.update, b"1")
+
+ # Too large
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ assoc_len=15)
+ self.assertRaises(ValueError, cipher.update, self.data)
+
+ def test_shorter_assoc_data_than_expected(self):
+ DATA_LEN = len(self.data)
+
+ # With plaintext
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ assoc_len=DATA_LEN + 1)
+ cipher.update(self.data)
+ self.assertRaises(ValueError, cipher.encrypt, self.data)
+
+ # With empty plaintext
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ assoc_len=DATA_LEN + 1)
+ cipher.update(self.data)
+ self.assertRaises(ValueError, cipher.digest)
+
+ # With ciphertext
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ assoc_len=DATA_LEN + 1)
+ cipher.update(self.data)
+ self.assertRaises(ValueError, cipher.decrypt, self.data)
+
+ # With empty ciphertext
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.update(self.data)
+ mac = cipher.digest()
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ assoc_len=DATA_LEN + 1)
+ cipher.update(self.data)
+ self.assertRaises(ValueError, cipher.verify, mac)
+
+ def test_shorter_and_longer_plaintext_than_declared(self):
+ DATA_LEN = len(self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ msg_len=DATA_LEN + 1)
+ cipher.encrypt(self.data)
+ self.assertRaises(ValueError, cipher.digest)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ msg_len=DATA_LEN - 1)
+ self.assertRaises(ValueError, cipher.encrypt, self.data)
+
+ def test_shorter_ciphertext_than_declared(self):
+ DATA_LEN = len(self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ ct, mac = cipher.encrypt_and_digest(self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ msg_len=DATA_LEN + 1)
+ cipher.decrypt(ct)
+ self.assertRaises(ValueError, cipher.verify, mac)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ msg_len=DATA_LEN - 1)
+ self.assertRaises(ValueError, cipher.decrypt, ct)
+
+ def test_message_chunks(self):
+ # Validate that both associated data and plaintext/ciphertext
+ # can be broken up in chunks of arbitrary length
+
+ auth_data = get_tag_random("authenticated data", 127)
+ plaintext = get_tag_random("plaintext", 127)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.update(auth_data)
+ ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext)
+
+ def break_up(data, chunk_length):
+ return [data[i:i+chunk_length] for i in range(0, len(data),
+ chunk_length)]
+
+ # Encryption
+ for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128:
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ msg_len=127, assoc_len=127)
+
+ for chunk in break_up(auth_data, chunk_length):
+ cipher.update(chunk)
+ pt2 = b""
+ for chunk in break_up(ciphertext, chunk_length):
+ pt2 += cipher.decrypt(chunk)
+ self.assertEqual(plaintext, pt2)
+ cipher.verify(ref_mac)
+
+ # Decryption
+ for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128:
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
+ msg_len=127, assoc_len=127)
+
+ for chunk in break_up(auth_data, chunk_length):
+ cipher.update(chunk)
+ ct2 = b""
+ for chunk in break_up(plaintext, chunk_length):
+ ct2 += cipher.encrypt(chunk)
+ self.assertEqual(ciphertext, ct2)
+ self.assertEqual(cipher.digest(), ref_mac)
+
+ def test_bytearray(self):
+
+ # Encrypt
+ key_ba = bytearray(self.key_128)
+ nonce_ba = bytearray(self.nonce_96)
+ header_ba = bytearray(self.data)
+ data_ba = bytearray(self.data)
+
+ cipher1 = AES.new(self.key_128,
+ AES.MODE_CCM,
+ nonce=self.nonce_96)
+ cipher1.update(self.data)
+ ct = cipher1.encrypt(self.data)
+ tag = cipher1.digest()
+
+ cipher2 = AES.new(key_ba,
+ AES.MODE_CCM,
+ nonce=nonce_ba)
+ key_ba[:3] = b"\xFF\xFF\xFF"
+ nonce_ba[:3] = b"\xFF\xFF\xFF"
+ cipher2.update(header_ba)
+ header_ba[:3] = b"\xFF\xFF\xFF"
+ ct_test = cipher2.encrypt(data_ba)
+ data_ba[:3] = b"\xFF\xFF\xFF"
+ tag_test = cipher2.digest()
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key_ba = bytearray(self.key_128)
+ nonce_ba = bytearray(self.nonce_96)
+ header_ba = bytearray(self.data)
+ del data_ba
+
+ cipher4 = AES.new(key_ba,
+ AES.MODE_CCM,
+ nonce=nonce_ba)
+ key_ba[:3] = b"\xFF\xFF\xFF"
+ nonce_ba[:3] = b"\xFF\xFF\xFF"
+ cipher4.update(header_ba)
+ header_ba[:3] = b"\xFF\xFF\xFF"
+ pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test))
+
+ self.assertEqual(self.data, pt_test)
+
+ def test_memoryview(self):
+
+ # Encrypt
+ key_mv = memoryview(bytearray(self.key_128))
+ nonce_mv = memoryview(bytearray(self.nonce_96))
+ header_mv = memoryview(bytearray(self.data))
+ data_mv = memoryview(bytearray(self.data))
+
+ cipher1 = AES.new(self.key_128,
+ AES.MODE_CCM,
+ nonce=self.nonce_96)
+ cipher1.update(self.data)
+ ct = cipher1.encrypt(self.data)
+ tag = cipher1.digest()
+
+ cipher2 = AES.new(key_mv,
+ AES.MODE_CCM,
+ nonce=nonce_mv)
+ key_mv[:3] = b"\xFF\xFF\xFF"
+ nonce_mv[:3] = b"\xFF\xFF\xFF"
+ cipher2.update(header_mv)
+ header_mv[:3] = b"\xFF\xFF\xFF"
+ ct_test = cipher2.encrypt(data_mv)
+ data_mv[:3] = b"\xFF\xFF\xFF"
+ tag_test = cipher2.digest()
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key_mv = memoryview(bytearray(self.key_128))
+ nonce_mv = memoryview(bytearray(self.nonce_96))
+ header_mv = memoryview(bytearray(self.data))
+ del data_mv
+
+ cipher4 = AES.new(key_mv,
+ AES.MODE_CCM,
+ nonce=nonce_mv)
+ key_mv[:3] = b"\xFF\xFF\xFF"
+ nonce_mv[:3] = b"\xFF\xFF\xFF"
+ cipher4.update(header_mv)
+ header_mv[:3] = b"\xFF\xFF\xFF"
+ pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test))
+
+ self.assertEqual(self.data, pt_test)
+
+ def test_output_param(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ ct = cipher.encrypt(pt)
+ tag = cipher.digest()
+
+ output = bytearray(128)
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ res, tag_out = cipher.encrypt_and_digest(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+ self.assertEqual(tag, tag_out)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ res = cipher.decrypt_and_verify(ct, tag, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ def test_output_param_memoryview(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ ct = cipher.encrypt(pt)
+
+ output = memoryview(bytearray(128))
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ def test_output_param_neg(self):
+
+ pt = b'5' * 16
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ ct = cipher.encrypt(pt)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16)
+
+ shorter_output = bytearray(15)
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+class CcmFSMTests(unittest.TestCase):
+
+ key_128 = get_tag_random("key_128", 16)
+ nonce_96 = get_tag_random("nonce_128", 12)
+ data = get_tag_random("data", 16)
+
+ def test_valid_init_encrypt_decrypt_digest_verify(self):
+ # No authenticated data, fixed plaintext
+ for assoc_len in (None, 0):
+ for msg_len in (None, len(self.data)):
+ # Verify path INIT->ENCRYPT->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_CCM,
+ nonce=self.nonce_96,
+ assoc_len=assoc_len,
+ msg_len=msg_len)
+ ct = cipher.encrypt(self.data)
+ mac = cipher.digest()
+
+ # Verify path INIT->DECRYPT->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_CCM,
+ nonce=self.nonce_96,
+ assoc_len=assoc_len,
+ msg_len=msg_len)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+
+ def test_valid_init_update_digest_verify(self):
+ # No plaintext, fixed authenticated data
+ for assoc_len in (None, len(self.data)):
+ for msg_len in (None, 0):
+ # Verify path INIT->UPDATE->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_CCM,
+ nonce=self.nonce_96,
+ assoc_len=assoc_len,
+ msg_len=msg_len)
+ cipher.update(self.data)
+ mac = cipher.digest()
+
+ # Verify path INIT->UPDATE->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_CCM,
+ nonce=self.nonce_96,
+ assoc_len=assoc_len,
+ msg_len=msg_len)
+ cipher.update(self.data)
+ cipher.verify(mac)
+
+ def test_valid_full_path(self):
+ # Fixed authenticated data, fixed plaintext
+ for assoc_len in (None, len(self.data)):
+ for msg_len in (None, len(self.data)):
+ # Verify path INIT->UPDATE->ENCRYPT->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_CCM,
+ nonce=self.nonce_96,
+ assoc_len=assoc_len,
+ msg_len=msg_len)
+ cipher.update(self.data)
+ ct = cipher.encrypt(self.data)
+ mac = cipher.digest()
+
+ # Verify path INIT->UPDATE->DECRYPT->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_CCM,
+ nonce=self.nonce_96,
+ assoc_len=assoc_len,
+ msg_len=msg_len)
+ cipher.update(self.data)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+
+ def test_valid_init_digest(self):
+ # Verify path INIT->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.digest()
+
+ def test_valid_init_verify(self):
+ # Verify path INIT->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ mac = cipher.digest()
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.verify(mac)
+
+ def test_valid_multiple_encrypt_or_decrypt(self):
+ # Only possible if msg_len is declared in advance
+ for method_name in "encrypt", "decrypt":
+ for auth_data in (None, b"333", self.data,
+ self.data + b"3"):
+ if auth_data is None:
+ assoc_len = None
+ else:
+ assoc_len = len(auth_data)
+ cipher = AES.new(self.key_128, AES.MODE_CCM,
+ nonce=self.nonce_96,
+ msg_len=64,
+ assoc_len=assoc_len)
+ if auth_data is not None:
+ cipher.update(auth_data)
+ method = getattr(cipher, method_name)
+ method(self.data)
+ method(self.data)
+ method(self.data)
+ method(self.data)
+
+ def test_valid_multiple_digest_or_verify(self):
+ # Multiple calls to digest
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.update(self.data)
+ first_mac = cipher.digest()
+ for x in range(4):
+ self.assertEqual(first_mac, cipher.digest())
+
+ # Multiple calls to verify
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.update(self.data)
+ for x in range(5):
+ cipher.verify(first_mac)
+
+ def test_valid_encrypt_and_digest_decrypt_and_verify(self):
+ # encrypt_and_digest
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.update(self.data)
+ ct, mac = cipher.encrypt_and_digest(self.data)
+
+ # decrypt_and_verify
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.update(self.data)
+ pt = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(self.data, pt)
+
+ def test_invalid_multiple_encrypt_decrypt_without_msg_len(self):
+ # Once per method, with or without assoc. data
+ for method_name in "encrypt", "decrypt":
+ for assoc_data_present in (True, False):
+ cipher = AES.new(self.key_128, AES.MODE_CCM,
+ nonce=self.nonce_96)
+ if assoc_data_present:
+ cipher.update(self.data)
+ method = getattr(cipher, method_name)
+ method(self.data)
+ self.assertRaises(TypeError, method, self.data)
+
+ def test_invalid_mixing_encrypt_decrypt(self):
+ # Once per method, with or without assoc. data
+ for method1_name, method2_name in (("encrypt", "decrypt"),
+ ("decrypt", "encrypt")):
+ for assoc_data_present in (True, False):
+ cipher = AES.new(self.key_128, AES.MODE_CCM,
+ nonce=self.nonce_96,
+ msg_len=32)
+ if assoc_data_present:
+ cipher.update(self.data)
+ getattr(cipher, method1_name)(self.data)
+ self.assertRaises(TypeError, getattr(cipher, method2_name),
+ self.data)
+
+ def test_invalid_encrypt_or_update_after_digest(self):
+ for method_name in "encrypt", "update":
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.encrypt(self.data)
+ cipher.digest()
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.encrypt_and_digest(self.data)
+
+ def test_invalid_decrypt_or_update_after_verify(self):
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ ct = cipher.encrypt(self.data)
+ mac = cipher.digest()
+
+ for method_name in "decrypt", "update":
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
+ cipher.decrypt_and_verify(ct, mac)
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data)
+
+
+class TestVectors(unittest.TestCase):
+ """Class exercising the CCM test vectors found in Appendix C
+ of NIST SP 800-38C and in RFC 3610"""
+
+ # List of test vectors, each made up of:
+ # - authenticated data
+ # - plaintext
+ # - ciphertext
+ # - MAC
+ # - AES key
+ # - nonce
+ test_vectors_hex = [
+ # NIST SP 800 38C
+ ( '0001020304050607',
+ '20212223',
+ '7162015b',
+ '4dac255d',
+ '404142434445464748494a4b4c4d4e4f',
+ '10111213141516'),
+ ( '000102030405060708090a0b0c0d0e0f',
+ '202122232425262728292a2b2c2d2e2f',
+ 'd2a1f0e051ea5f62081a7792073d593d',
+ '1fc64fbfaccd',
+ '404142434445464748494a4b4c4d4e4f',
+ '1011121314151617'),
+ ( '000102030405060708090a0b0c0d0e0f10111213',
+ '202122232425262728292a2b2c2d2e2f3031323334353637',
+ 'e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5',
+ '484392fbc1b09951',
+ '404142434445464748494a4b4c4d4e4f',
+ '101112131415161718191a1b'),
+ ( (''.join(["%02X" % (x*16+y) for x in range(0,16) for y in range(0,16)]))*256,
+ '202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f',
+ '69915dad1e84c6376a68c2967e4dab615ae0fd1faec44cc484828529463ccf72',
+ 'b4ac6bec93e8598e7f0dadbcea5b',
+ '404142434445464748494a4b4c4d4e4f',
+ '101112131415161718191a1b1c'),
+ # RFC3610
+ ( '0001020304050607',
+ '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e',
+ '588c979a61c663d2f066d0c2c0f989806d5f6b61dac384',
+ '17e8d12cfdf926e0',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '00000003020100a0a1a2a3a4a5'),
+ (
+ '0001020304050607',
+ '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
+ '72c91a36e135f8cf291ca894085c87e3cc15c439c9e43a3b',
+ 'a091d56e10400916',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '00000004030201a0a1a2a3a4a5'),
+ ( '0001020304050607',
+ '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20',
+ '51b1e5f44a197d1da46b0f8e2d282ae871e838bb64da859657',
+ '4adaa76fbd9fb0c5',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '00000005040302A0A1A2A3A4A5'),
+ ( '000102030405060708090a0b',
+ '0c0d0e0f101112131415161718191a1b1c1d1e',
+ 'a28c6865939a9a79faaa5c4c2a9d4a91cdac8c',
+ '96c861b9c9e61ef1',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '00000006050403a0a1a2a3a4a5'),
+ ( '000102030405060708090a0b',
+ '0c0d0e0f101112131415161718191a1b1c1d1e1f',
+ 'dcf1fb7b5d9e23fb9d4e131253658ad86ebdca3e',
+ '51e83f077d9c2d93',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '00000007060504a0a1a2a3a4a5'),
+ ( '000102030405060708090a0b',
+ '0c0d0e0f101112131415161718191a1b1c1d1e1f20',
+ '6fc1b011f006568b5171a42d953d469b2570a4bd87',
+ '405a0443ac91cb94',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '00000008070605a0a1a2a3a4a5'),
+ ( '0001020304050607',
+ '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e',
+ '0135d1b2c95f41d5d1d4fec185d166b8094e999dfed96c',
+ '048c56602c97acbb7490',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '00000009080706a0a1a2a3a4a5'),
+ ( '0001020304050607',
+ '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
+ '7b75399ac0831dd2f0bbd75879a2fd8f6cae6b6cd9b7db24',
+ 'c17b4433f434963f34b4',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '0000000a090807a0a1a2a3a4a5'),
+ ( '0001020304050607',
+ '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20',
+ '82531a60cc24945a4b8279181ab5c84df21ce7f9b73f42e197',
+ 'ea9c07e56b5eb17e5f4e',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '0000000b0a0908a0a1a2a3a4a5'),
+ ( '000102030405060708090a0b',
+ '0c0d0e0f101112131415161718191a1b1c1d1e',
+ '07342594157785152b074098330abb141b947b',
+ '566aa9406b4d999988dd',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '0000000c0b0a09a0a1a2a3a4a5'),
+ ( '000102030405060708090a0b',
+ '0c0d0e0f101112131415161718191a1b1c1d1e1f',
+ '676bb20380b0e301e8ab79590a396da78b834934',
+ 'f53aa2e9107a8b6c022c',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '0000000d0c0b0aa0a1a2a3a4a5'),
+ ( '000102030405060708090a0b',
+ '0c0d0e0f101112131415161718191a1b1c1d1e1f20',
+ 'c0ffa0d6f05bdb67f24d43a4338d2aa4bed7b20e43',
+ 'cd1aa31662e7ad65d6db',
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
+ '0000000e0d0c0ba0a1a2a3a4a5'),
+ ( '0be1a88bace018b1',
+ '08e8cf97d820ea258460e96ad9cf5289054d895ceac47c',
+ '4cb97f86a2a4689a877947ab8091ef5386a6ffbdd080f8',
+ 'e78cf7cb0cddd7b3',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '00412b4ea9cdbe3c9696766cfa'),
+ ( '63018f76dc8a1bcb',
+ '9020ea6f91bdd85afa0039ba4baff9bfb79c7028949cd0ec',
+ '4ccb1e7ca981befaa0726c55d378061298c85c92814abc33',
+ 'c52ee81d7d77c08a',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '0033568ef7b2633c9696766cfa'),
+ ( 'aa6cfa36cae86b40',
+ 'b916e0eacc1c00d7dcec68ec0b3bbb1a02de8a2d1aa346132e',
+ 'b1d23a2220ddc0ac900d9aa03c61fcf4a559a4417767089708',
+ 'a776796edb723506',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '00103fe41336713c9696766cfa'),
+ ( 'd0d0735c531e1becf049c244',
+ '12daac5630efa5396f770ce1a66b21f7b2101c',
+ '14d253c3967b70609b7cbb7c49916028324526',
+ '9a6f49975bcadeaf',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '00764c63b8058e3c9696766cfa'),
+ ( '77b60f011c03e1525899bcae',
+ 'e88b6a46c78d63e52eb8c546efb5de6f75e9cc0d',
+ '5545ff1a085ee2efbf52b2e04bee1e2336c73e3f',
+ '762c0c7744fe7e3c',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '00f8b678094e3b3c9696766cfa'),
+ ( 'cd9044d2b71fdb8120ea60c0',
+ '6435acbafb11a82e2f071d7ca4a5ebd93a803ba87f',
+ '009769ecabdf48625594c59251e6035722675e04c8',
+ '47099e5ae0704551',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '00d560912d3f703c9696766cfa'),
+ ( 'd85bc7e69f944fb8',
+ '8a19b950bcf71a018e5e6701c91787659809d67dbedd18',
+ 'bc218daa947427b6db386a99ac1aef23ade0b52939cb6a',
+ '637cf9bec2408897c6ba',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '0042fff8f1951c3c9696766cfa'),
+ ( '74a0ebc9069f5b37',
+ '1761433c37c5a35fc1f39f406302eb907c6163be38c98437',
+ '5810e6fd25874022e80361a478e3e9cf484ab04f447efff6',
+ 'f0a477cc2fc9bf548944',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '00920f40e56cdc3c9696766cfa'),
+ ( '44a3aa3aae6475ca',
+ 'a434a8e58500c6e41530538862d686ea9e81301b5ae4226bfa',
+ 'f2beed7bc5098e83feb5b31608f8e29c38819a89c8e776f154',
+ '4d4151a4ed3a8b87b9ce',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '0027ca0c7120bc3c9696766cfa'),
+ ( 'ec46bb63b02520c33c49fd70',
+ 'b96b49e21d621741632875db7f6c9243d2d7c2',
+ '31d750a09da3ed7fddd49a2032aabf17ec8ebf',
+ '7d22c8088c666be5c197',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '005b8ccbcd9af83c9696766cfa'),
+ ( '47a65ac78b3d594227e85e71',
+ 'e2fcfbb880442c731bf95167c8ffd7895e337076',
+ 'e882f1dbd38ce3eda7c23f04dd65071eb41342ac',
+ 'df7e00dccec7ae52987d',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '003ebe94044b9a3c9696766cfa'),
+ ( '6e37a6ef546d955d34ab6059',
+ 'abf21c0b02feb88f856df4a37381bce3cc128517d4',
+ 'f32905b88a641b04b9c9ffb58cc390900f3da12ab1',
+ '6dce9e82efa16da62059',
+ 'd7828d13b2b0bdc325a76236df93cc6b',
+ '008d493b30ae8b3c9696766cfa'),
+ ]
+
+ test_vectors = [[unhexlify(x) for x in tv] for tv in test_vectors_hex]
+
+ def runTest(self):
+ for assoc_data, pt, ct, mac, key, nonce in self.test_vectors:
+ # Encrypt
+ cipher = AES.new(key, AES.MODE_CCM, nonce, mac_len=len(mac))
+ cipher.update(assoc_data)
+ ct2, mac2 = cipher.encrypt_and_digest(pt)
+ self.assertEqual(ct, ct2)
+ self.assertEqual(mac, mac2)
+
+ # Decrypt
+ cipher = AES.new(key, AES.MODE_CCM, nonce, mac_len=len(mac))
+ cipher.update(assoc_data)
+ pt2 = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(pt, pt2)
+
+
+class TestVectorsWycheproof(unittest.TestCase):
+
+ def __init__(self, wycheproof_warnings, **extra_params):
+ unittest.TestCase.__init__(self)
+ self._wycheproof_warnings = wycheproof_warnings
+ self._extra_params = extra_params
+ self._id = "None"
+
+ def setUp(self):
+
+ def filter_tag(group):
+ return group['tagSize'] // 8
+
+ self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"),
+ "aes_ccm_test.json",
+ "Wycheproof AES CCM",
+ group_tag={'tag_size': filter_tag})
+
+ def shortDescription(self):
+ return self._id
+
+ def warn(self, tv):
+ if tv.warning and self._wycheproof_warnings:
+ import warnings
+ warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment))
+
+ def test_encrypt(self, tv):
+ self._id = "Wycheproof Encrypt CCM Test #" + str(tv.id)
+
+ try:
+ cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size,
+ **self._extra_params)
+ except ValueError as e:
+ if len(tv.iv) not in range(7, 13 + 1, 2) and "Length of parameter 'nonce'" in str(e):
+ assert not tv.valid
+ return
+ if tv.tag_size not in range(4, 16 + 1, 2) and "Parameter 'mac_len'" in str(e):
+ assert not tv.valid
+ return
+ raise e
+
+ cipher.update(tv.aad)
+ ct, tag = cipher.encrypt_and_digest(tv.msg)
+ if tv.valid:
+ self.assertEqual(ct, tv.ct)
+ self.assertEqual(tag, tv.tag)
+ self.warn(tv)
+
+ def test_decrypt(self, tv):
+ self._id = "Wycheproof Decrypt CCM Test #" + str(tv.id)
+
+ try:
+ cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size,
+ **self._extra_params)
+ except ValueError as e:
+ if len(tv.iv) not in range(7, 13 + 1, 2) and "Length of parameter 'nonce'" in str(e):
+ assert not tv.valid
+ return
+ if tv.tag_size not in range(4, 16 + 1, 2) and "Parameter 'mac_len'" in str(e):
+ assert not tv.valid
+ return
+ raise e
+
+ cipher.update(tv.aad)
+ try:
+ pt = cipher.decrypt_and_verify(tv.ct, tv.tag)
+ except ValueError:
+ assert not tv.valid
+ else:
+ assert tv.valid
+ self.assertEqual(pt, tv.msg)
+ self.warn(tv)
+
+ def test_corrupt_decrypt(self, tv):
+ self._id = "Wycheproof Corrupt Decrypt CCM Test #" + str(tv.id)
+ if len(tv.iv) not in range(7, 13 + 1, 2) or len(tv.ct) == 0:
+ return
+ cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size,
+ **self._extra_params)
+ cipher.update(tv.aad)
+ ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01")
+ self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag)
+
+ def runTest(self):
+
+ for tv in self.tv:
+ self.test_encrypt(tv)
+ self.test_decrypt(tv)
+ self.test_corrupt_decrypt(tv)
+
+
+def get_tests(config={}):
+ wycheproof_warnings = config.get('wycheproof_warnings')
+
+ tests = []
+ tests += list_test_cases(CcmTests)
+ tests += list_test_cases(CcmFSMTests)
+ tests += [TestVectors()]
+ tests += [TestVectorsWycheproof(wycheproof_warnings)]
+
+ return tests
+
+
+if __name__ == '__main__':
+ def suite():
+ unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_CFB.py b/lib/Crypto/SelfTest/Cipher/test_CFB.py
new file mode 100644
index 0000000..cb0c352
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_CFB.py
@@ -0,0 +1,411 @@
+# ===================================================================
+#
+# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+import unittest
+from binascii import unhexlify
+
+from Crypto.SelfTest.loader import load_test_vectors
+from Crypto.SelfTest.st_common import list_test_cases
+from Crypto.Util.py3compat import tobytes, is_string
+from Crypto.Cipher import AES, DES3, DES
+from Crypto.Hash import SHAKE128
+
+from Crypto.SelfTest.Cipher.test_CBC import BlockChainingTests
+
+
+def get_tag_random(tag, length):
+ return SHAKE128.new(data=tobytes(tag)).read(length)
+
+
+class CfbTests(BlockChainingTests):
+
+ aes_mode = AES.MODE_CFB
+ des3_mode = DES3.MODE_CFB
+
+ # Redefine test_unaligned_data_128/64
+
+ def test_unaligned_data_128(self):
+ plaintexts = [ b"7777777" ] * 100
+
+ cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ def test_unaligned_data_64(self):
+ plaintexts = [ b"7777777" ] * 100
+ cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ # Extra
+
+ def test_segment_size_128(self):
+ for bits in range(8, 129, 8):
+ cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128,
+ segment_size=bits)
+
+ for bits in 0, 7, 9, 127, 129:
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CFB,
+ self.iv_128,
+ segment_size=bits)
+
+ def test_segment_size_64(self):
+ for bits in range(8, 65, 8):
+ cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64,
+ segment_size=bits)
+
+ for bits in 0, 7, 9, 63, 65:
+ self.assertRaises(ValueError, DES3.new, self.key_192, AES.MODE_CFB,
+ self.iv_64,
+ segment_size=bits)
+
+
+class NistCfbVectors(unittest.TestCase):
+
+ def _do_kat_aes_test(self, file_name, segment_size):
+
+ test_vectors = load_test_vectors(("Cipher", "AES"),
+ file_name,
+ "AES CFB%d KAT" % segment_size,
+ { "count" : lambda x: int(x) } )
+ if test_vectors is None:
+ return
+
+ direction = None
+ for tv in test_vectors:
+
+ # The test vector file contains some directive lines
+ if is_string(tv):
+ direction = tv
+ continue
+
+ self.description = tv.desc
+ cipher = AES.new(tv.key, AES.MODE_CFB, tv.iv,
+ segment_size=segment_size)
+ if direction == "[ENCRYPT]":
+ self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext)
+ elif direction == "[DECRYPT]":
+ self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext)
+ else:
+ assert False
+
+ # See Section 6.4.5 in AESAVS
+ def _do_mct_aes_test(self, file_name, segment_size):
+
+ test_vectors = load_test_vectors(("Cipher", "AES"),
+ file_name,
+ "AES CFB%d Montecarlo" % segment_size,
+ { "count" : lambda x: int(x) } )
+ if test_vectors is None:
+ return
+
+ assert(segment_size in (8, 128))
+
+ direction = None
+ for tv in test_vectors:
+
+ # The test vector file contains some directive lines
+ if is_string(tv):
+ direction = tv
+ continue
+
+ self.description = tv.desc
+ cipher = AES.new(tv.key, AES.MODE_CFB, tv.iv,
+ segment_size=segment_size)
+
+ def get_input(input_text, output_seq, j):
+ # CFB128
+ if segment_size == 128:
+ if j >= 2:
+ return output_seq[-2]
+ return [input_text, tv.iv][j]
+ # CFB8
+ if j == 0:
+ return input_text
+ elif j <= 16:
+ return tv.iv[j - 1:j]
+ return output_seq[j - 17]
+
+ if direction == '[ENCRYPT]':
+ cts = []
+ for j in range(1000):
+ plaintext = get_input(tv.plaintext, cts, j)
+ cts.append(cipher.encrypt(plaintext))
+ self.assertEqual(cts[-1], tv.ciphertext)
+ elif direction == '[DECRYPT]':
+ pts = []
+ for j in range(1000):
+ ciphertext = get_input(tv.ciphertext, pts, j)
+ pts.append(cipher.decrypt(ciphertext))
+ self.assertEqual(pts[-1], tv.plaintext)
+ else:
+ assert False
+
+ def _do_tdes_test(self, file_name, segment_size):
+
+ test_vectors = load_test_vectors(("Cipher", "TDES"),
+ file_name,
+ "TDES CFB%d KAT" % segment_size,
+ { "count" : lambda x: int(x) } )
+ if test_vectors is None:
+ return
+
+ direction = None
+ for tv in test_vectors:
+
+ # The test vector file contains some directive lines
+ if is_string(tv):
+ direction = tv
+ continue
+
+ self.description = tv.desc
+ if hasattr(tv, "keys"):
+ cipher = DES.new(tv.keys, DES.MODE_CFB, tv.iv,
+ segment_size=segment_size)
+ else:
+ if tv.key1 != tv.key3:
+ key = tv.key1 + tv.key2 + tv.key3 # Option 3
+ else:
+ key = tv.key1 + tv.key2 # Option 2
+ cipher = DES3.new(key, DES3.MODE_CFB, tv.iv,
+ segment_size=segment_size)
+ if direction == "[ENCRYPT]":
+ self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext)
+ elif direction == "[DECRYPT]":
+ self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext)
+ else:
+ assert False
+
+
+# Create one test method per file
+nist_aes_kat_mmt_files = (
+ # KAT
+ "CFB?GFSbox128.rsp",
+ "CFB?GFSbox192.rsp",
+ "CFB?GFSbox256.rsp",
+ "CFB?KeySbox128.rsp",
+ "CFB?KeySbox192.rsp",
+ "CFB?KeySbox256.rsp",
+ "CFB?VarKey128.rsp",
+ "CFB?VarKey192.rsp",
+ "CFB?VarKey256.rsp",
+ "CFB?VarTxt128.rsp",
+ "CFB?VarTxt192.rsp",
+ "CFB?VarTxt256.rsp",
+ # MMT
+ "CFB?MMT128.rsp",
+ "CFB?MMT192.rsp",
+ "CFB?MMT256.rsp",
+ )
+nist_aes_mct_files = (
+ "CFB?MCT128.rsp",
+ "CFB?MCT192.rsp",
+ "CFB?MCT256.rsp",
+ )
+
+for file_gen_name in nist_aes_kat_mmt_files:
+ for bits in "8", "128":
+ file_name = file_gen_name.replace("?", bits)
+ def new_func(self, file_name=file_name, bits=bits):
+ self._do_kat_aes_test(file_name, int(bits))
+ setattr(NistCfbVectors, "test_AES_" + file_name, new_func)
+
+for file_gen_name in nist_aes_mct_files:
+ for bits in "8", "128":
+ file_name = file_gen_name.replace("?", bits)
+ def new_func(self, file_name=file_name, bits=bits):
+ self._do_mct_aes_test(file_name, int(bits))
+ setattr(NistCfbVectors, "test_AES_" + file_name, new_func)
+del file_name, new_func
+
+nist_tdes_files = (
+ "TCFB?MMT2.rsp", # 2TDES
+ "TCFB?MMT3.rsp", # 3TDES
+ "TCFB?invperm.rsp", # Single DES
+ "TCFB?permop.rsp",
+ "TCFB?subtab.rsp",
+ "TCFB?varkey.rsp",
+ "TCFB?vartext.rsp",
+ )
+
+for file_gen_name in nist_tdes_files:
+ for bits in "8", "64":
+ file_name = file_gen_name.replace("?", bits)
+ def new_func(self, file_name=file_name, bits=bits):
+ self._do_tdes_test(file_name, int(bits))
+ setattr(NistCfbVectors, "test_TDES_" + file_name, new_func)
+
+# END OF NIST CBC TEST VECTORS
+
+
+class SP800TestVectors(unittest.TestCase):
+ """Class exercising the CFB test vectors found in Section F.3
+ of NIST SP 800-3A"""
+
+ def test_aes_128_cfb8(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172aae2d'
+ ciphertext = '3b79424c9c0dd436bace9e0ed4586a4f32b9'
+ key = '2b7e151628aed2a6abf7158809cf4f3c'
+ iv = '000102030405060708090a0b0c0d0e0f'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ def test_aes_192_cfb8(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172aae2d'
+ ciphertext = 'cda2521ef0a905ca44cd057cbf0d47a0678a'
+ key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'
+ iv = '000102030405060708090a0b0c0d0e0f'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ def test_aes_256_cfb8(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172aae2d'
+ ciphertext = 'dc1f1a8520a64db55fcc8ac554844e889700'
+ key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'
+ iv = '000102030405060708090a0b0c0d0e0f'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ def test_aes_128_cfb128(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ ciphertext = '3b3fd92eb72dad20333449f8e83cfb4a' +\
+ 'c8a64537a0b3a93fcde3cdad9f1ce58b' +\
+ '26751f67a3cbb140b1808cf187a4f4df' +\
+ 'c04b05357c5d1c0eeac4c66f9ff7f2e6'
+ key = '2b7e151628aed2a6abf7158809cf4f3c'
+ iv = '000102030405060708090a0b0c0d0e0f'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ def test_aes_192_cfb128(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ ciphertext = 'cdc80d6fddf18cab34c25909c99a4174' +\
+ '67ce7f7f81173621961a2b70171d3d7a' +\
+ '2e1e8a1dd59b88b1c8e60fed1efac4c9' +\
+ 'c05f9f9ca9834fa042ae8fba584b09ff'
+ key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'
+ iv = '000102030405060708090a0b0c0d0e0f'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ def test_aes_256_cfb128(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+
+ ciphertext = 'dc7e84bfda79164b7ecd8486985d3860' +\
+ '39ffed143b28b1c832113c6331e5407b' +\
+ 'df10132415e54b92a13ed0a8267ae2f9' +\
+ '75a385741ab9cef82031623d55b1e471'
+ key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'
+ iv = '000102030405060708090a0b0c0d0e0f'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+
+def get_tests(config={}):
+ tests = []
+ tests += list_test_cases(CfbTests)
+ if config.get('slow_tests'):
+ tests += list_test_cases(NistCfbVectors)
+ tests += list_test_cases(SP800TestVectors)
+ return tests
+
+
+if __name__ == '__main__':
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_CTR.py b/lib/Crypto/SelfTest/Cipher/test_CTR.py
new file mode 100644
index 0000000..6fc43ef
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_CTR.py
@@ -0,0 +1,472 @@
+# ===================================================================
+#
+# Copyright (c) 2015, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+import unittest
+from binascii import hexlify, unhexlify
+
+from Crypto.SelfTest.st_common import list_test_cases
+from Crypto.Util.py3compat import tobytes, bchr
+from Crypto.Cipher import AES, DES3
+from Crypto.Hash import SHAKE128, SHA256
+from Crypto.Util import Counter
+
+def get_tag_random(tag, length):
+ return SHAKE128.new(data=tobytes(tag)).read(length)
+
+class CtrTests(unittest.TestCase):
+
+ key_128 = get_tag_random("key_128", 16)
+ key_192 = get_tag_random("key_192", 24)
+ nonce_32 = get_tag_random("nonce_32", 4)
+ nonce_64 = get_tag_random("nonce_64", 8)
+ ctr_64 = Counter.new(32, prefix=nonce_32)
+ ctr_128 = Counter.new(64, prefix=nonce_64)
+
+ def test_loopback_128(self):
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
+ pt = get_tag_random("plaintext", 16 * 100)
+ ct = cipher.encrypt(pt)
+
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def test_loopback_64(self):
+ cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64)
+ pt = get_tag_random("plaintext", 8 * 100)
+ ct = cipher.encrypt(pt)
+
+ cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def test_invalid_counter_parameter(self):
+ # Counter object is required for ciphers with short block size
+ self.assertRaises(TypeError, DES3.new, self.key_192, AES.MODE_CTR)
+ # Positional arguments are not allowed (Counter must be passed as
+ # keyword)
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, self.ctr_128)
+
+ def test_nonce_attribute(self):
+ # Nonce attribute is the prefix passed to Counter (DES3)
+ cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64)
+ self.assertEqual(cipher.nonce, self.nonce_32)
+
+ # Nonce attribute is the prefix passed to Counter (AES)
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
+ self.assertEqual(cipher.nonce, self.nonce_64)
+
+ # Nonce attribute is not defined if suffix is used in Counter
+ counter = Counter.new(64, prefix=self.nonce_32, suffix=self.nonce_32)
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter)
+ self.assertFalse(hasattr(cipher, "nonce"))
+
+ def test_nonce_parameter(self):
+ # Nonce parameter becomes nonce attribute
+ cipher1 = AES.new(self.key_128, AES.MODE_CTR, nonce=self.nonce_64)
+ self.assertEqual(cipher1.nonce, self.nonce_64)
+
+ counter = Counter.new(64, prefix=self.nonce_64, initial_value=0)
+ cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ pt = get_tag_random("plaintext", 65536)
+ self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt))
+
+ # Nonce is implicitly created (for AES) when no parameters are passed
+ nonce1 = AES.new(self.key_128, AES.MODE_CTR).nonce
+ nonce2 = AES.new(self.key_128, AES.MODE_CTR).nonce
+ self.assertNotEqual(nonce1, nonce2)
+ self.assertEqual(len(nonce1), 8)
+
+ # Nonce can be zero-length
+ cipher = AES.new(self.key_128, AES.MODE_CTR, nonce=b"")
+ self.assertEqual(b"", cipher.nonce)
+ cipher.encrypt(b'0'*300)
+
+ # Nonce and Counter are mutually exclusive
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR,
+ counter=self.ctr_128, nonce=self.nonce_64)
+
+ def test_initial_value_parameter(self):
+ # Test with nonce parameter
+ cipher1 = AES.new(self.key_128, AES.MODE_CTR,
+ nonce=self.nonce_64, initial_value=0xFFFF)
+ counter = Counter.new(64, prefix=self.nonce_64, initial_value=0xFFFF)
+ cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter)
+ pt = get_tag_random("plaintext", 65536)
+ self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt))
+
+ # Test without nonce parameter
+ cipher1 = AES.new(self.key_128, AES.MODE_CTR,
+ initial_value=0xFFFF)
+ counter = Counter.new(64, prefix=cipher1.nonce, initial_value=0xFFFF)
+ cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter)
+ pt = get_tag_random("plaintext", 65536)
+ self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt))
+
+ # Initial_value and Counter are mutually exclusive
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR,
+ counter=self.ctr_128, initial_value=0)
+
+ def test_initial_value_bytes_parameter(self):
+ # Same result as when passing an integer
+ cipher1 = AES.new(self.key_128, AES.MODE_CTR,
+ nonce=self.nonce_64,
+ initial_value=b"\x00"*6+b"\xFF\xFF")
+ cipher2 = AES.new(self.key_128, AES.MODE_CTR,
+ nonce=self.nonce_64, initial_value=0xFFFF)
+ pt = get_tag_random("plaintext", 65536)
+ self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt))
+
+ # Fail if the iv is too large
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR,
+ initial_value=b"5"*17)
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR,
+ nonce=self.nonce_64, initial_value=b"5"*9)
+
+ # Fail if the iv is too short
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR,
+ initial_value=b"5"*15)
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR,
+ nonce=self.nonce_64, initial_value=b"5"*7)
+
+ def test_iv_with_matching_length(self):
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR,
+ counter=Counter.new(120))
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR,
+ counter=Counter.new(136))
+
+ def test_block_size_128(self):
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
+ self.assertEqual(cipher.block_size, AES.block_size)
+
+ def test_block_size_64(self):
+ cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64)
+ self.assertEqual(cipher.block_size, DES3.block_size)
+
+ def test_unaligned_data_128(self):
+ plaintexts = [ b"7777777" ] * 100
+
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ def test_unaligned_data_64(self):
+ plaintexts = [ b"7777777" ] * 100
+ cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ def test_unknown_parameters(self):
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR,
+ 7, counter=self.ctr_128)
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR,
+ counter=self.ctr_128, unknown=7)
+ # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module)
+ AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128, use_aesni=False)
+
+ def test_null_encryption_decryption(self):
+ for func in "encrypt", "decrypt":
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
+ result = getattr(cipher, func)(b"")
+ self.assertEqual(result, b"")
+
+ def test_either_encrypt_or_decrypt(self):
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
+ cipher.encrypt(b"")
+ self.assertRaises(TypeError, cipher.decrypt, b"")
+
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
+ cipher.decrypt(b"")
+ self.assertRaises(TypeError, cipher.encrypt, b"")
+
+ def test_wrap_around(self):
+ # Counter is only 8 bits, so we can only encrypt/decrypt 256 blocks (=4096 bytes)
+ counter = Counter.new(8, prefix=bchr(9) * 15)
+ max_bytes = 4096
+
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter)
+ cipher.encrypt(b'9' * max_bytes)
+ self.assertRaises(OverflowError, cipher.encrypt, b'9')
+
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter)
+ self.assertRaises(OverflowError, cipher.encrypt, b'9' * (max_bytes + 1))
+
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter)
+ cipher.decrypt(b'9' * max_bytes)
+ self.assertRaises(OverflowError, cipher.decrypt, b'9')
+
+ cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter)
+ self.assertRaises(OverflowError, cipher.decrypt, b'9' * (max_bytes + 1))
+
+ def test_bytearray(self):
+ data = b"1" * 16
+ iv = b"\x00" * 6 + b"\xFF\xFF"
+
+ # Encrypt
+ cipher1 = AES.new(self.key_128, AES.MODE_CTR,
+ nonce=self.nonce_64,
+ initial_value=iv)
+ ref1 = cipher1.encrypt(data)
+
+ cipher2 = AES.new(self.key_128, AES.MODE_CTR,
+ nonce=bytearray(self.nonce_64),
+ initial_value=bytearray(iv))
+ ref2 = cipher2.encrypt(bytearray(data))
+
+ self.assertEqual(ref1, ref2)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ cipher3 = AES.new(self.key_128, AES.MODE_CTR,
+ nonce=self.nonce_64,
+ initial_value=iv)
+ ref3 = cipher3.decrypt(data)
+
+ cipher4 = AES.new(self.key_128, AES.MODE_CTR,
+ nonce=bytearray(self.nonce_64),
+ initial_value=bytearray(iv))
+ ref4 = cipher4.decrypt(bytearray(data))
+
+ self.assertEqual(ref3, ref4)
+
+ def test_very_long_data(self):
+ cipher = AES.new(b'A' * 32, AES.MODE_CTR, nonce=b'')
+ ct = cipher.encrypt(b'B' * 1000000)
+ digest = SHA256.new(ct).hexdigest()
+ self.assertEqual(digest, "96204fc470476561a3a8f3b6fe6d24be85c87510b638142d1d0fb90989f8a6a6")
+
+ def test_output_param(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64)
+ ct = cipher.encrypt(pt)
+
+ output = bytearray(128)
+ cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64)
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ def test_output_param_memoryview(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64)
+ ct = cipher.encrypt(pt)
+
+ output = memoryview(bytearray(128))
+ cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64)
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64)
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ def test_output_param_neg(self):
+ LEN_PT = 128
+
+ pt = b'5' * LEN_PT
+ cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64)
+ ct = cipher.encrypt(pt)
+
+ cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64)
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT)
+
+ cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT)
+
+ shorter_output = bytearray(LEN_PT - 1)
+ cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+ cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+class SP800TestVectors(unittest.TestCase):
+ """Class exercising the CTR test vectors found in Section F.5
+ of NIST SP 800-38A"""
+
+ def test_aes_128(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ ciphertext = '874d6191b620e3261bef6864990db6ce' +\
+ '9806f66b7970fdff8617187bb9fffdff' +\
+ '5ae4df3edbd5d35e5b4f09020db03eab' +\
+ '1e031dda2fbe03d1792170a0f3009cee'
+ key = '2b7e151628aed2a6abf7158809cf4f3c'
+ counter = Counter.new(nbits=16,
+ prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'),
+ initial_value=0xfeff)
+
+ key = unhexlify(key)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CTR, counter=counter)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CTR, counter=counter)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ def test_aes_192(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ ciphertext = '1abc932417521ca24f2b0459fe7e6e0b' +\
+ '090339ec0aa6faefd5ccc2c6f4ce8e94' +\
+ '1e36b26bd1ebc670d1bd1d665620abf7' +\
+ '4f78a7f6d29809585a97daec58c6b050'
+ key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'
+ counter = Counter.new(nbits=16,
+ prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'),
+ initial_value=0xfeff)
+
+ key = unhexlify(key)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CTR, counter=counter)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CTR, counter=counter)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ def test_aes_256(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ ciphertext = '601ec313775789a5b7a7f504bbf3d228' +\
+ 'f443e3ca4d62b59aca84e990cacaf5c5' +\
+ '2b0930daa23de94ce87017ba2d84988d' +\
+ 'dfc9c58db67aada613c2dd08457941a6'
+ key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'
+ counter = Counter.new(nbits=16,
+ prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'),
+ initial_value=0xfeff)
+ key = unhexlify(key)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_CTR, counter=counter)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_CTR, counter=counter)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+
+class RFC3686TestVectors(unittest.TestCase):
+
+ # Each item is a test vector with:
+ # - plaintext
+ # - ciphertext
+ # - key (AES 128, 192 or 256 bits)
+ # - counter prefix (4 byte nonce + 8 byte nonce)
+ data = (
+ ('53696e676c6520626c6f636b206d7367',
+ 'e4095d4fb7a7b3792d6175a3261311b8',
+ 'ae6852f8121067cc4bf7a5765577f39e',
+ '000000300000000000000000'),
+ ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
+ '5104a106168a72d9790d41ee8edad388eb2e1efc46da57c8fce630df9141be28',
+ '7e24067817fae0d743d6ce1f32539163',
+ '006cb6dbc0543b59da48d90b'),
+ ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223',
+ 'c1cf48a89f2ffdd9cf4652e9efdb72d74540a42bde6d7836d59a5ceaaef3105325b2072f',
+ '7691be035e5020a8ac6e618529f9a0dc',
+ '00e0017b27777f3f4a1786f0'),
+ ('53696e676c6520626c6f636b206d7367',
+ '4b55384fe259c9c84e7935a003cbe928',
+ '16af5b145fc9f579c175f93e3bfb0eed863d06ccfdb78515',
+ '0000004836733c147d6d93cb'),
+ ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
+ '453243fc609b23327edfaafa7131cd9f8490701c5ad4a79cfc1fe0ff42f4fb00',
+ '7c5cb2401b3dc33c19e7340819e0f69c678c3db8e6f6a91a',
+ '0096b03b020c6eadc2cb500d'),
+ ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223',
+ '96893fc55e5c722f540b7dd1ddf7e758d288bc95c69165884536c811662f2188abee0935',
+ '02bf391ee8ecb159b959617b0965279bf59b60a786d3e0fe',
+ '0007bdfd5cbd60278dcc0912'),
+ ('53696e676c6520626c6f636b206d7367',
+ '145ad01dbf824ec7560863dc71e3e0c0',
+ '776beff2851db06f4c8a0542c8696f6c6a81af1eec96b4d37fc1d689e6c1c104',
+ '00000060db5672c97aa8f0b2'),
+ ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
+ 'f05e231b3894612c49ee000b804eb2a9b8306b508f839d6a5530831d9344af1c',
+ 'f6d66d6bd52d59bb0796365879eff886c66dd51a5b6a99744b50590c87a23884',
+ '00faac24c1585ef15a43d875'),
+ ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223',
+ 'eb6c52821d0bbbf7ce7594462aca4faab407df866569fd07f48cc0b583d6071f1ec0e6b8',
+ 'ff7a617ce69148e4f1726e2f43581de2aa62d9f805532edff1eed687fb54153d',
+ '001cc5b751a51d70a1c11148')
+ )
+
+ bindata = []
+ for tv in data:
+ bindata.append([unhexlify(x) for x in tv])
+
+ def runTest(self):
+ for pt, ct, key, prefix in self.bindata:
+ counter = Counter.new(32, prefix=prefix)
+ cipher = AES.new(key, AES.MODE_CTR, counter=counter)
+ result = cipher.encrypt(pt)
+ self.assertEqual(hexlify(ct), hexlify(result))
+
+
+def get_tests(config={}):
+ tests = []
+ tests += list_test_cases(CtrTests)
+ tests += list_test_cases(SP800TestVectors)
+ tests += [ RFC3686TestVectors() ]
+ return tests
+
+
+if __name__ == '__main__':
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_ChaCha20.py b/lib/Crypto/SelfTest/Cipher/test_ChaCha20.py
new file mode 100644
index 0000000..4396ac2
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_ChaCha20.py
@@ -0,0 +1,529 @@
+# ===================================================================
+#
+# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+import os
+import re
+import unittest
+from binascii import hexlify, unhexlify
+
+from Crypto.Util.py3compat import b, tobytes, bchr
+from Crypto.Util.strxor import strxor_c
+from Crypto.SelfTest.st_common import list_test_cases
+
+from Crypto.Cipher import ChaCha20
+
+
+class ChaCha20Test(unittest.TestCase):
+
+ def test_new_positive(self):
+ cipher = ChaCha20.new(key=b("0")*32, nonce=b"0"*8)
+ self.assertEqual(cipher.nonce, b"0" * 8)
+ cipher = ChaCha20.new(key=b("0")*32, nonce=b"0"*12)
+ self.assertEqual(cipher.nonce, b"0" * 12)
+
+ def test_new_negative(self):
+ new = ChaCha20.new
+ self.assertRaises(TypeError, new)
+ self.assertRaises(TypeError, new, nonce=b("0"))
+ self.assertRaises(ValueError, new, nonce=b("0")*8, key=b("0"))
+ self.assertRaises(ValueError, new, nonce=b("0"), key=b("0")*32)
+
+ def test_default_nonce(self):
+ cipher1 = ChaCha20.new(key=bchr(1) * 32)
+ cipher2 = ChaCha20.new(key=bchr(1) * 32)
+ self.assertEqual(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"""
+
+ c1 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8)
+ c1.encrypt(b("8"))
+ self.assertRaises(TypeError, c1.decrypt, b("9"))
+
+ c2 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8)
+ c2.decrypt(b("8"))
+ self.assertRaises(TypeError, c2.encrypt, b("9"))
+
+ def test_round_trip(self):
+ pt = b("A") * 1024
+ c1 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8)
+ c2 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8)
+ ct = c1.encrypt(pt)
+ self.assertEqual(c2.decrypt(ct), pt)
+
+ self.assertEqual(c1.encrypt(b("")), b(""))
+ self.assertEqual(c2.decrypt(b("")), b(""))
+
+ def test_streaming(self):
+ """Verify that an arbitrary number of bytes can be encrypted/decrypted"""
+ from Crypto.Hash import SHA1
+
+ segments = (1, 3, 5, 7, 11, 17, 23)
+ total = sum(segments)
+
+ pt = b("")
+ while len(pt) < total:
+ pt += SHA1.new(pt).digest()
+
+ cipher1 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8)
+ ct = cipher1.encrypt(pt)
+
+ cipher2 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8)
+ cipher3 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8)
+ idx = 0
+ for segment in segments:
+ self.assertEqual(cipher2.decrypt(ct[idx:idx+segment]), pt[idx:idx+segment])
+ self.assertEqual(cipher3.encrypt(pt[idx:idx+segment]), ct[idx:idx+segment])
+ idx += segment
+
+ def test_seek(self):
+ cipher1 = ChaCha20.new(key=b("9") * 32, nonce=b("e") * 8)
+
+ offset = 64 * 900 + 7
+ pt = b("1") * 64
+
+ cipher1.encrypt(b("0") * offset)
+ ct1 = cipher1.encrypt(pt)
+
+ cipher2 = ChaCha20.new(key=b("9") * 32, nonce=b("e") * 8)
+ cipher2.seek(offset)
+ ct2 = cipher2.encrypt(pt)
+
+ self.assertEqual(ct1, ct2)
+
+ def test_seek_tv(self):
+ # Test Vector #4, A.1 from
+ # http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
+ key = bchr(0) + bchr(255) + bchr(0) * 30
+ nonce = bchr(0) * 8
+ cipher = ChaCha20.new(key=key, nonce=nonce)
+ cipher.seek(64 * 2)
+ expected_key_stream = unhexlify(b(
+ "72d54dfbf12ec44b362692df94137f32"
+ "8fea8da73990265ec1bbbea1ae9af0ca"
+ "13b25aa26cb4a648cb9b9d1be65b2c09"
+ "24a66c54d545ec1b7374f4872e99f096"
+ ))
+ ct = cipher.encrypt(bchr(0) * len(expected_key_stream))
+ self.assertEqual(expected_key_stream, ct)
+
+ def test_rfc7539(self):
+ # from https://tools.ietf.org/html/rfc7539 Annex A.1
+ # Each item is: key, nonce, block #, plaintext, ciphertext
+ tvs = [
+ # Test Vector #1
+ (
+ "00"*32,
+ "00"*12,
+ 0,
+ "00"*16*4,
+ "76b8e0ada0f13d90405d6ae55386bd28"
+ "bdd219b8a08ded1aa836efcc8b770dc7"
+ "da41597c5157488d7724e03fb8d84a37"
+ "6a43b8f41518a11cc387b669b2ee6586"
+ ),
+ # Test Vector #2
+ (
+ "00"*31 + "01",
+ "00"*11 + "02",
+ 1,
+ "416e79207375626d697373696f6e2074"
+ "6f20746865204945544620696e74656e"
+ "6465642062792074686520436f6e7472"
+ "696275746f7220666f72207075626c69"
+ "636174696f6e20617320616c6c206f72"
+ "2070617274206f6620616e2049455446"
+ "20496e7465726e65742d447261667420"
+ "6f722052464320616e6420616e792073"
+ "746174656d656e74206d616465207769"
+ "7468696e2074686520636f6e74657874"
+ "206f6620616e20494554462061637469"
+ "7669747920697320636f6e7369646572"
+ "656420616e20224945544620436f6e74"
+ "7269627574696f6e222e205375636820"
+ "73746174656d656e747320696e636c75"
+ "6465206f72616c2073746174656d656e"
+ "747320696e2049455446207365737369"
+ "6f6e732c2061732077656c6c20617320"
+ "7772697474656e20616e6420656c6563"
+ "74726f6e696320636f6d6d756e696361"
+ "74696f6e73206d61646520617420616e"
+ "792074696d65206f7220706c6163652c"
+ "20776869636820617265206164647265"
+ "7373656420746f",
+ "a3fbf07df3fa2fde4f376ca23e827370"
+ "41605d9f4f4f57bd8cff2c1d4b7955ec"
+ "2a97948bd3722915c8f3d337f7d37005"
+ "0e9e96d647b7c39f56e031ca5eb6250d"
+ "4042e02785ececfa4b4bb5e8ead0440e"
+ "20b6e8db09d881a7c6132f420e527950"
+ "42bdfa7773d8a9051447b3291ce1411c"
+ "680465552aa6c405b7764d5e87bea85a"
+ "d00f8449ed8f72d0d662ab052691ca66"
+ "424bc86d2df80ea41f43abf937d3259d"
+ "c4b2d0dfb48a6c9139ddd7f76966e928"
+ "e635553ba76c5c879d7b35d49eb2e62b"
+ "0871cdac638939e25e8a1e0ef9d5280f"
+ "a8ca328b351c3c765989cbcf3daa8b6c"
+ "cc3aaf9f3979c92b3720fc88dc95ed84"
+ "a1be059c6499b9fda236e7e818b04b0b"
+ "c39c1e876b193bfe5569753f88128cc0"
+ "8aaa9b63d1a16f80ef2554d7189c411f"
+ "5869ca52c5b83fa36ff216b9c1d30062"
+ "bebcfd2dc5bce0911934fda79a86f6e6"
+ "98ced759c3ff9b6477338f3da4f9cd85"
+ "14ea9982ccafb341b2384dd902f3d1ab"
+ "7ac61dd29c6f21ba5b862f3730e37cfd"
+ "c4fd806c22f221"
+ ),
+ # Test Vector #3
+ (
+ "1c9240a5eb55d38af333888604f6b5f0"
+ "473917c1402b80099dca5cbc207075c0",
+ "00"*11 + "02",
+ 42,
+ "2754776173206272696c6c69672c2061"
+ "6e642074686520736c6974687920746f"
+ "7665730a446964206779726520616e64"
+ "2067696d626c6520696e207468652077"
+ "6162653a0a416c6c206d696d73792077"
+ "6572652074686520626f726f676f7665"
+ "732c0a416e6420746865206d6f6d6520"
+ "7261746873206f757467726162652e",
+ "62e6347f95ed87a45ffae7426f27a1df"
+ "5fb69110044c0d73118effa95b01e5cf"
+ "166d3df2d721caf9b21e5fb14c616871"
+ "fd84c54f9d65b283196c7fe4f60553eb"
+ "f39c6402c42234e32a356b3e764312a6"
+ "1a5532055716ead6962568f87d3f3f77"
+ "04c6a8d1bcd1bf4d50d6154b6da731b1"
+ "87b58dfd728afa36757a797ac188d1"
+ )
+ ]
+
+ for tv in tvs:
+ key = unhexlify(tv[0])
+ nonce = unhexlify(tv[1])
+ offset = tv[2] * 64
+ pt = unhexlify(tv[3])
+ ct_expect = unhexlify(tv[4])
+
+ cipher = ChaCha20.new(key=key, nonce=nonce)
+ if offset != 0:
+ cipher.seek(offset)
+ ct = cipher.encrypt(pt)
+ assert(ct == ct_expect)
+
+
+class XChaCha20Test(unittest.TestCase):
+
+ # From https://tools.ietf.org/html/draft-arciszewski-xchacha-03
+
+ def test_hchacha20(self):
+ # Section 2.2.1
+
+ from Crypto.Cipher.ChaCha20 import _HChaCha20
+
+ key = b"00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f"
+ key = unhexlify(key.replace(b":", b""))
+
+ nonce = b"00:00:00:09:00:00:00:4a:00:00:00:00:31:41:59:27"
+ nonce = unhexlify(nonce.replace(b":", b""))
+
+ subkey = _HChaCha20(key, nonce)
+
+ expected = b"82413b42 27b27bfe d30e4250 8a877d73 a0f9e4d5 8a74a853 c12ec413 26d3ecdc"
+ expected = unhexlify(expected.replace(b" ", b""))
+
+ 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
+
+ pt = b"""
+ 5468652064686f6c65202870726f6e6f756e6365642022646f6c652229206973
+ 20616c736f206b6e6f776e2061732074686520417369617469632077696c6420
+ 646f672c2072656420646f672c20616e642077686973746c696e6720646f672e
+ 2049742069732061626f7574207468652073697a65206f662061204765726d61
+ 6e20736865706865726420627574206c6f6f6b73206d6f7265206c696b652061
+ 206c6f6e672d6c656767656420666f782e205468697320686967686c7920656c
+ 757369766520616e6420736b696c6c6564206a756d70657220697320636c6173
+ 736966696564207769746820776f6c7665732c20636f796f7465732c206a6163
+ 6b616c732c20616e6420666f78657320696e20746865207461786f6e6f6d6963
+ 2066616d696c792043616e696461652e"""
+ pt = unhexlify(pt.replace(b"\n", b"").replace(b" ", b""))
+
+ key = unhexlify(b"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f")
+ iv = unhexlify(b"404142434445464748494a4b4c4d4e4f5051525354555658")
+
+ ct = b"""
+ 7d0a2e6b7f7c65a236542630294e063b7ab9b555a5d5149aa21e4ae1e4fbce87
+ ecc8e08a8b5e350abe622b2ffa617b202cfad72032a3037e76ffdcdc4376ee05
+ 3a190d7e46ca1de04144850381b9cb29f051915386b8a710b8ac4d027b8b050f
+ 7cba5854e028d564e453b8a968824173fc16488b8970cac828f11ae53cabd201
+ 12f87107df24ee6183d2274fe4c8b1485534ef2c5fbc1ec24bfc3663efaa08bc
+ 047d29d25043532db8391a8a3d776bf4372a6955827ccb0cdd4af403a7ce4c63
+ d595c75a43e045f0cce1f29c8b93bd65afc5974922f214a40b7c402cdb91ae73
+ c0b63615cdad0480680f16515a7ace9d39236464328a37743ffc28f4ddb324f4
+ d0f5bbdc270c65b1749a6efff1fbaa09536175ccd29fb9e6057b307320d31683
+ 8a9c71f70b5b5907a66f7ea49aadc409"""
+ ct = unhexlify(ct.replace(b"\n", b"").replace(b" ", b""))
+
+ cipher = ChaCha20.new(key=key, nonce=iv)
+ cipher.seek(64) # Counter = 1
+ ct_test = cipher.encrypt(pt)
+ self.assertEqual(ct, ct_test)
+
+
+class ByteArrayTest(unittest.TestCase):
+ """Verify we can encrypt or decrypt bytearrays"""
+
+ def runTest(self):
+
+ data = b"0123"
+ key = b"9" * 32
+ nonce = b"t" * 8
+
+ # Encryption
+ data_ba = bytearray(data)
+ key_ba = bytearray(key)
+ nonce_ba = bytearray(nonce)
+
+ cipher1 = ChaCha20.new(key=key, nonce=nonce)
+ ct = cipher1.encrypt(data)
+
+ cipher2 = ChaCha20.new(key=key_ba, nonce=nonce_ba)
+ key_ba[:1] = b'\xFF'
+ nonce_ba[:1] = b'\xFF'
+ ct_test = cipher2.encrypt(data_ba)
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decryption
+ key_ba = bytearray(key)
+ nonce_ba = bytearray(nonce)
+ ct_ba = bytearray(ct)
+
+ cipher3 = ChaCha20.new(key=key_ba, nonce=nonce_ba)
+ key_ba[:1] = b'\xFF'
+ nonce_ba[:1] = b'\xFF'
+ pt_test = cipher3.decrypt(ct_ba)
+
+ self.assertEqual(data, pt_test)
+
+
+class MemoryviewTest(unittest.TestCase):
+ """Verify we can encrypt or decrypt bytearrays"""
+
+ def runTest(self):
+
+ data = b"0123"
+ key = b"9" * 32
+ nonce = b"t" * 8
+
+ # Encryption
+ data_mv = memoryview(bytearray(data))
+ key_mv = memoryview(bytearray(key))
+ nonce_mv = memoryview(bytearray(nonce))
+
+ cipher1 = ChaCha20.new(key=key, nonce=nonce)
+ ct = cipher1.encrypt(data)
+
+ cipher2 = ChaCha20.new(key=key_mv, nonce=nonce_mv)
+ key_mv[:1] = b'\xFF'
+ nonce_mv[:1] = b'\xFF'
+ ct_test = cipher2.encrypt(data_mv)
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decryption
+ key_mv = memoryview(bytearray(key))
+ nonce_mv = memoryview(bytearray(nonce))
+ ct_mv = memoryview(bytearray(ct))
+
+ cipher3 = ChaCha20.new(key=key_mv, nonce=nonce_mv)
+ key_mv[:1] = b'\xFF'
+ nonce_mv[:1] = b'\xFF'
+ pt_test = cipher3.decrypt(ct_mv)
+
+ self.assertEqual(data, pt_test)
+
+
+class ChaCha20_AGL_NIR(unittest.TestCase):
+
+ # From http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
+ # and http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
+ tv = [
+ ( "00" * 32,
+ "00" * 8,
+ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc"
+ "8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11c"
+ "c387b669b2ee6586"
+ "9f07e7be5551387a98ba977c732d080d"
+ "cb0f29a048e3656912c6533e32ee7aed"
+ "29b721769ce64e43d57133b074d839d5"
+ "31ed1f28510afb45ace10a1f4b794d6f"
+ ),
+ ( "00" * 31 + "01",
+ "00" * 8,
+ "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952"
+ "ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea81"
+ "7e9ad275ae546963"
+ "3aeb5224ecf849929b9d828db1ced4dd"
+ "832025e8018b8160b82284f3c949aa5a"
+ "8eca00bbb4a73bdad192b5c42f73f2fd"
+ "4e273644c8b36125a64addeb006c13a0"
+ ),
+ ( "00" * 32,
+ "00" * 7 + "01",
+ "de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df1"
+ "37821031e85a050278a7084527214f73efc7fa5b5277062eb7a0433e"
+ "445f41e3"
+ ),
+ ( "00" * 32,
+ "01" + "00" * 7,
+ "ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd1"
+ "38e50d32111e4caf237ee53ca8ad6426194a88545ddc497a0b466e7d"
+ "6bbdb0041b2f586b"
+ ),
+ ( "000102030405060708090a0b0c0d0e0f101112131415161718191a1b"
+ "1c1d1e1f",
+ "0001020304050607",
+ "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56"
+ "f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f1"
+ "5916155c2be8241a38008b9a26bc35941e2444177c8ade6689de9526"
+ "4986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e"
+ "09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a4750"
+ "32b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c5"
+ "07b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f7"
+ "6dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2"
+ "ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab7"
+ "8fab78c9"
+ ),
+ ( "00" * 32,
+ "00" * 7 + "02",
+ "c2c64d378cd536374ae204b9ef933fcd"
+ "1a8b2288b3dfa49672ab765b54ee27c7"
+ "8a970e0e955c14f3a88e741b97c286f7"
+ "5f8fc299e8148362fa198a39531bed6d"
+ ),
+ ]
+
+ def runTest(self):
+ for (key, nonce, stream) in self.tv:
+ c = ChaCha20.new(key=unhexlify(b(key)), nonce=unhexlify(b(nonce)))
+ ct = unhexlify(b(stream))
+ pt = b("\x00") * len(ct)
+ self.assertEqual(c.encrypt(pt), ct)
+
+
+class TestOutput(unittest.TestCase):
+
+ def runTest(self):
+ # Encrypt/Decrypt data and test output parameter
+
+ key = b'4' * 32
+ nonce = b'5' * 8
+ cipher = ChaCha20.new(key=key, nonce=nonce)
+
+ pt = b'5' * 300
+ ct = cipher.encrypt(pt)
+
+ output = bytearray(len(pt))
+ cipher = ChaCha20.new(key=key, nonce=nonce)
+ 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)
+ self.assertEqual(res, None)
+
+ output = memoryview(bytearray(len(pt)))
+ 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'*len(pt))
+
+ cipher = ChaCha20.new(key=key, nonce=nonce)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*len(pt))
+
+ shorter_output = bytearray(len(pt) - 1)
+
+ 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)
+
+
+def get_tests(config={}):
+ tests = []
+ tests += list_test_cases(ChaCha20Test)
+ tests += list_test_cases(XChaCha20Test)
+ tests.append(ChaCha20_AGL_NIR())
+ tests.append(ByteArrayTest())
+ tests.append(MemoryviewTest())
+ tests.append(TestOutput())
+
+ return tests
+
+
+if __name__ == '__main__':
+ import unittest
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py b/lib/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py
new file mode 100644
index 0000000..67440d7
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py
@@ -0,0 +1,770 @@
+# ===================================================================
+#
+# Copyright (c) 2018, Helder Eijs <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+import unittest
+from binascii import unhexlify
+
+from Crypto.SelfTest.st_common import list_test_cases
+from Crypto.SelfTest.loader import load_test_vectors_wycheproof
+from Crypto.Util.py3compat import tobytes
+from Crypto.Cipher import ChaCha20_Poly1305
+from Crypto.Hash import SHAKE128
+
+from Crypto.Util._file_system import pycryptodome_filename
+from Crypto.Util.strxor import strxor
+
+
+def get_tag_random(tag, length):
+ return SHAKE128.new(data=tobytes(tag)).read(length)
+
+
+class ChaCha20Poly1305Tests(unittest.TestCase):
+
+ key_256 = get_tag_random("key_256", 32)
+ nonce_96 = get_tag_random("nonce_96", 12)
+ data_128 = get_tag_random("data_128", 16)
+
+ def test_loopback(self):
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ pt = get_tag_random("plaintext", 16 * 100)
+ ct = cipher.encrypt(pt)
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def test_nonce(self):
+ # Nonce can only be 8 or 12 bytes
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=b'H' * 8)
+ self.assertEqual(len(cipher.nonce), 8)
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=b'H' * 12)
+ self.assertEqual(len(cipher.nonce), 12)
+
+ # If not passed, the nonce is created randomly
+ cipher = ChaCha20_Poly1305.new(key=self.key_256)
+ nonce1 = cipher.nonce
+ cipher = ChaCha20_Poly1305.new(key=self.key_256)
+ nonce2 = cipher.nonce
+ self.assertEqual(len(nonce1), 12)
+ self.assertNotEqual(nonce1, nonce2)
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ ct = cipher.encrypt(self.data_128)
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ self.assertEqual(ct, cipher.encrypt(self.data_128))
+
+ def test_nonce_must_be_bytes(self):
+ self.assertRaises(TypeError,
+ ChaCha20_Poly1305.new,
+ key=self.key_256,
+ nonce=u'test12345678')
+
+ def test_nonce_length(self):
+ # nonce can only be 8 or 12 bytes long
+ self.assertRaises(ValueError,
+ ChaCha20_Poly1305.new,
+ key=self.key_256,
+ nonce=b'0' * 7)
+ self.assertRaises(ValueError,
+ ChaCha20_Poly1305.new,
+ key=self.key_256,
+ nonce=b'')
+
+ def test_block_size(self):
+ # Not based on block ciphers
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ self.assertFalse(hasattr(cipher, 'block_size'))
+
+ def test_nonce_attribute(self):
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ self.assertEqual(cipher.nonce, self.nonce_96)
+
+ # By default, a 12 bytes long nonce is randomly generated
+ nonce1 = ChaCha20_Poly1305.new(key=self.key_256).nonce
+ nonce2 = ChaCha20_Poly1305.new(key=self.key_256).nonce
+ self.assertEqual(len(nonce1), 12)
+ self.assertNotEqual(nonce1, nonce2)
+
+ def test_unknown_parameters(self):
+ self.assertRaises(TypeError,
+ ChaCha20_Poly1305.new,
+ key=self.key_256,
+ param=9)
+
+ def test_null_encryption_decryption(self):
+ for func in "encrypt", "decrypt":
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ result = getattr(cipher, func)(b"")
+ self.assertEqual(result, b"")
+
+ def test_either_encrypt_or_decrypt(self):
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.encrypt(b"")
+ self.assertRaises(TypeError, cipher.decrypt, b"")
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.decrypt(b"")
+ self.assertRaises(TypeError, cipher.encrypt, b"")
+
+ def test_data_must_be_bytes(self):
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*')
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*')
+
+ def test_mac_len(self):
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ _, mac = cipher.encrypt_and_digest(self.data_128)
+ self.assertEqual(len(mac), 16)
+
+ def test_invalid_mac(self):
+ from Crypto.Util.strxor import strxor_c
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ ct, mac = cipher.encrypt_and_digest(self.data_128)
+
+ invalid_mac = strxor_c(mac, 0x01)
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.decrypt_and_verify, ct,
+ invalid_mac)
+
+ def test_hex_mac(self):
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ mac_hex = cipher.hexdigest()
+ self.assertEqual(cipher.digest(), unhexlify(mac_hex))
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.hexverify(mac_hex)
+
+ def test_message_chunks(self):
+ # Validate that both associated data and plaintext/ciphertext
+ # can be broken up in chunks of arbitrary length
+
+ auth_data = get_tag_random("authenticated data", 127)
+ plaintext = get_tag_random("plaintext", 127)
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.update(auth_data)
+ ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext)
+
+ def break_up(data, chunk_length):
+ return [data[i:i+chunk_length] for i in range(0, len(data),
+ chunk_length)]
+
+ # Encryption
+ for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128:
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+
+ for chunk in break_up(auth_data, chunk_length):
+ cipher.update(chunk)
+ pt2 = b""
+ for chunk in break_up(ciphertext, chunk_length):
+ pt2 += cipher.decrypt(chunk)
+ self.assertEqual(plaintext, pt2)
+ cipher.verify(ref_mac)
+
+ # Decryption
+ for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128:
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+
+ for chunk in break_up(auth_data, chunk_length):
+ cipher.update(chunk)
+ ct2 = b""
+ for chunk in break_up(plaintext, chunk_length):
+ ct2 += cipher.encrypt(chunk)
+ self.assertEqual(ciphertext, ct2)
+ self.assertEqual(cipher.digest(), ref_mac)
+
+ def test_bytearray(self):
+
+ # Encrypt
+ key_ba = bytearray(self.key_256)
+ nonce_ba = bytearray(self.nonce_96)
+ header_ba = bytearray(self.data_128)
+ data_ba = bytearray(self.data_128)
+
+ cipher1 = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher1.update(self.data_128)
+ ct = cipher1.encrypt(self.data_128)
+ tag = cipher1.digest()
+
+ cipher2 = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ key_ba[:3] = b'\xFF\xFF\xFF'
+ nonce_ba[:3] = b'\xFF\xFF\xFF'
+ cipher2.update(header_ba)
+ header_ba[:3] = b'\xFF\xFF\xFF'
+ ct_test = cipher2.encrypt(data_ba)
+ data_ba[:3] = b'\x99\x99\x99'
+ tag_test = cipher2.digest()
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key_ba = bytearray(self.key_256)
+ nonce_ba = bytearray(self.nonce_96)
+ header_ba = bytearray(self.data_128)
+ ct_ba = bytearray(ct)
+ tag_ba = bytearray(tag)
+ del data_ba
+
+ cipher3 = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ key_ba[:3] = b'\xFF\xFF\xFF'
+ nonce_ba[:3] = b'\xFF\xFF\xFF'
+ cipher3.update(header_ba)
+ header_ba[:3] = b'\xFF\xFF\xFF'
+ pt_test = cipher3.decrypt(ct_ba)
+ ct_ba[:3] = b'\xFF\xFF\xFF'
+ cipher3.verify(tag_ba)
+
+ self.assertEqual(pt_test, self.data_128)
+
+ def test_memoryview(self):
+
+ # Encrypt
+ key_mv = memoryview(bytearray(self.key_256))
+ nonce_mv = memoryview(bytearray(self.nonce_96))
+ header_mv = memoryview(bytearray(self.data_128))
+ data_mv = memoryview(bytearray(self.data_128))
+
+ cipher1 = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher1.update(self.data_128)
+ ct = cipher1.encrypt(self.data_128)
+ tag = cipher1.digest()
+
+ cipher2 = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ key_mv[:3] = b'\xFF\xFF\xFF'
+ nonce_mv[:3] = b'\xFF\xFF\xFF'
+ cipher2.update(header_mv)
+ header_mv[:3] = b'\xFF\xFF\xFF'
+ ct_test = cipher2.encrypt(data_mv)
+ data_mv[:3] = b'\x99\x99\x99'
+ tag_test = cipher2.digest()
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key_mv = memoryview(bytearray(self.key_256))
+ nonce_mv = memoryview(bytearray(self.nonce_96))
+ header_mv = memoryview(bytearray(self.data_128))
+ ct_mv = memoryview(bytearray(ct))
+ tag_mv = memoryview(bytearray(tag))
+ del data_mv
+
+ cipher3 = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ key_mv[:3] = b'\xFF\xFF\xFF'
+ nonce_mv[:3] = b'\xFF\xFF\xFF'
+ cipher3.update(header_mv)
+ header_mv[:3] = b'\xFF\xFF\xFF'
+ pt_test = cipher3.decrypt(ct_mv)
+ ct_mv[:3] = b'\x99\x99\x99'
+ cipher3.verify(tag_mv)
+
+ self.assertEqual(pt_test, self.data_128)
+
+
+class XChaCha20Poly1305Tests(unittest.TestCase):
+
+ def test_encrypt(self):
+ # From https://tools.ietf.org/html/draft-arciszewski-xchacha-03
+ # Section A.3.1
+
+ pt = b"""
+ 4c616469657320616e642047656e746c656d656e206f662074686520636c6173
+ 73206f66202739393a204966204920636f756c64206f6666657220796f75206f
+ 6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73
+ 637265656e20776f756c642062652069742e"""
+ pt = unhexlify(pt.replace(b"\n", b"").replace(b" ", b""))
+
+ aad = unhexlify(b"50515253c0c1c2c3c4c5c6c7")
+ key = unhexlify(b"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f")
+ iv = unhexlify(b"404142434445464748494a4b4c4d4e4f5051525354555657")
+
+ ct = b"""
+ bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb
+ 731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b452
+ 2f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff9
+ 21f9664c97637da9768812f615c68b13b52e"""
+ ct = unhexlify(ct.replace(b"\n", b"").replace(b" ", b""))
+
+ tag = unhexlify(b"c0875924c1c7987947deafd8780acf49")
+
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=iv)
+ cipher.update(aad)
+ ct_test, tag_test = cipher.encrypt_and_digest(pt)
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=iv)
+ cipher.update(aad)
+ cipher.decrypt_and_verify(ct, tag)
+
+
+class ChaCha20Poly1305FSMTests(unittest.TestCase):
+
+ key_256 = get_tag_random("key_256", 32)
+ nonce_96 = get_tag_random("nonce_96", 12)
+ data_128 = get_tag_random("data_128", 16)
+
+ def test_valid_init_encrypt_decrypt_digest_verify(self):
+ # No authenticated data, fixed plaintext
+ # Verify path INIT->ENCRYPT->DIGEST
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ ct = cipher.encrypt(self.data_128)
+ mac = cipher.digest()
+
+ # Verify path INIT->DECRYPT->VERIFY
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+
+ def test_valid_init_update_digest_verify(self):
+ # No plaintext, fixed authenticated data
+ # Verify path INIT->UPDATE->DIGEST
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ mac = cipher.digest()
+
+ # Verify path INIT->UPDATE->VERIFY
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ cipher.verify(mac)
+
+ def test_valid_full_path(self):
+ # Fixed authenticated data, fixed plaintext
+ # Verify path INIT->UPDATE->ENCRYPT->DIGEST
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ ct = cipher.encrypt(self.data_128)
+ mac = cipher.digest()
+
+ # Verify path INIT->UPDATE->DECRYPT->VERIFY
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+
+ def test_valid_init_digest(self):
+ # Verify path INIT->DIGEST
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.digest()
+
+ def test_valid_init_verify(self):
+ # Verify path INIT->VERIFY
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ mac = cipher.digest()
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.verify(mac)
+
+ def test_valid_multiple_encrypt_or_decrypt(self):
+ for method_name in "encrypt", "decrypt":
+ for auth_data in (None, b"333", self.data_128,
+ self.data_128 + b"3"):
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ if auth_data is not None:
+ cipher.update(auth_data)
+ method = getattr(cipher, method_name)
+ method(self.data_128)
+ method(self.data_128)
+ method(self.data_128)
+ method(self.data_128)
+
+ def test_valid_multiple_digest_or_verify(self):
+ # Multiple calls to digest
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ first_mac = cipher.digest()
+ for x in range(4):
+ self.assertEqual(first_mac, cipher.digest())
+
+ # Multiple calls to verify
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ for x in range(5):
+ cipher.verify(first_mac)
+
+ def test_valid_encrypt_and_digest_decrypt_and_verify(self):
+ # encrypt_and_digest
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ ct, mac = cipher.encrypt_and_digest(self.data_128)
+
+ # decrypt_and_verify
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ pt = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(self.data_128, pt)
+
+ def test_invalid_mixing_encrypt_decrypt(self):
+ # Once per method, with or without assoc. data
+ for method1_name, method2_name in (("encrypt", "decrypt"),
+ ("decrypt", "encrypt")):
+ for assoc_data_present in (True, False):
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ if assoc_data_present:
+ cipher.update(self.data_128)
+ getattr(cipher, method1_name)(self.data_128)
+ self.assertRaises(TypeError, getattr(cipher, method2_name),
+ self.data_128)
+
+ def test_invalid_encrypt_or_update_after_digest(self):
+ for method_name in "encrypt", "update":
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.encrypt(self.data_128)
+ cipher.digest()
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data_128)
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.encrypt_and_digest(self.data_128)
+
+ def test_invalid_decrypt_or_update_after_verify(self):
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ ct = cipher.encrypt(self.data_128)
+ mac = cipher.digest()
+
+ for method_name in "decrypt", "update":
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data_128)
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data_128)
+
+ cipher = ChaCha20_Poly1305.new(key=self.key_256,
+ nonce=self.nonce_96)
+ cipher.decrypt_and_verify(ct, mac)
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data_128)
+
+
+def compact(x):
+ return unhexlify(x.replace(" ", "").replace(":", ""))
+
+
+class TestVectorsRFC(unittest.TestCase):
+ """Test cases from RFC7539"""
+
+ # AAD, PT, CT, MAC, KEY, NONCE
+ test_vectors_hex = [
+ ( '50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c7',
+ '4c 61 64 69 65 73 20 61 6e 64 20 47 65 6e 74 6c'
+ '65 6d 65 6e 20 6f 66 20 74 68 65 20 63 6c 61 73'
+ '73 20 6f 66 20 27 39 39 3a 20 49 66 20 49 20 63'
+ '6f 75 6c 64 20 6f 66 66 65 72 20 79 6f 75 20 6f'
+ '6e 6c 79 20 6f 6e 65 20 74 69 70 20 66 6f 72 20'
+ '74 68 65 20 66 75 74 75 72 65 2c 20 73 75 6e 73'
+ '63 72 65 65 6e 20 77 6f 75 6c 64 20 62 65 20 69'
+ '74 2e',
+ 'd3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2'
+ 'a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6'
+ '3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b'
+ '1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36'
+ '92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58'
+ 'fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc'
+ '3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b'
+ '61 16',
+ '1a:e1:0b:59:4f:09:e2:6a:7e:90:2e:cb:d0:60:06:91',
+ '80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f'
+ '90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f',
+ '07 00 00 00' + '40 41 42 43 44 45 46 47',
+ ),
+ ( 'f3 33 88 86 00 00 00 00 00 00 4e 91',
+ '49 6e 74 65 72 6e 65 74 2d 44 72 61 66 74 73 20'
+ '61 72 65 20 64 72 61 66 74 20 64 6f 63 75 6d 65'
+ '6e 74 73 20 76 61 6c 69 64 20 66 6f 72 20 61 20'
+ '6d 61 78 69 6d 75 6d 20 6f 66 20 73 69 78 20 6d'
+ '6f 6e 74 68 73 20 61 6e 64 20 6d 61 79 20 62 65'
+ '20 75 70 64 61 74 65 64 2c 20 72 65 70 6c 61 63'
+ '65 64 2c 20 6f 72 20 6f 62 73 6f 6c 65 74 65 64'
+ '20 62 79 20 6f 74 68 65 72 20 64 6f 63 75 6d 65'
+ '6e 74 73 20 61 74 20 61 6e 79 20 74 69 6d 65 2e'
+ '20 49 74 20 69 73 20 69 6e 61 70 70 72 6f 70 72'
+ '69 61 74 65 20 74 6f 20 75 73 65 20 49 6e 74 65'
+ '72 6e 65 74 2d 44 72 61 66 74 73 20 61 73 20 72'
+ '65 66 65 72 65 6e 63 65 20 6d 61 74 65 72 69 61'
+ '6c 20 6f 72 20 74 6f 20 63 69 74 65 20 74 68 65'
+ '6d 20 6f 74 68 65 72 20 74 68 61 6e 20 61 73 20'
+ '2f e2 80 9c 77 6f 72 6b 20 69 6e 20 70 72 6f 67'
+ '72 65 73 73 2e 2f e2 80 9d',
+ '64 a0 86 15 75 86 1a f4 60 f0 62 c7 9b e6 43 bd'
+ '5e 80 5c fd 34 5c f3 89 f1 08 67 0a c7 6c 8c b2'
+ '4c 6c fc 18 75 5d 43 ee a0 9e e9 4e 38 2d 26 b0'
+ 'bd b7 b7 3c 32 1b 01 00 d4 f0 3b 7f 35 58 94 cf'
+ '33 2f 83 0e 71 0b 97 ce 98 c8 a8 4a bd 0b 94 81'
+ '14 ad 17 6e 00 8d 33 bd 60 f9 82 b1 ff 37 c8 55'
+ '97 97 a0 6e f4 f0 ef 61 c1 86 32 4e 2b 35 06 38'
+ '36 06 90 7b 6a 7c 02 b0 f9 f6 15 7b 53 c8 67 e4'
+ 'b9 16 6c 76 7b 80 4d 46 a5 9b 52 16 cd e7 a4 e9'
+ '90 40 c5 a4 04 33 22 5e e2 82 a1 b0 a0 6c 52 3e'
+ 'af 45 34 d7 f8 3f a1 15 5b 00 47 71 8c bc 54 6a'
+ '0d 07 2b 04 b3 56 4e ea 1b 42 22 73 f5 48 27 1a'
+ '0b b2 31 60 53 fa 76 99 19 55 eb d6 31 59 43 4e'
+ 'ce bb 4e 46 6d ae 5a 10 73 a6 72 76 27 09 7a 10'
+ '49 e6 17 d9 1d 36 10 94 fa 68 f0 ff 77 98 71 30'
+ '30 5b ea ba 2e da 04 df 99 7b 71 4d 6c 6f 2c 29'
+ 'a6 ad 5c b4 02 2b 02 70 9b',
+ 'ee ad 9d 67 89 0c bb 22 39 23 36 fe a1 85 1f 38',
+ '1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0'
+ '47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0',
+ '00 00 00 00 01 02 03 04 05 06 07 08',
+ )
+ ]
+
+ test_vectors = [[unhexlify(x.replace(" ","").replace(":","")) for x in tv] for tv in test_vectors_hex]
+
+ def runTest(self):
+ for assoc_data, pt, ct, mac, key, nonce in self.test_vectors:
+ # Encrypt
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
+ cipher.update(assoc_data)
+ ct2, mac2 = cipher.encrypt_and_digest(pt)
+ self.assertEqual(ct, ct2)
+ self.assertEqual(mac, mac2)
+
+ # Decrypt
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
+ cipher.update(assoc_data)
+ pt2 = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(pt, pt2)
+
+
+class TestVectorsWycheproof(unittest.TestCase):
+
+ def __init__(self, wycheproof_warnings):
+ unittest.TestCase.__init__(self)
+ self._wycheproof_warnings = wycheproof_warnings
+ self._id = "None"
+
+ def load_tests(self, filename):
+
+ def filter_tag(group):
+ return group['tagSize'] // 8
+
+ def filter_algo(root):
+ return root['algorithm']
+
+ result = load_test_vectors_wycheproof(("Cipher", "wycheproof"),
+ filename,
+ "Wycheproof ChaCha20-Poly1305",
+ root_tag={'algo': filter_algo},
+ group_tag={'tag_size': filter_tag})
+ return result
+
+ def setUp(self):
+ self.tv = []
+ self.tv.extend(self.load_tests("chacha20_poly1305_test.json"))
+ self.tv.extend(self.load_tests("xchacha20_poly1305_test.json"))
+
+ def shortDescription(self):
+ return self._id
+
+ def warn(self, tv):
+ if tv.warning and self._wycheproof_warnings:
+ import warnings
+ warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment))
+
+ def test_encrypt(self, tv):
+ self._id = "Wycheproof Encrypt %s Test #%s" % (tv.algo, tv.id)
+
+ try:
+ cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv)
+ except ValueError as e:
+ assert len(tv.iv) not in (8, 12) and "Nonce must be" in str(e)
+ return
+
+ cipher.update(tv.aad)
+ ct, tag = cipher.encrypt_and_digest(tv.msg)
+ if tv.valid:
+ self.assertEqual(ct, tv.ct)
+ self.assertEqual(tag, tv.tag)
+ self.warn(tv)
+
+ def test_decrypt(self, tv):
+ self._id = "Wycheproof Decrypt %s Test #%s" % (tv.algo, tv.id)
+
+ try:
+ cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv)
+ except ValueError as e:
+ assert len(tv.iv) not in (8, 12) and "Nonce must be" in str(e)
+ return
+
+ cipher.update(tv.aad)
+ try:
+ pt = cipher.decrypt_and_verify(tv.ct, tv.tag)
+ except ValueError:
+ assert not tv.valid
+ else:
+ assert tv.valid
+ self.assertEqual(pt, tv.msg)
+ self.warn(tv)
+
+ def test_corrupt_decrypt(self, tv):
+ self._id = "Wycheproof Corrupt Decrypt ChaCha20-Poly1305 Test #" + str(tv.id)
+ if len(tv.iv) == 0 or len(tv.ct) < 1:
+ return
+ cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv)
+ cipher.update(tv.aad)
+ ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01")
+ self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag)
+
+ def runTest(self):
+
+ for tv in self.tv:
+ self.test_encrypt(tv)
+ self.test_decrypt(tv)
+ self.test_corrupt_decrypt(tv)
+
+
+class TestOutput(unittest.TestCase):
+
+ def runTest(self):
+ # Encrypt/Decrypt data and test output parameter
+
+ key = b'4' * 32
+ nonce = b'5' * 12
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
+
+ pt = b'5' * 16
+ ct = cipher.encrypt(pt)
+
+ output = bytearray(16)
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ output = memoryview(bytearray(16))
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16)
+
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16)
+
+ shorter_output = bytearray(7)
+
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+
+ cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+def get_tests(config={}):
+ wycheproof_warnings = config.get('wycheproof_warnings')
+
+ tests = []
+ tests += list_test_cases(ChaCha20Poly1305Tests)
+ tests += list_test_cases(XChaCha20Poly1305Tests)
+ tests += list_test_cases(ChaCha20Poly1305FSMTests)
+ tests += [TestVectorsRFC()]
+ tests += [TestVectorsWycheproof(wycheproof_warnings)]
+ tests += [TestOutput()]
+ return tests
+
+
+if __name__ == '__main__':
+ def suite():
+ unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_DES.py b/lib/Crypto/SelfTest/Cipher/test_DES.py
new file mode 100644
index 0000000..ee261bc
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_DES.py
@@ -0,0 +1,374 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Cipher/DES.py: Self-test for the (Single) DES cipher
+#
+# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+"""Self-test suite for Crypto.Cipher.DES"""
+
+import unittest
+
+from Crypto.Cipher import DES
+
+# This is a list of (plaintext, ciphertext, key, description) tuples.
+SP800_17_B1_KEY = '01' * 8
+SP800_17_B2_PT = '00' * 8
+test_data = [
+ # Test vectors from Appendix A of NIST SP 800-17
+ # "Modes of Operation Validation System (MOVS): Requirements and Procedures"
+ # http://csrc.nist.gov/publications/nistpubs/800-17/800-17.pdf
+
+ # Appendix A - "Sample Round Outputs for the DES"
+ ('0000000000000000', '82dcbafbdeab6602', '10316e028c8f3b4a',
+ "NIST SP800-17 A"),
+
+ # Table B.1 - Variable Plaintext Known Answer Test
+ ('8000000000000000', '95f8a5e5dd31d900', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #0'),
+ ('4000000000000000', 'dd7f121ca5015619', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #1'),
+ ('2000000000000000', '2e8653104f3834ea', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #2'),
+ ('1000000000000000', '4bd388ff6cd81d4f', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #3'),
+ ('0800000000000000', '20b9e767b2fb1456', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #4'),
+ ('0400000000000000', '55579380d77138ef', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #5'),
+ ('0200000000000000', '6cc5defaaf04512f', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #6'),
+ ('0100000000000000', '0d9f279ba5d87260', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #7'),
+ ('0080000000000000', 'd9031b0271bd5a0a', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #8'),
+ ('0040000000000000', '424250b37c3dd951', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #9'),
+ ('0020000000000000', 'b8061b7ecd9a21e5', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #10'),
+ ('0010000000000000', 'f15d0f286b65bd28', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #11'),
+ ('0008000000000000', 'add0cc8d6e5deba1', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #12'),
+ ('0004000000000000', 'e6d5f82752ad63d1', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #13'),
+ ('0002000000000000', 'ecbfe3bd3f591a5e', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #14'),
+ ('0001000000000000', 'f356834379d165cd', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #15'),
+ ('0000800000000000', '2b9f982f20037fa9', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #16'),
+ ('0000400000000000', '889de068a16f0be6', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #17'),
+ ('0000200000000000', 'e19e275d846a1298', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #18'),
+ ('0000100000000000', '329a8ed523d71aec', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #19'),
+ ('0000080000000000', 'e7fce22557d23c97', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #20'),
+ ('0000040000000000', '12a9f5817ff2d65d', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #21'),
+ ('0000020000000000', 'a484c3ad38dc9c19', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #22'),
+ ('0000010000000000', 'fbe00a8a1ef8ad72', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #23'),
+ ('0000008000000000', '750d079407521363', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #24'),
+ ('0000004000000000', '64feed9c724c2faf', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #25'),
+ ('0000002000000000', 'f02b263b328e2b60', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #26'),
+ ('0000001000000000', '9d64555a9a10b852', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #27'),
+ ('0000000800000000', 'd106ff0bed5255d7', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #28'),
+ ('0000000400000000', 'e1652c6b138c64a5', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #29'),
+ ('0000000200000000', 'e428581186ec8f46', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #30'),
+ ('0000000100000000', 'aeb5f5ede22d1a36', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #31'),
+ ('0000000080000000', 'e943d7568aec0c5c', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #32'),
+ ('0000000040000000', 'df98c8276f54b04b', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #33'),
+ ('0000000020000000', 'b160e4680f6c696f', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #34'),
+ ('0000000010000000', 'fa0752b07d9c4ab8', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #35'),
+ ('0000000008000000', 'ca3a2b036dbc8502', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #36'),
+ ('0000000004000000', '5e0905517bb59bcf', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #37'),
+ ('0000000002000000', '814eeb3b91d90726', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #38'),
+ ('0000000001000000', '4d49db1532919c9f', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #39'),
+ ('0000000000800000', '25eb5fc3f8cf0621', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #40'),
+ ('0000000000400000', 'ab6a20c0620d1c6f', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #41'),
+ ('0000000000200000', '79e90dbc98f92cca', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #42'),
+ ('0000000000100000', '866ecedd8072bb0e', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #43'),
+ ('0000000000080000', '8b54536f2f3e64a8', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #44'),
+ ('0000000000040000', 'ea51d3975595b86b', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #45'),
+ ('0000000000020000', 'caffc6ac4542de31', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #46'),
+ ('0000000000010000', '8dd45a2ddf90796c', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #47'),
+ ('0000000000008000', '1029d55e880ec2d0', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #48'),
+ ('0000000000004000', '5d86cb23639dbea9', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #49'),
+ ('0000000000002000', '1d1ca853ae7c0c5f', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #50'),
+ ('0000000000001000', 'ce332329248f3228', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #51'),
+ ('0000000000000800', '8405d1abe24fb942', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #52'),
+ ('0000000000000400', 'e643d78090ca4207', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #53'),
+ ('0000000000000200', '48221b9937748a23', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #54'),
+ ('0000000000000100', 'dd7c0bbd61fafd54', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #55'),
+ ('0000000000000080', '2fbc291a570db5c4', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #56'),
+ ('0000000000000040', 'e07c30d7e4e26e12', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #57'),
+ ('0000000000000020', '0953e2258e8e90a1', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #58'),
+ ('0000000000000010', '5b711bc4ceebf2ee', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #59'),
+ ('0000000000000008', 'cc083f1e6d9e85f6', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #60'),
+ ('0000000000000004', 'd2fd8867d50d2dfe', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #61'),
+ ('0000000000000002', '06e7ea22ce92708f', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #62'),
+ ('0000000000000001', '166b40b44aba4bd6', SP800_17_B1_KEY,
+ 'NIST SP800-17 B.1 #63'),
+
+ # Table B.2 - Variable Key Known Answer Test
+ (SP800_17_B2_PT, '95a8d72813daa94d', '8001010101010101',
+ 'NIST SP800-17 B.2 #0'),
+ (SP800_17_B2_PT, '0eec1487dd8c26d5', '4001010101010101',
+ 'NIST SP800-17 B.2 #1'),
+ (SP800_17_B2_PT, '7ad16ffb79c45926', '2001010101010101',
+ 'NIST SP800-17 B.2 #2'),
+ (SP800_17_B2_PT, 'd3746294ca6a6cf3', '1001010101010101',
+ 'NIST SP800-17 B.2 #3'),
+ (SP800_17_B2_PT, '809f5f873c1fd761', '0801010101010101',
+ 'NIST SP800-17 B.2 #4'),
+ (SP800_17_B2_PT, 'c02faffec989d1fc', '0401010101010101',
+ 'NIST SP800-17 B.2 #5'),
+ (SP800_17_B2_PT, '4615aa1d33e72f10', '0201010101010101',
+ 'NIST SP800-17 B.2 #6'),
+ (SP800_17_B2_PT, '2055123350c00858', '0180010101010101',
+ 'NIST SP800-17 B.2 #7'),
+ (SP800_17_B2_PT, 'df3b99d6577397c8', '0140010101010101',
+ 'NIST SP800-17 B.2 #8'),
+ (SP800_17_B2_PT, '31fe17369b5288c9', '0120010101010101',
+ 'NIST SP800-17 B.2 #9'),
+ (SP800_17_B2_PT, 'dfdd3cc64dae1642', '0110010101010101',
+ 'NIST SP800-17 B.2 #10'),
+ (SP800_17_B2_PT, '178c83ce2b399d94', '0108010101010101',
+ 'NIST SP800-17 B.2 #11'),
+ (SP800_17_B2_PT, '50f636324a9b7f80', '0104010101010101',
+ 'NIST SP800-17 B.2 #12'),
+ (SP800_17_B2_PT, 'a8468ee3bc18f06d', '0102010101010101',
+ 'NIST SP800-17 B.2 #13'),
+ (SP800_17_B2_PT, 'a2dc9e92fd3cde92', '0101800101010101',
+ 'NIST SP800-17 B.2 #14'),
+ (SP800_17_B2_PT, 'cac09f797d031287', '0101400101010101',
+ 'NIST SP800-17 B.2 #15'),
+ (SP800_17_B2_PT, '90ba680b22aeb525', '0101200101010101',
+ 'NIST SP800-17 B.2 #16'),
+ (SP800_17_B2_PT, 'ce7a24f350e280b6', '0101100101010101',
+ 'NIST SP800-17 B.2 #17'),
+ (SP800_17_B2_PT, '882bff0aa01a0b87', '0101080101010101',
+ 'NIST SP800-17 B.2 #18'),
+ (SP800_17_B2_PT, '25610288924511c2', '0101040101010101',
+ 'NIST SP800-17 B.2 #19'),
+ (SP800_17_B2_PT, 'c71516c29c75d170', '0101020101010101',
+ 'NIST SP800-17 B.2 #20'),
+ (SP800_17_B2_PT, '5199c29a52c9f059', '0101018001010101',
+ 'NIST SP800-17 B.2 #21'),
+ (SP800_17_B2_PT, 'c22f0a294a71f29f', '0101014001010101',
+ 'NIST SP800-17 B.2 #22'),
+ (SP800_17_B2_PT, 'ee371483714c02ea', '0101012001010101',
+ 'NIST SP800-17 B.2 #23'),
+ (SP800_17_B2_PT, 'a81fbd448f9e522f', '0101011001010101',
+ 'NIST SP800-17 B.2 #24'),
+ (SP800_17_B2_PT, '4f644c92e192dfed', '0101010801010101',
+ 'NIST SP800-17 B.2 #25'),
+ (SP800_17_B2_PT, '1afa9a66a6df92ae', '0101010401010101',
+ 'NIST SP800-17 B.2 #26'),
+ (SP800_17_B2_PT, 'b3c1cc715cb879d8', '0101010201010101',
+ 'NIST SP800-17 B.2 #27'),
+ (SP800_17_B2_PT, '19d032e64ab0bd8b', '0101010180010101',
+ 'NIST SP800-17 B.2 #28'),
+ (SP800_17_B2_PT, '3cfaa7a7dc8720dc', '0101010140010101',
+ 'NIST SP800-17 B.2 #29'),
+ (SP800_17_B2_PT, 'b7265f7f447ac6f3', '0101010120010101',
+ 'NIST SP800-17 B.2 #30'),
+ (SP800_17_B2_PT, '9db73b3c0d163f54', '0101010110010101',
+ 'NIST SP800-17 B.2 #31'),
+ (SP800_17_B2_PT, '8181b65babf4a975', '0101010108010101',
+ 'NIST SP800-17 B.2 #32'),
+ (SP800_17_B2_PT, '93c9b64042eaa240', '0101010104010101',
+ 'NIST SP800-17 B.2 #33'),
+ (SP800_17_B2_PT, '5570530829705592', '0101010102010101',
+ 'NIST SP800-17 B.2 #34'),
+ (SP800_17_B2_PT, '8638809e878787a0', '0101010101800101',
+ 'NIST SP800-17 B.2 #35'),
+ (SP800_17_B2_PT, '41b9a79af79ac208', '0101010101400101',
+ 'NIST SP800-17 B.2 #36'),
+ (SP800_17_B2_PT, '7a9be42f2009a892', '0101010101200101',
+ 'NIST SP800-17 B.2 #37'),
+ (SP800_17_B2_PT, '29038d56ba6d2745', '0101010101100101',
+ 'NIST SP800-17 B.2 #38'),
+ (SP800_17_B2_PT, '5495c6abf1e5df51', '0101010101080101',
+ 'NIST SP800-17 B.2 #39'),
+ (SP800_17_B2_PT, 'ae13dbd561488933', '0101010101040101',
+ 'NIST SP800-17 B.2 #40'),
+ (SP800_17_B2_PT, '024d1ffa8904e389', '0101010101020101',
+ 'NIST SP800-17 B.2 #41'),
+ (SP800_17_B2_PT, 'd1399712f99bf02e', '0101010101018001',
+ 'NIST SP800-17 B.2 #42'),
+ (SP800_17_B2_PT, '14c1d7c1cffec79e', '0101010101014001',
+ 'NIST SP800-17 B.2 #43'),
+ (SP800_17_B2_PT, '1de5279dae3bed6f', '0101010101012001',
+ 'NIST SP800-17 B.2 #44'),
+ (SP800_17_B2_PT, 'e941a33f85501303', '0101010101011001',
+ 'NIST SP800-17 B.2 #45'),
+ (SP800_17_B2_PT, 'da99dbbc9a03f379', '0101010101010801',
+ 'NIST SP800-17 B.2 #46'),
+ (SP800_17_B2_PT, 'b7fc92f91d8e92e9', '0101010101010401',
+ 'NIST SP800-17 B.2 #47'),
+ (SP800_17_B2_PT, 'ae8e5caa3ca04e85', '0101010101010201',
+ 'NIST SP800-17 B.2 #48'),
+ (SP800_17_B2_PT, '9cc62df43b6eed74', '0101010101010180',
+ 'NIST SP800-17 B.2 #49'),
+ (SP800_17_B2_PT, 'd863dbb5c59a91a0', '0101010101010140',
+ 'NIST SP800-17 B.2 #50'),
+ (SP800_17_B2_PT, 'a1ab2190545b91d7', '0101010101010120',
+ 'NIST SP800-17 B.2 #51'),
+ (SP800_17_B2_PT, '0875041e64c570f7', '0101010101010110',
+ 'NIST SP800-17 B.2 #52'),
+ (SP800_17_B2_PT, '5a594528bebef1cc', '0101010101010108',
+ 'NIST SP800-17 B.2 #53'),
+ (SP800_17_B2_PT, 'fcdb3291de21f0c0', '0101010101010104',
+ 'NIST SP800-17 B.2 #54'),
+ (SP800_17_B2_PT, '869efd7f9f265a09', '0101010101010102',
+ 'NIST SP800-17 B.2 #55'),
+]
+
+class RonRivestTest(unittest.TestCase):
+ """ Ronald L. Rivest's DES test, see
+ http://people.csail.mit.edu/rivest/Destest.txt
+ ABSTRACT
+ --------
+
+ We present a simple way to test the correctness of a DES implementation:
+ Use the recurrence relation:
+
+ X0 = 9474B8E8C73BCA7D (hexadecimal)
+
+ X(i+1) = IF (i is even) THEN E(Xi,Xi) ELSE D(Xi,Xi)
+
+ to compute a sequence of 64-bit values: X0, X1, X2, ..., X16. Here
+ E(X,K) denotes the DES encryption of X using key K, and D(X,K) denotes
+ the DES decryption of X using key K. If you obtain
+
+ X16 = 1B1A2DDB4C642438
+
+ your implementation does not have any of the 36,568 possible single-fault
+ errors described herein.
+ """
+ def runTest(self):
+ from binascii import b2a_hex
+
+ X = []
+ X[0:] = [b'\x94\x74\xB8\xE8\xC7\x3B\xCA\x7D']
+
+ for i in range(16):
+ c = DES.new(X[i],DES.MODE_ECB)
+ if not (i&1): # (num&1) returns 1 for odd numbers
+ X[i+1:] = [c.encrypt(X[i])] # even
+ else:
+ X[i+1:] = [c.decrypt(X[i])] # odd
+
+ self.assertEqual(b2a_hex(X[16]),
+ b2a_hex(b'\x1B\x1A\x2D\xDB\x4C\x64\x24\x38'))
+
+
+class TestOutput(unittest.TestCase):
+
+ def runTest(self):
+ # Encrypt/Decrypt data and test output parameter
+
+ cipher = DES.new(b'4'*8, DES.MODE_ECB)
+
+ pt = b'5' * 8
+ ct = cipher.encrypt(pt)
+
+ output = bytearray(8)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ output = memoryview(bytearray(8))
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*8)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*8)
+
+ shorter_output = bytearray(7)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+def get_tests(config={}):
+ from .common import make_block_tests
+ tests = make_block_tests(DES, "DES", test_data)
+ tests += [RonRivestTest()]
+ tests += [TestOutput()]
+ return tests
+
+
+if __name__ == '__main__':
+ import unittest
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
+
+# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/SelfTest/Cipher/test_DES3.py b/lib/Crypto/SelfTest/Cipher/test_DES3.py
new file mode 100644
index 0000000..8d6a648
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_DES3.py
@@ -0,0 +1,195 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Cipher/DES3.py: Self-test for the Triple-DES cipher
+#
+# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+"""Self-test suite for Crypto.Cipher.DES3"""
+
+import unittest
+from binascii import hexlify, unhexlify
+
+from Crypto.Cipher import DES3
+
+from Crypto.Util.strxor import strxor_c
+from Crypto.Util.py3compat import bchr, tostr
+from Crypto.SelfTest.loader import load_test_vectors
+from Crypto.SelfTest.st_common import list_test_cases
+
+# This is a list of (plaintext, ciphertext, key, description) tuples.
+test_data = [
+ # Test vector from Appendix B of NIST SP 800-67
+ # "Recommendation for the Triple Data Encryption Algorithm (TDEA) Block
+ # Cipher"
+ # http://csrc.nist.gov/publications/nistpubs/800-67/SP800-67.pdf
+ ('54686520717566636b2062726f776e20666f78206a756d70',
+ 'a826fd8ce53b855fcce21c8112256fe668d5c05dd9b6b900',
+ '0123456789abcdef23456789abcdef01456789abcdef0123',
+ 'NIST SP800-67 B.1'),
+
+ # This test is designed to test the DES3 API, not the correctness of the
+ # output.
+ ('21e81b7ade88a259', '5c577d4d9b20c0f8',
+ '9b397ebf81b1181e282f4bb8adbadc6b', 'Two-key 3DES'),
+]
+
+# NIST CAVP test vectors
+
+nist_tdes_mmt_files = ("TECBMMT2.rsp", "TECBMMT3.rsp")
+
+for tdes_file in nist_tdes_mmt_files:
+
+ test_vectors = load_test_vectors(
+ ("Cipher", "TDES"),
+ tdes_file,
+ "TDES ECB (%s)" % tdes_file,
+ {"count": lambda x: int(x)}) or []
+
+ for index, tv in enumerate(test_vectors):
+
+ # The test vector file contains some directive lines
+ if isinstance(tv, str):
+ continue
+
+ key = tv.key1 + tv.key2 + tv.key3
+ test_data_item = (tostr(hexlify(tv.plaintext)),
+ tostr(hexlify(tv.ciphertext)),
+ tostr(hexlify(key)),
+ "%s (%s)" % (tdes_file, index))
+ test_data.append(test_data_item)
+
+
+class CheckParity(unittest.TestCase):
+
+ def test_parity_option2(self):
+ before_2k = unhexlify("CABF326FA56734324FFCCABCDEFACABF")
+ after_2k = DES3.adjust_key_parity(before_2k)
+ self.assertEqual(after_2k,
+ unhexlify("CBBF326EA46734324FFDCBBCDFFBCBBF"))
+
+ def test_parity_option3(self):
+ before_3k = unhexlify("AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCC")
+ after_3k = DES3.adjust_key_parity(before_3k)
+ self.assertEqual(after_3k,
+ unhexlify("ABABABABABABABABBABABABABABABABACDCDCDCDCDCDCDCD"))
+
+ def test_degradation(self):
+ sub_key1 = bchr(1) * 8
+ sub_key2 = bchr(255) * 8
+
+ # K1 == K2
+ self.assertRaises(ValueError, DES3.adjust_key_parity,
+ sub_key1 * 2 + sub_key2)
+
+ # K2 == K3
+ self.assertRaises(ValueError, DES3.adjust_key_parity,
+ sub_key1 + sub_key2 * 2)
+
+ # K1 == K2 == K3
+ self.assertRaises(ValueError, DES3.adjust_key_parity,
+ sub_key1 * 3)
+
+ # K1 == K2 (with different parity)
+ self.assertRaises(ValueError, DES3.adjust_key_parity,
+ sub_key1 + strxor_c(sub_key1, 1) + sub_key2)
+
+
+class DegenerateToDESTest(unittest.TestCase):
+
+ def runTest(self):
+ sub_key1 = bchr(1) * 8
+ sub_key2 = bchr(255) * 8
+
+ # K1 == K2
+ self.assertRaises(ValueError, DES3.new,
+ sub_key1 * 2 + sub_key2,
+ DES3.MODE_ECB)
+
+ # K2 == K3
+ self.assertRaises(ValueError, DES3.new,
+ sub_key1 + sub_key2 * 2,
+ DES3.MODE_ECB)
+
+ # K1 == K2 == K3
+ self.assertRaises(ValueError, DES3.new,
+ sub_key1 * 3,
+ DES3.MODE_ECB)
+
+ # K2 == K3 (parity is ignored)
+ self.assertRaises(ValueError, DES3.new,
+ sub_key1 + sub_key2 + strxor_c(sub_key2, 0x1),
+ DES3.MODE_ECB)
+
+
+class TestOutput(unittest.TestCase):
+
+ def runTest(self):
+ # Encrypt/Decrypt data and test output parameter
+
+ cipher = DES3.new(b'4'*8 + b'G'*8 + b'T'*8, DES3.MODE_ECB)
+
+ pt = b'5' * 16
+ ct = cipher.encrypt(pt)
+
+ output = bytearray(16)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ output = memoryview(bytearray(16))
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16)
+
+ shorter_output = bytearray(7)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+def get_tests(config={}):
+ from .common import make_block_tests
+
+ tests = []
+ tests = make_block_tests(DES3, "DES3", test_data)
+ tests.append(DegenerateToDESTest())
+ tests += list_test_cases(CheckParity)
+ tests += [TestOutput()]
+ return tests
+
+
+if __name__ == '__main__':
+ import unittest
+
+ def suite():
+ unittest.TestSuite(get_tests())
+
+ unittest.main(defaultTest='suite')
+
+# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/SelfTest/Cipher/test_EAX.py b/lib/Crypto/SelfTest/Cipher/test_EAX.py
new file mode 100644
index 0000000..fe93d71
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_EAX.py
@@ -0,0 +1,773 @@
+# ===================================================================
+#
+# Copyright (c) 2015, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+import unittest
+from binascii import unhexlify
+
+from Crypto.SelfTest.st_common import list_test_cases
+from Crypto.SelfTest.loader import load_test_vectors_wycheproof
+from Crypto.Util.py3compat import tobytes, bchr
+from Crypto.Cipher import AES, DES3
+from Crypto.Hash import SHAKE128
+
+from Crypto.Util.strxor import strxor
+
+
+def get_tag_random(tag, length):
+ return SHAKE128.new(data=tobytes(tag)).read(length)
+
+
+class EaxTests(unittest.TestCase):
+
+ key_128 = get_tag_random("key_128", 16)
+ key_192 = get_tag_random("key_192", 16)
+ nonce_96 = get_tag_random("nonce_128", 12)
+ data_128 = get_tag_random("data_128", 16)
+
+ def test_loopback_128(self):
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ pt = get_tag_random("plaintext", 16 * 100)
+ ct = cipher.encrypt(pt)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def test_loopback_64(self):
+ cipher = DES3.new(self.key_192, DES3.MODE_EAX, nonce=self.nonce_96)
+ pt = get_tag_random("plaintext", 8 * 100)
+ ct = cipher.encrypt(pt)
+
+ cipher = DES3.new(self.key_192, DES3.MODE_EAX, nonce=self.nonce_96)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def test_nonce(self):
+ # If not passed, the nonce is created randomly
+ cipher = AES.new(self.key_128, AES.MODE_EAX)
+ nonce1 = cipher.nonce
+ cipher = AES.new(self.key_128, AES.MODE_EAX)
+ nonce2 = cipher.nonce
+ self.assertEqual(len(nonce1), 16)
+ self.assertNotEqual(nonce1, nonce2)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, self.nonce_96)
+ ct = cipher.encrypt(self.data_128)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ self.assertEqual(ct, cipher.encrypt(self.data_128))
+
+ def test_nonce_must_be_bytes(self):
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX,
+ nonce=u'test12345678')
+
+ def test_nonce_length(self):
+ # nonce can be of any length (but not empty)
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX,
+ nonce=b"")
+
+ for x in range(1, 128):
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=bchr(1) * x)
+ cipher.encrypt(bchr(1))
+
+ def test_block_size_128(self):
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ self.assertEqual(cipher.block_size, AES.block_size)
+
+ def test_block_size_64(self):
+ cipher = DES3.new(self.key_192, AES.MODE_EAX, nonce=self.nonce_96)
+ self.assertEqual(cipher.block_size, DES3.block_size)
+
+ def test_nonce_attribute(self):
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ self.assertEqual(cipher.nonce, self.nonce_96)
+
+ # By default, a 16 bytes long nonce is randomly generated
+ nonce1 = AES.new(self.key_128, AES.MODE_EAX).nonce
+ nonce2 = AES.new(self.key_128, AES.MODE_EAX).nonce
+ self.assertEqual(len(nonce1), 16)
+ self.assertNotEqual(nonce1, nonce2)
+
+ def test_unknown_parameters(self):
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX,
+ self.nonce_96, 7)
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX,
+ nonce=self.nonce_96, unknown=7)
+
+ # But some are only known by the base cipher
+ # (e.g. use_aesni consumed by the AES module)
+ AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96,
+ use_aesni=False)
+
+ def test_null_encryption_decryption(self):
+ for func in "encrypt", "decrypt":
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ result = getattr(cipher, func)(b"")
+ self.assertEqual(result, b"")
+
+ def test_either_encrypt_or_decrypt(self):
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.encrypt(b"")
+ self.assertRaises(TypeError, cipher.decrypt, b"")
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.decrypt(b"")
+ self.assertRaises(TypeError, cipher.encrypt, b"")
+
+ def test_data_must_be_bytes(self):
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*')
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*')
+
+ def test_mac_len(self):
+ # Invalid MAC length
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX,
+ nonce=self.nonce_96, mac_len=3)
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX,
+ nonce=self.nonce_96, mac_len=16+1)
+
+ # Valid MAC length
+ for mac_len in range(5, 16 + 1):
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96,
+ mac_len=mac_len)
+ _, mac = cipher.encrypt_and_digest(self.data_128)
+ self.assertEqual(len(mac), mac_len)
+
+ # Default MAC length
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ _, mac = cipher.encrypt_and_digest(self.data_128)
+ self.assertEqual(len(mac), 16)
+
+ def test_invalid_mac(self):
+ from Crypto.Util.strxor import strxor_c
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ ct, mac = cipher.encrypt_and_digest(self.data_128)
+
+ invalid_mac = strxor_c(mac, 0x01)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.decrypt_and_verify, ct,
+ invalid_mac)
+
+ def test_hex_mac(self):
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ mac_hex = cipher.hexdigest()
+ self.assertEqual(cipher.digest(), unhexlify(mac_hex))
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.hexverify(mac_hex)
+
+ def test_message_chunks(self):
+ # Validate that both associated data and plaintext/ciphertext
+ # can be broken up in chunks of arbitrary length
+
+ auth_data = get_tag_random("authenticated data", 127)
+ plaintext = get_tag_random("plaintext", 127)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.update(auth_data)
+ ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext)
+
+ def break_up(data, chunk_length):
+ return [data[i:i+chunk_length] for i in range(0, len(data),
+ chunk_length)]
+
+ # Encryption
+ for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128:
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+
+ for chunk in break_up(auth_data, chunk_length):
+ cipher.update(chunk)
+ pt2 = b""
+ for chunk in break_up(ciphertext, chunk_length):
+ pt2 += cipher.decrypt(chunk)
+ self.assertEqual(plaintext, pt2)
+ cipher.verify(ref_mac)
+
+ # Decryption
+ for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128:
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+
+ for chunk in break_up(auth_data, chunk_length):
+ cipher.update(chunk)
+ ct2 = b""
+ for chunk in break_up(plaintext, chunk_length):
+ ct2 += cipher.encrypt(chunk)
+ self.assertEqual(ciphertext, ct2)
+ self.assertEqual(cipher.digest(), ref_mac)
+
+ def test_bytearray(self):
+
+ # Encrypt
+ key_ba = bytearray(self.key_128)
+ nonce_ba = bytearray(self.nonce_96)
+ header_ba = bytearray(self.data_128)
+ data_ba = bytearray(self.data_128)
+
+ cipher1 = AES.new(self.key_128,
+ AES.MODE_EAX,
+ nonce=self.nonce_96)
+ cipher1.update(self.data_128)
+ ct = cipher1.encrypt(self.data_128)
+ tag = cipher1.digest()
+
+ cipher2 = AES.new(key_ba,
+ AES.MODE_EAX,
+ nonce=nonce_ba)
+ key_ba[:3] = b'\xFF\xFF\xFF'
+ nonce_ba[:3] = b'\xFF\xFF\xFF'
+ cipher2.update(header_ba)
+ header_ba[:3] = b'\xFF\xFF\xFF'
+ ct_test = cipher2.encrypt(data_ba)
+ data_ba[:3] = b'\x99\x99\x99'
+ tag_test = cipher2.digest()
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key_ba = bytearray(self.key_128)
+ nonce_ba = bytearray(self.nonce_96)
+ header_ba = bytearray(self.data_128)
+ ct_ba = bytearray(ct)
+ tag_ba = bytearray(tag)
+ del data_ba
+
+ cipher3 = AES.new(key_ba,
+ AES.MODE_EAX,
+ nonce=nonce_ba)
+ key_ba[:3] = b'\xFF\xFF\xFF'
+ nonce_ba[:3] = b'\xFF\xFF\xFF'
+ cipher3.update(header_ba)
+ header_ba[:3] = b'\xFF\xFF\xFF'
+ pt_test = cipher3.decrypt(ct_ba)
+ ct_ba[:3] = b'\xFF\xFF\xFF'
+ cipher3.verify(tag_ba)
+
+ self.assertEqual(pt_test, self.data_128)
+
+ def test_memoryview(self):
+
+ # Encrypt
+ key_mv = memoryview(bytearray(self.key_128))
+ nonce_mv = memoryview(bytearray(self.nonce_96))
+ header_mv = memoryview(bytearray(self.data_128))
+ data_mv = memoryview(bytearray(self.data_128))
+
+ cipher1 = AES.new(self.key_128,
+ AES.MODE_EAX,
+ nonce=self.nonce_96)
+ cipher1.update(self.data_128)
+ ct = cipher1.encrypt(self.data_128)
+ tag = cipher1.digest()
+
+ cipher2 = AES.new(key_mv,
+ AES.MODE_EAX,
+ nonce=nonce_mv)
+ key_mv[:3] = b'\xFF\xFF\xFF'
+ nonce_mv[:3] = b'\xFF\xFF\xFF'
+ cipher2.update(header_mv)
+ header_mv[:3] = b'\xFF\xFF\xFF'
+ ct_test = cipher2.encrypt(data_mv)
+ data_mv[:3] = b'\x99\x99\x99'
+ tag_test = cipher2.digest()
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key_mv = memoryview(bytearray(self.key_128))
+ nonce_mv = memoryview(bytearray(self.nonce_96))
+ header_mv = memoryview(bytearray(self.data_128))
+ ct_mv = memoryview(bytearray(ct))
+ tag_mv = memoryview(bytearray(tag))
+ del data_mv
+
+ cipher3 = AES.new(key_mv,
+ AES.MODE_EAX,
+ nonce=nonce_mv)
+ key_mv[:3] = b'\xFF\xFF\xFF'
+ nonce_mv[:3] = b'\xFF\xFF\xFF'
+ cipher3.update(header_mv)
+ header_mv[:3] = b'\xFF\xFF\xFF'
+ pt_test = cipher3.decrypt(ct_mv)
+ ct_mv[:3] = b'\x99\x99\x99'
+ cipher3.verify(tag_mv)
+
+ self.assertEqual(pt_test, self.data_128)
+
+ def test_output_param(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ ct = cipher.encrypt(pt)
+ tag = cipher.digest()
+
+ output = bytearray(128)
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ res, tag_out = cipher.encrypt_and_digest(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+ self.assertEqual(tag, tag_out)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ res = cipher.decrypt_and_verify(ct, tag, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ def test_output_param_memoryview(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ ct = cipher.encrypt(pt)
+
+ output = memoryview(bytearray(128))
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ def test_output_param_neg(self):
+ LEN_PT = 16
+
+ pt = b'5' * LEN_PT
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ ct = cipher.encrypt(pt)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT)
+
+ shorter_output = bytearray(LEN_PT - 1)
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+class EaxFSMTests(unittest.TestCase):
+
+ key_128 = get_tag_random("key_128", 16)
+ nonce_96 = get_tag_random("nonce_128", 12)
+ data_128 = get_tag_random("data_128", 16)
+
+ def test_valid_init_encrypt_decrypt_digest_verify(self):
+ # No authenticated data, fixed plaintext
+ # Verify path INIT->ENCRYPT->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_EAX,
+ nonce=self.nonce_96)
+ ct = cipher.encrypt(self.data_128)
+ mac = cipher.digest()
+
+ # Verify path INIT->DECRYPT->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_EAX,
+ nonce=self.nonce_96)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+
+ def test_valid_init_update_digest_verify(self):
+ # No plaintext, fixed authenticated data
+ # Verify path INIT->UPDATE->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_EAX,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ mac = cipher.digest()
+
+ # Verify path INIT->UPDATE->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_EAX,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ cipher.verify(mac)
+
+ def test_valid_full_path(self):
+ # Fixed authenticated data, fixed plaintext
+ # Verify path INIT->UPDATE->ENCRYPT->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_EAX,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ ct = cipher.encrypt(self.data_128)
+ mac = cipher.digest()
+
+ # Verify path INIT->UPDATE->DECRYPT->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_EAX,
+ nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+
+ def test_valid_init_digest(self):
+ # Verify path INIT->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.digest()
+
+ def test_valid_init_verify(self):
+ # Verify path INIT->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ mac = cipher.digest()
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.verify(mac)
+
+ def test_valid_multiple_encrypt_or_decrypt(self):
+ for method_name in "encrypt", "decrypt":
+ for auth_data in (None, b"333", self.data_128,
+ self.data_128 + b"3"):
+ if auth_data is None:
+ assoc_len = None
+ else:
+ assoc_len = len(auth_data)
+ cipher = AES.new(self.key_128, AES.MODE_EAX,
+ nonce=self.nonce_96)
+ if auth_data is not None:
+ cipher.update(auth_data)
+ method = getattr(cipher, method_name)
+ method(self.data_128)
+ method(self.data_128)
+ method(self.data_128)
+ method(self.data_128)
+
+ def test_valid_multiple_digest_or_verify(self):
+ # Multiple calls to digest
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ first_mac = cipher.digest()
+ for x in range(4):
+ self.assertEqual(first_mac, cipher.digest())
+
+ # Multiple calls to verify
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ for x in range(5):
+ cipher.verify(first_mac)
+
+ def test_valid_encrypt_and_digest_decrypt_and_verify(self):
+ # encrypt_and_digest
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ ct, mac = cipher.encrypt_and_digest(self.data_128)
+
+ # decrypt_and_verify
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.update(self.data_128)
+ pt = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(self.data_128, pt)
+
+ def test_invalid_mixing_encrypt_decrypt(self):
+ # Once per method, with or without assoc. data
+ for method1_name, method2_name in (("encrypt", "decrypt"),
+ ("decrypt", "encrypt")):
+ for assoc_data_present in (True, False):
+ cipher = AES.new(self.key_128, AES.MODE_EAX,
+ nonce=self.nonce_96)
+ if assoc_data_present:
+ cipher.update(self.data_128)
+ getattr(cipher, method1_name)(self.data_128)
+ self.assertRaises(TypeError, getattr(cipher, method2_name),
+ self.data_128)
+
+ def test_invalid_encrypt_or_update_after_digest(self):
+ for method_name in "encrypt", "update":
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.encrypt(self.data_128)
+ cipher.digest()
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data_128)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.encrypt_and_digest(self.data_128)
+
+ def test_invalid_decrypt_or_update_after_verify(self):
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ ct = cipher.encrypt(self.data_128)
+ mac = cipher.digest()
+
+ for method_name in "decrypt", "update":
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data_128)
+
+ cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
+ cipher.decrypt_and_verify(ct, mac)
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data_128)
+
+
+class TestVectorsPaper(unittest.TestCase):
+ """Class exercising the EAX test vectors found in
+ http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf"""
+
+ test_vectors_hex = [
+ ( '6bfb914fd07eae6b',
+ '',
+ '',
+ 'e037830e8389f27b025a2d6527e79d01',
+ '233952dee4d5ed5f9b9c6d6ff80ff478',
+ '62EC67F9C3A4A407FCB2A8C49031A8B3'
+ ),
+ (
+ 'fa3bfd4806eb53fa',
+ 'f7fb',
+ '19dd',
+ '5c4c9331049d0bdab0277408f67967e5',
+ '91945d3f4dcbee0bf45ef52255f095a4',
+ 'BECAF043B0A23D843194BA972C66DEBD'
+ ),
+ ( '234a3463c1264ac6',
+ '1a47cb4933',
+ 'd851d5bae0',
+ '3a59f238a23e39199dc9266626c40f80',
+ '01f74ad64077f2e704c0f60ada3dd523',
+ '70C3DB4F0D26368400A10ED05D2BFF5E'
+ ),
+ (
+ '33cce2eabff5a79d',
+ '481c9e39b1',
+ '632a9d131a',
+ 'd4c168a4225d8e1ff755939974a7bede',
+ 'd07cf6cbb7f313bdde66b727afd3c5e8',
+ '8408DFFF3C1A2B1292DC199E46B7D617'
+ ),
+ (
+ 'aeb96eaebe2970e9',
+ '40d0c07da5e4',
+ '071dfe16c675',
+ 'cb0677e536f73afe6a14b74ee49844dd',
+ '35b6d0580005bbc12b0587124557d2c2',
+ 'FDB6B06676EEDC5C61D74276E1F8E816'
+ ),
+ (
+ 'd4482d1ca78dce0f',
+ '4de3b35c3fc039245bd1fb7d',
+ '835bb4f15d743e350e728414',
+ 'abb8644fd6ccb86947c5e10590210a4f',
+ 'bd8e6e11475e60b268784c38c62feb22',
+ '6EAC5C93072D8E8513F750935E46DA1B'
+ ),
+ (
+ '65d2017990d62528',
+ '8b0a79306c9ce7ed99dae4f87f8dd61636',
+ '02083e3979da014812f59f11d52630da30',
+ '137327d10649b0aa6e1c181db617d7f2',
+ '7c77d6e813bed5ac98baa417477a2e7d',
+ '1A8C98DCD73D38393B2BF1569DEEFC19'
+ ),
+ (
+ '54b9f04e6a09189a',
+ '1bda122bce8a8dbaf1877d962b8592dd2d56',
+ '2ec47b2c4954a489afc7ba4897edcdae8cc3',
+ '3b60450599bd02c96382902aef7f832a',
+ '5fff20cafab119ca2fc73549e20f5b0d',
+ 'DDE59B97D722156D4D9AFF2BC7559826'
+ ),
+ (
+ '899a175897561d7e',
+ '6cf36720872b8513f6eab1a8a44438d5ef11',
+ '0de18fd0fdd91e7af19f1d8ee8733938b1e8',
+ 'e7f6d2231618102fdb7fe55ff1991700',
+ 'a4a4782bcffd3ec5e7ef6d8c34a56123',
+ 'B781FCF2F75FA5A8DE97A9CA48E522EC'
+ ),
+ (
+ '126735fcc320d25a',
+ 'ca40d7446e545ffaed3bd12a740a659ffbbb3ceab7',
+ 'cb8920f87a6c75cff39627b56e3ed197c552d295a7',
+ 'cfc46afc253b4652b1af3795b124ab6e',
+ '8395fcf1e95bebd697bd010bc766aac3',
+ '22E7ADD93CFC6393C57EC0B3C17D6B44'
+ ),
+ ]
+
+ test_vectors = [[unhexlify(x) for x in tv] for tv in test_vectors_hex]
+
+ def runTest(self):
+ for assoc_data, pt, ct, mac, key, nonce in self.test_vectors:
+ # Encrypt
+ cipher = AES.new(key, AES.MODE_EAX, nonce, mac_len=len(mac))
+ cipher.update(assoc_data)
+ ct2, mac2 = cipher.encrypt_and_digest(pt)
+ self.assertEqual(ct, ct2)
+ self.assertEqual(mac, mac2)
+
+ # Decrypt
+ cipher = AES.new(key, AES.MODE_EAX, nonce, mac_len=len(mac))
+ cipher.update(assoc_data)
+ pt2 = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(pt, pt2)
+
+
+class TestVectorsWycheproof(unittest.TestCase):
+
+ def __init__(self, wycheproof_warnings):
+ unittest.TestCase.__init__(self)
+ self._wycheproof_warnings = wycheproof_warnings
+ self._id = "None"
+
+ def setUp(self):
+
+ def filter_tag(group):
+ return group['tagSize'] // 8
+
+ self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"),
+ "aes_eax_test.json",
+ "Wycheproof EAX",
+ group_tag={'tag_size': filter_tag})
+
+ def shortDescription(self):
+ return self._id
+
+ def warn(self, tv):
+ if tv.warning and self._wycheproof_warnings:
+ import warnings
+ warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment))
+
+ def test_encrypt(self, tv):
+ self._id = "Wycheproof Encrypt EAX Test #" + str(tv.id)
+
+ try:
+ cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size)
+ except ValueError as e:
+ assert len(tv.iv) == 0 and "Nonce cannot be empty" in str(e)
+ return
+
+ cipher.update(tv.aad)
+ ct, tag = cipher.encrypt_and_digest(tv.msg)
+ if tv.valid:
+ self.assertEqual(ct, tv.ct)
+ self.assertEqual(tag, tv.tag)
+ self.warn(tv)
+
+ def test_decrypt(self, tv):
+ self._id = "Wycheproof Decrypt EAX Test #" + str(tv.id)
+
+ try:
+ cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size)
+ except ValueError as e:
+ assert len(tv.iv) == 0 and "Nonce cannot be empty" in str(e)
+ return
+
+ cipher.update(tv.aad)
+ try:
+ pt = cipher.decrypt_and_verify(tv.ct, tv.tag)
+ except ValueError:
+ assert not tv.valid
+ else:
+ assert tv.valid
+ self.assertEqual(pt, tv.msg)
+ self.warn(tv)
+
+ def test_corrupt_decrypt(self, tv):
+ self._id = "Wycheproof Corrupt Decrypt EAX Test #" + str(tv.id)
+ if len(tv.iv) == 0 or len(tv.ct) < 1:
+ return
+ cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size)
+ cipher.update(tv.aad)
+ ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01")
+ self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag)
+
+ def runTest(self):
+
+ for tv in self.tv:
+ self.test_encrypt(tv)
+ self.test_decrypt(tv)
+ self.test_corrupt_decrypt(tv)
+
+
+class TestOtherCiphers(unittest.TestCase):
+
+ @classmethod
+ def create_test(cls, name, factory, key_size):
+
+ def test_template(self, factory=factory, key_size=key_size):
+ cipher = factory.new(get_tag_random("cipher", key_size),
+ factory.MODE_EAX,
+ nonce=b"nonce")
+ ct, mac = cipher.encrypt_and_digest(b"plaintext")
+
+ cipher = factory.new(get_tag_random("cipher", key_size),
+ factory.MODE_EAX,
+ nonce=b"nonce")
+ pt2 = cipher.decrypt_and_verify(ct, mac)
+
+ self.assertEqual(b"plaintext", pt2)
+
+ setattr(cls, "test_" + name, test_template)
+
+
+from Crypto.Cipher import DES, DES3, ARC2, CAST, Blowfish
+
+TestOtherCiphers.create_test("DES_" + str(DES.key_size), DES, DES.key_size)
+for ks in DES3.key_size:
+ TestOtherCiphers.create_test("DES3_" + str(ks), DES3, ks)
+for ks in ARC2.key_size:
+ TestOtherCiphers.create_test("ARC2_" + str(ks), ARC2, ks)
+for ks in CAST.key_size:
+ TestOtherCiphers.create_test("CAST_" + str(ks), CAST, ks)
+for ks in Blowfish.key_size:
+ TestOtherCiphers.create_test("Blowfish_" + str(ks), Blowfish, ks)
+
+
+def get_tests(config={}):
+ wycheproof_warnings = config.get('wycheproof_warnings')
+
+ tests = []
+ tests += list_test_cases(EaxTests)
+ tests += list_test_cases(EaxFSMTests)
+ tests += [ TestVectorsPaper() ]
+ tests += [ TestVectorsWycheproof(wycheproof_warnings) ]
+ tests += list_test_cases(TestOtherCiphers)
+ return tests
+
+
+if __name__ == '__main__':
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_GCM.py b/lib/Crypto/SelfTest/Cipher/test_GCM.py
new file mode 100644
index 0000000..dd8da2f
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_GCM.py
@@ -0,0 +1,951 @@
+# ===================================================================
+#
+# Copyright (c) 2015, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+from __future__ import print_function
+
+import unittest
+from binascii import unhexlify
+
+from Crypto.SelfTest.st_common import list_test_cases
+from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof
+
+from Crypto.Util.py3compat import tobytes, bchr
+from Crypto.Cipher import AES
+from Crypto.Hash import SHAKE128, SHA256
+
+from Crypto.Util.strxor import strxor
+
+
+def get_tag_random(tag, length):
+ return SHAKE128.new(data=tobytes(tag)).read(length)
+
+
+class GcmTests(unittest.TestCase):
+
+ key_128 = get_tag_random("key_128", 16)
+ nonce_96 = get_tag_random("nonce_128", 12)
+ data = get_tag_random("data", 128)
+
+ def test_loopback_128(self):
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ pt = get_tag_random("plaintext", 16 * 100)
+ ct = cipher.encrypt(pt)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def test_nonce(self):
+ # Nonce is optional (a random one will be created)
+ AES.new(self.key_128, AES.MODE_GCM)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, self.nonce_96)
+ ct = cipher.encrypt(self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ self.assertEqual(ct, cipher.encrypt(self.data))
+
+ def test_nonce_must_be_bytes(self):
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM,
+ nonce=u'test12345678')
+
+ def test_nonce_length(self):
+ # nonce can be of any length (but not empty)
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM,
+ nonce=b"")
+
+ for x in range(1, 128):
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=bchr(1) * x)
+ cipher.encrypt(bchr(1))
+
+ def test_block_size_128(self):
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ self.assertEqual(cipher.block_size, AES.block_size)
+
+ def test_nonce_attribute(self):
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ self.assertEqual(cipher.nonce, self.nonce_96)
+
+ # By default, a 15 bytes long nonce is randomly generated
+ nonce1 = AES.new(self.key_128, AES.MODE_GCM).nonce
+ nonce2 = AES.new(self.key_128, AES.MODE_GCM).nonce
+ self.assertEqual(len(nonce1), 16)
+ self.assertNotEqual(nonce1, nonce2)
+
+ def test_unknown_parameters(self):
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM,
+ self.nonce_96, 7)
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM,
+ nonce=self.nonce_96, unknown=7)
+
+ # But some are only known by the base cipher
+ # (e.g. use_aesni consumed by the AES module)
+ AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96,
+ use_aesni=False)
+
+ def test_null_encryption_decryption(self):
+ for func in "encrypt", "decrypt":
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ result = getattr(cipher, func)(b"")
+ self.assertEqual(result, b"")
+
+ def test_either_encrypt_or_decrypt(self):
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.encrypt(b"")
+ self.assertRaises(TypeError, cipher.decrypt, b"")
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.decrypt(b"")
+ self.assertRaises(TypeError, cipher.encrypt, b"")
+
+ def test_data_must_be_bytes(self):
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*')
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*')
+
+ def test_mac_len(self):
+ # Invalid MAC length
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM,
+ nonce=self.nonce_96, mac_len=3)
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM,
+ nonce=self.nonce_96, mac_len=16+1)
+
+ # Valid MAC length
+ for mac_len in range(5, 16 + 1):
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96,
+ mac_len=mac_len)
+ _, mac = cipher.encrypt_and_digest(self.data)
+ self.assertEqual(len(mac), mac_len)
+
+ # Default MAC length
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ _, mac = cipher.encrypt_and_digest(self.data)
+ self.assertEqual(len(mac), 16)
+
+ def test_invalid_mac(self):
+ from Crypto.Util.strxor import strxor_c
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ ct, mac = cipher.encrypt_and_digest(self.data)
+
+ invalid_mac = strxor_c(mac, 0x01)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.decrypt_and_verify, ct,
+ invalid_mac)
+
+ def test_hex_mac(self):
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ mac_hex = cipher.hexdigest()
+ self.assertEqual(cipher.digest(), unhexlify(mac_hex))
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.hexverify(mac_hex)
+
+ def test_message_chunks(self):
+ # Validate that both associated data and plaintext/ciphertext
+ # can be broken up in chunks of arbitrary length
+
+ auth_data = get_tag_random("authenticated data", 127)
+ plaintext = get_tag_random("plaintext", 127)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.update(auth_data)
+ ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext)
+
+ def break_up(data, chunk_length):
+ return [data[i:i+chunk_length] for i in range(0, len(data),
+ chunk_length)]
+
+ # Encryption
+ for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128:
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+
+ for chunk in break_up(auth_data, chunk_length):
+ cipher.update(chunk)
+ pt2 = b""
+ for chunk in break_up(ciphertext, chunk_length):
+ pt2 += cipher.decrypt(chunk)
+ self.assertEqual(plaintext, pt2)
+ cipher.verify(ref_mac)
+
+ # Decryption
+ for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128:
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+
+ for chunk in break_up(auth_data, chunk_length):
+ cipher.update(chunk)
+ ct2 = b""
+ for chunk in break_up(plaintext, chunk_length):
+ ct2 += cipher.encrypt(chunk)
+ self.assertEqual(ciphertext, ct2)
+ self.assertEqual(cipher.digest(), ref_mac)
+
+ def test_bytearray(self):
+
+ # Encrypt
+ key_ba = bytearray(self.key_128)
+ nonce_ba = bytearray(self.nonce_96)
+ header_ba = bytearray(self.data)
+ data_ba = bytearray(self.data)
+
+ cipher1 = AES.new(self.key_128,
+ AES.MODE_GCM,
+ nonce=self.nonce_96)
+ cipher1.update(self.data)
+ ct = cipher1.encrypt(self.data)
+ tag = cipher1.digest()
+
+ cipher2 = AES.new(key_ba,
+ AES.MODE_GCM,
+ nonce=nonce_ba)
+ key_ba[:3] = b"\xFF\xFF\xFF"
+ nonce_ba[:3] = b"\xFF\xFF\xFF"
+ cipher2.update(header_ba)
+ header_ba[:3] = b"\xFF\xFF\xFF"
+ ct_test = cipher2.encrypt(data_ba)
+ data_ba[:3] = b"\xFF\xFF\xFF"
+ tag_test = cipher2.digest()
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key_ba = bytearray(self.key_128)
+ nonce_ba = bytearray(self.nonce_96)
+ header_ba = bytearray(self.data)
+ del data_ba
+
+ cipher4 = AES.new(key_ba,
+ AES.MODE_GCM,
+ nonce=nonce_ba)
+ key_ba[:3] = b"\xFF\xFF\xFF"
+ nonce_ba[:3] = b"\xFF\xFF\xFF"
+ cipher4.update(header_ba)
+ header_ba[:3] = b"\xFF\xFF\xFF"
+ pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test))
+
+ self.assertEqual(self.data, pt_test)
+
+ def test_memoryview(self):
+
+ # Encrypt
+ key_mv = memoryview(bytearray(self.key_128))
+ nonce_mv = memoryview(bytearray(self.nonce_96))
+ header_mv = memoryview(bytearray(self.data))
+ data_mv = memoryview(bytearray(self.data))
+
+ cipher1 = AES.new(self.key_128,
+ AES.MODE_GCM,
+ nonce=self.nonce_96)
+ cipher1.update(self.data)
+ ct = cipher1.encrypt(self.data)
+ tag = cipher1.digest()
+
+ cipher2 = AES.new(key_mv,
+ AES.MODE_GCM,
+ nonce=nonce_mv)
+ key_mv[:3] = b"\xFF\xFF\xFF"
+ nonce_mv[:3] = b"\xFF\xFF\xFF"
+ cipher2.update(header_mv)
+ header_mv[:3] = b"\xFF\xFF\xFF"
+ ct_test = cipher2.encrypt(data_mv)
+ data_mv[:3] = b"\xFF\xFF\xFF"
+ tag_test = cipher2.digest()
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key_mv = memoryview(bytearray(self.key_128))
+ nonce_mv = memoryview(bytearray(self.nonce_96))
+ header_mv = memoryview(bytearray(self.data))
+ del data_mv
+
+ cipher4 = AES.new(key_mv,
+ AES.MODE_GCM,
+ nonce=nonce_mv)
+ key_mv[:3] = b"\xFF\xFF\xFF"
+ nonce_mv[:3] = b"\xFF\xFF\xFF"
+ cipher4.update(header_mv)
+ header_mv[:3] = b"\xFF\xFF\xFF"
+ pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test))
+
+ self.assertEqual(self.data, pt_test)
+
+ def test_output_param(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ ct = cipher.encrypt(pt)
+ tag = cipher.digest()
+
+ output = bytearray(128)
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ res, tag_out = cipher.encrypt_and_digest(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+ self.assertEqual(tag, tag_out)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ res = cipher.decrypt_and_verify(ct, tag, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ def test_output_param_memoryview(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ ct = cipher.encrypt(pt)
+
+ output = memoryview(bytearray(128))
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ def test_output_param_neg(self):
+ LEN_PT = 128
+
+ pt = b'5' * LEN_PT
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ ct = cipher.encrypt(pt)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT)
+
+ shorter_output = bytearray(LEN_PT - 1)
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+class GcmFSMTests(unittest.TestCase):
+
+ key_128 = get_tag_random("key_128", 16)
+ nonce_96 = get_tag_random("nonce_128", 12)
+ data = get_tag_random("data", 128)
+
+ def test_valid_init_encrypt_decrypt_digest_verify(self):
+ # No authenticated data, fixed plaintext
+ # Verify path INIT->ENCRYPT->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_GCM,
+ nonce=self.nonce_96)
+ ct = cipher.encrypt(self.data)
+ mac = cipher.digest()
+
+ # Verify path INIT->DECRYPT->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_GCM,
+ nonce=self.nonce_96)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+
+ def test_valid_init_update_digest_verify(self):
+ # No plaintext, fixed authenticated data
+ # Verify path INIT->UPDATE->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_GCM,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ mac = cipher.digest()
+
+ # Verify path INIT->UPDATE->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_GCM,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ cipher.verify(mac)
+
+ def test_valid_full_path(self):
+ # Fixed authenticated data, fixed plaintext
+ # Verify path INIT->UPDATE->ENCRYPT->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_GCM,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ ct = cipher.encrypt(self.data)
+ mac = cipher.digest()
+
+ # Verify path INIT->UPDATE->DECRYPT->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_GCM,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+
+ def test_valid_init_digest(self):
+ # Verify path INIT->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.digest()
+
+ def test_valid_init_verify(self):
+ # Verify path INIT->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ mac = cipher.digest()
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.verify(mac)
+
+ def test_valid_multiple_encrypt_or_decrypt(self):
+ for method_name in "encrypt", "decrypt":
+ for auth_data in (None, b"333", self.data,
+ self.data + b"3"):
+ if auth_data is None:
+ assoc_len = None
+ else:
+ assoc_len = len(auth_data)
+ cipher = AES.new(self.key_128, AES.MODE_GCM,
+ nonce=self.nonce_96)
+ if auth_data is not None:
+ cipher.update(auth_data)
+ method = getattr(cipher, method_name)
+ method(self.data)
+ method(self.data)
+ method(self.data)
+ method(self.data)
+
+ def test_valid_multiple_digest_or_verify(self):
+ # Multiple calls to digest
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.update(self.data)
+ first_mac = cipher.digest()
+ for x in range(4):
+ self.assertEqual(first_mac, cipher.digest())
+
+ # Multiple calls to verify
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.update(self.data)
+ for x in range(5):
+ cipher.verify(first_mac)
+
+ def test_valid_encrypt_and_digest_decrypt_and_verify(self):
+ # encrypt_and_digest
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.update(self.data)
+ ct, mac = cipher.encrypt_and_digest(self.data)
+
+ # decrypt_and_verify
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.update(self.data)
+ pt = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(self.data, pt)
+
+ def test_invalid_mixing_encrypt_decrypt(self):
+ # Once per method, with or without assoc. data
+ for method1_name, method2_name in (("encrypt", "decrypt"),
+ ("decrypt", "encrypt")):
+ for assoc_data_present in (True, False):
+ cipher = AES.new(self.key_128, AES.MODE_GCM,
+ nonce=self.nonce_96)
+ if assoc_data_present:
+ cipher.update(self.data)
+ getattr(cipher, method1_name)(self.data)
+ self.assertRaises(TypeError, getattr(cipher, method2_name),
+ self.data)
+
+ def test_invalid_encrypt_or_update_after_digest(self):
+ for method_name in "encrypt", "update":
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.encrypt(self.data)
+ cipher.digest()
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.encrypt_and_digest(self.data)
+
+ def test_invalid_decrypt_or_update_after_verify(self):
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ ct = cipher.encrypt(self.data)
+ mac = cipher.digest()
+
+ for method_name in "decrypt", "update":
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.decrypt(ct)
+ cipher.verify(mac)
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
+ cipher.decrypt_and_verify(ct, mac)
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data)
+
+
+class TestVectors(unittest.TestCase):
+ """Class exercising the GCM test vectors found in
+ http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf"""
+
+ # List of test vectors, each made up of:
+ # - authenticated data
+ # - plaintext
+ # - ciphertext
+ # - MAC
+ # - AES key
+ # - nonce
+ test_vectors_hex = [
+ (
+ '',
+ '',
+ '',
+ '58e2fccefa7e3061367f1d57a4e7455a',
+ '00000000000000000000000000000000',
+ '000000000000000000000000'
+ ),
+ (
+ '',
+ '00000000000000000000000000000000',
+ '0388dace60b6a392f328c2b971b2fe78',
+ 'ab6e47d42cec13bdf53a67b21257bddf',
+ '00000000000000000000000000000000',
+ '000000000000000000000000'
+ ),
+ (
+ '',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255',
+ '42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e' +
+ '21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985',
+ '4d5c2af327cd64a62cf35abd2ba6fab4',
+ 'feffe9928665731c6d6a8f9467308308',
+ 'cafebabefacedbaddecaf888'
+ ),
+ (
+ 'feedfacedeadbeeffeedfacedeadbeefabaddad2',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
+ '42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e' +
+ '21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091',
+ '5bc94fbc3221a5db94fae95ae7121a47',
+ 'feffe9928665731c6d6a8f9467308308',
+ 'cafebabefacedbaddecaf888'
+ ),
+ (
+ 'feedfacedeadbeeffeedfacedeadbeefabaddad2',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
+ '61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c7423' +
+ '73806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598',
+ '3612d2e79e3b0785561be14aaca2fccb',
+ 'feffe9928665731c6d6a8f9467308308',
+ 'cafebabefacedbad'
+ ),
+ (
+ 'feedfacedeadbeeffeedfacedeadbeefabaddad2',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
+ '8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca7' +
+ '01e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5',
+ '619cc5aefffe0bfa462af43c1699d050',
+ 'feffe9928665731c6d6a8f9467308308',
+ '9313225df88406e555909c5aff5269aa' +
+ '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' +
+ '16aedbf5a0de6a57a637b39b'
+ ),
+ (
+ '',
+ '',
+ '',
+ 'cd33b28ac773f74ba00ed1f312572435',
+ '000000000000000000000000000000000000000000000000',
+ '000000000000000000000000'
+ ),
+ (
+ '',
+ '00000000000000000000000000000000',
+ '98e7247c07f0fe411c267e4384b0f600',
+ '2ff58d80033927ab8ef4d4587514f0fb',
+ '000000000000000000000000000000000000000000000000',
+ '000000000000000000000000'
+ ),
+ (
+ '',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255',
+ '3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c' +
+ '7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256',
+ '9924a7c8587336bfb118024db8674a14',
+ 'feffe9928665731c6d6a8f9467308308feffe9928665731c',
+ 'cafebabefacedbaddecaf888'
+ ),
+ (
+ 'feedfacedeadbeeffeedfacedeadbeefabaddad2',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
+ '3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c' +
+ '7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710',
+ '2519498e80f1478f37ba55bd6d27618c',
+ 'feffe9928665731c6d6a8f9467308308feffe9928665731c',
+ 'cafebabefacedbaddecaf888'
+ ),
+ (
+ 'feedfacedeadbeeffeedfacedeadbeefabaddad2',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
+ '0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057' +
+ 'fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7',
+ '65dcc57fcf623a24094fcca40d3533f8',
+ 'feffe9928665731c6d6a8f9467308308feffe9928665731c',
+ 'cafebabefacedbad'
+ ),
+ (
+ 'feedfacedeadbeeffeedfacedeadbeefabaddad2',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
+ 'd27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e45' +
+ '81e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b',
+ 'dcf566ff291c25bbb8568fc3d376a6d9',
+ 'feffe9928665731c6d6a8f9467308308feffe9928665731c',
+ '9313225df88406e555909c5aff5269aa' +
+ '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' +
+ '16aedbf5a0de6a57a637b39b'
+ ),
+ (
+ '',
+ '',
+ '',
+ '530f8afbc74536b9a963b4f1c4cb738b',
+ '0000000000000000000000000000000000000000000000000000000000000000',
+ '000000000000000000000000'
+ ),
+ (
+ '',
+ '00000000000000000000000000000000',
+ 'cea7403d4d606b6e074ec5d3baf39d18',
+ 'd0d1c8a799996bf0265b98b5d48ab919',
+ '0000000000000000000000000000000000000000000000000000000000000000',
+ '000000000000000000000000'
+ ),
+ ( '',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255',
+ '522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa' +
+ '8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad',
+ 'b094dac5d93471bdec1a502270e3cc6c',
+ 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308',
+ 'cafebabefacedbaddecaf888'
+ ),
+ (
+ 'feedfacedeadbeeffeedfacedeadbeefabaddad2',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
+ '522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa' +
+ '8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662',
+ '76fc6ece0f4e1768cddf8853bb2d551b',
+ 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308',
+ 'cafebabefacedbaddecaf888'
+ ),
+ (
+ 'feedfacedeadbeeffeedfacedeadbeefabaddad2',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
+ 'c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0' +
+ 'feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f',
+ '3a337dbf46a792c45e454913fe2ea8f2',
+ 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308',
+ 'cafebabefacedbad'
+ ),
+ (
+ 'feedfacedeadbeeffeedfacedeadbeefabaddad2',
+ 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
+ '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
+ '5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf4' +
+ '0fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f',
+ 'a44a8266ee1c8eb0c8b5d4cf5ae9f19a',
+ 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308',
+ '9313225df88406e555909c5aff5269aa' +
+ '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' +
+ '16aedbf5a0de6a57a637b39b'
+ )
+ ]
+
+ test_vectors = [[unhexlify(x) for x in tv] for tv in test_vectors_hex]
+
+ def runTest(self):
+ for assoc_data, pt, ct, mac, key, nonce in self.test_vectors:
+
+ # Encrypt
+ cipher = AES.new(key, AES.MODE_GCM, nonce, mac_len=len(mac))
+ cipher.update(assoc_data)
+ ct2, mac2 = cipher.encrypt_and_digest(pt)
+ self.assertEqual(ct, ct2)
+ self.assertEqual(mac, mac2)
+
+ # Decrypt
+ cipher = AES.new(key, AES.MODE_GCM, nonce, mac_len=len(mac))
+ cipher.update(assoc_data)
+ pt2 = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(pt, pt2)
+
+
+class TestVectorsGueronKrasnov(unittest.TestCase):
+ """Class exercising the GCM test vectors found in
+ 'The fragility of AES-GCM authentication algorithm', Gueron, Krasnov
+ https://eprint.iacr.org/2013/157.pdf"""
+
+ def test_1(self):
+ key = unhexlify("3da6c536d6295579c0959a7043efb503")
+ iv = unhexlify("2b926197d34e091ef722db94")
+ aad = unhexlify("00000000000000000000000000000000" +
+ "000102030405060708090a0b0c0d0e0f" +
+ "101112131415161718191a1b1c1d1e1f" +
+ "202122232425262728292a2b2c2d2e2f" +
+ "303132333435363738393a3b3c3d3e3f")
+ digest = unhexlify("69dd586555ce3fcc89663801a71d957b")
+
+ cipher = AES.new(key, AES.MODE_GCM, iv).update(aad)
+ self.assertEqual(digest, cipher.digest())
+
+ def test_2(self):
+ key = unhexlify("843ffcf5d2b72694d19ed01d01249412")
+ iv = unhexlify("dbcca32ebf9b804617c3aa9e")
+ aad = unhexlify("00000000000000000000000000000000" +
+ "101112131415161718191a1b1c1d1e1f")
+ pt = unhexlify("000102030405060708090a0b0c0d0e0f" +
+ "101112131415161718191a1b1c1d1e1f" +
+ "202122232425262728292a2b2c2d2e2f" +
+ "303132333435363738393a3b3c3d3e3f" +
+ "404142434445464748494a4b4c4d4e4f")
+ ct = unhexlify("6268c6fa2a80b2d137467f092f657ac0" +
+ "4d89be2beaa623d61b5a868c8f03ff95" +
+ "d3dcee23ad2f1ab3a6c80eaf4b140eb0" +
+ "5de3457f0fbc111a6b43d0763aa422a3" +
+ "013cf1dc37fe417d1fbfc449b75d4cc5")
+ digest = unhexlify("3b629ccfbc1119b7319e1dce2cd6fd6d")
+
+ cipher = AES.new(key, AES.MODE_GCM, iv).update(aad)
+ ct2, digest2 = cipher.encrypt_and_digest(pt)
+
+ self.assertEqual(ct, ct2)
+ self.assertEqual(digest, digest2)
+
+
+class NISTTestVectorsGCM(unittest.TestCase):
+
+ def __init__(self, a):
+ self.use_clmul = True
+ unittest.TestCase.__init__(self, a)
+
+
+class NISTTestVectorsGCM_no_clmul(unittest.TestCase):
+
+ def __init__(self, a):
+ self.use_clmul = False
+ unittest.TestCase.__init__(self, a)
+
+
+test_vectors_nist = load_test_vectors(
+ ("Cipher", "AES"),
+ "gcmDecrypt128.rsp",
+ "GCM decrypt",
+ {"count": lambda x: int(x)}) or []
+
+test_vectors_nist += load_test_vectors(
+ ("Cipher", "AES"),
+ "gcmEncryptExtIV128.rsp",
+ "GCM encrypt",
+ {"count": lambda x: int(x)}) or []
+
+for idx, tv in enumerate(test_vectors_nist):
+
+ # The test vector file contains some directive lines
+ if isinstance(tv, str):
+ continue
+
+ def single_test(self, tv=tv):
+
+ self.description = tv.desc
+ cipher = AES.new(tv.key, AES.MODE_GCM, nonce=tv.iv,
+ mac_len=len(tv.tag), use_clmul=self.use_clmul)
+ cipher.update(tv.aad)
+ if "FAIL" in tv.others:
+ self.assertRaises(ValueError, cipher.decrypt_and_verify,
+ tv.ct, tv.tag)
+ else:
+ pt = cipher.decrypt_and_verify(tv.ct, tv.tag)
+ self.assertEqual(pt, tv.pt)
+
+ setattr(NISTTestVectorsGCM, "test_%d" % idx, single_test)
+ setattr(NISTTestVectorsGCM_no_clmul, "test_%d" % idx, single_test)
+
+
+class TestVectorsWycheproof(unittest.TestCase):
+
+ def __init__(self, wycheproof_warnings, **extra_params):
+ unittest.TestCase.__init__(self)
+ self._wycheproof_warnings = wycheproof_warnings
+ self._extra_params = extra_params
+ self._id = "None"
+
+ def setUp(self):
+
+ def filter_tag(group):
+ return group['tagSize'] // 8
+
+ self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"),
+ "aes_gcm_test.json",
+ "Wycheproof GCM",
+ group_tag={'tag_size': filter_tag})
+
+ def shortDescription(self):
+ return self._id
+
+ def warn(self, tv):
+ if tv.warning and self._wycheproof_warnings:
+ import warnings
+ warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment))
+
+ def test_encrypt(self, tv):
+ self._id = "Wycheproof Encrypt GCM Test #" + str(tv.id)
+
+ try:
+ cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size,
+ **self._extra_params)
+ except ValueError as e:
+ if len(tv.iv) == 0 and "Nonce cannot be empty" in str(e):
+ return
+ raise e
+
+ cipher.update(tv.aad)
+ ct, tag = cipher.encrypt_and_digest(tv.msg)
+ if tv.valid:
+ self.assertEqual(ct, tv.ct)
+ self.assertEqual(tag, tv.tag)
+ self.warn(tv)
+
+ def test_decrypt(self, tv):
+ self._id = "Wycheproof Decrypt GCM Test #" + str(tv.id)
+
+ try:
+ cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size,
+ **self._extra_params)
+ except ValueError as e:
+ if len(tv.iv) == 0 and "Nonce cannot be empty" in str(e):
+ return
+ raise e
+
+ cipher.update(tv.aad)
+ try:
+ pt = cipher.decrypt_and_verify(tv.ct, tv.tag)
+ except ValueError:
+ assert not tv.valid
+ else:
+ assert tv.valid
+ self.assertEqual(pt, tv.msg)
+ self.warn(tv)
+
+ def test_corrupt_decrypt(self, tv):
+ self._id = "Wycheproof Corrupt Decrypt GCM Test #" + str(tv.id)
+ if len(tv.iv) == 0 or len(tv.ct) < 1:
+ return
+ cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size,
+ **self._extra_params)
+ cipher.update(tv.aad)
+ ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01")
+ self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag)
+
+ def runTest(self):
+
+ for tv in self.tv:
+ self.test_encrypt(tv)
+ self.test_decrypt(tv)
+ self.test_corrupt_decrypt(tv)
+
+
+class TestVariableLength(unittest.TestCase):
+
+ def __init__(self, **extra_params):
+ unittest.TestCase.__init__(self)
+ self._extra_params = extra_params
+
+ def runTest(self):
+ key = b'0' * 16
+ h = SHA256.new()
+
+ for length in range(160):
+ nonce = '{0:04d}'.format(length).encode('utf-8')
+ data = bchr(length) * length
+ cipher = AES.new(key, AES.MODE_GCM, nonce=nonce, **self._extra_params)
+ ct, tag = cipher.encrypt_and_digest(data)
+ h.update(ct)
+ h.update(tag)
+
+ self.assertEqual(h.hexdigest(), "7b7eb1ffbe67a2e53a912067c0ec8e62ebc7ce4d83490ea7426941349811bdf4")
+
+
+def get_tests(config={}):
+ from Crypto.Util import _cpu_features
+
+ wycheproof_warnings = config.get('wycheproof_warnings')
+
+ tests = []
+ tests += list_test_cases(GcmTests)
+ tests += list_test_cases(GcmFSMTests)
+ tests += [TestVectors()]
+ tests += [TestVectorsWycheproof(wycheproof_warnings)]
+ tests += list_test_cases(TestVectorsGueronKrasnov)
+ tests += [TestVariableLength()]
+ if config.get('slow_tests'):
+ tests += list_test_cases(NISTTestVectorsGCM)
+
+ if _cpu_features.have_clmul():
+ tests += [TestVectorsWycheproof(wycheproof_warnings, use_clmul=False)]
+ tests += [TestVariableLength(use_clmul=False)]
+ if config.get('slow_tests'):
+ tests += list_test_cases(NISTTestVectorsGCM_no_clmul)
+ else:
+ print("Skipping test of PCLMULDQD in AES GCM")
+
+ return tests
+
+
+if __name__ == '__main__':
+ def suite():
+ unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_OCB.py b/lib/Crypto/SelfTest/Cipher/test_OCB.py
new file mode 100644
index 0000000..3a89122
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_OCB.py
@@ -0,0 +1,742 @@
+# ===================================================================
+#
+# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+import os
+import re
+import unittest
+from binascii import hexlify, unhexlify
+
+from Crypto.Util.py3compat import b, tobytes, bchr
+from Crypto.Util.strxor import strxor_c
+from Crypto.Util.number import long_to_bytes
+from Crypto.SelfTest.st_common import list_test_cases
+
+from Crypto.Cipher import AES
+from Crypto.Hash import SHAKE128
+
+
+def get_tag_random(tag, length):
+ return SHAKE128.new(data=tobytes(tag)).read(length)
+
+
+class OcbTests(unittest.TestCase):
+
+ key_128 = get_tag_random("key_128", 16)
+ nonce_96 = get_tag_random("nonce_128", 12)
+ data = get_tag_random("data", 128)
+
+ def test_loopback_128(self):
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ pt = get_tag_random("plaintext", 16 * 100)
+ ct, mac = cipher.encrypt_and_digest(pt)
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ pt2 = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(pt, pt2)
+
+ def test_nonce(self):
+ # Nonce is optional
+ AES.new(self.key_128, AES.MODE_OCB)
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, self.nonce_96)
+ ct = cipher.encrypt(self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ self.assertEqual(ct, cipher.encrypt(self.data))
+
+ def test_nonce_must_be_bytes(self):
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB,
+ nonce=u'test12345678')
+
+ def test_nonce_length(self):
+ # nonce cannot be empty
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB,
+ nonce=b(""))
+
+ # nonce can be up to 15 bytes long
+ for length in range(1, 16):
+ AES.new(self.key_128, AES.MODE_OCB, nonce=self.data[:length])
+
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB,
+ nonce=self.data)
+
+ def test_block_size_128(self):
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ self.assertEqual(cipher.block_size, AES.block_size)
+
+ # By default, a 15 bytes long nonce is randomly generated
+ nonce1 = AES.new(self.key_128, AES.MODE_OCB).nonce
+ nonce2 = AES.new(self.key_128, AES.MODE_OCB).nonce
+ self.assertEqual(len(nonce1), 15)
+ self.assertNotEqual(nonce1, nonce2)
+
+ def test_nonce_attribute(self):
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ self.assertEqual(cipher.nonce, self.nonce_96)
+
+ # By default, a 15 bytes long nonce is randomly generated
+ nonce1 = AES.new(self.key_128, AES.MODE_OCB).nonce
+ nonce2 = AES.new(self.key_128, AES.MODE_OCB).nonce
+ self.assertEqual(len(nonce1), 15)
+ self.assertNotEqual(nonce1, nonce2)
+
+ def test_unknown_parameters(self):
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB,
+ self.nonce_96, 7)
+ self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96, unknown=7)
+
+ # But some are only known by the base cipher
+ # (e.g. use_aesni consumed by the AES module)
+ AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96,
+ use_aesni=False)
+
+ def test_null_encryption_decryption(self):
+ for func in "encrypt", "decrypt":
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ result = getattr(cipher, func)(b(""))
+ self.assertEqual(result, b(""))
+
+ def test_either_encrypt_or_decrypt(self):
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.encrypt(b("xyz"))
+ self.assertRaises(TypeError, cipher.decrypt, b("xyz"))
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.decrypt(b("xyz"))
+ self.assertRaises(TypeError, cipher.encrypt, b("xyz"))
+
+ def test_data_must_be_bytes(self):
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*')
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*')
+
+ def test_mac_len(self):
+ # Invalid MAC length
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96, mac_len=7)
+ self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96, mac_len=16+1)
+
+ # Valid MAC length
+ for mac_len in range(8, 16 + 1):
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96,
+ mac_len=mac_len)
+ _, mac = cipher.encrypt_and_digest(self.data)
+ self.assertEqual(len(mac), mac_len)
+
+ # Default MAC length
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ _, mac = cipher.encrypt_and_digest(self.data)
+ self.assertEqual(len(mac), 16)
+
+ def test_invalid_mac(self):
+ from Crypto.Util.strxor import strxor_c
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ ct, mac = cipher.encrypt_and_digest(self.data)
+
+ invalid_mac = strxor_c(mac, 0x01)
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.decrypt_and_verify, ct,
+ invalid_mac)
+
+ def test_hex_mac(self):
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ mac_hex = cipher.hexdigest()
+ self.assertEqual(cipher.digest(), unhexlify(mac_hex))
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.hexverify(mac_hex)
+
+ def test_message_chunks(self):
+ # Validate that both associated data and plaintext/ciphertext
+ # can be broken up in chunks of arbitrary length
+
+ auth_data = get_tag_random("authenticated data", 127)
+ plaintext = get_tag_random("plaintext", 127)
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.update(auth_data)
+ ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext)
+
+ def break_up(data, chunk_length):
+ return [data[i:i+chunk_length] for i in range(0, len(data),
+ chunk_length)]
+
+ # Encryption
+ for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128:
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+
+ for chunk in break_up(auth_data, chunk_length):
+ cipher.update(chunk)
+ pt2 = b("")
+ for chunk in break_up(ciphertext, chunk_length):
+ pt2 += cipher.decrypt(chunk)
+ pt2 += cipher.decrypt()
+ self.assertEqual(plaintext, pt2)
+ cipher.verify(ref_mac)
+
+ # Decryption
+ for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128:
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+
+ for chunk in break_up(auth_data, chunk_length):
+ cipher.update(chunk)
+ ct2 = b("")
+ for chunk in break_up(plaintext, chunk_length):
+ ct2 += cipher.encrypt(chunk)
+ ct2 += cipher.encrypt()
+ self.assertEqual(ciphertext, ct2)
+ self.assertEqual(cipher.digest(), ref_mac)
+
+ def test_bytearray(self):
+
+ # Encrypt
+ key_ba = bytearray(self.key_128)
+ nonce_ba = bytearray(self.nonce_96)
+ header_ba = bytearray(self.data)
+ data_ba = bytearray(self.data)
+
+ cipher1 = AES.new(self.key_128,
+ AES.MODE_OCB,
+ nonce=self.nonce_96)
+ cipher1.update(self.data)
+ ct = cipher1.encrypt(self.data) + cipher1.encrypt()
+ tag = cipher1.digest()
+
+ cipher2 = AES.new(key_ba,
+ AES.MODE_OCB,
+ nonce=nonce_ba)
+ key_ba[:3] = b"\xFF\xFF\xFF"
+ nonce_ba[:3] = b"\xFF\xFF\xFF"
+ cipher2.update(header_ba)
+ header_ba[:3] = b"\xFF\xFF\xFF"
+ ct_test = cipher2.encrypt(data_ba) + cipher2.encrypt()
+ data_ba[:3] = b"\xFF\xFF\xFF"
+ tag_test = cipher2.digest()
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key_ba = bytearray(self.key_128)
+ nonce_ba = bytearray(self.nonce_96)
+ header_ba = bytearray(self.data)
+ del data_ba
+
+ cipher4 = AES.new(key_ba,
+ AES.MODE_OCB,
+ nonce=nonce_ba)
+ key_ba[:3] = b"\xFF\xFF\xFF"
+ nonce_ba[:3] = b"\xFF\xFF\xFF"
+ cipher4.update(header_ba)
+ header_ba[:3] = b"\xFF\xFF\xFF"
+ pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test))
+
+ self.assertEqual(self.data, pt_test)
+
+ def test_memoryview(self):
+
+ # Encrypt
+ key_mv = memoryview(bytearray(self.key_128))
+ nonce_mv = memoryview(bytearray(self.nonce_96))
+ header_mv = memoryview(bytearray(self.data))
+ data_mv = memoryview(bytearray(self.data))
+
+ cipher1 = AES.new(self.key_128,
+ AES.MODE_OCB,
+ nonce=self.nonce_96)
+ cipher1.update(self.data)
+ ct = cipher1.encrypt(self.data) + cipher1.encrypt()
+ tag = cipher1.digest()
+
+ cipher2 = AES.new(key_mv,
+ AES.MODE_OCB,
+ nonce=nonce_mv)
+ key_mv[:3] = b"\xFF\xFF\xFF"
+ nonce_mv[:3] = b"\xFF\xFF\xFF"
+ cipher2.update(header_mv)
+ header_mv[:3] = b"\xFF\xFF\xFF"
+ ct_test = cipher2.encrypt(data_mv) + cipher2.encrypt()
+ data_mv[:3] = b"\xFF\xFF\xFF"
+ tag_test = cipher2.digest()
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key_mv = memoryview(bytearray(self.key_128))
+ nonce_mv = memoryview(bytearray(self.nonce_96))
+ header_mv = memoryview(bytearray(self.data))
+ del data_mv
+
+ cipher4 = AES.new(key_mv,
+ AES.MODE_OCB,
+ nonce=nonce_mv)
+ key_mv[:3] = b"\xFF\xFF\xFF"
+ nonce_mv[:3] = b"\xFF\xFF\xFF"
+ cipher4.update(header_mv)
+ header_mv[:3] = b"\xFF\xFF\xFF"
+ pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test))
+
+ self.assertEqual(self.data, pt_test)
+
+
+class OcbFSMTests(unittest.TestCase):
+
+ key_128 = get_tag_random("key_128", 16)
+ nonce_96 = get_tag_random("nonce_128", 12)
+ data = get_tag_random("data", 128)
+
+ def test_valid_init_encrypt_decrypt_digest_verify(self):
+ # No authenticated data, fixed plaintext
+ # Verify path INIT->ENCRYPT->ENCRYPT(NONE)->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ ct = cipher.encrypt(self.data)
+ ct += cipher.encrypt()
+ mac = cipher.digest()
+
+ # Verify path INIT->DECRYPT->DECRYPT(NONCE)->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ cipher.decrypt(ct)
+ cipher.decrypt()
+ cipher.verify(mac)
+
+ def test_invalid_init_encrypt_decrypt_digest_verify(self):
+ # No authenticated data, fixed plaintext
+ # Verify path INIT->ENCRYPT->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ ct = cipher.encrypt(self.data)
+ self.assertRaises(TypeError, cipher.digest)
+
+ # Verify path INIT->DECRYPT->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ cipher.decrypt(ct)
+ self.assertRaises(TypeError, cipher.verify)
+
+ def test_valid_init_update_digest_verify(self):
+ # No plaintext, fixed authenticated data
+ # Verify path INIT->UPDATE->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ mac = cipher.digest()
+
+ # Verify path INIT->UPDATE->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ cipher.verify(mac)
+
+ def test_valid_full_path(self):
+ # Fixed authenticated data, fixed plaintext
+ # Verify path INIT->UPDATE->ENCRYPT->ENCRYPT(NONE)->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ ct = cipher.encrypt(self.data)
+ ct += cipher.encrypt()
+ mac = cipher.digest()
+
+ # Verify path INIT->UPDATE->DECRYPT->DECRYPT(NONE)->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ cipher.decrypt(ct)
+ cipher.decrypt()
+ cipher.verify(mac)
+
+ def test_invalid_encrypt_after_final(self):
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ cipher.encrypt(self.data)
+ cipher.encrypt()
+ self.assertRaises(TypeError, cipher.encrypt, self.data)
+
+ def test_invalid_decrypt_after_final(self):
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ cipher.decrypt(self.data)
+ cipher.decrypt()
+ self.assertRaises(TypeError, cipher.decrypt, self.data)
+
+ def test_valid_init_digest(self):
+ # Verify path INIT->DIGEST
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.digest()
+
+ def test_valid_init_verify(self):
+ # Verify path INIT->VERIFY
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ mac = cipher.digest()
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.verify(mac)
+
+ def test_valid_multiple_encrypt_or_decrypt(self):
+ for method_name in "encrypt", "decrypt":
+ for auth_data in (None, b("333"), self.data,
+ self.data + b("3")):
+ if auth_data is None:
+ assoc_len = None
+ else:
+ assoc_len = len(auth_data)
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ if auth_data is not None:
+ cipher.update(auth_data)
+ method = getattr(cipher, method_name)
+ method(self.data)
+ method(self.data)
+ method(self.data)
+ method(self.data)
+ method()
+
+ def test_valid_multiple_digest_or_verify(self):
+ # Multiple calls to digest
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.update(self.data)
+ first_mac = cipher.digest()
+ for x in range(4):
+ self.assertEqual(first_mac, cipher.digest())
+
+ # Multiple calls to verify
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.update(self.data)
+ for x in range(5):
+ cipher.verify(first_mac)
+
+ def test_valid_encrypt_and_digest_decrypt_and_verify(self):
+ # encrypt_and_digest
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.update(self.data)
+ ct, mac = cipher.encrypt_and_digest(self.data)
+
+ # decrypt_and_verify
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.update(self.data)
+ pt = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(self.data, pt)
+
+ def test_invalid_mixing_encrypt_decrypt(self):
+ # Once per method, with or without assoc. data
+ for method1_name, method2_name in (("encrypt", "decrypt"),
+ ("decrypt", "encrypt")):
+ for assoc_data_present in (True, False):
+ cipher = AES.new(self.key_128, AES.MODE_OCB,
+ nonce=self.nonce_96)
+ if assoc_data_present:
+ cipher.update(self.data)
+ getattr(cipher, method1_name)(self.data)
+ self.assertRaises(TypeError, getattr(cipher, method2_name),
+ self.data)
+
+ def test_invalid_encrypt_or_update_after_digest(self):
+ for method_name in "encrypt", "update":
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.encrypt(self.data)
+ cipher.encrypt()
+ cipher.digest()
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.encrypt_and_digest(self.data)
+
+ def test_invalid_decrypt_or_update_after_verify(self):
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ ct = cipher.encrypt(self.data)
+ ct += cipher.encrypt()
+ mac = cipher.digest()
+
+ for method_name in "decrypt", "update":
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.decrypt(ct)
+ cipher.decrypt()
+ cipher.verify(mac)
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data)
+
+ cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
+ cipher.decrypt_and_verify(ct, mac)
+ self.assertRaises(TypeError, getattr(cipher, method_name),
+ self.data)
+
+
+class OcbRfc7253Test(unittest.TestCase):
+
+ # Tuple with
+ # - nonce
+ # - authenticated data
+ # - plaintext
+ # - ciphertext and 16 byte MAC tag
+ tv1_key = "000102030405060708090A0B0C0D0E0F"
+ tv1 = (
+ (
+ "BBAA99887766554433221100",
+ "",
+ "",
+ "785407BFFFC8AD9EDCC5520AC9111EE6"
+ ),
+ (
+ "BBAA99887766554433221101",
+ "0001020304050607",
+ "0001020304050607",
+ "6820B3657B6F615A5725BDA0D3B4EB3A257C9AF1F8F03009"
+ ),
+ (
+ "BBAA99887766554433221102",
+ "0001020304050607",
+ "",
+ "81017F8203F081277152FADE694A0A00"
+ ),
+ (
+ "BBAA99887766554433221103",
+ "",
+ "0001020304050607",
+ "45DD69F8F5AAE72414054CD1F35D82760B2CD00D2F99BFA9"
+ ),
+ (
+ "BBAA99887766554433221104",
+ "000102030405060708090A0B0C0D0E0F",
+ "000102030405060708090A0B0C0D0E0F",
+ "571D535B60B277188BE5147170A9A22C3AD7A4FF3835B8C5"
+ "701C1CCEC8FC3358"
+ ),
+ (
+ "BBAA99887766554433221105",
+ "000102030405060708090A0B0C0D0E0F",
+ "",
+ "8CF761B6902EF764462AD86498CA6B97"
+ ),
+ (
+ "BBAA99887766554433221106",
+ "",
+ "000102030405060708090A0B0C0D0E0F",
+ "5CE88EC2E0692706A915C00AEB8B2396F40E1C743F52436B"
+ "DF06D8FA1ECA343D"
+ ),
+ (
+ "BBAA99887766554433221107",
+ "000102030405060708090A0B0C0D0E0F1011121314151617",
+ "000102030405060708090A0B0C0D0E0F1011121314151617",
+ "1CA2207308C87C010756104D8840CE1952F09673A448A122"
+ "C92C62241051F57356D7F3C90BB0E07F"
+ ),
+ (
+ "BBAA99887766554433221108",
+ "000102030405060708090A0B0C0D0E0F1011121314151617",
+ "",
+ "6DC225A071FC1B9F7C69F93B0F1E10DE"
+ ),
+ (
+ "BBAA99887766554433221109",
+ "",
+ "000102030405060708090A0B0C0D0E0F1011121314151617",
+ "221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3C"
+ "E725F32494B9F914D85C0B1EB38357FF"
+ ),
+ (
+ "BBAA9988776655443322110A",
+ "000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F",
+ "000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F",
+ "BD6F6C496201C69296C11EFD138A467ABD3C707924B964DE"
+ "AFFC40319AF5A48540FBBA186C5553C68AD9F592A79A4240"
+ ),
+ (
+ "BBAA9988776655443322110B",
+ "000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F",
+ "",
+ "FE80690BEE8A485D11F32965BC9D2A32"
+ ),
+ (
+ "BBAA9988776655443322110C",
+ "",
+ "000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F",
+ "2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF4"
+ "6040C53F1432BCDFB5E1DDE3BC18A5F840B52E653444D5DF"
+ ),
+ (
+ "BBAA9988776655443322110D",
+ "000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F2021222324252627",
+ "000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F2021222324252627",
+ "D5CA91748410C1751FF8A2F618255B68A0A12E093FF45460"
+ "6E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483"
+ "A7035490C5769E60"
+ ),
+ (
+ "BBAA9988776655443322110E",
+ "000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F2021222324252627",
+ "",
+ "C5CD9D1850C141E358649994EE701B68"
+ ),
+ (
+ "BBAA9988776655443322110F",
+ "",
+ "000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F2021222324252627",
+ "4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15"
+ "A5DDBFC5787E50B5CC55EE507BCB084E479AD363AC366B95"
+ "A98CA5F3000B1479"
+ )
+ )
+
+ # Tuple with
+ # - key
+ # - nonce
+ # - authenticated data
+ # - plaintext
+ # - ciphertext and 12 byte MAC tag
+ tv2 = (
+ "0F0E0D0C0B0A09080706050403020100",
+ "BBAA9988776655443322110D",
+ "000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F2021222324252627",
+ "000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F2021222324252627",
+ "1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1"
+ "A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FD"
+ "AC4F02AA"
+ )
+
+ # Tuple with
+ # - key length
+ # - MAC tag length
+ # - Expected output
+ tv3 = (
+ (128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2"),
+ (192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17"),
+ (256, 128, "D90EB8E9C977C88B79DD793D7FFA161C"),
+ (128, 96, "77A3D8E73589158D25D01209"),
+ (192, 96, "05D56EAD2752C86BE6932C5E"),
+ (256, 96, "5458359AC23B0CBA9E6330DD"),
+ (128, 64, "192C9B7BD90BA06A"),
+ (192, 64, "0066BC6E0EF34E24"),
+ (256, 64, "7D4EA5D445501CBE"),
+ )
+
+ def test1(self):
+ key = unhexlify(b(self.tv1_key))
+ for tv in self.tv1:
+ nonce, aad, pt, ct = [ unhexlify(b(x)) for x in tv ]
+ ct, mac_tag = ct[:-16], ct[-16:]
+
+ cipher = AES.new(key, AES.MODE_OCB, nonce=nonce)
+ cipher.update(aad)
+ ct2 = cipher.encrypt(pt) + cipher.encrypt()
+ self.assertEqual(ct, ct2)
+ self.assertEqual(mac_tag, cipher.digest())
+
+ cipher = AES.new(key, AES.MODE_OCB, nonce=nonce)
+ cipher.update(aad)
+ pt2 = cipher.decrypt(ct) + cipher.decrypt()
+ self.assertEqual(pt, pt2)
+ cipher.verify(mac_tag)
+
+ def test2(self):
+
+ key, nonce, aad, pt, ct = [ unhexlify(b(x)) for x in self.tv2 ]
+ ct, mac_tag = ct[:-12], ct[-12:]
+
+ cipher = AES.new(key, AES.MODE_OCB, nonce=nonce, mac_len=12)
+ cipher.update(aad)
+ ct2 = cipher.encrypt(pt) + cipher.encrypt()
+ self.assertEqual(ct, ct2)
+ self.assertEqual(mac_tag, cipher.digest())
+
+ cipher = AES.new(key, AES.MODE_OCB, nonce=nonce, mac_len=12)
+ cipher.update(aad)
+ pt2 = cipher.decrypt(ct) + cipher.decrypt()
+ self.assertEqual(pt, pt2)
+ cipher.verify(mac_tag)
+
+ def test3(self):
+
+ for keylen, taglen, result in self.tv3:
+
+ key = bchr(0) * (keylen // 8 - 1) + bchr(taglen)
+ C = b("")
+
+ for i in range(128):
+ S = bchr(0) * i
+
+ N = long_to_bytes(3 * i + 1, 12)
+ cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
+ cipher.update(S)
+ C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest()
+
+ N = long_to_bytes(3 * i + 2, 12)
+ cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
+ C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest()
+
+ N = long_to_bytes(3 * i + 3, 12)
+ cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
+ cipher.update(S)
+ C += cipher.encrypt() + cipher.digest()
+
+ N = long_to_bytes(385, 12)
+ cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
+ cipher.update(C)
+ result2 = cipher.encrypt() + cipher.digest()
+ self.assertEqual(unhexlify(b(result)), result2)
+
+
+def get_tests(config={}):
+ tests = []
+ tests += list_test_cases(OcbTests)
+ tests += list_test_cases(OcbFSMTests)
+ tests += list_test_cases(OcbRfc7253Test)
+ return tests
+
+
+if __name__ == '__main__':
+ import unittest
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_OFB.py b/lib/Crypto/SelfTest/Cipher/test_OFB.py
new file mode 100644
index 0000000..ec145ad
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_OFB.py
@@ -0,0 +1,238 @@
+# ===================================================================
+#
+# Copyright (c) 2015, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+import unittest
+from binascii import unhexlify
+
+from Crypto.SelfTest.st_common import list_test_cases
+from Crypto.Util.py3compat import tobytes
+from Crypto.Cipher import AES, DES3, DES
+from Crypto.Hash import SHAKE128
+from Crypto.SelfTest.loader import load_test_vectors_wycheproof
+
+def get_tag_random(tag, length):
+ return SHAKE128.new(data=tobytes(tag)).read(length)
+
+from Crypto.SelfTest.Cipher.test_CBC import BlockChainingTests
+
+class OfbTests(BlockChainingTests):
+
+ aes_mode = AES.MODE_OFB
+ des3_mode = DES3.MODE_OFB
+
+ # Redefine test_unaligned_data_128/64
+
+ def test_unaligned_data_128(self):
+ plaintexts = [ b"7777777" ] * 100
+
+ cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ def test_unaligned_data_64(self):
+ plaintexts = [ b"7777777" ] * 100
+ cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+
+from Crypto.SelfTest.Cipher.test_CBC import NistBlockChainingVectors
+
+class NistOfbVectors(NistBlockChainingVectors):
+ aes_mode = AES.MODE_OFB
+ des_mode = DES.MODE_OFB
+ des3_mode = DES3.MODE_OFB
+
+
+# Create one test method per file
+nist_aes_kat_mmt_files = (
+ # KAT
+ "OFBGFSbox128.rsp",
+ "OFBGFSbox192.rsp",
+ "OFBGFSbox256.rsp",
+ "OFBKeySbox128.rsp",
+ "OFBKeySbox192.rsp",
+ "OFBKeySbox256.rsp",
+ "OFBVarKey128.rsp",
+ "OFBVarKey192.rsp",
+ "OFBVarKey256.rsp",
+ "OFBVarTxt128.rsp",
+ "OFBVarTxt192.rsp",
+ "OFBVarTxt256.rsp",
+ # MMT
+ "OFBMMT128.rsp",
+ "OFBMMT192.rsp",
+ "OFBMMT256.rsp",
+ )
+nist_aes_mct_files = (
+ "OFBMCT128.rsp",
+ "OFBMCT192.rsp",
+ "OFBMCT256.rsp",
+ )
+
+for file_name in nist_aes_kat_mmt_files:
+ def new_func(self, file_name=file_name):
+ self._do_kat_aes_test(file_name)
+ setattr(NistOfbVectors, "test_AES_" + file_name, new_func)
+
+for file_name in nist_aes_mct_files:
+ def new_func(self, file_name=file_name):
+ self._do_mct_aes_test(file_name)
+ setattr(NistOfbVectors, "test_AES_" + file_name, new_func)
+del file_name, new_func
+
+nist_tdes_files = (
+ "TOFBMMT2.rsp", # 2TDES
+ "TOFBMMT3.rsp", # 3TDES
+ "TOFBinvperm.rsp", # Single DES
+ "TOFBpermop.rsp",
+ "TOFBsubtab.rsp",
+ "TOFBvarkey.rsp",
+ "TOFBvartext.rsp",
+ )
+
+for file_name in nist_tdes_files:
+ def new_func(self, file_name=file_name):
+ self._do_tdes_test(file_name)
+ setattr(NistOfbVectors, "test_TDES_" + file_name, new_func)
+
+# END OF NIST OFB TEST VECTORS
+
+
+class SP800TestVectors(unittest.TestCase):
+ """Class exercising the OFB test vectors found in Section F.4
+ of NIST SP 800-3A"""
+
+ def test_aes_128(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ ciphertext = '3b3fd92eb72dad20333449f8e83cfb4a' +\
+ '7789508d16918f03f53c52dac54ed825' +\
+ '9740051e9c5fecf64344f7a82260edcc' +\
+ '304c6528f659c77866a510d9c1d6ae5e'
+ key = '2b7e151628aed2a6abf7158809cf4f3c'
+ iv = '000102030405060708090a0b0c0d0e0f'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8])
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8])
+
+ def test_aes_192(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ ciphertext = 'cdc80d6fddf18cab34c25909c99a4174' +\
+ 'fcc28b8d4c63837c09e81700c1100401' +\
+ '8d9a9aeac0f6596f559c6d4daf59a5f2' +\
+ '6d9f200857ca6c3e9cac524bd9acc92a'
+ key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'
+ iv = '000102030405060708090a0b0c0d0e0f'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8])
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8])
+
+ def test_aes_256(self):
+ plaintext = '6bc1bee22e409f96e93d7e117393172a' +\
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\
+ '30c81c46a35ce411e5fbc1191a0a52ef' +\
+ 'f69f2445df4f9b17ad2b417be66c3710'
+ ciphertext = 'dc7e84bfda79164b7ecd8486985d3860' +\
+ '4febdc6740d20b3ac88f6ad82a4fb08d' +\
+ '71ab47a086e86eedf39d1c5bba97c408' +\
+ '0126141d67f37be8538f5a8be740e484'
+ key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'
+ iv = '000102030405060708090a0b0c0d0e0f'
+
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.encrypt(plaintext), ciphertext)
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.decrypt(ciphertext), plaintext)
+
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8])
+ cipher = AES.new(key, AES.MODE_OFB, iv)
+ self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8])
+
+
+def get_tests(config={}):
+ tests = []
+ tests += list_test_cases(OfbTests)
+ if config.get('slow_tests'):
+ tests += list_test_cases(NistOfbVectors)
+ tests += list_test_cases(SP800TestVectors)
+ return tests
+
+
+if __name__ == '__main__':
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_OpenPGP.py b/lib/Crypto/SelfTest/Cipher/test_OpenPGP.py
new file mode 100644
index 0000000..e6cae67
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_OpenPGP.py
@@ -0,0 +1,218 @@
+# ===================================================================
+#
+# Copyright (c) 2015, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+import unittest
+from binascii import unhexlify
+
+from Crypto.SelfTest.st_common import list_test_cases
+from Crypto.Util.py3compat import tobytes
+from Crypto.Cipher import AES, DES3, DES
+from Crypto.Hash import SHAKE128
+
+def get_tag_random(tag, length):
+ return SHAKE128.new(data=tobytes(tag)).read(length)
+
+
+from Crypto.SelfTest.Cipher.test_CBC import BlockChainingTests
+
+class OpenPGPTests(BlockChainingTests):
+
+ aes_mode = AES.MODE_OPENPGP
+ des3_mode = DES3.MODE_OPENPGP
+
+ # Redefine test_unaligned_data_128/64
+
+ key_128 = get_tag_random("key_128", 16)
+ key_192 = get_tag_random("key_192", 24)
+ iv_128 = get_tag_random("iv_128", 16)
+ iv_64 = get_tag_random("iv_64", 8)
+ data_128 = get_tag_random("data_128", 16)
+
+ def test_loopback_128(self):
+ cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128)
+ pt = get_tag_random("plaintext", 16 * 100)
+ ct = cipher.encrypt(pt)
+
+ eiv, ct = ct[:18], ct[18:]
+
+ cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def test_loopback_64(self):
+ cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64)
+ pt = get_tag_random("plaintext", 8 * 100)
+ ct = cipher.encrypt(pt)
+
+ eiv, ct = ct[:10], ct[10:]
+
+ cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, eiv)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def test_IV_iv_attributes(self):
+ cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128)
+ eiv = cipher.encrypt(b"")
+ self.assertEqual(cipher.iv, self.iv_128)
+
+ cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv)
+ self.assertEqual(cipher.iv, self.iv_128)
+
+ def test_null_encryption_decryption(self):
+ cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128)
+ eiv = cipher.encrypt(b"")
+
+ cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv)
+ self.assertEqual(cipher.decrypt(b""), b"")
+
+ def test_either_encrypt_or_decrypt(self):
+ cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128)
+ eiv = cipher.encrypt(b"")
+ self.assertRaises(TypeError, cipher.decrypt, b"")
+
+ cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv)
+ cipher.decrypt(b"")
+ self.assertRaises(TypeError, cipher.encrypt, b"")
+
+ def test_unaligned_data_128(self):
+ plaintexts = [ b"7777777" ] * 100
+
+ cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ def test_unaligned_data_64(self):
+ plaintexts = [ b"7777777" ] * 100
+
+ cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64)
+ ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
+ cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64)
+ self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
+
+ def test_output_param(self):
+ pass
+
+ def test_output_param_same_buffer(self):
+ pass
+
+ def test_output_param_memoryview(self):
+ pass
+
+ def test_output_param_neg(self):
+ pass
+
+
+class TestVectors(unittest.TestCase):
+
+ def test_aes(self):
+ # The following test vectors have been generated with gpg v1.4.0.
+ # The command line used was:
+ #
+ # gpg -c -z 0 --cipher-algo AES --passphrase secret_passphrase \
+ # --disable-mdc --s2k-mode 0 --output ct pt
+ #
+ # As result, the content of the file 'pt' is encrypted with a key derived
+ # from 'secret_passphrase' and written to file 'ct'.
+ # Test vectors must be extracted from 'ct', which is a collection of
+ # TLVs (see RFC4880 for all details):
+ # - the encrypted data (with the encrypted IV as prefix) is the payload
+ # of the TLV with tag 9 (Symmetrical Encrypted Data Packet).
+ # This is the ciphertext in the test vector.
+ # - inside the encrypted part, there is a further layer of TLVs. One must
+ # look for tag 11 (Literal Data Packet); in its payload, after a short
+ # but time dependent header, there is the content of file 'pt'.
+ # In the test vector, the plaintext is the complete set of TLVs that gets
+ # encrypted. It is not just the content of 'pt'.
+ # - the key is the leftmost 16 bytes of the SHA1 digest of the password.
+ # The test vector contains such shortened digest.
+ #
+ # Note that encryption uses a clear IV, and decryption an encrypted IV
+
+ plaintext = 'ac18620270744fb4f647426c61636b4361745768697465436174'
+ ciphertext = 'dc6b9e1f095de609765c59983db5956ae4f63aea7405389d2ebb'
+ key = '5baa61e4c9b93f3f0682250b6cf8331b'
+ iv = '3d7d3e62282add7eb203eeba5c800733'
+ encrypted_iv='fd934601ef49cb58b6d9aebca6056bdb96ef'
+
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ encrypted_iv = unhexlify(encrypted_iv)
+
+ cipher = AES.new(key, AES.MODE_OPENPGP, iv)
+ ct = cipher.encrypt(plaintext)
+ self.assertEqual(ct[:18], encrypted_iv)
+ self.assertEqual(ct[18:], ciphertext)
+
+ cipher = AES.new(key, AES.MODE_OPENPGP, encrypted_iv)
+ pt = cipher.decrypt(ciphertext)
+ self.assertEqual(pt, plaintext)
+
+ def test_des3(self):
+ # The following test vectors have been generated with gpg v1.4.0.
+ # The command line used was:
+ # gpg -c -z 0 --cipher-algo 3DES --passphrase secret_passphrase \
+ # --disable-mdc --s2k-mode 0 --output ct pt
+ # For an explanation, see test_AES.py .
+
+ plaintext = 'ac1762037074324fb53ba3596f73656d69746556616c6c6579'
+ ciphertext = '9979238528357b90e2e0be549cb0b2d5999b9a4a447e5c5c7d'
+ key = '7ade65b460f5ea9be35f9e14aa883a2048e3824aa616c0b2'
+ iv='cd47e2afb8b7e4b0'
+ encrypted_iv='6a7eef0b58050e8b904a'
+
+ plaintext = unhexlify(plaintext)
+ ciphertext = unhexlify(ciphertext)
+ key = unhexlify(key)
+ iv = unhexlify(iv)
+ encrypted_iv = unhexlify(encrypted_iv)
+
+ cipher = DES3.new(key, DES3.MODE_OPENPGP, iv)
+ ct = cipher.encrypt(plaintext)
+ self.assertEqual(ct[:10], encrypted_iv)
+ self.assertEqual(ct[10:], ciphertext)
+
+ cipher = DES3.new(key, DES3.MODE_OPENPGP, encrypted_iv)
+ pt = cipher.decrypt(ciphertext)
+ self.assertEqual(pt, plaintext)
+
+
+def get_tests(config={}):
+ tests = []
+ tests += list_test_cases(OpenPGPTests)
+ tests += list_test_cases(TestVectors)
+ return tests
+
+
+if __name__ == '__main__':
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_SIV.py b/lib/Crypto/SelfTest/Cipher/test_SIV.py
new file mode 100644
index 0000000..a80ddc1
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_SIV.py
@@ -0,0 +1,552 @@
+# ===================================================================
+#
+# Copyright (c) 2015, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+import json
+import unittest
+from binascii import unhexlify
+
+from Crypto.SelfTest.st_common import list_test_cases
+from Crypto.SelfTest.loader import load_test_vectors_wycheproof
+
+from Crypto.Util.py3compat import tobytes, bchr
+from Crypto.Cipher import AES
+from Crypto.Hash import SHAKE128
+
+from Crypto.Util.strxor import strxor
+
+
+def get_tag_random(tag, length):
+ return SHAKE128.new(data=tobytes(tag)).read(length)
+
+
+class SivTests(unittest.TestCase):
+
+ key_256 = get_tag_random("key_256", 32)
+ key_384 = get_tag_random("key_384", 48)
+ key_512 = get_tag_random("key_512", 64)
+ nonce_96 = get_tag_random("nonce_128", 12)
+ data = get_tag_random("data", 128)
+
+ def test_loopback_128(self):
+ for key in self.key_256, self.key_384, self.key_512:
+ cipher = AES.new(key, AES.MODE_SIV, nonce=self.nonce_96)
+ pt = get_tag_random("plaintext", 16 * 100)
+ ct, mac = cipher.encrypt_and_digest(pt)
+
+ cipher = AES.new(key, AES.MODE_SIV, nonce=self.nonce_96)
+ pt2 = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(pt, pt2)
+
+ def test_nonce(self):
+ # Deterministic encryption
+ AES.new(self.key_256, AES.MODE_SIV)
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, self.nonce_96)
+ ct1, tag1 = cipher.encrypt_and_digest(self.data)
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ ct2, tag2 = cipher.encrypt_and_digest(self.data)
+ self.assertEqual(ct1 + tag1, ct2 + tag2)
+
+ def test_nonce_must_be_bytes(self):
+ self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV,
+ nonce=u'test12345678')
+
+ def test_nonce_length(self):
+ # nonce can be of any length (but not empty)
+ self.assertRaises(ValueError, AES.new, self.key_256, AES.MODE_SIV,
+ nonce=b"")
+
+ for x in range(1, 128):
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=bchr(1) * x)
+ cipher.encrypt_and_digest(b'\x01')
+
+ def test_block_size_128(self):
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ self.assertEqual(cipher.block_size, AES.block_size)
+
+ def test_nonce_attribute(self):
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ self.assertEqual(cipher.nonce, self.nonce_96)
+
+ # By default, no nonce is randomly generated
+ self.assertFalse(hasattr(AES.new(self.key_256, AES.MODE_SIV), "nonce"))
+
+ def test_unknown_parameters(self):
+ self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV,
+ self.nonce_96, 7)
+ self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV,
+ nonce=self.nonce_96, unknown=7)
+
+ # But some are only known by the base cipher
+ # (e.g. use_aesni consumed by the AES module)
+ AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96,
+ use_aesni=False)
+
+ def test_encrypt_excludes_decrypt(self):
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.encrypt_and_digest(self.data)
+ self.assertRaises(TypeError, cipher.decrypt, self.data)
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.encrypt_and_digest(self.data)
+ self.assertRaises(TypeError, cipher.decrypt_and_verify,
+ self.data, self.data)
+
+ def test_data_must_be_bytes(self):
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*')
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.decrypt_and_verify,
+ u'test1234567890-*', b"xxxx")
+
+ def test_mac_len(self):
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ _, mac = cipher.encrypt_and_digest(self.data)
+ self.assertEqual(len(mac), 16)
+
+ def test_invalid_mac(self):
+ from Crypto.Util.strxor import strxor_c
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ ct, mac = cipher.encrypt_and_digest(self.data)
+
+ invalid_mac = strxor_c(mac, 0x01)
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.decrypt_and_verify, ct,
+ invalid_mac)
+
+ def test_hex_mac(self):
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ mac_hex = cipher.hexdigest()
+ self.assertEqual(cipher.digest(), unhexlify(mac_hex))
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.hexverify(mac_hex)
+
+ def test_bytearray(self):
+
+ # Encrypt
+ key = bytearray(self.key_256)
+ nonce = bytearray(self.nonce_96)
+ data = bytearray(self.data)
+ header = bytearray(self.data)
+
+ cipher1 = AES.new(self.key_256,
+ AES.MODE_SIV,
+ nonce=self.nonce_96)
+ cipher1.update(self.data)
+ ct, tag = cipher1.encrypt_and_digest(self.data)
+
+ cipher2 = AES.new(key,
+ AES.MODE_SIV,
+ nonce=nonce)
+ key[:3] = b'\xFF\xFF\xFF'
+ nonce[:3] = b'\xFF\xFF\xFF'
+ cipher2.update(header)
+ header[:3] = b'\xFF\xFF\xFF'
+ ct_test, tag_test = cipher2.encrypt_and_digest(data)
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key = bytearray(self.key_256)
+ nonce = bytearray(self.nonce_96)
+ header = bytearray(self.data)
+ ct_ba = bytearray(ct)
+ tag_ba = bytearray(tag)
+
+ cipher3 = AES.new(key,
+ AES.MODE_SIV,
+ nonce=nonce)
+ key[:3] = b'\xFF\xFF\xFF'
+ nonce[:3] = b'\xFF\xFF\xFF'
+ cipher3.update(header)
+ header[:3] = b'\xFF\xFF\xFF'
+ pt_test = cipher3.decrypt_and_verify(ct_ba, tag_ba)
+
+ self.assertEqual(self.data, pt_test)
+
+ def test_memoryview(self):
+
+ # Encrypt
+ key = memoryview(bytearray(self.key_256))
+ nonce = memoryview(bytearray(self.nonce_96))
+ data = memoryview(bytearray(self.data))
+ header = memoryview(bytearray(self.data))
+
+ cipher1 = AES.new(self.key_256,
+ AES.MODE_SIV,
+ nonce=self.nonce_96)
+ cipher1.update(self.data)
+ ct, tag = cipher1.encrypt_and_digest(self.data)
+
+ cipher2 = AES.new(key,
+ AES.MODE_SIV,
+ nonce=nonce)
+ key[:3] = b'\xFF\xFF\xFF'
+ nonce[:3] = b'\xFF\xFF\xFF'
+ cipher2.update(header)
+ header[:3] = b'\xFF\xFF\xFF'
+ ct_test, tag_test= cipher2.encrypt_and_digest(data)
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(tag, tag_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decrypt
+ key = memoryview(bytearray(self.key_256))
+ nonce = memoryview(bytearray(self.nonce_96))
+ header = memoryview(bytearray(self.data))
+ ct_ba = memoryview(bytearray(ct))
+ tag_ba = memoryview(bytearray(tag))
+
+ cipher3 = AES.new(key,
+ AES.MODE_SIV,
+ nonce=nonce)
+ key[:3] = b'\xFF\xFF\xFF'
+ nonce[:3] = b'\xFF\xFF\xFF'
+ cipher3.update(header)
+ header[:3] = b'\xFF\xFF\xFF'
+ pt_test = cipher3.decrypt_and_verify(ct_ba, tag_ba)
+
+ self.assertEqual(self.data, pt_test)
+
+ def test_output_param(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ ct, tag = cipher.encrypt_and_digest(pt)
+
+ output = bytearray(128)
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ res, tag_out = cipher.encrypt_and_digest(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+ self.assertEqual(tag, tag_out)
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ res = cipher.decrypt_and_verify(ct, tag, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ def test_output_param_memoryview(self):
+
+ pt = b'5' * 128
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ ct, tag = cipher.encrypt_and_digest(pt)
+
+ output = memoryview(bytearray(128))
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.encrypt_and_digest(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.decrypt_and_verify(ct, tag, output=output)
+ self.assertEqual(pt, output)
+
+ def test_output_param_neg(self):
+ LEN_PT = 128
+
+ pt = b'5' * LEN_PT
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ ct, tag = cipher.encrypt_and_digest(pt)
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.encrypt_and_digest, pt, output=b'0' * LEN_PT)
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.decrypt_and_verify, ct, tag, output=b'0' * LEN_PT)
+
+ shorter_output = bytearray(LEN_PT - 1)
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.encrypt_and_digest, pt, output=shorter_output)
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, tag, output=shorter_output)
+
+
+class SivFSMTests(unittest.TestCase):
+
+ key_256 = get_tag_random("key_256", 32)
+ nonce_96 = get_tag_random("nonce_96", 12)
+ data = get_tag_random("data", 128)
+
+ def test_invalid_init_encrypt(self):
+ # Path INIT->ENCRYPT fails
+ cipher = AES.new(self.key_256, AES.MODE_SIV,
+ nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.encrypt, b"xxx")
+
+ def test_invalid_init_decrypt(self):
+ # Path INIT->DECRYPT fails
+ cipher = AES.new(self.key_256, AES.MODE_SIV,
+ nonce=self.nonce_96)
+ self.assertRaises(TypeError, cipher.decrypt, b"xxx")
+
+ def test_valid_init_update_digest_verify(self):
+ # No plaintext, fixed authenticated data
+ # Verify path INIT->UPDATE->DIGEST
+ cipher = AES.new(self.key_256, AES.MODE_SIV,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ mac = cipher.digest()
+
+ # Verify path INIT->UPDATE->VERIFY
+ cipher = AES.new(self.key_256, AES.MODE_SIV,
+ nonce=self.nonce_96)
+ cipher.update(self.data)
+ cipher.verify(mac)
+
+ def test_valid_init_digest(self):
+ # Verify path INIT->DIGEST
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.digest()
+
+ def test_valid_init_verify(self):
+ # Verify path INIT->VERIFY
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ mac = cipher.digest()
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.verify(mac)
+
+ def test_valid_multiple_digest_or_verify(self):
+ # Multiple calls to digest
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.update(self.data)
+ first_mac = cipher.digest()
+ for x in range(4):
+ self.assertEqual(first_mac, cipher.digest())
+
+ # Multiple calls to verify
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.update(self.data)
+ for x in range(5):
+ cipher.verify(first_mac)
+
+ def test_valid_encrypt_and_digest_decrypt_and_verify(self):
+ # encrypt_and_digest
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.update(self.data)
+ ct, mac = cipher.encrypt_and_digest(self.data)
+
+ # decrypt_and_verify
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.update(self.data)
+ pt = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(self.data, pt)
+
+ def test_invalid_multiple_encrypt_and_digest(self):
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ ct, tag = cipher.encrypt_and_digest(self.data)
+ self.assertRaises(TypeError, cipher.encrypt_and_digest, b'')
+
+ def test_invalid_multiple_decrypt_and_verify(self):
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ ct, tag = cipher.encrypt_and_digest(self.data)
+
+ cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
+ cipher.decrypt_and_verify(ct, tag)
+ self.assertRaises(TypeError, cipher.decrypt_and_verify, ct, tag)
+
+
+def transform(tv):
+ new_tv = [[unhexlify(x) for x in tv[0].split("-")]]
+ new_tv += [ unhexlify(x) for x in tv[1:5]]
+ if tv[5]:
+ nonce = unhexlify(tv[5])
+ else:
+ nonce = None
+ new_tv += [ nonce ]
+ return new_tv
+
+
+class TestVectors(unittest.TestCase):
+ """Class exercising the SIV test vectors found in RFC5297"""
+
+ # This is a list of tuples with 5 items:
+ #
+ # 1. Header + '|' + plaintext
+ # 2. Header + '|' + ciphertext + '|' + MAC
+ # 3. AES-128 key
+ # 4. Description
+ # 5. Dictionary of parameters to be passed to AES.new().
+ # It must include the nonce.
+ #
+ # A "Header" is a dash ('-') separated sequece of components.
+ #
+ test_vectors_hex = [
+ (
+ '101112131415161718191a1b1c1d1e1f2021222324252627',
+ '112233445566778899aabbccddee',
+ '40c02b9690c4dc04daef7f6afe5c',
+ '85632d07c6e8f37f950acd320a2ecc93',
+ 'fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff',
+ None
+ ),
+ (
+ '00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddccbbaa9988' +
+ '7766554433221100-102030405060708090a0',
+ '7468697320697320736f6d6520706c61696e7465787420746f20656e63727970' +
+ '74207573696e67205349562d414553',
+ 'cb900f2fddbe404326601965c889bf17dba77ceb094fa663b7a3f748ba8af829' +
+ 'ea64ad544a272e9c485b62a3fd5c0d',
+ '7bdb6e3b432667eb06f4d14bff2fbd0f',
+ '7f7e7d7c7b7a79787776757473727170404142434445464748494a4b4c4d4e4f',
+ '09f911029d74e35bd84156c5635688c0'
+ ),
+ ]
+
+ test_vectors = [ transform(tv) for tv in test_vectors_hex ]
+
+ def runTest(self):
+ for assoc_data, pt, ct, mac, key, nonce in self.test_vectors:
+
+ # Encrypt
+ cipher = AES.new(key, AES.MODE_SIV, nonce=nonce)
+ for x in assoc_data:
+ cipher.update(x)
+ ct2, mac2 = cipher.encrypt_and_digest(pt)
+ self.assertEqual(ct, ct2)
+ self.assertEqual(mac, mac2)
+
+ # Decrypt
+ cipher = AES.new(key, AES.MODE_SIV, nonce=nonce)
+ for x in assoc_data:
+ cipher.update(x)
+ pt2 = cipher.decrypt_and_verify(ct, mac)
+ self.assertEqual(pt, pt2)
+
+
+class TestVectorsWycheproof(unittest.TestCase):
+
+ def __init__(self):
+ unittest.TestCase.__init__(self)
+ self._id = "None"
+
+ def setUp(self):
+ self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"),
+ "aes_siv_cmac_test.json",
+ "Wycheproof AES SIV")
+
+ def shortDescription(self):
+ return self._id
+
+ def test_encrypt(self, tv):
+ self._id = "Wycheproof Encrypt AES-SIV Test #" + str(tv.id)
+
+ cipher = AES.new(tv.key, AES.MODE_SIV)
+ cipher.update(tv.aad)
+ ct, tag = cipher.encrypt_and_digest(tv.msg)
+ if tv.valid:
+ self.assertEqual(tag + ct, tv.ct)
+
+ def test_decrypt(self, tv):
+ self._id = "Wycheproof Decrypt AES_SIV Test #" + str(tv.id)
+
+ cipher = AES.new(tv.key, AES.MODE_SIV)
+ cipher.update(tv.aad)
+ try:
+ pt = cipher.decrypt_and_verify(tv.ct[16:], tv.ct[:16])
+ except ValueError:
+ assert not tv.valid
+ else:
+ assert tv.valid
+ self.assertEqual(pt, tv.msg)
+
+ def runTest(self):
+
+ for tv in self.tv:
+ self.test_encrypt(tv)
+ self.test_decrypt(tv)
+
+
+class TestVectorsWycheproof2(unittest.TestCase):
+
+ def __init__(self):
+ unittest.TestCase.__init__(self)
+ self._id = "None"
+
+ def setUp(self):
+ self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"),
+ "aead_aes_siv_cmac_test.json",
+ "Wycheproof AEAD SIV")
+
+ def shortDescription(self):
+ return self._id
+
+ def test_encrypt(self, tv):
+ self._id = "Wycheproof Encrypt AEAD-AES-SIV Test #" + str(tv.id)
+
+ cipher = AES.new(tv.key, AES.MODE_SIV, nonce=tv.iv)
+ cipher.update(tv.aad)
+ ct, tag = cipher.encrypt_and_digest(tv.msg)
+ if tv.valid:
+ self.assertEqual(ct, tv.ct)
+ self.assertEqual(tag, tv.tag)
+
+ def test_decrypt(self, tv):
+ self._id = "Wycheproof Decrypt AEAD-AES-SIV Test #" + str(tv.id)
+
+ cipher = AES.new(tv.key, AES.MODE_SIV, nonce=tv.iv)
+ cipher.update(tv.aad)
+ try:
+ pt = cipher.decrypt_and_verify(tv.ct, tv.tag)
+ except ValueError:
+ assert not tv.valid
+ else:
+ assert tv.valid
+ self.assertEqual(pt, tv.msg)
+
+ def runTest(self):
+
+ for tv in self.tv:
+ self.test_encrypt(tv)
+ self.test_decrypt(tv)
+
+
+def get_tests(config={}):
+ wycheproof_warnings = config.get('wycheproof_warnings')
+
+ tests = []
+ tests += list_test_cases(SivTests)
+ tests += list_test_cases(SivFSMTests)
+ tests += [ TestVectors() ]
+ tests += [ TestVectorsWycheproof() ]
+ tests += [ TestVectorsWycheproof2() ]
+ return tests
+
+
+if __name__ == '__main__':
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
diff --git a/lib/Crypto/SelfTest/Cipher/test_Salsa20.py b/lib/Crypto/SelfTest/Cipher/test_Salsa20.py
new file mode 100644
index 0000000..a710462
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_Salsa20.py
@@ -0,0 +1,367 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Cipher/Salsa20.py: Self-test for the Salsa20 stream cipher
+#
+# Written in 2013 by Fabrizio Tarizzo <fabrizio@fabriziotarizzo.org>
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+"""Self-test suite for Crypto.Cipher.Salsa20"""
+
+import unittest
+
+from Crypto.Util.py3compat import bchr
+
+from Crypto.SelfTest.st_common import list_test_cases
+
+from Crypto.Cipher import Salsa20
+
+from .common import make_stream_tests
+
+# This is a list of (plaintext, ciphertext, key[, description[, params]])
+# tuples.
+test_data = [
+ # Test vectors are taken from
+ # http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors
+ ( '00' * 512,
+ '4dfa5e481da23ea09a31022050859936da52fcee218005164f267cb65f5cfd7f'
+ + '2b4f97e0ff16924a52df269515110a07f9e460bc65ef95da58f740b7d1dbb0aa'
+ + 'd64cec189c7eb8c6bbf3d7376c80a481d43e628701f6a27afb9fe23919f24114'
+ + '8db44f70d7063efcc3dd55a0893a613c3c6fe1c127bd6f59910589293bb6ef9e'
+ + 'e24819066dee1a64f49b0bbad5988635272b169af861f85df881939f29ada6fd'
+ + '0241410e8d332ae4798d929434a2630de451ec4e0169694cbaa7ebb121ea6a2b'
+ + 'da9c1581f429e0a00f7d67e23b730676783b262e8eb43a25f55fb90b3e753aef'
+ + '8c6713ec66c51881111593ccb3e8cb8f8de124080501eeeb389c4bcb6977cf95'
+ + '7d5789631eb4554400e1e025935dfa7b3e9039d61bdc58a8697d36815bf1985c'
+ + 'efdf7ae112e5bb81e37ecf0616ce7147fc08a93a367e08631f23c03b00a8da2f'
+ + 'aa5024e5c8d30aca43fc2d5082067b21b234bc741d68fb292c6012c3764ccee3'
+ + '1e364a5403e00cfee338a21a01e7d3cefd5a770ca0ab48c435ea6116435f7ad8'
+ + '30b217b49f978a68e207ed9f462af7fb195b2115fe8f24f152e4ddc32202d6f2'
+ + 'b52fafbcfbc202d8a259a611e901d3f62d065eb13f09bbc45cd45119b843efaa'
+ + 'b375703739daced4dd4059fd71c3c47fc2f9939670fad4a46066adcc6a564578'
+ + '3308b90ffb72be04a6b147cbe38cc0c3b9267c296a92a7c69873f9f263be9703',
+ '80000000000000000000000000000000',
+ '128 bits key, set 1, vector 0',
+ dict (iv='00'*8)),
+
+ ( '00' * 512,
+ 'e3be8fdd8beca2e3ea8ef9475b29a6e7003951e1097a5c38d23b7a5fad9f6844'
+ + 'b22c97559e2723c7cbbd3fe4fc8d9a0744652a83e72a9c461876af4d7ef1a117'
+ + '8da2b74eef1b6283e7e20166abcae538e9716e4669e2816b6b20c5c356802001'
+ + 'cc1403a9a117d12a2669f456366d6ebb0f1246f1265150f793cdb4b253e348ae'
+ + '203d89bc025e802a7e0e00621d70aa36b7e07cb1e7d5b38d5e222b8b0e4b8407'
+ + '0142b1e29504767d76824850320b5368129fdd74e861b498e3be8d16f2d7d169'
+ + '57be81f47b17d9ae7c4ff15429a73e10acf250ed3a90a93c711308a74c6216a9'
+ + 'ed84cd126da7f28e8abf8bb63517e1ca98e712f4fb2e1a6aed9fdc73291faa17'
+ + '958211c4ba2ebd5838c635edb81f513a91a294e194f1c039aeec657dce40aa7e'
+ + '7c0af57cacefa40c9f14b71a4b3456a63e162ec7d8d10b8ffb1810d71001b618'
+ + '2f9f73da53b85405c11f7b2d890fa8ae0c7f2e926d8a98c7ec4e91b65120e988'
+ + '349631a700c6facec3471cb0413656e75e309456584084d7e12c5b43a41c43ed'
+ + '9a048abd9b880da65f6a665a20fe7b77cd292fe62cae644b7f7df69f32bdb331'
+ + '903e6505ce44fdc293920c6a9ec7057e23df7dad298f82ddf4efb7fdc7bfc622'
+ + '696afcfd0cddcc83c7e77f11a649d79acdc3354e9635ff137e929933a0bd6f53'
+ + '77efa105a3a4266b7c0d089d08f1e855cc32b15b93784a36e56a76cc64bc8477',
+ '8000000000000000000000000000000000000000000000000000000000000000',
+ '256 bits key, set 1, vector 0',
+ dict (iv='00'*8)),
+
+ ( '00' * 512,
+ '169060ccb42bea7bee4d8012a02f3635eb7bca12859fa159cd559094b3507db8'
+ + '01735d1a1300102a9c9415546829cbd2021ba217b39b81d89c55b13d0c603359'
+ + '3f84159a3c84f4b4f4a0edcd9d38ff261a737909e0b66d68b5cac496f3a5be99'
+ + 'cb12c321ab711afaab36cc0947955e1a9bb952ed54425e7711279fbc81bb83f5'
+ + '6e55cea44e6daddb05858a153ea6213b3350c12aa1a83ef2726f09485fa71790'
+ + 'f9b9f922c7dda1113b1f9d56658ed3402803f511bc1f122601d5e7f0ff036e23'
+ + '23ef24bb24195b9fd574823cd8a40c29d86bd35c191e2038779ff696c712b6d8'
+ + '2e7014dbe1ac5d527af076c088c4a8d44317958189f6ef54933a7e0816b5b916'
+ + 'd8f12ed8afe9422b85e5cc9b8adec9d6cfabe8dbc1082bccc02f5a7266aa074c'
+ + 'a284e583a35837798cc0e69d4ce937653b8cdd65ce414b89138615ccb165ad19'
+ + '3c6b9c3d05eef4be921a10ea811fe61d11c6867600188e065daff90b509ec56b'
+ + 'd41e7e8968c478c78d590c2d2ee24ea009c8f49bc3d81672cfc47895a9e21c9a'
+ + '471ebf8e294bee5d2de436ac8d052bf31111b345f1da23c3a4d13b9fc5f0900a'
+ + 'a298f98f538973b8fad40d4d159777de2cfe2a3dead1645ddb49794827dba040'
+ + 'f70a0ff4ecd155e0f033604693a51e2363880e2ecf98699e7174af7c2c6b0fc6'
+ + '59ae329599a3949272a37b9b2183a0910922a3f325ae124dcbdd735364055ceb',
+ '09090909090909090909090909090909',
+ '128 bits key, set 2, vector 9',
+ dict (iv='00'*8)),
+
+ ( '00' * 512,
+ '7041e747ceb22ed7812985465f50333124f971da1c5d6efe5ca201b886f31046'
+ + 'e757e5c3ec914f60ed1f6bce2819b6810953f12b8ba1199bf82d746a8b8a88f1'
+ + '142002978ec4c35b95dc2c82990f9e847a0ab45f2ca72625f5190c820f29f3aa'
+ + 'f5f0b5572b06b70a144f2a240c3b3098d4831fa1ce1459f8d1df226a6a79b0ab'
+ + '41e91799ef31b5ff3d756c19126b19025858ee70fbd69f2be955cb011c005e31'
+ + '32b271b378f39b0cb594e95c99ce6ff17735a541891845bbf0450afcb4a850b9'
+ + '4ee90afb713ae7e01295c74381180a3816d7020d5a396c0d97aaa783eaabb6ec'
+ + '44d5111157f2212d1b1b8fca7893e8b520cd482418c272ab119b569a2b9598eb'
+ + '355624d12e79adab81153b58cd22eaf1b2a32395dedc4a1c66f4d274070b9800'
+ + 'ea95766f0245a8295f8aadb36ddbbdfa936417c8dbc6235d19494036964d3e70'
+ + 'b125b0f800c3d53881d9d11e7970f827c2f9556935cd29e927b0aceb8cae5fd4'
+ + '0fd88a8854010a33db94c96c98735858f1c5df6844f864feaca8f41539313e7f'
+ + '3c0610214912cd5e6362197646207e2d64cd5b26c9dfe0822629dcbeb16662e8'
+ + '9ff5bf5cf2e499138a5e27bd5027329d0e68ddf53103e9e409523662e27f61f6'
+ + '5cf38c1232023e6a6ef66c315bcb2a4328642faabb7ca1e889e039e7c444b34b'
+ + 'b3443f596ac730f3df3dfcdb343c307c80f76e43e8898c5e8f43dc3bb280add0',
+ '0909090909090909090909090909090909090909090909090909090909090909',
+ '256 bits key, set 2, vector 9',
+ dict (iv='00'*8)),
+
+ ( '00' * 1024,
+ '71daee5142d0728b41b6597933ebf467e43279e30978677078941602629cbf68'
+ + 'b73d6bd2c95f118d2b3e6ec955dabb6dc61c4143bc9a9b32b99dbe6866166dc0'
+ + '8631b7d6553050303d7252c264d3a90d26c853634813e09ad7545a6ce7e84a5d'
+ + 'fc75ec43431207d5319970b0faadb0e1510625bb54372c8515e28e2accf0a993'
+ + '0ad15f431874923d2a59e20d9f2a5367dba6051564f150287debb1db536ff9b0'
+ + '9ad981f25e5010d85d76ee0c305f755b25e6f09341e0812f95c94f42eead346e'
+ + '81f39c58c5faa2c88953dc0cac90469db2063cb5cdb22c9eae22afbf0506fca4'
+ + '1dc710b846fbdfe3c46883dd118f3a5e8b11b6afd9e71680d8666557301a2daa'
+ + 'fb9496c559784d35a035360885f9b17bd7191977deea932b981ebdb29057ae3c'
+ + '92cfeff5e6c5d0cb62f209ce342d4e35c69646ccd14e53350e488bb310a32f8b'
+ + '0248e70acc5b473df537ced3f81a014d4083932bedd62ed0e447b6766cd2604b'
+ + '706e9b346c4468beb46a34ecf1610ebd38331d52bf33346afec15eefb2a7699e'
+ + '8759db5a1f636a48a039688e39de34d995df9f27ed9edc8dd795e39e53d9d925'
+ + 'b278010565ff665269042f05096d94da3433d957ec13d2fd82a0066283d0d1ee'
+ + 'b81bf0ef133b7fd90248b8ffb499b2414cd4fa003093ff0864575a43749bf596'
+ + '02f26c717fa96b1d057697db08ebc3fa664a016a67dcef8807577cc3a09385d3'
+ + 'f4dc79b34364bb3b166ce65fe1dd28e3950fe6fa81063f7b16ce1c0e6daac1f8'
+ + '188455b77752045e863c9b256ad92bc6e2d08314c5bba191c274f42dfbb3d652'
+ + 'bb771956555e880f84cd8b827a4c5a52f3a099fa0259bd4aac3efd541f191170'
+ + '4412d6e85fbcc628b335875b9fef24807f6e1bc66c3186159e1e7f5a13913e02'
+ + 'd241ce2efdbcaa275039fb14eac5923d17ffbc7f1abd3b45e92127575bfbabf9'
+ + '3a257ebef0aa1437b326e41b585af572f7239c33b32981a1577a4f629b027e1e'
+ + 'b49d58cc497e944d79cef44357c2bf25442ab779651e991147bf79d6fd3a8868'
+ + '0cd3b1748e07fd10d78aceef6db8a5e563570d40127f754146c34a440f2a991a'
+ + '23fa39d365141f255041f2135c5cba4373452c114da1801bacca38610e3a6524'
+ + '2b822d32de4ab5a7d3cf9b61b37493c863bd12e2cae10530cddcda2cb7a5436b'
+ + 'ef8988d4d24e8cdc31b2d2a3586340bc5141f8f6632d0dd543bfed81eb471ba1'
+ + 'f3dc2225a15ffddcc03eb48f44e27e2aa390598adf83f15c6608a5f18d4dfcf0'
+ + 'f547d467a4d70b281c83a595d7660d0b62de78b9cca023cca89d7b1f83484638'
+ + '0e228c25f049184a612ef5bb3d37454e6cfa5b10dceda619d898a699b3c8981a'
+ + '173407844bb89b4287bf57dd6600c79e352c681d74b03fa7ea0d7bf6ad69f8a6'
+ + '8ecb001963bd2dd8a2baa0083ec09751cd9742402ad716be16d5c052304cfca1',
+ '0F62B5085BAE0154A7FA4DA0F34699EC',
+ '128 bits key, Set 6, vector# 3',
+ dict (iv='288FF65DC42B92F9')),
+
+ ( '00' * 1024,
+ '5e5e71f90199340304abb22a37b6625bf883fb89ce3b21f54a10b81066ef87da'
+ + '30b77699aa7379da595c77dd59542da208e5954f89e40eb7aa80a84a6176663f'
+ + 'd910cde567cf1ff60f7040548d8f376bfd1f44c4774aac37410ede7d5c3463fc'
+ + '4508a603201d8495ad257894e5eb1914b53e8da5e4bf2bc83ac87ce55cc67df7'
+ + '093d9853d2a83a9c8be969175df7c807a17156df768445dd0874a9271c6537f5'
+ + 'ce0466473582375f067fa4fcdaf65dbc0139cd75e8c21a482f28c0fb8c3d9f94'
+ + '22606cc8e88fe28fe73ec3cb10ff0e8cc5f2a49e540f007265c65b7130bfdb98'
+ + '795b1df9522da46e48b30e55d9f0d787955ece720205b29c85f3ad9be33b4459'
+ + '7d21b54d06c9a60b04b8e640c64e566e51566730e86cf128ab14174f91bd8981'
+ + 'a6fb00fe587bbd6c38b5a1dfdb04ea7e61536fd229f957aa9b070ca931358e85'
+ + '11b92c53c523cb54828fb1513c5636fa9a0645b4a3c922c0db94986d92f314ff'
+ + '7852c03b231e4dceea5dd8cced621869cff818daf3c270ff3c8be2e5c74be767'
+ + 'a4e1fdf3327a934fe31e46df5a74ae2021cee021d958c4f615263d99a5ddae7f'
+ + 'eab45e6eccbafefe4761c57750847b7e75ee2e2f14333c0779ce4678f47b1e1b'
+ + '760a03a5f17d6e91d4b42313b3f1077ee270e432fe04917ed1fc8babebf7c941'
+ + '42b80dfb44a28a2a3e59093027606f6860bfb8c2e5897078cfccda7314c70035'
+ + 'f137de6f05daa035891d5f6f76e1df0fce1112a2ff0ac2bd3534b5d1bf4c7165'
+ + 'fb40a1b6eacb7f295711c4907ae457514a7010f3a342b4427593d61ba993bc59'
+ + '8bd09c56b9ee53aac5dd861fa4b4bb53888952a4aa9d8ca8671582de716270e1'
+ + '97375b3ee49e51fa2bf4ef32015dd9a764d966aa2ae541592d0aa650849e99ca'
+ + '5c6c39beebf516457cc32fe4c105bff314a12f1ec94bdf4d626f5d9b1cbbde42'
+ + 'e5733f0885765ba29e2e82c829d312f5fc7e180679ac84826c08d0a644b326d0'
+ + '44da0fdcc75fa53cfe4ced0437fa4df5a7ecbca8b4cb7c4a9ecf9a60d00a56eb'
+ + '81da52adc21f508dbb60a9503a3cc94a896616d86020d5b0e5c637329b6d396a'
+ + '41a21ba2c4a9493cf33fa2d4f10f77d5b12fdad7e478ccfe79b74851fc96a7ca'
+ + '6320c5efd561a222c0ab0fb44bbda0e42149611d2262bb7d1719150fa798718a'
+ + '0eec63ee297cad459869c8b0f06c4e2b56cbac03cd2605b2a924efedf85ec8f1'
+ + '9b0b6c90e7cbd933223ffeb1b3a3f9677657905829294c4c70acdb8b0891b47d'
+ + '0875d0cd6c0f4efe2917fc44b581ef0d1e4280197065d07da34ab33283364552'
+ + 'efad0bd9257b059acdd0a6f246812feb69e7e76065f27dbc2eee94da9cc41835'
+ + 'bf826e36e5cebe5d4d6a37a6a666246290ce51a0c082718ab0ec855668db1add'
+ + 'a658e5f257e0db39384d02e6145c4c00eaa079098f6d820d872de711b6ed08cf',
+ '0F62B5085BAE0154A7FA4DA0F34699EC3F92E5388BDE3184D72A7DD02376C91C',
+ '256 bits key, Set 6, vector# 3',
+ dict (iv='288FF65DC42B92F9')),
+
+]
+
+
+class KeyLength(unittest.TestCase):
+
+ def runTest(self):
+
+ nonce = bchr(0) * 8
+ for key_length in (15, 30, 33):
+ key = bchr(1) * key_length
+ self.assertRaises(ValueError, Salsa20.new, key, nonce)
+
+
+class NonceTests(unittest.TestCase):
+
+ def test_invalid_nonce_length(self):
+ key = bchr(1) * 16
+ self.assertRaises(ValueError, Salsa20.new, key, bchr(0) * 7)
+ self.assertRaises(ValueError, Salsa20.new, key, bchr(0) * 9)
+
+ def test_default_nonce(self):
+
+ cipher1 = Salsa20.new(bchr(1) * 16)
+ cipher2 = Salsa20.new(bchr(1) * 16)
+ self.assertEqual(len(cipher1.nonce), 8)
+ self.assertNotEqual(cipher1.nonce, cipher2.nonce)
+
+
+class ByteArrayTest(unittest.TestCase):
+ """Verify we can encrypt or decrypt bytearrays"""
+
+ def runTest(self):
+
+ data = b"0123"
+ key = b"9" * 32
+ nonce = b"t" * 8
+
+ # Encryption
+ data_ba = bytearray(data)
+ key_ba = bytearray(key)
+ nonce_ba = bytearray(nonce)
+
+ cipher1 = Salsa20.new(key=key, nonce=nonce)
+ ct = cipher1.encrypt(data)
+
+ cipher2 = Salsa20.new(key=key_ba, nonce=nonce_ba)
+ key_ba[:1] = b'\xFF'
+ nonce_ba[:1] = b'\xFF'
+ ct_test = cipher2.encrypt(data_ba)
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decryption
+ key_ba = bytearray(key)
+ nonce_ba = bytearray(nonce)
+ ct_ba = bytearray(ct)
+
+ cipher3 = Salsa20.new(key=key_ba, nonce=nonce_ba)
+ key_ba[:1] = b'\xFF'
+ nonce_ba[:1] = b'\xFF'
+ pt_test = cipher3.decrypt(ct_ba)
+
+ self.assertEqual(data, pt_test)
+
+
+class MemoryviewTest(unittest.TestCase):
+ """Verify we can encrypt or decrypt bytearrays"""
+
+ def runTest(self):
+
+ data = b"0123"
+ key = b"9" * 32
+ nonce = b"t" * 8
+
+ # Encryption
+ data_mv = memoryview(bytearray(data))
+ key_mv = memoryview(bytearray(key))
+ nonce_mv = memoryview(bytearray(nonce))
+
+ cipher1 = Salsa20.new(key=key, nonce=nonce)
+ ct = cipher1.encrypt(data)
+
+ cipher2 = Salsa20.new(key=key_mv, nonce=nonce_mv)
+ key_mv[:1] = b'\xFF'
+ nonce_mv[:1] = b'\xFF'
+ ct_test = cipher2.encrypt(data_mv)
+
+ self.assertEqual(ct, ct_test)
+ self.assertEqual(cipher1.nonce, cipher2.nonce)
+
+ # Decryption
+ key_mv = memoryview(bytearray(key))
+ nonce_mv = memoryview(bytearray(nonce))
+ ct_mv = memoryview(bytearray(ct))
+
+ cipher3 = Salsa20.new(key=key_mv, nonce=nonce_mv)
+ key_mv[:1] = b'\xFF'
+ nonce_mv[:1] = b'\xFF'
+ pt_test = cipher3.decrypt(ct_mv)
+
+ self.assertEqual(data, pt_test)
+
+
+class TestOutput(unittest.TestCase):
+
+ def runTest(self):
+ # Encrypt/Decrypt data and test output parameter
+
+ key = b'4' * 32
+ nonce = b'5' * 8
+ cipher = Salsa20.new(key=key, nonce=nonce)
+
+ pt = b'5' * 300
+ ct = cipher.encrypt(pt)
+
+ output = bytearray(len(pt))
+ cipher = Salsa20.new(key=key, nonce=nonce)
+ res = cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+ self.assertEqual(res, None)
+
+ cipher = Salsa20.new(key=key, nonce=nonce)
+ res = cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+ self.assertEqual(res, None)
+
+ output = memoryview(bytearray(len(pt)))
+ cipher = Salsa20.new(key=key, nonce=nonce)
+ cipher.encrypt(pt, output=output)
+ self.assertEqual(ct, output)
+
+ cipher = Salsa20.new(key=key, nonce=nonce)
+ cipher.decrypt(ct, output=output)
+ self.assertEqual(pt, output)
+
+ cipher = Salsa20.new(key=key, nonce=nonce)
+ self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*len(pt))
+
+ cipher = Salsa20.new(key=key, nonce=nonce)
+ self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*len(ct))
+
+ shorter_output = bytearray(len(pt) - 1)
+
+ cipher = Salsa20.new(key=key, nonce=nonce)
+ self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output)
+
+ cipher = Salsa20.new(key=key, nonce=nonce)
+ self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
+
+
+def get_tests(config={}):
+ tests = make_stream_tests(Salsa20, "Salsa20", test_data)
+ tests.append(KeyLength())
+ tests += list_test_cases(NonceTests)
+ tests.append(ByteArrayTest())
+ tests.append(MemoryviewTest())
+ tests.append(TestOutput())
+
+ return tests
+
+
+if __name__ == '__main__':
+ import unittest
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
+
+# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/SelfTest/Cipher/test_pkcs1_15.py b/lib/Crypto/SelfTest/Cipher/test_pkcs1_15.py
new file mode 100644
index 0000000..e16a543
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_pkcs1_15.py
@@ -0,0 +1,283 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Cipher/test_pkcs1_15.py: Self-test for PKCS#1 v1.5 encryption
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+from __future__ import print_function
+
+import unittest
+
+from Crypto.PublicKey import RSA
+from Crypto.SelfTest.st_common import list_test_cases, a2b_hex
+from Crypto import Random
+from Crypto.Cipher import PKCS1_v1_5 as PKCS
+from Crypto.Util.py3compat import b
+from Crypto.Util.number import bytes_to_long, long_to_bytes
+from Crypto.SelfTest.loader import load_test_vectors_wycheproof
+
+
+def rws(t):
+ """Remove white spaces, tabs, and new lines from a string"""
+ for c in ['\n', '\t', ' ']:
+ t = t.replace(c, '')
+ return t
+
+
+def t2b(t):
+ """Convert a text string with bytes in hex form to a byte string"""
+ clean = b(rws(t))
+ if len(clean) % 2 == 1:
+ raise ValueError("Even number of characters expected")
+ return a2b_hex(clean)
+
+
+class PKCS1_15_Tests(unittest.TestCase):
+
+ def setUp(self):
+ self.rng = Random.new().read
+ self.key1024 = RSA.generate(1024, self.rng)
+
+ # List of tuples with test data for PKCS#1 v1.5.
+ # Each tuple is made up by:
+ # Item #0: dictionary with RSA key component, or key to import
+ # Item #1: plaintext
+ # Item #2: ciphertext
+ # Item #3: random data
+
+ _testData = (
+
+ #
+ # Generated with openssl 0.9.8o
+ #
+ (
+ # Private key
+ '''-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDAiAnvIAOvqVwJTaYzsKnefZftgtXGE2hPJppGsWl78yz9jeXY
+W/FxX/gTPURArNhdnhP6n3p2ZaDIBrO2zizbgIXs0IsljTTcr4vnI8fMXzyNUOjA
+zP3nzMqZDZK6757XQAobOssMkBFqRWwilT/3DsBhRpl3iMUhF+wvpTSHewIDAQAB
+AoGAC4HV/inOrpgTvSab8Wj0riyZgQOZ3U3ZpSlsfR8ra9Ib9Uee3jCYnKscu6Gk
+y6zI/cdt8EPJ4PuwAWSNJzbpbVaDvUq25OD+CX8/uRT08yBS4J8TzBitZJTD4lS7
+atdTnKT0Wmwk+u8tDbhvMKwnUHdJLcuIsycts9rwJVapUtkCQQDvDpx2JMun0YKG
+uUttjmL8oJ3U0m3ZvMdVwBecA0eebZb1l2J5PvI3EJD97eKe91Nsw8T3lwpoN40k
+IocSVDklAkEAzi1HLHE6EzVPOe5+Y0kGvrIYRRhncOb72vCvBZvD6wLZpQgqo6c4
+d3XHFBBQWA6xcvQb5w+VVEJZzw64y25sHwJBAMYReRl6SzL0qA0wIYrYWrOt8JeQ
+8mthulcWHXmqTgC6FEXP9Es5GD7/fuKl4wqLKZgIbH4nqvvGay7xXLCXD/ECQH9a
+1JYNMtRen5unSAbIOxRcKkWz92F0LKpm9ZW/S9vFHO+mBcClMGoKJHiuQxLBsLbT
+NtEZfSJZAeS2sUtn3/0CQDb2M2zNBTF8LlM0nxmh0k9VGm5TVIyBEMcipmvOgqIs
+HKukWBcq9f/UOmS0oEhai/6g+Uf7VHJdWaeO5LzuvwU=
+-----END RSA PRIVATE KEY-----''',
+ # Plaintext
+ '''THIS IS PLAINTEXT\x0A''',
+ # Ciphertext
+ '''3f dc fd 3c cd 5c 9b 12 af 65 32 e3 f7 d0 da 36
+ 8f 8f d9 e3 13 1c 7f c8 b3 f9 c1 08 e4 eb 79 9c
+ 91 89 1f 96 3b 94 77 61 99 a4 b1 ee 5d e6 17 c9
+ 5d 0a b5 63 52 0a eb 00 45 38 2a fb b0 71 3d 11
+ f7 a1 9e a7 69 b3 af 61 c0 bb 04 5b 5d 4b 27 44
+ 1f 5b 97 89 ba 6a 08 95 ee 4f a2 eb 56 64 e5 0f
+ da 7c f9 9a 61 61 06 62 ed a0 bc 5f aa 6c 31 78
+ 70 28 1a bb 98 3c e3 6a 60 3c d1 0b 0f 5a f4 75''',
+ # Random data
+ '''eb d7 7d 86 a4 35 23 a3 54 7e 02 0b 42 1d
+ 61 6c af 67 b8 4e 17 56 80 66 36 04 64 34 26 8a
+ 47 dd 44 b3 1a b2 17 60 f4 91 2e e2 b5 95 64 cc
+ f9 da c8 70 94 54 86 4c ef 5b 08 7d 18 c4 ab 8d
+ 04 06 33 8f ca 15 5f 52 60 8a a1 0c f5 08 b5 4c
+ bb 99 b8 94 25 04 9c e6 01 75 e6 f9 63 7a 65 61
+ 13 8a a7 47 77 81 ae 0d b8 2c 4d 50 a5'''
+ ),
+ )
+
+ def testEncrypt1(self):
+ for test in self._testData:
+ # Build the key
+ key = RSA.importKey(test[0])
+ # RNG that takes its random numbers from a pool given
+ # at initialization
+ class randGen:
+ def __init__(self, data):
+ self.data = data
+ self.idx = 0
+ def __call__(self, N):
+ r = self.data[self.idx:self.idx+N]
+ self.idx += N
+ return r
+ # The real test
+ cipher = PKCS.new(key, randfunc=randGen(t2b(test[3])))
+ ct = cipher.encrypt(b(test[1]))
+ self.assertEqual(ct, t2b(test[2]))
+
+ def testEncrypt2(self):
+ # Verify that encryption fail if plaintext is too long
+ pt = '\x00'*(128-11+1)
+ cipher = PKCS.new(self.key1024)
+ self.assertRaises(ValueError, cipher.encrypt, pt)
+
+ def testVerify1(self):
+ for test in self._testData:
+ key = RSA.importKey(test[0])
+ expected_pt = b(test[1])
+ ct = t2b(test[2])
+ cipher = PKCS.new(key)
+
+ # The real test
+ pt = cipher.decrypt(ct, None)
+ self.assertEqual(pt, expected_pt)
+
+ pt = cipher.decrypt(ct, b'\xFF' * len(expected_pt))
+ self.assertEqual(pt, expected_pt)
+
+ def testVerify2(self):
+ # Verify that decryption fails if ciphertext is not as long as
+ # RSA modulus
+ cipher = PKCS.new(self.key1024)
+ self.assertRaises(ValueError, cipher.decrypt, '\x00'*127, "---")
+ self.assertRaises(ValueError, cipher.decrypt, '\x00'*129, "---")
+
+ # Verify that decryption fails if there are less then 8 non-zero padding
+ # bytes
+ pt = b('\x00\x02' + '\xFF'*7 + '\x00' + '\x45'*118)
+ pt_int = bytes_to_long(pt)
+ ct_int = self.key1024._encrypt(pt_int)
+ ct = long_to_bytes(ct_int, 128)
+ self.assertEqual(b"---", cipher.decrypt(ct, b"---"))
+
+ def testEncryptVerify1(self):
+ # Encrypt/Verify messages of length [0..RSAlen-11]
+ # and therefore padding [8..117]
+ for pt_len in range(0, 128 - 11 + 1):
+ pt = self.rng(pt_len)
+ cipher = PKCS.new(self.key1024)
+ ct = cipher.encrypt(pt)
+ pt2 = cipher.decrypt(ct, b'\xAA' * pt_len)
+ self.assertEqual(pt, pt2)
+
+ def test_encrypt_verify_exp_pt_len(self):
+
+ cipher = PKCS.new(self.key1024)
+ pt = b'5' * 16
+ ct = cipher.encrypt(pt)
+ sentinel = b'\xAA' * 16
+
+ pt_A = cipher.decrypt(ct, sentinel, 16)
+ self.assertEqual(pt, pt_A)
+
+ pt_B = cipher.decrypt(ct, sentinel, 15)
+ self.assertEqual(sentinel, pt_B)
+
+ pt_C = cipher.decrypt(ct, sentinel, 17)
+ self.assertEqual(sentinel, pt_C)
+
+ def testByteArray(self):
+ pt = b"XER"
+ cipher = PKCS.new(self.key1024)
+ ct = cipher.encrypt(bytearray(pt))
+ pt2 = cipher.decrypt(bytearray(ct), '\xFF' * len(pt))
+ self.assertEqual(pt, pt2)
+
+ def testMemoryview(self):
+ pt = b"XER"
+ cipher = PKCS.new(self.key1024)
+ ct = cipher.encrypt(memoryview(bytearray(pt)))
+ pt2 = cipher.decrypt(memoryview(bytearray(ct)), b'\xFF' * len(pt))
+ self.assertEqual(pt, pt2)
+
+ def test_return_type(self):
+ pt = b"XYZ"
+ cipher = PKCS.new(self.key1024)
+ ct = cipher.encrypt(pt)
+ self.assertTrue(isinstance(ct, bytes))
+ pt2 = cipher.decrypt(ct, b'\xAA' * 3)
+ self.assertTrue(isinstance(pt2, bytes))
+
+
+class TestVectorsWycheproof(unittest.TestCase):
+
+ def __init__(self, wycheproof_warnings, skip_slow_tests):
+ unittest.TestCase.__init__(self)
+ self._wycheproof_warnings = wycheproof_warnings
+ self._skip_slow_tests = skip_slow_tests
+ self._id = "None"
+
+ def load_tests(self, filename):
+
+ def filter_rsa(group):
+ return RSA.import_key(group['privateKeyPem'])
+
+ result = load_test_vectors_wycheproof(("Cipher", "wycheproof"),
+ filename,
+ "Wycheproof PKCS#1v1.5 (%s)" % filename,
+ group_tag={'rsa_key': filter_rsa}
+ )
+ return result
+
+ def setUp(self):
+ self.tv = []
+ self.tv.extend(self.load_tests("rsa_pkcs1_2048_test.json"))
+ if not self._skip_slow_tests:
+ self.tv.extend(self.load_tests("rsa_pkcs1_3072_test.json"))
+ self.tv.extend(self.load_tests("rsa_pkcs1_4096_test.json"))
+
+ def shortDescription(self):
+ return self._id
+
+ def warn(self, tv):
+ if tv.warning and self._wycheproof_warnings:
+ import warnings
+ warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment))
+
+ def test_decrypt(self, tv):
+ self._id = "Wycheproof Decrypt PKCS#1v1.5 Test #%s" % tv.id
+ sentinel = b'\xAA' * max(3, len(tv.msg))
+ cipher = PKCS.new(tv.rsa_key)
+ try:
+ pt = cipher.decrypt(tv.ct, sentinel=sentinel)
+ except ValueError:
+ assert not tv.valid
+ else:
+ if pt == sentinel:
+ assert not tv.valid
+ else:
+ assert tv.valid
+ self.assertEqual(pt, tv.msg)
+ self.warn(tv)
+
+ def runTest(self):
+
+ for tv in self.tv:
+ self.test_decrypt(tv)
+
+
+def get_tests(config={}):
+ skip_slow_tests = not config.get('slow_tests')
+ wycheproof_warnings = config.get('wycheproof_warnings')
+
+ tests = []
+ tests += list_test_cases(PKCS1_15_Tests)
+ tests += [TestVectorsWycheproof(wycheproof_warnings, skip_slow_tests)]
+ return tests
+
+
+if __name__ == '__main__':
+ def suite():
+ return unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
+
+# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py b/lib/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py
new file mode 100644
index 0000000..1711581
--- /dev/null
+++ b/lib/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py
@@ -0,0 +1,506 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Cipher/test_pkcs1_oaep.py: Self-test for PKCS#1 OAEP encryption
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+import unittest
+
+from Crypto.SelfTest.st_common import list_test_cases, a2b_hex
+from Crypto.SelfTest.loader import load_test_vectors_wycheproof
+
+from Crypto.PublicKey import RSA
+from Crypto.Cipher import PKCS1_OAEP as PKCS
+from Crypto.Hash import MD2, MD5, SHA1, SHA256, RIPEMD160, SHA224, SHA384, SHA512
+from Crypto import Random
+from Crypto.Signature.pss import MGF1
+
+from Crypto.Util.py3compat import b, bchr
+
+
+def rws(t):
+ """Remove white spaces, tabs, and new lines from a string"""
+ for c in ['\n', '\t', ' ']:
+ t = t.replace(c, '')
+ return t
+
+
+def t2b(t):
+ """Convert a text string with bytes in hex form to a byte string"""
+ clean = rws(t)
+ if len(clean) % 2 == 1:
+ raise ValueError("Even number of characters expected")
+ return a2b_hex(clean)
+
+
+class PKCS1_OAEP_Tests(unittest.TestCase):
+
+ def setUp(self):
+ self.rng = Random.new().read
+ self.key1024 = RSA.generate(1024, self.rng)
+
+ # List of tuples with test data for PKCS#1 OAEP
+ # Each tuple is made up by:
+ # Item #0: dictionary with RSA key component
+ # Item #1: plaintext
+ # Item #2: ciphertext
+ # Item #3: random data (=seed)
+ # Item #4: hash object
+
+ _testData = (
+
+ #
+ # From in oaep-int.txt to be found in
+ # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip
+ #
+ (
+ # Private key
+ {
+ 'n':'''bb f8 2f 09 06 82 ce 9c 23 38 ac 2b 9d a8 71 f7
+ 36 8d 07 ee d4 10 43 a4 40 d6 b6 f0 74 54 f5 1f
+ b8 df ba af 03 5c 02 ab 61 ea 48 ce eb 6f cd 48
+ 76 ed 52 0d 60 e1 ec 46 19 71 9d 8a 5b 8b 80 7f
+ af b8 e0 a3 df c7 37 72 3e e6 b4 b7 d9 3a 25 84
+ ee 6a 64 9d 06 09 53 74 88 34 b2 45 45 98 39 4e
+ e0 aa b1 2d 7b 61 a5 1f 52 7a 9a 41 f6 c1 68 7f
+ e2 53 72 98 ca 2a 8f 59 46 f8 e5 fd 09 1d bd cb''',
+ # Public key
+ 'e':'11',
+ # In the test vector, only p and q were given...
+ # d is computed offline as e^{-1} mod (p-1)(q-1)
+ 'd':'''a5dafc5341faf289c4b988db30c1cdf83f31251e0
+ 668b42784813801579641b29410b3c7998d6bc465745e5c3
+ 92669d6870da2c082a939e37fdcb82ec93edac97ff3ad595
+ 0accfbc111c76f1a9529444e56aaf68c56c092cd38dc3bef
+ 5d20a939926ed4f74a13eddfbe1a1cecc4894af9428c2b7b
+ 8883fe4463a4bc85b1cb3c1'''
+ }
+ ,
+ # Plaintext
+ '''d4 36 e9 95 69 fd 32 a7 c8 a0 5b bc 90 d3 2c 49''',
+ # Ciphertext
+ '''12 53 e0 4d c0 a5 39 7b b4 4a 7a b8 7e 9b f2 a0
+ 39 a3 3d 1e 99 6f c8 2a 94 cc d3 00 74 c9 5d f7
+ 63 72 20 17 06 9e 52 68 da 5d 1c 0b 4f 87 2c f6
+ 53 c1 1d f8 23 14 a6 79 68 df ea e2 8d ef 04 bb
+ 6d 84 b1 c3 1d 65 4a 19 70 e5 78 3b d6 eb 96 a0
+ 24 c2 ca 2f 4a 90 fe 9f 2e f5 c9 c1 40 e5 bb 48
+ da 95 36 ad 87 00 c8 4f c9 13 0a de a7 4e 55 8d
+ 51 a7 4d df 85 d8 b5 0d e9 68 38 d6 06 3e 09 55''',
+ # Random
+ '''aa fd 12 f6 59 ca e6 34 89 b4 79 e5 07 6d de c2
+ f0 6c b5 8f''',
+ # Hash
+ SHA1,
+ ),
+
+ #
+ # From in oaep-vect.txt to be found in Example 1.1
+ # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip
+ #
+ (
+ # Private key
+ {
+ 'n':'''a8 b3 b2 84 af 8e b5 0b 38 70 34 a8 60 f1 46 c4
+ 91 9f 31 87 63 cd 6c 55 98 c8 ae 48 11 a1 e0 ab
+ c4 c7 e0 b0 82 d6 93 a5 e7 fc ed 67 5c f4 66 85
+ 12 77 2c 0c bc 64 a7 42 c6 c6 30 f5 33 c8 cc 72
+ f6 2a e8 33 c4 0b f2 58 42 e9 84 bb 78 bd bf 97
+ c0 10 7d 55 bd b6 62 f5 c4 e0 fa b9 84 5c b5 14
+ 8e f7 39 2d d3 aa ff 93 ae 1e 6b 66 7b b3 d4 24
+ 76 16 d4 f5 ba 10 d4 cf d2 26 de 88 d3 9f 16 fb''',
+ 'e':'''01 00 01''',
+ 'd':'''53 33 9c fd b7 9f c8 46 6a 65 5c 73 16 ac a8 5c
+ 55 fd 8f 6d d8 98 fd af 11 95 17 ef 4f 52 e8 fd
+ 8e 25 8d f9 3f ee 18 0f a0 e4 ab 29 69 3c d8 3b
+ 15 2a 55 3d 4a c4 d1 81 2b 8b 9f a5 af 0e 7f 55
+ fe 73 04 df 41 57 09 26 f3 31 1f 15 c4 d6 5a 73
+ 2c 48 31 16 ee 3d 3d 2d 0a f3 54 9a d9 bf 7c bf
+ b7 8a d8 84 f8 4d 5b eb 04 72 4d c7 36 9b 31 de
+ f3 7d 0c f5 39 e9 cf cd d3 de 65 37 29 ea d5 d1 '''
+ }
+ ,
+ # Plaintext
+ '''66 28 19 4e 12 07 3d b0 3b a9 4c da 9e f9 53 23
+ 97 d5 0d ba 79 b9 87 00 4a fe fe 34''',
+ # Ciphertext
+ '''35 4f e6 7b 4a 12 6d 5d 35 fe 36 c7 77 79 1a 3f
+ 7b a1 3d ef 48 4e 2d 39 08 af f7 22 fa d4 68 fb
+ 21 69 6d e9 5d 0b e9 11 c2 d3 17 4f 8a fc c2 01
+ 03 5f 7b 6d 8e 69 40 2d e5 45 16 18 c2 1a 53 5f
+ a9 d7 bf c5 b8 dd 9f c2 43 f8 cf 92 7d b3 13 22
+ d6 e8 81 ea a9 1a 99 61 70 e6 57 a0 5a 26 64 26
+ d9 8c 88 00 3f 84 77 c1 22 70 94 a0 d9 fa 1e 8c
+ 40 24 30 9c e1 ec cc b5 21 00 35 d4 7a c7 2e 8a''',
+ # Random
+ '''18 b7 76 ea 21 06 9d 69 77 6a 33 e9 6b ad 48 e1
+ dd a0 a5 ef''',
+ SHA1
+ ),
+
+ #
+ # From in oaep-vect.txt to be found in Example 2.1
+ # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip
+ #
+ (
+ # Private key
+ {
+ 'n':'''01 94 7c 7f ce 90 42 5f 47 27 9e 70 85 1f 25 d5
+ e6 23 16 fe 8a 1d f1 93 71 e3 e6 28 e2 60 54 3e
+ 49 01 ef 60 81 f6 8c 0b 81 41 19 0d 2a e8 da ba
+ 7d 12 50 ec 6d b6 36 e9 44 ec 37 22 87 7c 7c 1d
+ 0a 67 f1 4b 16 94 c5 f0 37 94 51 a4 3e 49 a3 2d
+ de 83 67 0b 73 da 91 a1 c9 9b c2 3b 43 6a 60 05
+ 5c 61 0f 0b af 99 c1 a0 79 56 5b 95 a3 f1 52 66
+ 32 d1 d4 da 60 f2 0e da 25 e6 53 c4 f0 02 76 6f
+ 45''',
+ 'e':'''01 00 01''',
+ 'd':'''08 23 f2 0f ad b5 da 89 08 8a 9d 00 89 3e 21 fa
+ 4a 1b 11 fb c9 3c 64 a3 be 0b aa ea 97 fb 3b 93
+ c3 ff 71 37 04 c1 9c 96 3c 1d 10 7a ae 99 05 47
+ 39 f7 9e 02 e1 86 de 86 f8 7a 6d de fe a6 d8 cc
+ d1 d3 c8 1a 47 bf a7 25 5b e2 06 01 a4 a4 b2 f0
+ 8a 16 7b 5e 27 9d 71 5b 1b 45 5b dd 7e ab 24 59
+ 41 d9 76 8b 9a ce fb 3c cd a5 95 2d a3 ce e7 25
+ 25 b4 50 16 63 a8 ee 15 c9 e9 92 d9 24 62 fe 39'''
+ },
+ # Plaintext
+ '''8f f0 0c aa 60 5c 70 28 30 63 4d 9a 6c 3d 42 c6
+ 52 b5 8c f1 d9 2f ec 57 0b ee e7''',
+ # Ciphertext
+ '''01 81 af 89 22 b9 fc b4 d7 9d 92 eb e1 98 15 99
+ 2f c0 c1 43 9d 8b cd 49 13 98 a0 f4 ad 3a 32 9a
+ 5b d9 38 55 60 db 53 26 83 c8 b7 da 04 e4 b1 2a
+ ed 6a ac df 47 1c 34 c9 cd a8 91 ad dc c2 df 34
+ 56 65 3a a6 38 2e 9a e5 9b 54 45 52 57 eb 09 9d
+ 56 2b be 10 45 3f 2b 6d 13 c5 9c 02 e1 0f 1f 8a
+ bb 5d a0 d0 57 09 32 da cf 2d 09 01 db 72 9d 0f
+ ef cc 05 4e 70 96 8e a5 40 c8 1b 04 bc ae fe 72
+ 0e''',
+ # Random
+ '''8c 40 7b 5e c2 89 9e 50 99 c5 3e 8c e7 93 bf 94
+ e7 1b 17 82''',
+ SHA1
+ ),
+
+ #
+ # From in oaep-vect.txt to be found in Example 10.1
+ # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip
+ #
+ (
+ # Private key
+ {
+ 'n':'''ae 45 ed 56 01 ce c6 b8 cc 05 f8 03 93 5c 67 4d
+ db e0 d7 5c 4c 09 fd 79 51 fc 6b 0c ae c3 13 a8
+ df 39 97 0c 51 8b ff ba 5e d6 8f 3f 0d 7f 22 a4
+ 02 9d 41 3f 1a e0 7e 4e be 9e 41 77 ce 23 e7 f5
+ 40 4b 56 9e 4e e1 bd cf 3c 1f b0 3e f1 13 80 2d
+ 4f 85 5e b9 b5 13 4b 5a 7c 80 85 ad ca e6 fa 2f
+ a1 41 7e c3 76 3b e1 71 b0 c6 2b 76 0e de 23 c1
+ 2a d9 2b 98 08 84 c6 41 f5 a8 fa c2 6b da d4 a0
+ 33 81 a2 2f e1 b7 54 88 50 94 c8 25 06 d4 01 9a
+ 53 5a 28 6a fe b2 71 bb 9b a5 92 de 18 dc f6 00
+ c2 ae ea e5 6e 02 f7 cf 79 fc 14 cf 3b dc 7c d8
+ 4f eb bb f9 50 ca 90 30 4b 22 19 a7 aa 06 3a ef
+ a2 c3 c1 98 0e 56 0c d6 4a fe 77 95 85 b6 10 76
+ 57 b9 57 85 7e fd e6 01 09 88 ab 7d e4 17 fc 88
+ d8 f3 84 c4 e6 e7 2c 3f 94 3e 0c 31 c0 c4 a5 cc
+ 36 f8 79 d8 a3 ac 9d 7d 59 86 0e aa da 6b 83 bb''',
+ 'e':'''01 00 01''',
+ 'd':'''05 6b 04 21 6f e5 f3 54 ac 77 25 0a 4b 6b 0c 85
+ 25 a8 5c 59 b0 bd 80 c5 64 50 a2 2d 5f 43 8e 59
+ 6a 33 3a a8 75 e2 91 dd 43 f4 8c b8 8b 9d 5f c0
+ d4 99 f9 fc d1 c3 97 f9 af c0 70 cd 9e 39 8c 8d
+ 19 e6 1d b7 c7 41 0a 6b 26 75 df bf 5d 34 5b 80
+ 4d 20 1a dd 50 2d 5c e2 df cb 09 1c e9 99 7b be
+ be 57 30 6f 38 3e 4d 58 81 03 f0 36 f7 e8 5d 19
+ 34 d1 52 a3 23 e4 a8 db 45 1d 6f 4a 5b 1b 0f 10
+ 2c c1 50 e0 2f ee e2 b8 8d ea 4a d4 c1 ba cc b2
+ 4d 84 07 2d 14 e1 d2 4a 67 71 f7 40 8e e3 05 64
+ fb 86 d4 39 3a 34 bc f0 b7 88 50 1d 19 33 03 f1
+ 3a 22 84 b0 01 f0 f6 49 ea f7 93 28 d4 ac 5c 43
+ 0a b4 41 49 20 a9 46 0e d1 b7 bc 40 ec 65 3e 87
+ 6d 09 ab c5 09 ae 45 b5 25 19 01 16 a0 c2 61 01
+ 84 82 98 50 9c 1c 3b f3 a4 83 e7 27 40 54 e1 5e
+ 97 07 50 36 e9 89 f6 09 32 80 7b 52 57 75 1e 79'''
+ },
+ # Plaintext
+ '''8b ba 6b f8 2a 6c 0f 86 d5 f1 75 6e 97 95 68 70
+ b0 89 53 b0 6b 4e b2 05 bc 16 94 ee''',
+ # Ciphertext
+ '''53 ea 5d c0 8c d2 60 fb 3b 85 85 67 28 7f a9 15
+ 52 c3 0b 2f eb fb a2 13 f0 ae 87 70 2d 06 8d 19
+ ba b0 7f e5 74 52 3d fb 42 13 9d 68 c3 c5 af ee
+ e0 bf e4 cb 79 69 cb f3 82 b8 04 d6 e6 13 96 14
+ 4e 2d 0e 60 74 1f 89 93 c3 01 4b 58 b9 b1 95 7a
+ 8b ab cd 23 af 85 4f 4c 35 6f b1 66 2a a7 2b fc
+ c7 e5 86 55 9d c4 28 0d 16 0c 12 67 85 a7 23 eb
+ ee be ff 71 f1 15 94 44 0a ae f8 7d 10 79 3a 87
+ 74 a2 39 d4 a0 4c 87 fe 14 67 b9 da f8 52 08 ec
+ 6c 72 55 79 4a 96 cc 29 14 2f 9a 8b d4 18 e3 c1
+ fd 67 34 4b 0c d0 82 9d f3 b2 be c6 02 53 19 62
+ 93 c6 b3 4d 3f 75 d3 2f 21 3d d4 5c 62 73 d5 05
+ ad f4 cc ed 10 57 cb 75 8f c2 6a ee fa 44 12 55
+ ed 4e 64 c1 99 ee 07 5e 7f 16 64 61 82 fd b4 64
+ 73 9b 68 ab 5d af f0 e6 3e 95 52 01 68 24 f0 54
+ bf 4d 3c 8c 90 a9 7b b6 b6 55 32 84 eb 42 9f cc''',
+ # Random
+ '''47 e1 ab 71 19 fe e5 6c 95 ee 5e aa d8 6f 40 d0
+ aa 63 bd 33''',
+ SHA1
+ ),
+ )
+
+ def testEncrypt1(self):
+ # Verify encryption using all test vectors
+ for test in self._testData:
+ # Build the key
+ comps = [int(rws(test[0][x]), 16) for x in ('n', 'e')]
+ key = RSA.construct(comps)
+
+ # RNG that takes its random numbers from a pool given
+ # at initialization
+ class randGen:
+
+ def __init__(self, data):
+ self.data = data
+ self.idx = 0
+
+ def __call__(self, N):
+ r = self.data[self.idx:N]
+ self.idx += N
+ return r
+
+ # The real test
+ cipher = PKCS.new(key, test[4], randfunc=randGen(t2b(test[3])))
+ ct = cipher.encrypt(t2b(test[1]))
+ self.assertEqual(ct, t2b(test[2]))
+
+ def testEncrypt2(self):
+ # Verify that encryption fails if plaintext is too long
+ pt = '\x00'*(128-2*20-2+1)
+ cipher = PKCS.new(self.key1024)
+ self.assertRaises(ValueError, cipher.encrypt, pt)
+
+ def testDecrypt1(self):
+ # Verify decryption using all test vectors
+ for test in self._testData:
+ # Build the key
+ comps = [int(rws(test[0][x]),16) for x in ('n', 'e', 'd')]
+ key = RSA.construct(comps)
+ # The real test
+ cipher = PKCS.new(key, test[4])
+ pt = cipher.decrypt(t2b(test[2]))
+ self.assertEqual(pt, t2b(test[1]))
+
+ def testDecrypt2(self):
+ # Simplest possible negative tests
+ for ct_size in (127, 128, 129):
+ cipher = PKCS.new(self.key1024)
+ self.assertRaises(ValueError, cipher.decrypt, bchr(0x00)*ct_size)
+
+ def testEncryptDecrypt1(self):
+ # Encrypt/Decrypt messages of length [0..128-2*20-2]
+ for pt_len in range(0, 128-2*20-2):
+ pt = self.rng(pt_len)
+ cipher = PKCS.new(self.key1024)
+ ct = cipher.encrypt(pt)
+ pt2 = cipher.decrypt(ct)
+ self.assertEqual(pt, pt2)
+
+ def testEncryptDecrypt2(self):
+ # Helper function to monitor what's requested from RNG
+ global asked
+
+ def localRng(N):
+ global asked
+ asked += N
+ return self.rng(N)
+
+ # Verify that OAEP is friendly to all hashes
+ for hashmod in (MD2, MD5, SHA1, SHA256, RIPEMD160):
+ # Verify that encrypt() asks for as many random bytes
+ # as the hash output size
+ asked = 0
+ pt = self.rng(40)
+ cipher = PKCS.new(self.key1024, hashmod, randfunc=localRng)
+ ct = cipher.encrypt(pt)
+ self.assertEqual(cipher.decrypt(ct), pt)
+ self.assertEqual(asked, hashmod.digest_size)
+
+ def testEncryptDecrypt3(self):
+ # Verify that OAEP supports labels
+ pt = self.rng(35)
+ xlabel = self.rng(22)
+ cipher = PKCS.new(self.key1024, label=xlabel)
+ ct = cipher.encrypt(pt)
+ self.assertEqual(cipher.decrypt(ct), pt)
+
+ def testEncryptDecrypt4(self):
+ # Verify that encrypt() uses the custom MGF
+ global mgfcalls
+ # Helper function to monitor what's requested from MGF
+
+ def newMGF(seed, maskLen):
+ global mgfcalls
+ mgfcalls += 1
+ return b'\x00' * maskLen
+
+ mgfcalls = 0
+ pt = self.rng(32)
+ cipher = PKCS.new(self.key1024, mgfunc=newMGF)
+ ct = cipher.encrypt(pt)
+ self.assertEqual(mgfcalls, 2)
+ self.assertEqual(cipher.decrypt(ct), pt)
+
+ def testByteArray(self):
+ pt = b("XER")
+ cipher = PKCS.new(self.key1024)
+ ct = cipher.encrypt(bytearray(pt))
+ pt2 = cipher.decrypt(bytearray(ct))
+ self.assertEqual(pt, pt2)
+
+ def testMemoryview(self):
+ pt = b("XER")
+ cipher = PKCS.new(self.key1024)
+ ct = cipher.encrypt(memoryview(bytearray(pt)))
+ pt2 = cipher.decrypt(memoryview(bytearray(ct)))
+ self.assertEqual(pt, pt2)
+
+
+class TestVectorsWycheproof(unittest.TestCase):
+
+ def __init__(self, wycheproof_warnings, skip_slow_tests):
+ unittest.TestCase.__init__(self)
+ self._wycheproof_warnings = wycheproof_warnings
+ self._skip_slow_tests = skip_slow_tests
+ self._id = "None"
+
+ def load_tests(self, filename):
+
+ def filter_rsa(group):
+ return RSA.import_key(group['privateKeyPem'])
+
+ def filter_sha(group):
+ if group['sha'] == "SHA-1":
+ return SHA1
+ elif group['sha'] == "SHA-224":
+ return SHA224
+ elif group['sha'] == "SHA-256":
+ return SHA256
+ elif group['sha'] == "SHA-384":
+ return SHA384
+ elif group['sha'] == "SHA-512":
+ return SHA512
+ else:
+ raise ValueError("Unknown sha " + group['sha'])
+
+ def filter_mgf(group):
+ if group['mgfSha'] == "SHA-1":
+ return lambda x, y: MGF1(x, y, SHA1)
+ elif group['mgfSha'] == "SHA-224":
+ return lambda x, y: MGF1(x, y, SHA224)
+ elif group['mgfSha'] == "SHA-256":
+ return lambda x, y: MGF1(x, y, SHA256)
+ elif group['mgfSha'] == "SHA-384":
+ return lambda x, y: MGF1(x, y, SHA384)
+ elif group['mgfSha'] == "SHA-512":
+ return lambda x, y: MGF1(x, y, SHA512)
+ else:
+ raise ValueError("Unknown mgf/sha " + group['mgfSha'])
+
+ def filter_algo(group):
+ return "%s with MGF1/%s" % (group['sha'], group['mgfSha'])
+
+ result = load_test_vectors_wycheproof(("Cipher", "wycheproof"),
+ filename,
+ "Wycheproof PKCS#1 OAEP (%s)" % filename,
+ group_tag={'rsa_key': filter_rsa,
+ 'hash_mod': filter_sha,
+ 'mgf': filter_mgf,
+ 'algo': filter_algo}
+ )
+ return result
+
+ def setUp(self):
+ self.tv = []
+ self.tv.extend(self.load_tests("rsa_oaep_2048_sha1_mgf1sha1_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_2048_sha224_mgf1sha1_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_2048_sha224_mgf1sha224_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_2048_sha256_mgf1sha1_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_2048_sha256_mgf1sha256_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_2048_sha384_mgf1sha1_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_2048_sha384_mgf1sha384_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_2048_sha512_mgf1sha1_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_2048_sha512_mgf1sha512_test.json"))
+ if not self._skip_slow_tests:
+ self.tv.extend(self.load_tests("rsa_oaep_3072_sha256_mgf1sha1_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_3072_sha256_mgf1sha256_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_3072_sha512_mgf1sha1_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_3072_sha512_mgf1sha512_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_4096_sha256_mgf1sha1_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_4096_sha256_mgf1sha256_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha1_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha512_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha512_test.json"))
+ self.tv.extend(self.load_tests("rsa_oaep_misc_test.json"))
+
+ def shortDescription(self):
+ return self._id
+
+ def warn(self, tv):
+ if tv.warning and self._wycheproof_warnings:
+ import warnings
+ warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment))
+
+ def test_decrypt(self, tv):
+ self._id = "Wycheproof Decrypt %s Test #%s" % (tv.algo, tv.id)
+
+ cipher = PKCS.new(tv.rsa_key, hashAlgo=tv.hash_mod, mgfunc=tv.mgf, label=tv.label)
+ try:
+ pt = cipher.decrypt(tv.ct)
+ except ValueError:
+ assert not tv.valid
+ else:
+ assert tv.valid
+ self.assertEqual(pt, tv.msg)
+ self.warn(tv)
+
+ def runTest(self):
+
+ for tv in self.tv:
+ self.test_decrypt(tv)
+
+
+def get_tests(config={}):
+ skip_slow_tests = not config.get('slow_tests')
+ wycheproof_warnings = config.get('wycheproof_warnings')
+
+ tests = []
+ tests += list_test_cases(PKCS1_OAEP_Tests)
+ tests += [TestVectorsWycheproof(wycheproof_warnings, skip_slow_tests)]
+ return tests
+
+
+if __name__ == '__main__':
+ def suite():
+ unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
+
+# vim:set ts=4 sw=4 sts=4 expandtab: