扫码登录,获取cookies
This commit is contained in:
@@ -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:
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
510
backend/venv/Lib/site-packages/Crypto/SelfTest/Cipher/common.py
Normal file
510
backend/venv/Lib/site-packages/Crypto/SelfTest/Cipher/common.py
Normal file
@@ -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:
|
||||
1351
backend/venv/Lib/site-packages/Crypto/SelfTest/Cipher/test_AES.py
Normal file
1351
backend/venv/Lib/site-packages/Crypto/SelfTest/Cipher/test_AES.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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:
|
||||
@@ -0,0 +1,471 @@
|
||||
# -*- 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"""
|
||||
|
||||
import unittest
|
||||
|
||||
from Crypto.Util.py3compat import b
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
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"),
|
||||
# shortest key - generated with arc4 package
|
||||
('7468697320697320616e206578616d706c65',
|
||||
'7260677d38495a09585d69321e17eaf3cdd0',
|
||||
'01'),
|
||||
]
|
||||
|
||||
|
||||
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, b'')
|
||||
self.assertRaises(ValueError, ARC4.new, b'\x00' * 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__':
|
||||
def suite():
|
||||
return unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -0,0 +1,776 @@
|
||||
# ===================================================================
|
||||
#
|
||||
# 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.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_nonce(self):
|
||||
# Nonce can only be 24 bytes
|
||||
cipher = ChaCha20_Poly1305.new(key=b'Y' * 32,
|
||||
nonce=b'H' * 24)
|
||||
self.assertEqual(len(cipher.nonce), 24)
|
||||
self.assertEqual(cipher.nonce, b'H' * 24)
|
||||
|
||||
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')
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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=2-1)
|
||||
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(2, 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')
|
||||
@@ -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')
|
||||
@@ -0,0 +1,845 @@
|
||||
# ===================================================================
|
||||
#
|
||||
# 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.Util.py3compat import b, tobytes, bchr
|
||||
from Crypto.Util.number import long_to_bytes
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
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)
|
||||
|
||||
# Verify path INIT->UPDATE->ENCRYPT->ENCRYPT_AND_DIGEST
|
||||
cipher = AES.new(self.key_128, AES.MODE_OCB,
|
||||
nonce=self.nonce_96)
|
||||
cipher.update(self.data)
|
||||
ct1 = cipher.encrypt(self.data[:2])
|
||||
ct2, mac = cipher.encrypt_and_digest(self.data[2:])
|
||||
|
||||
# Verify path INIT->UPDATE->DECRYPT->DECRYPT_AND_VERIFY
|
||||
cipher = AES.new(self.key_128, AES.MODE_OCB,
|
||||
nonce=self.nonce_96)
|
||||
cipher.update(self.data)
|
||||
cipher.decrypt(ct1)
|
||||
cipher.decrypt_and_verify(ct2, 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")):
|
||||
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)
|
||||
|
||||
|
||||
def algo_rfc7253(keylen, taglen, noncelen):
|
||||
"""Implement the algorithm at page 18 of RFC 7253"""
|
||||
|
||||
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, noncelen // 8)
|
||||
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, noncelen // 8)
|
||||
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, noncelen // 8)
|
||||
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, noncelen // 8)
|
||||
cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
|
||||
cipher.update(C)
|
||||
return cipher.encrypt() + cipher.digest()
|
||||
|
||||
|
||||
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:
|
||||
result2 = algo_rfc7253(keylen, taglen, 96)
|
||||
self.assertEqual(unhexlify(b(result)), result2)
|
||||
|
||||
|
||||
class OcbDkgTest(unittest.TestCase):
|
||||
"""Test vectors from https://gitlab.com/dkg/ocb-test-vectors"""
|
||||
|
||||
def test_1_2(self):
|
||||
tvs = []
|
||||
for fi in (1, 2):
|
||||
for nb in (104, 112, 120):
|
||||
tv_file = load_test_vectors(("Cipher", "AES"),
|
||||
"test-vector-%d-nonce%d.txt" % (fi, nb),
|
||||
"DKG tests, %d, %d bits" % (fi, nb),
|
||||
{})
|
||||
if tv_file is None:
|
||||
break
|
||||
key = tv_file[0].k
|
||||
for tv in tv_file[1:]:
|
||||
tv.k = key
|
||||
tvs.append(tv)
|
||||
|
||||
for tv in tvs:
|
||||
k, n, a, p, c = tv.k, tv.n, tv.a, tv.p, tv.c
|
||||
mac_len = len(c) - len(p)
|
||||
cipher = AES.new(k, AES.MODE_OCB, nonce=n, mac_len=mac_len)
|
||||
cipher.update(a)
|
||||
c_out, tag_out = cipher.encrypt_and_digest(p)
|
||||
self.assertEqual(c, c_out + tag_out)
|
||||
|
||||
def test_3(self):
|
||||
|
||||
def check(keylen, taglen, noncelen, exp):
|
||||
result = algo_rfc7253(keylen, taglen, noncelen)
|
||||
self.assertEqual(result, unhexlify(exp))
|
||||
|
||||
# test-vector-3-nonce104.txt
|
||||
check(128, 128, 104, "C47F5F0341E15326D4D1C46F47F05062")
|
||||
check(192, 128, 104, "95B9167A38EB80495DFC561A8486E109")
|
||||
check(256, 128, 104, "AFE1CDDB97028FD92F8FB3C8CFBA7D83")
|
||||
check(128, 96, 104, "F471B4983BA80946DF217A54")
|
||||
check(192, 96, 104, "5AE828BC51C24D85FA5CC7B2")
|
||||
check(256, 96, 104, "8C8335982E2B734616CAD14C")
|
||||
check(128, 64, 104, "B553F74B85FD1E5B")
|
||||
check(192, 64, 104, "3B49D20E513531F9")
|
||||
check(256, 64, 104, "ED6DA5B1216BF8BB")
|
||||
|
||||
# test-vector-3-nonce112.txt
|
||||
check(128, 128, 112, "CA8AFCA031BAC3F480A583BD6C50A547")
|
||||
check(192, 128, 112, "D170C1DF356308079DA9A3F619147148")
|
||||
check(256, 128, 112, "57F94381F2F9231EFB04AECD323757C3")
|
||||
check(128, 96, 112, "3A618B2531ED39F260C750DC")
|
||||
check(192, 96, 112, "9071EB89FEDBADDA88FD286E")
|
||||
check(256, 96, 112, "FDF0EFB97F21A39AC4BAB5AC")
|
||||
check(128, 64, 112, "FAB2FF3A8DD82A13")
|
||||
check(192, 64, 112, "AC01D912BD0737D3")
|
||||
check(256, 64, 112, "9D1FD0B500EA4ECF")
|
||||
|
||||
# test-vector-3-nonce120.txt
|
||||
check(128, 128, 120, "9E043A7140A25FB91F43BCC9DD7E0F46")
|
||||
check(192, 128, 120, "680000E53908323A7F396B955B8EC641")
|
||||
check(256, 128, 120, "8304B97FAACDA56E676602E1878A7E6F")
|
||||
check(128, 96, 120, "81F978AC9867E825D339847D")
|
||||
check(192, 96, 120, "EFCF2D60B24926ADA48CF5B1")
|
||||
check(256, 96, 120, "84961DC56E917B165E58C174")
|
||||
check(128, 64, 120, "227AEE6C9D905A61")
|
||||
check(192, 64, 120, "541DE691B9E1A2F9")
|
||||
check(256, 64, 120, "B0E761381C7129FC")
|
||||
|
||||
def test_2_bugfix(self):
|
||||
nonce = unhexlify("EEDDCCBBAA9988776655443322110D")
|
||||
key = unhexlify("0F0E0D0C0B0A09080706050403020100")
|
||||
A = unhexlify("000102030405060708090A0B0C0D0E0F1011121314151617"
|
||||
"18191A1B1C1D1E1F2021222324252627")
|
||||
P = unhexlify("000102030405060708090A0B0C0D0E0F1011121314151617"
|
||||
"18191A1B1C1D1E1F2021222324252627")
|
||||
C = unhexlify("07E903BFC49552411ABC865F5ECE60F6FAD1F5A9F14D3070"
|
||||
"FA2F1308A563207FFE14C1EEA44B22059C7484319D8A2C53"
|
||||
"C236A7B3")
|
||||
mac_len = len(C) - len(P)
|
||||
|
||||
# Prior to version 3.17, a nonce of maximum length (15 bytes)
|
||||
# was actually used as a 14 byte nonce. The last byte was erroneously
|
||||
# ignored.
|
||||
buggy_result = unhexlify("BA015C4E5AE54D76C890AE81BD40DC57"
|
||||
"03EDC30E8AC2A58BC5D8FA4D61C5BAE6"
|
||||
"C39BEAC435B2FD56A2A5085C1B135D77"
|
||||
"0C8264B7")
|
||||
cipher = AES.new(key, AES.MODE_OCB, nonce=nonce[:-1], mac_len=mac_len)
|
||||
cipher.update(A)
|
||||
C_out2, tag_out2 = cipher.encrypt_and_digest(P)
|
||||
self.assertEqual(buggy_result, C_out2 + tag_out2)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
tests += list_test_cases(OcbTests)
|
||||
tests += list_test_cases(OcbFSMTests)
|
||||
tests += list_test_cases(OcbRfc7253Test)
|
||||
tests += list_test_cases(OcbDkgTest)
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def suite():
|
||||
return unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -0,0 +1,61 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/__init__.py: Self-test for hash 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 hash modules"""
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
from Crypto.SelfTest.Hash import test_HMAC; tests += test_HMAC.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_CMAC; tests += test_CMAC.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_MD2; tests += test_MD2.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_MD4; tests += test_MD4.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_MD5; tests += test_MD5.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_RIPEMD160; tests += test_RIPEMD160.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_SHA1; tests += test_SHA1.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_SHA224; tests += test_SHA224.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_SHA256; tests += test_SHA256.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_SHA384; tests += test_SHA384.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_SHA512; tests += test_SHA512.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_SHA3_224; tests += test_SHA3_224.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_SHA3_256; tests += test_SHA3_256.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_SHA3_384; tests += test_SHA3_384.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_SHA3_512; tests += test_SHA3_512.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_keccak; tests += test_keccak.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_SHAKE; tests += test_SHAKE.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_BLAKE2; tests += test_BLAKE2.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_Poly1305; tests += test_Poly1305.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_cSHAKE; tests += test_cSHAKE.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_KMAC; tests += test_KMAC.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_TupleHash; tests += test_TupleHash.get_tests(config=config)
|
||||
from Crypto.SelfTest.Hash import test_KangarooTwelve; tests += test_KangarooTwelve.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:
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
290
backend/venv/Lib/site-packages/Crypto/SelfTest/Hash/common.py
Normal file
290
backend/venv/Lib/site-packages/Crypto/SelfTest/Hash/common.py
Normal file
@@ -0,0 +1,290 @@
|
||||
# -*- 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 re
|
||||
import sys
|
||||
import unittest
|
||||
import binascii
|
||||
import Crypto.Hash
|
||||
from binascii import hexlify, unhexlify
|
||||
from Crypto.Util.py3compat import b, tobytes
|
||||
from Crypto.Util.strxor import strxor_c
|
||||
|
||||
def t2b(hex_string):
|
||||
shorter = re.sub(br'\s+', b'', tobytes(hex_string))
|
||||
return unhexlify(shorter)
|
||||
|
||||
|
||||
class HashDigestSizeSelfTest(unittest.TestCase):
|
||||
|
||||
def __init__(self, hashmod, description, expected, extra_params):
|
||||
unittest.TestCase.__init__(self)
|
||||
self.hashmod = hashmod
|
||||
self.expected = expected
|
||||
self.description = description
|
||||
self.extra_params = extra_params
|
||||
|
||||
def shortDescription(self):
|
||||
return self.description
|
||||
|
||||
def runTest(self):
|
||||
if "truncate" not in self.extra_params:
|
||||
self.assertTrue(hasattr(self.hashmod, "digest_size"))
|
||||
self.assertEqual(self.hashmod.digest_size, self.expected)
|
||||
h = self.hashmod.new(**self.extra_params)
|
||||
self.assertTrue(hasattr(h, "digest_size"))
|
||||
self.assertEqual(h.digest_size, self.expected)
|
||||
|
||||
|
||||
class HashSelfTest(unittest.TestCase):
|
||||
|
||||
def __init__(self, hashmod, description, expected, input, extra_params):
|
||||
unittest.TestCase.__init__(self)
|
||||
self.hashmod = hashmod
|
||||
self.expected = expected.lower()
|
||||
self.input = input
|
||||
self.description = description
|
||||
self.extra_params = extra_params
|
||||
|
||||
def shortDescription(self):
|
||||
return self.description
|
||||
|
||||
def runTest(self):
|
||||
h = self.hashmod.new(**self.extra_params)
|
||||
h.update(self.input)
|
||||
|
||||
out1 = binascii.b2a_hex(h.digest())
|
||||
out2 = h.hexdigest()
|
||||
|
||||
h = self.hashmod.new(self.input, **self.extra_params)
|
||||
|
||||
out3 = h.hexdigest()
|
||||
out4 = binascii.b2a_hex(h.digest())
|
||||
|
||||
# PY3K: hexdigest() should return str(), and digest() bytes
|
||||
self.assertEqual(self.expected, out1) # h = .new(); h.update(data); h.digest()
|
||||
if sys.version_info[0] == 2:
|
||||
self.assertEqual(self.expected, out2) # h = .new(); h.update(data); h.hexdigest()
|
||||
self.assertEqual(self.expected, out3) # h = .new(data); h.hexdigest()
|
||||
else:
|
||||
self.assertEqual(self.expected.decode(), out2) # h = .new(); h.update(data); h.hexdigest()
|
||||
self.assertEqual(self.expected.decode(), out3) # h = .new(data); h.hexdigest()
|
||||
self.assertEqual(self.expected, out4) # h = .new(data); h.digest()
|
||||
|
||||
# Verify that the .new() method produces a fresh hash object, except
|
||||
# for MD5 and SHA1, which are hashlib objects. (But test any .new()
|
||||
# method that does exist.)
|
||||
if self.hashmod.__name__ not in ('Crypto.Hash.MD5', 'Crypto.Hash.SHA1') or hasattr(h, 'new'):
|
||||
h2 = h.new()
|
||||
h2.update(self.input)
|
||||
out5 = binascii.b2a_hex(h2.digest())
|
||||
self.assertEqual(self.expected, out5)
|
||||
|
||||
|
||||
class HashTestOID(unittest.TestCase):
|
||||
def __init__(self, hashmod, oid, extra_params):
|
||||
unittest.TestCase.__init__(self)
|
||||
self.hashmod = hashmod
|
||||
self.oid = oid
|
||||
self.extra_params = extra_params
|
||||
|
||||
def runTest(self):
|
||||
h = self.hashmod.new(**self.extra_params)
|
||||
self.assertEqual(h.oid, self.oid)
|
||||
|
||||
|
||||
class ByteArrayTest(unittest.TestCase):
|
||||
|
||||
def __init__(self, module, extra_params):
|
||||
unittest.TestCase.__init__(self)
|
||||
self.module = module
|
||||
self.extra_params = extra_params
|
||||
|
||||
def runTest(self):
|
||||
data = b("\x00\x01\x02")
|
||||
|
||||
# Data can be a bytearray (during initialization)
|
||||
ba = bytearray(data)
|
||||
|
||||
h1 = self.module.new(data, **self.extra_params)
|
||||
h2 = self.module.new(ba, **self.extra_params)
|
||||
ba[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
# Data can be a bytearray (during operation)
|
||||
ba = bytearray(data)
|
||||
|
||||
h1 = self.module.new(**self.extra_params)
|
||||
h2 = self.module.new(**self.extra_params)
|
||||
|
||||
h1.update(data)
|
||||
h2.update(ba)
|
||||
|
||||
ba[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
|
||||
class MemoryViewTest(unittest.TestCase):
|
||||
|
||||
def __init__(self, module, extra_params):
|
||||
unittest.TestCase.__init__(self)
|
||||
self.module = module
|
||||
self.extra_params = extra_params
|
||||
|
||||
def runTest(self):
|
||||
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
def get_mv_ro(data):
|
||||
return memoryview(data)
|
||||
|
||||
def get_mv_rw(data):
|
||||
return memoryview(bytearray(data))
|
||||
|
||||
for get_mv in get_mv_ro, get_mv_rw:
|
||||
|
||||
# Data can be a memoryview (during initialization)
|
||||
mv = get_mv(data)
|
||||
|
||||
h1 = self.module.new(data, **self.extra_params)
|
||||
h2 = self.module.new(mv, **self.extra_params)
|
||||
if not mv.readonly:
|
||||
mv[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
# Data can be a memoryview (during operation)
|
||||
mv = get_mv(data)
|
||||
|
||||
h1 = self.module.new(**self.extra_params)
|
||||
h2 = self.module.new(**self.extra_params)
|
||||
h1.update(data)
|
||||
h2.update(mv)
|
||||
if not mv.readonly:
|
||||
mv[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
|
||||
class MACSelfTest(unittest.TestCase):
|
||||
|
||||
def __init__(self, module, description, result, data, key, params):
|
||||
unittest.TestCase.__init__(self)
|
||||
self.module = module
|
||||
self.result = t2b(result)
|
||||
self.data = t2b(data)
|
||||
self.key = t2b(key)
|
||||
self.params = params
|
||||
self.description = description
|
||||
|
||||
def shortDescription(self):
|
||||
return self.description
|
||||
|
||||
def runTest(self):
|
||||
|
||||
result_hex = hexlify(self.result)
|
||||
|
||||
# Verify result
|
||||
h = self.module.new(self.key, **self.params)
|
||||
h.update(self.data)
|
||||
self.assertEqual(self.result, h.digest())
|
||||
self.assertEqual(hexlify(self.result).decode('ascii'), h.hexdigest())
|
||||
|
||||
# Verify that correct MAC does not raise any exception
|
||||
h.verify(self.result)
|
||||
h.hexverify(result_hex)
|
||||
|
||||
# Verify that incorrect MAC does raise ValueError exception
|
||||
wrong_mac = strxor_c(self.result, 255)
|
||||
self.assertRaises(ValueError, h.verify, wrong_mac)
|
||||
self.assertRaises(ValueError, h.hexverify, "4556")
|
||||
|
||||
# Verify again, with data passed to new()
|
||||
h = self.module.new(self.key, self.data, **self.params)
|
||||
self.assertEqual(self.result, h.digest())
|
||||
self.assertEqual(hexlify(self.result).decode('ascii'), h.hexdigest())
|
||||
|
||||
# Test .copy()
|
||||
try:
|
||||
h = self.module.new(self.key, self.data, **self.params)
|
||||
h2 = h.copy()
|
||||
h3 = h.copy()
|
||||
|
||||
# Verify that changing the copy does not change the original
|
||||
h2.update(b"bla")
|
||||
self.assertEqual(h3.digest(), self.result)
|
||||
|
||||
# Verify that both can reach the same state
|
||||
h.update(b"bla")
|
||||
self.assertEqual(h.digest(), h2.digest())
|
||||
except NotImplementedError:
|
||||
pass
|
||||
|
||||
# PY3K: Check that hexdigest() returns str and digest() returns bytes
|
||||
self.assertTrue(isinstance(h.digest(), type(b"")))
|
||||
self.assertTrue(isinstance(h.hexdigest(), type("")))
|
||||
|
||||
# PY3K: Check that .hexverify() accepts bytes or str
|
||||
h.hexverify(h.hexdigest())
|
||||
h.hexverify(h.hexdigest().encode('ascii'))
|
||||
|
||||
|
||||
def make_hash_tests(module, module_name, test_data, digest_size, oid=None,
|
||||
extra_params={}):
|
||||
tests = []
|
||||
for i in range(len(test_data)):
|
||||
row = test_data[i]
|
||||
(expected, input) = map(tobytes,row[0:2])
|
||||
if len(row) < 3:
|
||||
description = repr(input)
|
||||
else:
|
||||
description = row[2]
|
||||
name = "%s #%d: %s" % (module_name, i+1, description)
|
||||
tests.append(HashSelfTest(module, name, expected, input, extra_params))
|
||||
|
||||
name = "%s #%d: digest_size" % (module_name, len(test_data) + 1)
|
||||
tests.append(HashDigestSizeSelfTest(module, name, digest_size, extra_params))
|
||||
|
||||
if oid is not None:
|
||||
tests.append(HashTestOID(module, oid, extra_params))
|
||||
|
||||
tests.append(ByteArrayTest(module, extra_params))
|
||||
|
||||
tests.append(MemoryViewTest(module, extra_params))
|
||||
|
||||
return tests
|
||||
|
||||
|
||||
def make_mac_tests(module, module_name, test_data):
|
||||
tests = []
|
||||
for i, row in enumerate(test_data):
|
||||
if len(row) == 4:
|
||||
(key, data, results, description, params) = list(row) + [ {} ]
|
||||
else:
|
||||
(key, data, results, description, params) = row
|
||||
name = "%s #%d: %s" % (module_name, i+1, description)
|
||||
tests.append(MACSelfTest(module, name, results, data, key, params))
|
||||
return tests
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||
@@ -0,0 +1,482 @@
|
||||
# ===================================================================
|
||||
#
|
||||
# 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
|
||||
import warnings
|
||||
from binascii import unhexlify, hexlify
|
||||
|
||||
from Crypto.Util.py3compat import tobytes
|
||||
from Crypto.Util.strxor import strxor_c
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
|
||||
from Crypto.Hash import BLAKE2b, BLAKE2s
|
||||
|
||||
|
||||
class Blake2Test(unittest.TestCase):
|
||||
|
||||
def test_new_positive(self):
|
||||
|
||||
h = self.BLAKE2.new(digest_bits=self.max_bits)
|
||||
for new_func in self.BLAKE2.new, h.new:
|
||||
|
||||
for dbits in range(8, self.max_bits + 1, 8):
|
||||
hobj = new_func(digest_bits=dbits)
|
||||
self.assertEqual(hobj.digest_size, dbits // 8)
|
||||
|
||||
for dbytes in range(1, self.max_bytes + 1):
|
||||
hobj = new_func(digest_bytes=dbytes)
|
||||
self.assertEqual(hobj.digest_size, dbytes)
|
||||
|
||||
digest1 = new_func(data=b"\x90", digest_bytes=self.max_bytes).digest()
|
||||
digest2 = new_func(digest_bytes=self.max_bytes).update(b"\x90").digest()
|
||||
self.assertEqual(digest1, digest2)
|
||||
|
||||
new_func(data=b"A", key=b"5", digest_bytes=self.max_bytes)
|
||||
|
||||
hobj = h.new()
|
||||
self.assertEqual(hobj.digest_size, self.max_bytes)
|
||||
|
||||
def test_new_negative(self):
|
||||
|
||||
h = self.BLAKE2.new(digest_bits=self.max_bits)
|
||||
for new_func in self.BLAKE2.new, h.new:
|
||||
self.assertRaises(TypeError, new_func,
|
||||
digest_bytes=self.max_bytes,
|
||||
digest_bits=self.max_bits)
|
||||
self.assertRaises(ValueError, new_func, digest_bytes=0)
|
||||
self.assertRaises(ValueError, new_func,
|
||||
digest_bytes=self.max_bytes + 1)
|
||||
self.assertRaises(ValueError, new_func, digest_bits=7)
|
||||
self.assertRaises(ValueError, new_func, digest_bits=15)
|
||||
self.assertRaises(ValueError, new_func,
|
||||
digest_bits=self.max_bits + 1)
|
||||
self.assertRaises(TypeError, new_func,
|
||||
digest_bytes=self.max_bytes,
|
||||
key=u"string")
|
||||
self.assertRaises(TypeError, new_func,
|
||||
digest_bytes=self.max_bytes,
|
||||
data=u"string")
|
||||
|
||||
def test_default_digest_size(self):
|
||||
digest = self.BLAKE2.new(data=b'abc').digest()
|
||||
self.assertEqual(len(digest), self.max_bytes)
|
||||
|
||||
def test_update(self):
|
||||
pieces = [b"\x0A" * 200, b"\x14" * 300]
|
||||
h = self.BLAKE2.new(digest_bytes=self.max_bytes)
|
||||
h.update(pieces[0]).update(pieces[1])
|
||||
digest = h.digest()
|
||||
h = self.BLAKE2.new(digest_bytes=self.max_bytes)
|
||||
h.update(pieces[0] + pieces[1])
|
||||
self.assertEqual(h.digest(), digest)
|
||||
|
||||
def test_update_negative(self):
|
||||
h = self.BLAKE2.new(digest_bytes=self.max_bytes)
|
||||
self.assertRaises(TypeError, h.update, u"string")
|
||||
|
||||
def test_digest(self):
|
||||
h = self.BLAKE2.new(digest_bytes=self.max_bytes)
|
||||
digest = h.digest()
|
||||
|
||||
# hexdigest does not change the state
|
||||
self.assertEqual(h.digest(), digest)
|
||||
# digest returns a byte string
|
||||
self.assertTrue(isinstance(digest, type(b"digest")))
|
||||
|
||||
def test_update_after_digest(self):
|
||||
msg = b"rrrrttt"
|
||||
|
||||
# Normally, update() cannot be done after digest()
|
||||
h = self.BLAKE2.new(digest_bits=256, data=msg[:4])
|
||||
dig1 = h.digest()
|
||||
self.assertRaises(TypeError, h.update, msg[4:])
|
||||
dig2 = self.BLAKE2.new(digest_bits=256, data=msg).digest()
|
||||
|
||||
# With the proper flag, it is allowed
|
||||
h = self.BLAKE2.new(digest_bits=256, data=msg[:4], update_after_digest=True)
|
||||
self.assertEqual(h.digest(), dig1)
|
||||
# ... and the subsequent digest applies to the entire message
|
||||
# up to that point
|
||||
h.update(msg[4:])
|
||||
self.assertEqual(h.digest(), dig2)
|
||||
|
||||
def test_hex_digest(self):
|
||||
mac = self.BLAKE2.new(digest_bits=self.max_bits)
|
||||
digest = mac.digest()
|
||||
hexdigest = mac.hexdigest()
|
||||
|
||||
# hexdigest is equivalent to digest
|
||||
self.assertEqual(hexlify(digest), tobytes(hexdigest))
|
||||
# hexdigest does not change the state
|
||||
self.assertEqual(mac.hexdigest(), hexdigest)
|
||||
# hexdigest returns a string
|
||||
self.assertTrue(isinstance(hexdigest, type("digest")))
|
||||
|
||||
def test_verify(self):
|
||||
h = self.BLAKE2.new(digest_bytes=self.max_bytes, key=b"4")
|
||||
mac = h.digest()
|
||||
h.verify(mac)
|
||||
wrong_mac = strxor_c(mac, 255)
|
||||
self.assertRaises(ValueError, h.verify, wrong_mac)
|
||||
|
||||
def test_hexverify(self):
|
||||
h = self.BLAKE2.new(digest_bytes=self.max_bytes, key=b"4")
|
||||
mac = h.hexdigest()
|
||||
h.hexverify(mac)
|
||||
self.assertRaises(ValueError, h.hexverify, "4556")
|
||||
|
||||
def test_oid(self):
|
||||
|
||||
prefix = "1.3.6.1.4.1.1722.12.2." + self.oid_variant + "."
|
||||
|
||||
for digest_bits in self.digest_bits_oid:
|
||||
h = self.BLAKE2.new(digest_bits=digest_bits)
|
||||
self.assertEqual(h.oid, prefix + str(digest_bits // 8))
|
||||
|
||||
h = self.BLAKE2.new(digest_bits=digest_bits, key=b"secret")
|
||||
self.assertRaises(AttributeError, lambda: h.oid)
|
||||
|
||||
for digest_bits in (8, self.max_bits):
|
||||
if digest_bits in self.digest_bits_oid:
|
||||
continue
|
||||
self.assertRaises(AttributeError, lambda: h.oid)
|
||||
|
||||
def test_bytearray(self):
|
||||
|
||||
key = b'0' * 16
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
# Data and key can be a bytearray (during initialization)
|
||||
key_ba = bytearray(key)
|
||||
data_ba = bytearray(data)
|
||||
|
||||
h1 = self.BLAKE2.new(data=data, key=key)
|
||||
h2 = self.BLAKE2.new(data=data_ba, key=key_ba)
|
||||
key_ba[:1] = b'\xFF'
|
||||
data_ba[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
# Data can be a bytearray (during operation)
|
||||
data_ba = bytearray(data)
|
||||
|
||||
h1 = self.BLAKE2.new()
|
||||
h2 = self.BLAKE2.new()
|
||||
h1.update(data)
|
||||
h2.update(data_ba)
|
||||
data_ba[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
def test_memoryview(self):
|
||||
|
||||
key = b'0' * 16
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
def get_mv_ro(data):
|
||||
return memoryview(data)
|
||||
|
||||
def get_mv_rw(data):
|
||||
return memoryview(bytearray(data))
|
||||
|
||||
for get_mv in (get_mv_ro, get_mv_rw):
|
||||
|
||||
# Data and key can be a memoryview (during initialization)
|
||||
key_mv = get_mv(key)
|
||||
data_mv = get_mv(data)
|
||||
|
||||
h1 = self.BLAKE2.new(data=data, key=key)
|
||||
h2 = self.BLAKE2.new(data=data_mv, key=key_mv)
|
||||
if not data_mv.readonly:
|
||||
data_mv[:1] = b'\xFF'
|
||||
key_mv[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
# Data can be a memoryview (during operation)
|
||||
data_mv = get_mv(data)
|
||||
|
||||
h1 = self.BLAKE2.new()
|
||||
h2 = self.BLAKE2.new()
|
||||
h1.update(data)
|
||||
h2.update(data_mv)
|
||||
if not data_mv.readonly:
|
||||
data_mv[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
|
||||
class Blake2bTest(Blake2Test):
|
||||
#: Module
|
||||
BLAKE2 = BLAKE2b
|
||||
#: Max output size (in bits)
|
||||
max_bits = 512
|
||||
#: Max output size (in bytes)
|
||||
max_bytes = 64
|
||||
#: Bit size of the digests for which an ASN OID exists
|
||||
digest_bits_oid = (160, 256, 384, 512)
|
||||
# http://tools.ietf.org/html/draft-saarinen-blake2-02
|
||||
oid_variant = "1"
|
||||
|
||||
|
||||
class Blake2sTest(Blake2Test):
|
||||
#: Module
|
||||
BLAKE2 = BLAKE2s
|
||||
#: Max output size (in bits)
|
||||
max_bits = 256
|
||||
#: Max output size (in bytes)
|
||||
max_bytes = 32
|
||||
#: Bit size of the digests for which an ASN OID exists
|
||||
digest_bits_oid = (128, 160, 224, 256)
|
||||
# http://tools.ietf.org/html/draft-saarinen-blake2-02
|
||||
oid_variant = "2"
|
||||
|
||||
|
||||
class Blake2OfficialTestVector(unittest.TestCase):
|
||||
|
||||
def _load_tests(self, test_vector_file):
|
||||
expected = "in"
|
||||
test_vectors = []
|
||||
with open(test_vector_file, "rt") as test_vector_fd:
|
||||
for line_number, line in enumerate(test_vector_fd):
|
||||
|
||||
if line.strip() == "" or line.startswith("#"):
|
||||
continue
|
||||
|
||||
res = re.match("%s:\t([0-9A-Fa-f]*)" % expected, line)
|
||||
if not res:
|
||||
raise ValueError("Incorrect test vector format (line %d)"
|
||||
% line_number)
|
||||
|
||||
if res.group(1):
|
||||
bin_value = unhexlify(tobytes(res.group(1)))
|
||||
else:
|
||||
bin_value = b""
|
||||
if expected == "in":
|
||||
input_data = bin_value
|
||||
expected = "key"
|
||||
elif expected == "key":
|
||||
key = bin_value
|
||||
expected = "hash"
|
||||
else:
|
||||
result = bin_value
|
||||
expected = "in"
|
||||
test_vectors.append((input_data, key, result))
|
||||
return test_vectors
|
||||
|
||||
def setUp(self):
|
||||
|
||||
dir_comps = ("Hash", self.name)
|
||||
file_name = self.name.lower() + "-test.txt"
|
||||
self.description = "%s tests" % self.name
|
||||
|
||||
try:
|
||||
import pycryptodome_test_vectors # type: ignore
|
||||
except ImportError:
|
||||
warnings.warn("Warning: skipping extended tests for %s" % self.name,
|
||||
UserWarning)
|
||||
self.test_vectors = []
|
||||
return
|
||||
|
||||
init_dir = os.path.dirname(pycryptodome_test_vectors.__file__)
|
||||
full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name)
|
||||
self.test_vectors = self._load_tests(full_file_name)
|
||||
|
||||
def runTest(self):
|
||||
for (input_data, key, result) in self.test_vectors:
|
||||
mac = self.BLAKE2.new(key=key, digest_bytes=self.max_bytes)
|
||||
mac.update(input_data)
|
||||
self.assertEqual(mac.digest(), result)
|
||||
|
||||
|
||||
class Blake2bOfficialTestVector(Blake2OfficialTestVector):
|
||||
#: Module
|
||||
BLAKE2 = BLAKE2b
|
||||
#: Hash name
|
||||
name = "BLAKE2b"
|
||||
#: Max digest size
|
||||
max_bytes = 64
|
||||
|
||||
|
||||
class Blake2sOfficialTestVector(Blake2OfficialTestVector):
|
||||
#: Module
|
||||
BLAKE2 = BLAKE2s
|
||||
#: Hash name
|
||||
name = "BLAKE2s"
|
||||
#: Max digest size
|
||||
max_bytes = 32
|
||||
|
||||
|
||||
class Blake2TestVector1(unittest.TestCase):
|
||||
|
||||
def _load_tests(self, test_vector_file):
|
||||
test_vectors = []
|
||||
with open(test_vector_file, "rt") as test_vector_fd:
|
||||
for line_number, line in enumerate(test_vector_fd):
|
||||
if line.strip() == "" or line.startswith("#"):
|
||||
continue
|
||||
res = re.match("digest: ([0-9A-Fa-f]*)", line)
|
||||
if not res:
|
||||
raise ValueError("Incorrect test vector format (line %d)"
|
||||
% line_number)
|
||||
|
||||
test_vectors.append(unhexlify(tobytes(res.group(1))))
|
||||
return test_vectors
|
||||
|
||||
def setUp(self):
|
||||
dir_comps = ("Hash", self.name)
|
||||
file_name = "tv1.txt"
|
||||
self.description = "%s tests" % self.name
|
||||
|
||||
try:
|
||||
import pycryptodome_test_vectors
|
||||
except ImportError:
|
||||
warnings.warn("Warning: skipping extended tests for %s" % self.name,
|
||||
UserWarning)
|
||||
self.test_vectors = []
|
||||
return
|
||||
|
||||
init_dir = os.path.dirname(pycryptodome_test_vectors.__file__)
|
||||
full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name)
|
||||
self.test_vectors = self._load_tests(full_file_name)
|
||||
|
||||
def runTest(self):
|
||||
|
||||
for tv in self.test_vectors:
|
||||
digest_bytes = len(tv)
|
||||
next_data = b""
|
||||
for _ in range(100):
|
||||
h = self.BLAKE2.new(digest_bytes=digest_bytes)
|
||||
h.update(next_data)
|
||||
next_data = h.digest() + next_data
|
||||
self.assertEqual(h.digest(), tv)
|
||||
|
||||
|
||||
class Blake2bTestVector1(Blake2TestVector1):
|
||||
#: Module
|
||||
BLAKE2 = BLAKE2b
|
||||
#: Hash name
|
||||
name = "BLAKE2b"
|
||||
|
||||
|
||||
class Blake2sTestVector1(Blake2TestVector1):
|
||||
#: Module
|
||||
BLAKE2 = BLAKE2s
|
||||
#: Hash name
|
||||
name = "BLAKE2s"
|
||||
|
||||
|
||||
class Blake2TestVector2(unittest.TestCase):
|
||||
|
||||
def _load_tests(self, test_vector_file):
|
||||
test_vectors = []
|
||||
with open(test_vector_file, "rt") as test_vector_fd:
|
||||
for line_number, line in enumerate(test_vector_fd):
|
||||
if line.strip() == "" or line.startswith("#"):
|
||||
continue
|
||||
res = re.match(r"digest\(([0-9]+)\): ([0-9A-Fa-f]*)", line)
|
||||
if not res:
|
||||
raise ValueError("Incorrect test vector format (line %d)"
|
||||
% line_number)
|
||||
key_size = int(res.group(1))
|
||||
result = unhexlify(tobytes(res.group(2)))
|
||||
test_vectors.append((key_size, result))
|
||||
return test_vectors
|
||||
|
||||
def setUp(self):
|
||||
dir_comps = ("Hash", self.name)
|
||||
file_name = "tv2.txt"
|
||||
self.description = "%s tests" % self.name
|
||||
|
||||
try:
|
||||
import pycryptodome_test_vectors # type: ignore
|
||||
except ImportError:
|
||||
warnings.warn("Warning: skipping extended tests for %s" % self.name,
|
||||
UserWarning)
|
||||
self.test_vectors = []
|
||||
return
|
||||
|
||||
init_dir = os.path.dirname(pycryptodome_test_vectors.__file__)
|
||||
full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name)
|
||||
self.test_vectors = self._load_tests(full_file_name)
|
||||
|
||||
def runTest(self):
|
||||
|
||||
for key_size, result in self.test_vectors:
|
||||
next_data = b""
|
||||
for _ in range(100):
|
||||
h = self.BLAKE2.new(digest_bytes=self.max_bytes,
|
||||
key=b"A" * key_size)
|
||||
h.update(next_data)
|
||||
next_data = h.digest() + next_data
|
||||
self.assertEqual(h.digest(), result)
|
||||
|
||||
|
||||
class Blake2bTestVector2(Blake2TestVector1):
|
||||
#: Module
|
||||
BLAKE2 = BLAKE2b
|
||||
#: Hash name
|
||||
name = "BLAKE2b"
|
||||
#: Max digest size in bytes
|
||||
max_bytes = 64
|
||||
|
||||
|
||||
class Blake2sTestVector2(Blake2TestVector1):
|
||||
#: Module
|
||||
BLAKE2 = BLAKE2s
|
||||
#: Hash name
|
||||
name = "BLAKE2s"
|
||||
#: Max digest size in bytes
|
||||
max_bytes = 32
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
|
||||
tests += list_test_cases(Blake2bTest)
|
||||
tests.append(Blake2bOfficialTestVector())
|
||||
tests.append(Blake2bTestVector1())
|
||||
tests.append(Blake2bTestVector2())
|
||||
|
||||
tests += list_test_cases(Blake2sTest)
|
||||
tests.append(Blake2sOfficialTestVector())
|
||||
tests.append(Blake2sTestVector1())
|
||||
tests.append(Blake2sTestVector2())
|
||||
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
def suite():
|
||||
return unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
448
backend/venv/Lib/site-packages/Crypto/SelfTest/Hash/test_CMAC.py
Normal file
448
backend/venv/Lib/site-packages/Crypto/SelfTest/Hash/test_CMAC.py
Normal file
@@ -0,0 +1,448 @@
|
||||
#
|
||||
# SelfTest/Hash/CMAC.py: Self-test for the CMAC module
|
||||
#
|
||||
# ===================================================================
|
||||
#
|
||||
# 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.
|
||||
# ===================================================================
|
||||
|
||||
"""Self-test suite for Crypto.Hash.CMAC"""
|
||||
|
||||
import json
|
||||
import unittest
|
||||
from binascii import unhexlify
|
||||
|
||||
from Crypto.Util.py3compat import tobytes
|
||||
|
||||
from Crypto.Hash import CMAC
|
||||
from Crypto.Cipher import AES, DES3
|
||||
from Crypto.Hash import SHAKE128
|
||||
|
||||
from Crypto.Util.strxor import strxor
|
||||
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
from Crypto.SelfTest.loader import load_test_vectors_wycheproof
|
||||
|
||||
# This is a list of (key, data, result, description, module) tuples.
|
||||
test_data = [
|
||||
|
||||
## Test vectors from RFC 4493 ##
|
||||
## The are also in NIST SP 800 38B D.2 ##
|
||||
( '2b7e151628aed2a6abf7158809cf4f3c',
|
||||
'',
|
||||
'bb1d6929e95937287fa37d129b756746',
|
||||
'RFC 4493 #1',
|
||||
AES
|
||||
),
|
||||
|
||||
( '2b7e151628aed2a6abf7158809cf4f3c',
|
||||
'6bc1bee22e409f96e93d7e117393172a',
|
||||
'070a16b46b4d4144f79bdd9dd04a287c',
|
||||
'RFC 4493 #2',
|
||||
AES
|
||||
),
|
||||
|
||||
( '2b7e151628aed2a6abf7158809cf4f3c',
|
||||
'6bc1bee22e409f96e93d7e117393172a'+
|
||||
'ae2d8a571e03ac9c9eb76fac45af8e51'+
|
||||
'30c81c46a35ce411',
|
||||
'dfa66747de9ae63030ca32611497c827',
|
||||
'RFC 4493 #3',
|
||||
AES
|
||||
),
|
||||
|
||||
( '2b7e151628aed2a6abf7158809cf4f3c',
|
||||
'6bc1bee22e409f96e93d7e117393172a'+
|
||||
'ae2d8a571e03ac9c9eb76fac45af8e51'+
|
||||
'30c81c46a35ce411e5fbc1191a0a52ef'+
|
||||
'f69f2445df4f9b17ad2b417be66c3710',
|
||||
'51f0bebf7e3b9d92fc49741779363cfe',
|
||||
'RFC 4493 #4',
|
||||
AES
|
||||
),
|
||||
|
||||
## The rest of Appendix D of NIST SP 800 38B
|
||||
## was not totally correct.
|
||||
## Values in Examples 14, 15, 18, and 19 were wrong.
|
||||
## The updated test values are published in:
|
||||
## http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf
|
||||
|
||||
( '8e73b0f7da0e6452c810f32b809079e5'+
|
||||
'62f8ead2522c6b7b',
|
||||
'',
|
||||
'd17ddf46adaacde531cac483de7a9367',
|
||||
'NIST SP 800 38B D.2 Example 5',
|
||||
AES
|
||||
),
|
||||
|
||||
( '8e73b0f7da0e6452c810f32b809079e5'+
|
||||
'62f8ead2522c6b7b',
|
||||
'6bc1bee22e409f96e93d7e117393172a',
|
||||
'9e99a7bf31e710900662f65e617c5184',
|
||||
'NIST SP 800 38B D.2 Example 6',
|
||||
AES
|
||||
),
|
||||
|
||||
( '8e73b0f7da0e6452c810f32b809079e5'+
|
||||
'62f8ead2522c6b7b',
|
||||
'6bc1bee22e409f96e93d7e117393172a'+
|
||||
'ae2d8a571e03ac9c9eb76fac45af8e51'+
|
||||
'30c81c46a35ce411',
|
||||
'8a1de5be2eb31aad089a82e6ee908b0e',
|
||||
'NIST SP 800 38B D.2 Example 7',
|
||||
AES
|
||||
),
|
||||
|
||||
( '8e73b0f7da0e6452c810f32b809079e5'+
|
||||
'62f8ead2522c6b7b',
|
||||
'6bc1bee22e409f96e93d7e117393172a'+
|
||||
'ae2d8a571e03ac9c9eb76fac45af8e51'+
|
||||
'30c81c46a35ce411e5fbc1191a0a52ef'+
|
||||
'f69f2445df4f9b17ad2b417be66c3710',
|
||||
'a1d5df0eed790f794d77589659f39a11',
|
||||
'NIST SP 800 38B D.2 Example 8',
|
||||
AES
|
||||
),
|
||||
|
||||
( '603deb1015ca71be2b73aef0857d7781'+
|
||||
'1f352c073b6108d72d9810a30914dff4',
|
||||
'',
|
||||
'028962f61b7bf89efc6b551f4667d983',
|
||||
'NIST SP 800 38B D.3 Example 9',
|
||||
AES
|
||||
),
|
||||
|
||||
( '603deb1015ca71be2b73aef0857d7781'+
|
||||
'1f352c073b6108d72d9810a30914dff4',
|
||||
'6bc1bee22e409f96e93d7e117393172a',
|
||||
'28a7023f452e8f82bd4bf28d8c37c35c',
|
||||
'NIST SP 800 38B D.3 Example 10',
|
||||
AES
|
||||
),
|
||||
|
||||
( '603deb1015ca71be2b73aef0857d7781'+
|
||||
'1f352c073b6108d72d9810a30914dff4',
|
||||
'6bc1bee22e409f96e93d7e117393172a'+
|
||||
'ae2d8a571e03ac9c9eb76fac45af8e51'+
|
||||
'30c81c46a35ce411',
|
||||
'aaf3d8f1de5640c232f5b169b9c911e6',
|
||||
'NIST SP 800 38B D.3 Example 11',
|
||||
AES
|
||||
),
|
||||
|
||||
( '603deb1015ca71be2b73aef0857d7781'+
|
||||
'1f352c073b6108d72d9810a30914dff4',
|
||||
'6bc1bee22e409f96e93d7e117393172a'+
|
||||
'ae2d8a571e03ac9c9eb76fac45af8e51'+
|
||||
'30c81c46a35ce411e5fbc1191a0a52ef'+
|
||||
'f69f2445df4f9b17ad2b417be66c3710',
|
||||
'e1992190549f6ed5696a2c056c315410',
|
||||
'NIST SP 800 38B D.3 Example 12',
|
||||
AES
|
||||
),
|
||||
|
||||
( '8aa83bf8cbda1062'+
|
||||
'0bc1bf19fbb6cd58'+
|
||||
'bc313d4a371ca8b5',
|
||||
'',
|
||||
'b7a688e122ffaf95',
|
||||
'NIST SP 800 38B D.4 Example 13',
|
||||
DES3
|
||||
),
|
||||
|
||||
( '8aa83bf8cbda1062'+
|
||||
'0bc1bf19fbb6cd58'+
|
||||
'bc313d4a371ca8b5',
|
||||
'6bc1bee22e409f96',
|
||||
'8e8f293136283797',
|
||||
'NIST SP 800 38B D.4 Example 14',
|
||||
DES3
|
||||
),
|
||||
|
||||
( '8aa83bf8cbda1062'+
|
||||
'0bc1bf19fbb6cd58'+
|
||||
'bc313d4a371ca8b5',
|
||||
'6bc1bee22e409f96'+
|
||||
'e93d7e117393172a'+
|
||||
'ae2d8a57',
|
||||
'743ddbe0ce2dc2ed',
|
||||
'NIST SP 800 38B D.4 Example 15',
|
||||
DES3
|
||||
),
|
||||
|
||||
( '8aa83bf8cbda1062'+
|
||||
'0bc1bf19fbb6cd58'+
|
||||
'bc313d4a371ca8b5',
|
||||
'6bc1bee22e409f96'+
|
||||
'e93d7e117393172a'+
|
||||
'ae2d8a571e03ac9c'+
|
||||
'9eb76fac45af8e51',
|
||||
'33e6b1092400eae5',
|
||||
'NIST SP 800 38B D.4 Example 16',
|
||||
DES3
|
||||
),
|
||||
|
||||
( '4cf15134a2850dd5'+
|
||||
'8a3d10ba80570d38',
|
||||
'',
|
||||
'bd2ebf9a3ba00361',
|
||||
'NIST SP 800 38B D.7 Example 17',
|
||||
DES3
|
||||
),
|
||||
|
||||
( '4cf15134a2850dd5'+
|
||||
'8a3d10ba80570d38',
|
||||
'6bc1bee22e409f96',
|
||||
'4ff2ab813c53ce83',
|
||||
'NIST SP 800 38B D.7 Example 18',
|
||||
DES3
|
||||
),
|
||||
|
||||
( '4cf15134a2850dd5'+
|
||||
'8a3d10ba80570d38',
|
||||
'6bc1bee22e409f96'+
|
||||
'e93d7e117393172a'+
|
||||
'ae2d8a57',
|
||||
'62dd1b471902bd4e',
|
||||
'NIST SP 800 38B D.7 Example 19',
|
||||
DES3
|
||||
),
|
||||
|
||||
( '4cf15134a2850dd5'+
|
||||
'8a3d10ba80570d38',
|
||||
'6bc1bee22e409f96'+
|
||||
'e93d7e117393172a'+
|
||||
'ae2d8a571e03ac9c'+
|
||||
'9eb76fac45af8e51',
|
||||
'31b1e431dabc4eb8',
|
||||
'NIST SP 800 38B D.7 Example 20',
|
||||
DES3
|
||||
),
|
||||
|
||||
]
|
||||
|
||||
|
||||
def get_tag_random(tag, length):
|
||||
return SHAKE128.new(data=tobytes(tag)).read(length)
|
||||
|
||||
|
||||
class TestCMAC(unittest.TestCase):
|
||||
|
||||
def test_internal_caching(self):
|
||||
"""Verify that internal caching is implemented correctly"""
|
||||
|
||||
data_to_mac = get_tag_random("data_to_mac", 128)
|
||||
key = get_tag_random("key", 16)
|
||||
ref_mac = CMAC.new(key, msg=data_to_mac, ciphermod=AES).digest()
|
||||
|
||||
# Break up in chunks of different length
|
||||
# The result must always be the same
|
||||
for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128:
|
||||
|
||||
chunks = [data_to_mac[i:i+chunk_length] for i in
|
||||
range(0, len(data_to_mac), chunk_length)]
|
||||
|
||||
mac = CMAC.new(key, ciphermod=AES)
|
||||
for chunk in chunks:
|
||||
mac.update(chunk)
|
||||
self.assertEqual(ref_mac, mac.digest())
|
||||
|
||||
def test_update_after_digest(self):
|
||||
msg = b"rrrrttt"
|
||||
key = b"4" * 16
|
||||
|
||||
# Normally, update() cannot be done after digest()
|
||||
h = CMAC.new(key, msg[:4], ciphermod=AES)
|
||||
dig1 = h.digest()
|
||||
self.assertRaises(TypeError, h.update, msg[4:])
|
||||
dig2 = CMAC.new(key, msg, ciphermod=AES).digest()
|
||||
|
||||
# With the proper flag, it is allowed
|
||||
h2 = CMAC.new(key, msg[:4], ciphermod=AES, update_after_digest=True)
|
||||
self.assertEqual(h2.digest(), dig1)
|
||||
# ... and the subsequent digest applies to the entire message
|
||||
# up to that point
|
||||
h2.update(msg[4:])
|
||||
self.assertEqual(h2.digest(), dig2)
|
||||
|
||||
|
||||
class ByteArrayTests(unittest.TestCase):
|
||||
|
||||
def runTest(self):
|
||||
|
||||
key = b"0" * 16
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
# Data and key can be a bytearray (during initialization)
|
||||
key_ba = bytearray(key)
|
||||
data_ba = bytearray(data)
|
||||
|
||||
h1 = CMAC.new(key, data, ciphermod=AES)
|
||||
h2 = CMAC.new(key_ba, data_ba, ciphermod=AES)
|
||||
key_ba[:1] = b'\xFF'
|
||||
data_ba[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
# Data can be a bytearray (during operation)
|
||||
key_ba = bytearray(key)
|
||||
data_ba = bytearray(data)
|
||||
|
||||
h1 = CMAC.new(key, ciphermod=AES)
|
||||
h2 = CMAC.new(key, ciphermod=AES)
|
||||
h1.update(data)
|
||||
h2.update(data_ba)
|
||||
data_ba[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
|
||||
class MemoryViewTests(unittest.TestCase):
|
||||
|
||||
def runTest(self):
|
||||
|
||||
key = b"0" * 16
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
def get_mv_ro(data):
|
||||
return memoryview(data)
|
||||
|
||||
def get_mv_rw(data):
|
||||
return memoryview(bytearray(data))
|
||||
|
||||
for get_mv in (get_mv_ro, get_mv_rw):
|
||||
|
||||
# Data and key can be a memoryview (during initialization)
|
||||
key_mv = get_mv(key)
|
||||
data_mv = get_mv(data)
|
||||
|
||||
h1 = CMAC.new(key, data, ciphermod=AES)
|
||||
h2 = CMAC.new(key_mv, data_mv, ciphermod=AES)
|
||||
if not data_mv.readonly:
|
||||
key_mv[:1] = b'\xFF'
|
||||
data_mv[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
# Data can be a memoryview (during operation)
|
||||
data_mv = get_mv(data)
|
||||
|
||||
h1 = CMAC.new(key, ciphermod=AES)
|
||||
h2 = CMAC.new(key, ciphermod=AES)
|
||||
h1.update(data)
|
||||
h2.update(data_mv)
|
||||
if not data_mv.readonly:
|
||||
data_mv[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
|
||||
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(("Hash", "wycheproof"),
|
||||
"aes_cmac_test.json",
|
||||
"Wycheproof CMAC",
|
||||
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_create_mac(self, tv):
|
||||
self._id = "Wycheproof MAC creation Test #" + str(tv.id)
|
||||
|
||||
try:
|
||||
tag = CMAC.new(tv.key, tv.msg, ciphermod=AES, mac_len=tv.tag_size).digest()
|
||||
except ValueError as e:
|
||||
if len(tv.key) not in (16, 24, 32) and "key length" in str(e):
|
||||
return
|
||||
raise e
|
||||
if tv.valid:
|
||||
self.assertEqual(tag, tv.tag)
|
||||
self.warn(tv)
|
||||
|
||||
def test_verify_mac(self, tv):
|
||||
self._id = "Wycheproof MAC verification Test #" + str(tv.id)
|
||||
|
||||
try:
|
||||
mac = CMAC.new(tv.key, tv.msg, ciphermod=AES, mac_len=tv.tag_size)
|
||||
except ValueError as e:
|
||||
if len(tv.key) not in (16, 24, 32) and "key length" in str(e):
|
||||
return
|
||||
raise e
|
||||
try:
|
||||
mac.verify(tv.tag)
|
||||
except ValueError:
|
||||
assert not tv.valid
|
||||
else:
|
||||
assert tv.valid
|
||||
self.warn(tv)
|
||||
|
||||
def runTest(self):
|
||||
|
||||
for tv in self.tv:
|
||||
self.test_create_mac(tv)
|
||||
self.test_verify_mac(tv)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
global test_data
|
||||
import types
|
||||
from .common import make_mac_tests
|
||||
|
||||
wycheproof_warnings = config.get('wycheproof_warnings')
|
||||
|
||||
# Add new() parameters to the back of each test vector
|
||||
params_test_data = []
|
||||
for row in test_data:
|
||||
t = list(row)
|
||||
t[4] = dict(ciphermod=t[4])
|
||||
params_test_data.append(t)
|
||||
|
||||
tests = make_mac_tests(CMAC, "CMAC", params_test_data)
|
||||
tests.append(ByteArrayTests())
|
||||
tests.append(list_test_cases(TestCMAC))
|
||||
tests.append(MemoryViewTests())
|
||||
tests += [ TestVectorsWycheproof(wycheproof_warnings) ]
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
548
backend/venv/Lib/site-packages/Crypto/SelfTest/Hash/test_HMAC.py
Normal file
548
backend/venv/Lib/site-packages/Crypto/SelfTest/Hash/test_HMAC.py
Normal file
@@ -0,0 +1,548 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/HMAC.py: Self-test for the HMAC module
|
||||
#
|
||||
# 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.Hash.HMAC"""
|
||||
|
||||
import unittest
|
||||
from binascii import hexlify
|
||||
from Crypto.Util.py3compat import tostr, tobytes
|
||||
|
||||
from Crypto.Hash import (HMAC, MD5, SHA1, SHA256,
|
||||
SHA224, SHA384, SHA512,
|
||||
RIPEMD160,
|
||||
SHA3_224, SHA3_256, SHA3_384, SHA3_512)
|
||||
|
||||
|
||||
hash_modules = dict(MD5=MD5, SHA1=SHA1, SHA256=SHA256,
|
||||
SHA224=SHA224, SHA384=SHA384, SHA512=SHA512,
|
||||
RIPEMD160=RIPEMD160,
|
||||
SHA3_224=SHA3_224, SHA3_256=SHA3_256,
|
||||
SHA3_384=SHA3_384, SHA3_512=SHA3_512)
|
||||
|
||||
default_hash = None
|
||||
|
||||
def xl(text):
|
||||
return tostr(hexlify(tobytes(text)))
|
||||
|
||||
# This is a list of (key, data, results, description) tuples.
|
||||
test_data = [
|
||||
## Test vectors from RFC 2202 ##
|
||||
# Test that the default hashmod is MD5
|
||||
('0b' * 16,
|
||||
'4869205468657265',
|
||||
dict(default_hash='9294727a3638bb1c13f48ef8158bfc9d'),
|
||||
'default-is-MD5'),
|
||||
|
||||
# Test case 1 (MD5)
|
||||
('0b' * 16,
|
||||
'4869205468657265',
|
||||
dict(MD5='9294727a3638bb1c13f48ef8158bfc9d'),
|
||||
'RFC 2202 #1-MD5 (HMAC-MD5)'),
|
||||
|
||||
# Test case 1 (SHA1)
|
||||
('0b' * 20,
|
||||
'4869205468657265',
|
||||
dict(SHA1='b617318655057264e28bc0b6fb378c8ef146be00'),
|
||||
'RFC 2202 #1-SHA1 (HMAC-SHA1)'),
|
||||
|
||||
# Test case 2
|
||||
('4a656665',
|
||||
'7768617420646f2079612077616e7420666f72206e6f7468696e673f',
|
||||
dict(MD5='750c783e6ab0b503eaa86e310a5db738',
|
||||
SHA1='effcdf6ae5eb2fa2d27416d5f184df9c259a7c79'),
|
||||
'RFC 2202 #2 (HMAC-MD5/SHA1)'),
|
||||
|
||||
# Test case 3 (MD5)
|
||||
('aa' * 16,
|
||||
'dd' * 50,
|
||||
dict(MD5='56be34521d144c88dbb8c733f0e8b3f6'),
|
||||
'RFC 2202 #3-MD5 (HMAC-MD5)'),
|
||||
|
||||
# Test case 3 (SHA1)
|
||||
('aa' * 20,
|
||||
'dd' * 50,
|
||||
dict(SHA1='125d7342b9ac11cd91a39af48aa17b4f63f175d3'),
|
||||
'RFC 2202 #3-SHA1 (HMAC-SHA1)'),
|
||||
|
||||
# Test case 4
|
||||
('0102030405060708090a0b0c0d0e0f10111213141516171819',
|
||||
'cd' * 50,
|
||||
dict(MD5='697eaf0aca3a3aea3a75164746ffaa79',
|
||||
SHA1='4c9007f4026250c6bc8414f9bf50c86c2d7235da'),
|
||||
'RFC 2202 #4 (HMAC-MD5/SHA1)'),
|
||||
|
||||
# Test case 5 (MD5)
|
||||
('0c' * 16,
|
||||
'546573742057697468205472756e636174696f6e',
|
||||
dict(MD5='56461ef2342edc00f9bab995690efd4c'),
|
||||
'RFC 2202 #5-MD5 (HMAC-MD5)'),
|
||||
|
||||
# Test case 5 (SHA1)
|
||||
# NB: We do not implement hash truncation, so we only test the full hash here.
|
||||
('0c' * 20,
|
||||
'546573742057697468205472756e636174696f6e',
|
||||
dict(SHA1='4c1a03424b55e07fe7f27be1d58bb9324a9a5a04'),
|
||||
'RFC 2202 #5-SHA1 (HMAC-SHA1)'),
|
||||
|
||||
# Test case 6
|
||||
('aa' * 80,
|
||||
'54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a'
|
||||
+ '65204b6579202d2048617368204b6579204669727374',
|
||||
dict(MD5='6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd',
|
||||
SHA1='aa4ae5e15272d00e95705637ce8a3b55ed402112'),
|
||||
'RFC 2202 #6 (HMAC-MD5/SHA1)'),
|
||||
|
||||
# Test case 7
|
||||
('aa' * 80,
|
||||
'54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a'
|
||||
+ '65204b657920616e64204c6172676572205468616e204f6e6520426c6f636b2d'
|
||||
+ '53697a652044617461',
|
||||
dict(MD5='6f630fad67cda0ee1fb1f562db3aa53e',
|
||||
SHA1='e8e99d0f45237d786d6bbaa7965c7808bbff1a91'),
|
||||
'RFC 2202 #7 (HMAC-MD5/SHA1)'),
|
||||
|
||||
## Test vectors from RFC 4231 ##
|
||||
# 4.2. Test Case 1
|
||||
('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b',
|
||||
'4869205468657265',
|
||||
dict(SHA256='''
|
||||
b0344c61d8db38535ca8afceaf0bf12b
|
||||
881dc200c9833da726e9376c2e32cff7
|
||||
'''),
|
||||
'RFC 4231 #1 (HMAC-SHA256)'),
|
||||
|
||||
# 4.3. Test Case 2 - Test with a key shorter than the length of the HMAC
|
||||
# output.
|
||||
('4a656665',
|
||||
'7768617420646f2079612077616e7420666f72206e6f7468696e673f',
|
||||
dict(SHA256='''
|
||||
5bdcc146bf60754e6a042426089575c7
|
||||
5a003f089d2739839dec58b964ec3843
|
||||
'''),
|
||||
'RFC 4231 #2 (HMAC-SHA256)'),
|
||||
|
||||
# 4.4. Test Case 3 - Test with a combined length of key and data that is
|
||||
# larger than 64 bytes (= block-size of SHA-224 and SHA-256).
|
||||
('aa' * 20,
|
||||
'dd' * 50,
|
||||
dict(SHA256='''
|
||||
773ea91e36800e46854db8ebd09181a7
|
||||
2959098b3ef8c122d9635514ced565fe
|
||||
'''),
|
||||
'RFC 4231 #3 (HMAC-SHA256)'),
|
||||
|
||||
# 4.5. Test Case 4 - Test with a combined length of key and data that is
|
||||
# larger than 64 bytes (= block-size of SHA-224 and SHA-256).
|
||||
('0102030405060708090a0b0c0d0e0f10111213141516171819',
|
||||
'cd' * 50,
|
||||
dict(SHA256='''
|
||||
82558a389a443c0ea4cc819899f2083a
|
||||
85f0faa3e578f8077a2e3ff46729665b
|
||||
'''),
|
||||
'RFC 4231 #4 (HMAC-SHA256)'),
|
||||
|
||||
# 4.6. Test Case 5 - Test with a truncation of output to 128 bits.
|
||||
#
|
||||
# Not included because we do not implement hash truncation.
|
||||
#
|
||||
|
||||
# 4.7. Test Case 6 - Test with a key larger than 128 bytes (= block-size of
|
||||
# SHA-384 and SHA-512).
|
||||
('aa' * 131,
|
||||
'54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a'
|
||||
+ '65204b6579202d2048617368204b6579204669727374',
|
||||
dict(SHA256='''
|
||||
60e431591ee0b67f0d8a26aacbf5b77f
|
||||
8e0bc6213728c5140546040f0ee37f54
|
||||
'''),
|
||||
'RFC 4231 #6 (HMAC-SHA256)'),
|
||||
|
||||
# 4.8. Test Case 7 - Test with a key and data that is larger than 128 bytes
|
||||
# (= block-size of SHA-384 and SHA-512).
|
||||
('aa' * 131,
|
||||
'5468697320697320612074657374207573696e672061206c6172676572207468'
|
||||
+ '616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074'
|
||||
+ '68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565'
|
||||
+ '647320746f20626520686173686564206265666f7265206265696e6720757365'
|
||||
+ '642062792074686520484d414320616c676f726974686d2e',
|
||||
dict(SHA256='''
|
||||
9b09ffa71b942fcb27635fbcd5b0e944
|
||||
bfdc63644f0713938a7f51535c3a35e2
|
||||
'''),
|
||||
'RFC 4231 #7 (HMAC-SHA256)'),
|
||||
|
||||
# Test case 8 (SHA224)
|
||||
('4a656665',
|
||||
'7768617420646f2079612077616e74'
|
||||
+ '20666f72206e6f7468696e673f',
|
||||
dict(SHA224='a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44'),
|
||||
'RFC 4634 8.4 SHA224 (HMAC-SHA224)'),
|
||||
|
||||
# Test case 9 (SHA384)
|
||||
('4a656665',
|
||||
'7768617420646f2079612077616e74'
|
||||
+ '20666f72206e6f7468696e673f',
|
||||
dict(SHA384='af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649'),
|
||||
'RFC 4634 8.4 SHA384 (HMAC-SHA384)'),
|
||||
|
||||
# Test case 10 (SHA512)
|
||||
('4a656665',
|
||||
'7768617420646f2079612077616e74'
|
||||
+ '20666f72206e6f7468696e673f',
|
||||
dict(SHA512='164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737'),
|
||||
'RFC 4634 8.4 SHA512 (HMAC-SHA512)'),
|
||||
|
||||
# Test case 11 (RIPEMD)
|
||||
('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b',
|
||||
xl("Hi There"),
|
||||
dict(RIPEMD160='24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668'),
|
||||
'RFC 2286 #1 (HMAC-RIPEMD)'),
|
||||
|
||||
# Test case 12 (RIPEMD)
|
||||
(xl("Jefe"),
|
||||
xl("what do ya want for nothing?"),
|
||||
dict(RIPEMD160='dda6c0213a485a9e24f4742064a7f033b43c4069'),
|
||||
'RFC 2286 #2 (HMAC-RIPEMD)'),
|
||||
|
||||
# Test case 13 (RIPEMD)
|
||||
('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
||||
'dd' * 50,
|
||||
dict(RIPEMD160='b0b105360de759960ab4f35298e116e295d8e7c1'),
|
||||
'RFC 2286 #3 (HMAC-RIPEMD)'),
|
||||
|
||||
# Test case 14 (RIPEMD)
|
||||
('0102030405060708090a0b0c0d0e0f10111213141516171819',
|
||||
'cd' * 50,
|
||||
dict(RIPEMD160='d5ca862f4d21d5e610e18b4cf1beb97a4365ecf4'),
|
||||
'RFC 2286 #4 (HMAC-RIPEMD)'),
|
||||
|
||||
# Test case 15 (RIPEMD)
|
||||
('0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c',
|
||||
xl("Test With Truncation"),
|
||||
dict(RIPEMD160='7619693978f91d90539ae786500ff3d8e0518e39'),
|
||||
'RFC 2286 #5 (HMAC-RIPEMD)'),
|
||||
|
||||
# Test case 16 (RIPEMD)
|
||||
('aa' * 80,
|
||||
xl("Test Using Larger Than Block-Size Key - Hash Key First"),
|
||||
dict(RIPEMD160='6466ca07ac5eac29e1bd523e5ada7605b791fd8b'),
|
||||
'RFC 2286 #6 (HMAC-RIPEMD)'),
|
||||
|
||||
# Test case 17 (RIPEMD)
|
||||
('aa' * 80,
|
||||
xl("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"),
|
||||
dict(RIPEMD160='69ea60798d71616cce5fd0871e23754cd75d5a0a'),
|
||||
'RFC 2286 #7 (HMAC-RIPEMD)'),
|
||||
|
||||
# From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-224.pdf
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'
|
||||
'101112131415161718191a1b',
|
||||
xl('Sample message for keylen<blocklen'),
|
||||
dict(SHA3_224='332cfd59347fdb8e576e77260be4aba2d6dc53117b3bfb52c6d18c04'),
|
||||
'NIST CSRC Sample #1 (SHA3-224)'
|
||||
),
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'\
|
||||
'101112131415161718191a1b1c1d1e1f'\
|
||||
'202122232425262728292a2b2c2d2e2f'\
|
||||
'303132333435363738393a3b3c3d3e3f'\
|
||||
'404142434445464748494a4b4c4d4e4f'\
|
||||
'505152535455565758595a5b5c5d5e5f'\
|
||||
'606162636465666768696a6b6c6d6e6f'\
|
||||
'707172737475767778797a7b7c7d7e7f'\
|
||||
'808182838485868788898a8b8c8d8e8f',
|
||||
xl('Sample message for keylen=blocklen'),
|
||||
dict(SHA3_224='d8b733bcf66c644a12323d564e24dcf3fc75f231f3b67968359100c7'),
|
||||
'NIST CSRC Sample #2 (SHA3-224)'
|
||||
),
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'\
|
||||
'101112131415161718191a1b1c1d1e1f'\
|
||||
'202122232425262728292a2b2c2d2e2f'\
|
||||
'303132333435363738393a3b3c3d3e3f'\
|
||||
'404142434445464748494a4b4c4d4e4f'\
|
||||
'505152535455565758595a5b5c5d5e5f'\
|
||||
'606162636465666768696a6b6c6d6e6f'\
|
||||
'707172737475767778797a7b7c7d7e7f'\
|
||||
'808182838485868788898a8b8c8d8e8f'\
|
||||
'909192939495969798999a9b9c9d9e9f'\
|
||||
'a0a1a2a3a4a5a6a7a8a9aaab',
|
||||
xl('Sample message for keylen>blocklen'),
|
||||
dict(SHA3_224='078695eecc227c636ad31d063a15dd05a7e819a66ec6d8de1e193e59'),
|
||||
'NIST CSRC Sample #3 (SHA3-224)'
|
||||
),
|
||||
|
||||
# From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-256.pdf
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'\
|
||||
'101112131415161718191a1b1c1d1e1f',
|
||||
xl('Sample message for keylen<blocklen'),
|
||||
dict(SHA3_256='4fe8e202c4f058e8dddc23d8c34e467343e23555e24fc2f025d598f558f67205'),
|
||||
'NIST CSRC Sample #1 (SHA3-256)'
|
||||
),
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'\
|
||||
'101112131415161718191a1b1c1d1e1f'\
|
||||
'202122232425262728292a2b2c2d2e2f'\
|
||||
'303132333435363738393a3b3c3d3e3f'\
|
||||
'404142434445464748494a4b4c4d4e4f'\
|
||||
'505152535455565758595a5b5c5d5e5f'\
|
||||
'606162636465666768696a6b6c6d6e6f'\
|
||||
'707172737475767778797a7b7c7d7e7f'\
|
||||
'8081828384858687',
|
||||
xl('Sample message for keylen=blocklen'),
|
||||
dict(SHA3_256='68b94e2e538a9be4103bebb5aa016d47961d4d1aa906061313b557f8af2c3faa'),
|
||||
'NIST CSRC Sample #2 (SHA3-256)'
|
||||
),
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'\
|
||||
'101112131415161718191a1b1c1d1e1f'\
|
||||
'202122232425262728292a2b2c2d2e2f'\
|
||||
'303132333435363738393a3b3c3d3e3f'\
|
||||
'404142434445464748494a4b4c4d4e4f'\
|
||||
'505152535455565758595a5b5c5d5e5f'\
|
||||
'606162636465666768696a6b6c6d6e6f'\
|
||||
'707172737475767778797a7b7c7d7e7f'\
|
||||
'808182838485868788898a8b8c8d8e8f'\
|
||||
'909192939495969798999a9b9c9d9e9f'\
|
||||
'a0a1a2a3a4a5a6a7',
|
||||
xl('Sample message for keylen>blocklen'),
|
||||
dict(SHA3_256='9bcf2c238e235c3ce88404e813bd2f3a97185ac6f238c63d6229a00b07974258'),
|
||||
'NIST CSRC Sample #3 (SHA3-256)'
|
||||
),
|
||||
|
||||
# From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-384.pdf
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'\
|
||||
'101112131415161718191a1b1c1d1e1f'
|
||||
'202122232425262728292a2b2c2d2e2f',
|
||||
xl('Sample message for keylen<blocklen'),
|
||||
dict(SHA3_384='d588a3c51f3f2d906e8298c1199aa8ff6296218127f6b38a90b6afe2c5617725bc99987f79b22a557b6520db710b7f42'),
|
||||
'NIST CSRC Sample #1 (SHA3-384)'
|
||||
),
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'\
|
||||
'101112131415161718191a1b1c1d1e1f'\
|
||||
'202122232425262728292a2b2c2d2e2f'\
|
||||
'303132333435363738393a3b3c3d3e3f'\
|
||||
'404142434445464748494a4b4c4d4e4f'\
|
||||
'505152535455565758595a5b5c5d5e5f'\
|
||||
'6061626364656667',
|
||||
xl('Sample message for keylen=blocklen'),
|
||||
dict(SHA3_384='a27d24b592e8c8cbf6d4ce6fc5bf62d8fc98bf2d486640d9eb8099e24047837f5f3bffbe92dcce90b4ed5b1e7e44fa90'),
|
||||
'NIST CSRC Sample #2 (SHA3-384)'
|
||||
),
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'\
|
||||
'101112131415161718191a1b1c1d1e1f'\
|
||||
'202122232425262728292a2b2c2d2e2f'\
|
||||
'303132333435363738393a3b3c3d3e3f'\
|
||||
'404142434445464748494a4b4c4d4e4f'\
|
||||
'505152535455565758595a5b5c5d5e5f'\
|
||||
'606162636465666768696a6b6c6d6e6f'\
|
||||
'707172737475767778797a7b7c7d7e7f'\
|
||||
'808182838485868788898a8b8c8d8e8f'\
|
||||
'9091929394959697',
|
||||
xl('Sample message for keylen>blocklen'),
|
||||
dict(SHA3_384='e5ae4c739f455279368ebf36d4f5354c95aa184c899d3870e460ebc288ef1f9470053f73f7c6da2a71bcaec38ce7d6ac'),
|
||||
'NIST CSRC Sample #3 (SHA3-384)'
|
||||
),
|
||||
|
||||
# From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-512.pdf
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'\
|
||||
'101112131415161718191a1b1c1d1e1f'\
|
||||
'202122232425262728292a2b2c2d2e2f'\
|
||||
'303132333435363738393a3b3c3d3e3f',
|
||||
xl('Sample message for keylen<blocklen'),
|
||||
dict(SHA3_512='4efd629d6c71bf86162658f29943b1c308ce27cdfa6db0d9c3ce81763f9cbce5f7ebe9868031db1a8f8eb7b6b95e5c5e3f657a8996c86a2f6527e307f0213196'),
|
||||
'NIST CSRC Sample #1 (SHA3-512)'
|
||||
),
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'\
|
||||
'101112131415161718191a1b1c1d1e1f'\
|
||||
'202122232425262728292a2b2c2d2e2f'\
|
||||
'303132333435363738393a3b3c3d3e3f'\
|
||||
'4041424344454647',
|
||||
xl('Sample message for keylen=blocklen'),
|
||||
dict(SHA3_512='544e257ea2a3e5ea19a590e6a24b724ce6327757723fe2751b75bf007d80f6b360744bf1b7a88ea585f9765b47911976d3191cf83c039f5ffab0d29cc9d9b6da'),
|
||||
'NIST CSRC Sample #2 (SHA3-512)'
|
||||
),
|
||||
(
|
||||
'000102030405060708090a0b0c0d0e0f'\
|
||||
'101112131415161718191a1b1c1d1e1f'\
|
||||
'202122232425262728292a2b2c2d2e2f'\
|
||||
'303132333435363738393a3b3c3d3e3f'\
|
||||
'404142434445464748494a4b4c4d4e4f'\
|
||||
'505152535455565758595a5b5c5d5e5f'\
|
||||
'606162636465666768696a6b6c6d6e6f'\
|
||||
'707172737475767778797a7b7c7d7e7f'\
|
||||
'8081828384858687',
|
||||
xl('Sample message for keylen>blocklen'),
|
||||
dict(SHA3_512='5f464f5e5b7848e3885e49b2c385f0694985d0e38966242dc4a5fe3fea4b37d46b65ceced5dcf59438dd840bab22269f0ba7febdb9fcf74602a35666b2a32915'),
|
||||
'NIST CSRC Sample #3 (SHA3-512)'
|
||||
),
|
||||
|
||||
]
|
||||
|
||||
|
||||
class HMAC_Module_and_Instance_Test(unittest.TestCase):
|
||||
"""Test the HMAC construction and verify that it does not
|
||||
matter if you initialize it with a hash module or
|
||||
with an hash instance.
|
||||
|
||||
See https://bugs.launchpad.net/pycrypto/+bug/1209399
|
||||
"""
|
||||
|
||||
def __init__(self, hashmods):
|
||||
"""Initialize the test with a dictionary of hash modules
|
||||
indexed by their names"""
|
||||
|
||||
unittest.TestCase.__init__(self)
|
||||
self.hashmods = hashmods
|
||||
self.description = ""
|
||||
|
||||
def shortDescription(self):
|
||||
return self.description
|
||||
|
||||
def runTest(self):
|
||||
key = b"\x90\x91\x92\x93" * 4
|
||||
payload = b"\x00" * 100
|
||||
|
||||
for hashname, hashmod in self.hashmods.items():
|
||||
if hashmod is None:
|
||||
continue
|
||||
self.description = "Test HMAC in combination with " + hashname
|
||||
one = HMAC.new(key, payload, hashmod).digest()
|
||||
two = HMAC.new(key, payload, hashmod.new()).digest()
|
||||
self.assertEqual(one, two)
|
||||
|
||||
|
||||
class HMAC_None(unittest.TestCase):
|
||||
|
||||
def runTest(self):
|
||||
|
||||
key = b"\x04" * 20
|
||||
one = HMAC.new(key, b"", SHA1).digest()
|
||||
two = HMAC.new(key, None, SHA1).digest()
|
||||
self.assertEqual(one, two)
|
||||
|
||||
|
||||
class ByteArrayTests(unittest.TestCase):
|
||||
|
||||
def runTest(self):
|
||||
|
||||
key = b"0" * 16
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
# Data and key can be a bytearray (during initialization)
|
||||
key_ba = bytearray(key)
|
||||
data_ba = bytearray(data)
|
||||
|
||||
h1 = HMAC.new(key, data)
|
||||
h2 = HMAC.new(key_ba, data_ba)
|
||||
key_ba[:1] = b'\xFF'
|
||||
data_ba[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
# Data can be a bytearray (during operation)
|
||||
key_ba = bytearray(key)
|
||||
data_ba = bytearray(data)
|
||||
|
||||
h1 = HMAC.new(key)
|
||||
h2 = HMAC.new(key)
|
||||
h1.update(data)
|
||||
h2.update(data_ba)
|
||||
data_ba[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
|
||||
class MemoryViewTests(unittest.TestCase):
|
||||
|
||||
def runTest(self):
|
||||
|
||||
key = b"0" * 16
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
def get_mv_ro(data):
|
||||
return memoryview(data)
|
||||
|
||||
def get_mv_rw(data):
|
||||
return memoryview(bytearray(data))
|
||||
|
||||
for get_mv in (get_mv_ro, get_mv_rw):
|
||||
|
||||
# Data and key can be a memoryview (during initialization)
|
||||
key_mv = get_mv(key)
|
||||
data_mv = get_mv(data)
|
||||
|
||||
h1 = HMAC.new(key, data)
|
||||
h2 = HMAC.new(key_mv, data_mv)
|
||||
if not data_mv.readonly:
|
||||
key_mv[:1] = b'\xFF'
|
||||
data_mv[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
# Data can be a memoryview (during operation)
|
||||
data_mv = get_mv(data)
|
||||
|
||||
h1 = HMAC.new(key)
|
||||
h2 = HMAC.new(key)
|
||||
h1.update(data)
|
||||
h2.update(data_mv)
|
||||
if not data_mv.readonly:
|
||||
data_mv[:1] = b'\xFF'
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
global test_data
|
||||
import types
|
||||
from .common import make_mac_tests
|
||||
|
||||
# A test vector contains multiple results, each one for a
|
||||
# different hash algorithm.
|
||||
# Here we expand each test vector into multiple ones,
|
||||
# and add the relevant parameters that will be passed to new()
|
||||
exp_test_data = []
|
||||
for row in test_data:
|
||||
for modname in row[2].keys():
|
||||
t = list(row)
|
||||
t[2] = row[2][modname]
|
||||
t.append(dict(digestmod=globals()[modname]))
|
||||
exp_test_data.append(t)
|
||||
tests = make_mac_tests(HMAC, "HMAC", exp_test_data)
|
||||
tests.append(HMAC_Module_and_Instance_Test(hash_modules))
|
||||
tests.append(HMAC_None())
|
||||
|
||||
tests.append(ByteArrayTests())
|
||||
tests.append(MemoryViewTests())
|
||||
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
346
backend/venv/Lib/site-packages/Crypto/SelfTest/Hash/test_KMAC.py
Normal file
346
backend/venv/Lib/site-packages/Crypto/SelfTest/Hash/test_KMAC.py
Normal file
@@ -0,0 +1,346 @@
|
||||
import unittest
|
||||
from binascii import unhexlify, hexlify
|
||||
|
||||
from Crypto.Util.py3compat import tobytes
|
||||
from Crypto.Util.strxor import strxor_c
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
|
||||
from Crypto.Hash import KMAC128, KMAC256
|
||||
|
||||
|
||||
class KMACTest(unittest.TestCase):
|
||||
|
||||
def new(self, *args, **kwargs):
|
||||
return self.KMAC.new(key=b'X' * (self.minimum_key_bits // 8), *args, **kwargs)
|
||||
|
||||
def test_new_positive(self):
|
||||
|
||||
key = b'X' * 32
|
||||
|
||||
h = self.new()
|
||||
for new_func in self.KMAC.new, h.new:
|
||||
|
||||
for dbytes in range(self.minimum_bytes, 128 + 1):
|
||||
hobj = new_func(key=key, mac_len=dbytes)
|
||||
self.assertEqual(hobj.digest_size, dbytes)
|
||||
|
||||
digest1 = new_func(key=key, data=b"\x90").digest()
|
||||
digest2 = new_func(key=key).update(b"\x90").digest()
|
||||
self.assertEqual(digest1, digest2)
|
||||
|
||||
new_func(data=b"A", key=key, custom=b"g")
|
||||
|
||||
hobj = h.new(key=key)
|
||||
self.assertEqual(hobj.digest_size, self.default_bytes)
|
||||
|
||||
def test_new_negative(self):
|
||||
|
||||
h = self.new()
|
||||
for new_func in self.KMAC.new, h.new:
|
||||
self.assertRaises(ValueError, new_func, key=b'X'*32,
|
||||
mac_len=0)
|
||||
self.assertRaises(ValueError, new_func, key=b'X'*32,
|
||||
mac_len=self.minimum_bytes - 1)
|
||||
self.assertRaises(TypeError, new_func,
|
||||
key=u"string")
|
||||
self.assertRaises(TypeError, new_func,
|
||||
data=u"string")
|
||||
|
||||
def test_default_digest_size(self):
|
||||
digest = self.new(data=b'abc').digest()
|
||||
self.assertEqual(len(digest), self.default_bytes)
|
||||
|
||||
def test_update(self):
|
||||
pieces = [b"\x0A" * 200, b"\x14" * 300]
|
||||
h = self.new()
|
||||
h.update(pieces[0]).update(pieces[1])
|
||||
digest = h.digest()
|
||||
h = self.new()
|
||||
h.update(pieces[0] + pieces[1])
|
||||
self.assertEqual(h.digest(), digest)
|
||||
|
||||
def test_update_negative(self):
|
||||
h = self.new()
|
||||
self.assertRaises(TypeError, h.update, u"string")
|
||||
|
||||
def test_digest(self):
|
||||
h = self.new()
|
||||
digest = h.digest()
|
||||
|
||||
# hexdigest does not change the state
|
||||
self.assertEqual(h.digest(), digest)
|
||||
# digest returns a byte string
|
||||
self.assertTrue(isinstance(digest, type(b"digest")))
|
||||
|
||||
def test_update_after_digest(self):
|
||||
msg = b"rrrrttt"
|
||||
|
||||
# Normally, update() cannot be done after digest()
|
||||
h = self.new(mac_len=32, data=msg[:4])
|
||||
dig1 = h.digest()
|
||||
self.assertRaises(TypeError, h.update, dig1)
|
||||
|
||||
def test_hex_digest(self):
|
||||
mac = self.new()
|
||||
digest = mac.digest()
|
||||
hexdigest = mac.hexdigest()
|
||||
|
||||
# hexdigest is equivalent to digest
|
||||
self.assertEqual(hexlify(digest), tobytes(hexdigest))
|
||||
# hexdigest does not change the state
|
||||
self.assertEqual(mac.hexdigest(), hexdigest)
|
||||
# hexdigest returns a string
|
||||
self.assertTrue(isinstance(hexdigest, type("digest")))
|
||||
|
||||
def test_verify(self):
|
||||
h = self.new()
|
||||
mac = h.digest()
|
||||
h.verify(mac)
|
||||
wrong_mac = strxor_c(mac, 255)
|
||||
self.assertRaises(ValueError, h.verify, wrong_mac)
|
||||
|
||||
def test_hexverify(self):
|
||||
h = self.new()
|
||||
mac = h.hexdigest()
|
||||
h.hexverify(mac)
|
||||
self.assertRaises(ValueError, h.hexverify, "4556")
|
||||
|
||||
def test_oid(self):
|
||||
|
||||
oid = "2.16.840.1.101.3.4.2." + self.oid_variant
|
||||
h = self.new()
|
||||
self.assertEqual(h.oid, oid)
|
||||
|
||||
def test_bytearray(self):
|
||||
|
||||
key = b'0' * 32
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
# Data and key can be a bytearray (during initialization)
|
||||
key_ba = bytearray(key)
|
||||
data_ba = bytearray(data)
|
||||
|
||||
h1 = self.KMAC.new(data=data, key=key)
|
||||
h2 = self.KMAC.new(data=data_ba, key=key_ba)
|
||||
key_ba[:1] = b'\xFF'
|
||||
data_ba[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
# Data can be a bytearray (during operation)
|
||||
data_ba = bytearray(data)
|
||||
|
||||
h1 = self.new()
|
||||
h2 = self.new()
|
||||
h1.update(data)
|
||||
h2.update(data_ba)
|
||||
data_ba[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
def test_memoryview(self):
|
||||
|
||||
key = b'0' * 32
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
def get_mv_ro(data):
|
||||
return memoryview(data)
|
||||
|
||||
def get_mv_rw(data):
|
||||
return memoryview(bytearray(data))
|
||||
|
||||
for get_mv in (get_mv_ro, get_mv_rw):
|
||||
|
||||
# Data and key can be a memoryview (during initialization)
|
||||
key_mv = get_mv(key)
|
||||
data_mv = get_mv(data)
|
||||
|
||||
h1 = self.KMAC.new(data=data, key=key)
|
||||
h2 = self.KMAC.new(data=data_mv, key=key_mv)
|
||||
if not data_mv.readonly:
|
||||
data_mv[:1] = b'\xFF'
|
||||
key_mv[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
# Data can be a memoryview (during operation)
|
||||
data_mv = get_mv(data)
|
||||
|
||||
h1 = self.new()
|
||||
h2 = self.new()
|
||||
h1.update(data)
|
||||
h2.update(data_mv)
|
||||
if not data_mv.readonly:
|
||||
data_mv[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
|
||||
class KMAC128Test(KMACTest):
|
||||
|
||||
KMAC = KMAC128
|
||||
|
||||
minimum_key_bits = 128
|
||||
|
||||
minimum_bytes = 8
|
||||
default_bytes = 64
|
||||
|
||||
oid_variant = "19"
|
||||
|
||||
|
||||
class KMAC256Test(KMACTest):
|
||||
|
||||
KMAC = KMAC256
|
||||
|
||||
minimum_key_bits = 256
|
||||
|
||||
minimum_bytes = 8
|
||||
default_bytes = 64
|
||||
|
||||
oid_variant = "20"
|
||||
|
||||
|
||||
class NISTExampleTestVectors(unittest.TestCase):
|
||||
|
||||
# https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf
|
||||
test_data = [
|
||||
(
|
||||
"40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F"
|
||||
"50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F",
|
||||
"00 01 02 03",
|
||||
"",
|
||||
"E5 78 0B 0D 3E A6 F7 D3 A4 29 C5 70 6A A4 3A 00"
|
||||
"FA DB D7 D4 96 28 83 9E 31 87 24 3F 45 6E E1 4E",
|
||||
"Sample #1 NIST",
|
||||
KMAC128
|
||||
),
|
||||
(
|
||||
"40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F"
|
||||
"50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F",
|
||||
"00 01 02 03",
|
||||
"My Tagged Application",
|
||||
"3B 1F BA 96 3C D8 B0 B5 9E 8C 1A 6D 71 88 8B 71"
|
||||
"43 65 1A F8 BA 0A 70 70 C0 97 9E 28 11 32 4A A5",
|
||||
"Sample #2 NIST",
|
||||
KMAC128
|
||||
),
|
||||
(
|
||||
"40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F"
|
||||
"50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F",
|
||||
"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"
|
||||
"20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F"
|
||||
"30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F"
|
||||
"40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F"
|
||||
"50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F"
|
||||
"60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F"
|
||||
"70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F"
|
||||
"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"
|
||||
"A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF"
|
||||
"B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF"
|
||||
"C0 C1 C2 C3 C4 C5 C6 C7",
|
||||
"My Tagged Application",
|
||||
"1F 5B 4E 6C CA 02 20 9E 0D CB 5C A6 35 B8 9A 15"
|
||||
"E2 71 EC C7 60 07 1D FD 80 5F AA 38 F9 72 92 30",
|
||||
"Sample #3 NIST",
|
||||
KMAC128
|
||||
),
|
||||
(
|
||||
"40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F"
|
||||
"50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F",
|
||||
"00 01 02 03",
|
||||
"My Tagged Application",
|
||||
"20 C5 70 C3 13 46 F7 03 C9 AC 36 C6 1C 03 CB 64"
|
||||
"C3 97 0D 0C FC 78 7E 9B 79 59 9D 27 3A 68 D2 F7"
|
||||
"F6 9D 4C C3 DE 9D 10 4A 35 16 89 F2 7C F6 F5 95"
|
||||
"1F 01 03 F3 3F 4F 24 87 10 24 D9 C2 77 73 A8 DD",
|
||||
"Sample #4 NIST",
|
||||
KMAC256
|
||||
),
|
||||
(
|
||||
"40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F"
|
||||
"50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F",
|
||||
"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"
|
||||
"20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F"
|
||||
"30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F"
|
||||
"40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F"
|
||||
"50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F"
|
||||
"60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F"
|
||||
"70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F"
|
||||
"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"
|
||||
"A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF"
|
||||
"B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF"
|
||||
"C0 C1 C2 C3 C4 C5 C6 C7",
|
||||
"",
|
||||
"75 35 8C F3 9E 41 49 4E 94 97 07 92 7C EE 0A F2"
|
||||
"0A 3F F5 53 90 4C 86 B0 8F 21 CC 41 4B CF D6 91"
|
||||
"58 9D 27 CF 5E 15 36 9C BB FF 8B 9A 4C 2E B1 78"
|
||||
"00 85 5D 02 35 FF 63 5D A8 25 33 EC 6B 75 9B 69",
|
||||
"Sample #5 NIST",
|
||||
KMAC256
|
||||
),
|
||||
(
|
||||
"40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F"
|
||||
"50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F",
|
||||
"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"
|
||||
"20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F"
|
||||
"30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F"
|
||||
"40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F"
|
||||
"50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F"
|
||||
"60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F"
|
||||
"70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F"
|
||||
"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"
|
||||
"A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF"
|
||||
"B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF"
|
||||
"C0 C1 C2 C3 C4 C5 C6 C7",
|
||||
"My Tagged Application",
|
||||
"B5 86 18 F7 1F 92 E1 D5 6C 1B 8C 55 DD D7 CD 18"
|
||||
"8B 97 B4 CA 4D 99 83 1E B2 69 9A 83 7D A2 E4 D9"
|
||||
"70 FB AC FD E5 00 33 AE A5 85 F1 A2 70 85 10 C3"
|
||||
"2D 07 88 08 01 BD 18 28 98 FE 47 68 76 FC 89 65",
|
||||
"Sample #6 NIST",
|
||||
KMAC256
|
||||
),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
td = []
|
||||
for key, data, custom, mac, text, module in self.test_data:
|
||||
ni = (
|
||||
unhexlify(key.replace(" ", "")),
|
||||
unhexlify(data.replace(" ", "")),
|
||||
custom.encode(),
|
||||
unhexlify(mac.replace(" ", "")),
|
||||
text,
|
||||
module
|
||||
)
|
||||
td.append(ni)
|
||||
self.test_data = td
|
||||
|
||||
def runTest(self):
|
||||
|
||||
for key, data, custom, mac, text, module in self.test_data:
|
||||
h = module.new(data=data, key=key, custom=custom, mac_len=len(mac))
|
||||
mac_tag = h.digest()
|
||||
self.assertEqual(mac_tag, mac, msg=text)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
|
||||
tests += list_test_cases(KMAC128Test)
|
||||
tests += list_test_cases(KMAC256Test)
|
||||
tests.append(NISTExampleTestVectors())
|
||||
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def suite():
|
||||
return unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -0,0 +1,324 @@
|
||||
# ===================================================================
|
||||
# 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.
|
||||
# ===================================================================
|
||||
|
||||
"""Self-test suite for Crypto.Hash.KangarooTwelve"""
|
||||
|
||||
import unittest
|
||||
from binascii import unhexlify
|
||||
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
|
||||
from Crypto.Hash import KangarooTwelve as K12
|
||||
from Crypto.Util.py3compat import b, bchr
|
||||
|
||||
|
||||
class KangarooTwelveTest(unittest.TestCase):
|
||||
|
||||
def test_length_encode(self):
|
||||
self.assertEqual(K12._length_encode(0), b'\x00')
|
||||
self.assertEqual(K12._length_encode(12), b'\x0C\x01')
|
||||
self.assertEqual(K12._length_encode(65538), b'\x01\x00\x02\x03')
|
||||
|
||||
def test_new_positive(self):
|
||||
|
||||
xof1 = K12.new()
|
||||
xof2 = K12.new(data=b("90"))
|
||||
xof3 = K12.new().update(b("90"))
|
||||
|
||||
self.assertNotEqual(xof1.read(10), xof2.read(10))
|
||||
xof3.read(10)
|
||||
self.assertEqual(xof2.read(10), xof3.read(10))
|
||||
|
||||
xof1 = K12.new()
|
||||
ref = xof1.read(10)
|
||||
xof2 = K12.new(custom=b(""))
|
||||
xof3 = K12.new(custom=b("foo"))
|
||||
|
||||
self.assertEqual(ref, xof2.read(10))
|
||||
self.assertNotEqual(ref, xof3.read(10))
|
||||
|
||||
xof1 = K12.new(custom=b("foo"))
|
||||
xof2 = K12.new(custom=b("foo"), data=b("90"))
|
||||
xof3 = K12.new(custom=b("foo")).update(b("90"))
|
||||
|
||||
self.assertNotEqual(xof1.read(10), xof2.read(10))
|
||||
xof3.read(10)
|
||||
self.assertEqual(xof2.read(10), xof3.read(10))
|
||||
|
||||
def test_update(self):
|
||||
pieces = [bchr(10) * 200, bchr(20) * 300]
|
||||
h = K12.new()
|
||||
h.update(pieces[0]).update(pieces[1])
|
||||
digest = h.read(10)
|
||||
h = K12.new()
|
||||
h.update(pieces[0] + pieces[1])
|
||||
self.assertEqual(h.read(10), digest)
|
||||
|
||||
def test_update_negative(self):
|
||||
h = K12.new()
|
||||
self.assertRaises(TypeError, h.update, u"string")
|
||||
|
||||
def test_digest(self):
|
||||
h = K12.new()
|
||||
digest = h.read(90)
|
||||
|
||||
# read returns a byte string of the right length
|
||||
self.assertTrue(isinstance(digest, type(b("digest"))))
|
||||
self.assertEqual(len(digest), 90)
|
||||
|
||||
def test_update_after_read(self):
|
||||
mac = K12.new()
|
||||
mac.update(b("rrrr"))
|
||||
mac.read(90)
|
||||
self.assertRaises(TypeError, mac.update, b("ttt"))
|
||||
|
||||
|
||||
def txt2bin(txt):
|
||||
clean = txt.replace(" ", "").replace("\n", "").replace("\r", "")
|
||||
return unhexlify(clean)
|
||||
|
||||
|
||||
def ptn(n):
|
||||
res = bytearray(n)
|
||||
pattern = b"".join([bchr(x) for x in range(0, 0xFB)])
|
||||
for base in range(0, n - 0xFB, 0xFB):
|
||||
res[base:base + 0xFB] = pattern
|
||||
remain = n % 0xFB
|
||||
if remain:
|
||||
base = (n // 0xFB) * 0xFB
|
||||
res[base:] = pattern[:remain]
|
||||
assert(len(res) == n)
|
||||
return res
|
||||
|
||||
|
||||
def chunked(source, size):
|
||||
for i in range(0, len(source), size):
|
||||
yield source[i:i+size]
|
||||
|
||||
|
||||
# https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KangarooTwelve.txt
|
||||
class KangarooTwelveTV(unittest.TestCase):
|
||||
|
||||
def test_zero_1(self):
|
||||
tv = """1A C2 D4 50 FC 3B 42 05 D1 9D A7 BF CA 1B 37 51
|
||||
3C 08 03 57 7A C7 16 7F 06 FE 2C E1 F0 EF 39 E5"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
res = K12.new().read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_zero_2(self):
|
||||
tv = """1A C2 D4 50 FC 3B 42 05 D1 9D A7 BF CA 1B 37 51
|
||||
3C 08 03 57 7A C7 16 7F 06 FE 2C E1 F0 EF 39 E5
|
||||
42 69 C0 56 B8 C8 2E 48 27 60 38 B6 D2 92 96 6C
|
||||
C0 7A 3D 46 45 27 2E 31 FF 38 50 81 39 EB 0A 71"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
res = K12.new().read(64)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_zero_3(self):
|
||||
tv = """E8 DC 56 36 42 F7 22 8C 84 68 4C 89 84 05 D3 A8
|
||||
34 79 91 58 C0 79 B1 28 80 27 7A 1D 28 E2 FF 6D"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
res = K12.new().read(10032)
|
||||
self.assertEqual(res[-32:], btv)
|
||||
|
||||
def test_ptn_1(self):
|
||||
tv = """2B DA 92 45 0E 8B 14 7F 8A 7C B6 29 E7 84 A0 58
|
||||
EF CA 7C F7 D8 21 8E 02 D3 45 DF AA 65 24 4A 1F"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
res = K12.new(data=ptn(1)).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_ptn_17(self):
|
||||
tv = """6B F7 5F A2 23 91 98 DB 47 72 E3 64 78 F8 E1 9B
|
||||
0F 37 12 05 F6 A9 A9 3A 27 3F 51 DF 37 12 28 88"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
res = K12.new(data=ptn(17)).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_ptn_17_2(self):
|
||||
tv = """0C 31 5E BC DE DB F6 14 26 DE 7D CF 8F B7 25 D1
|
||||
E7 46 75 D7 F5 32 7A 50 67 F3 67 B1 08 EC B6 7C"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
res = K12.new(data=ptn(17**2)).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_ptn_17_3(self):
|
||||
tv = """CB 55 2E 2E C7 7D 99 10 70 1D 57 8B 45 7D DF 77
|
||||
2C 12 E3 22 E4 EE 7F E4 17 F9 2C 75 8F 0D 59 D0"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
res = K12.new(data=ptn(17**3)).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_ptn_17_4(self):
|
||||
tv = """87 01 04 5E 22 20 53 45 FF 4D DA 05 55 5C BB 5C
|
||||
3A F1 A7 71 C2 B8 9B AE F3 7D B4 3D 99 98 B9 FE"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
data = ptn(17**4)
|
||||
|
||||
# All at once
|
||||
res = K12.new(data=data).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
# Byte by byte
|
||||
k12 = K12.new()
|
||||
for x in data:
|
||||
k12.update(bchr(x))
|
||||
res = k12.read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
# Chunks of various prime sizes
|
||||
for chunk_size in (13, 17, 19, 23, 31):
|
||||
k12 = K12.new()
|
||||
for x in chunked(data, chunk_size):
|
||||
k12.update(x)
|
||||
res = k12.read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_ptn_17_5(self):
|
||||
tv = """84 4D 61 09 33 B1 B9 96 3C BD EB 5A E3 B6 B0 5C
|
||||
C7 CB D6 7C EE DF 88 3E B6 78 A0 A8 E0 37 16 82"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
data = ptn(17**5)
|
||||
|
||||
# All at once
|
||||
res = K12.new(data=data).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
# Chunks
|
||||
k12 = K12.new()
|
||||
for chunk in chunked(data, 8192):
|
||||
k12.update(chunk)
|
||||
res = k12.read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_ptn_17_6(self):
|
||||
tv = """3C 39 07 82 A8 A4 E8 9F A6 36 7F 72 FE AA F1 32
|
||||
55 C8 D9 58 78 48 1D 3C D8 CE 85 F5 8E 88 0A F8"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
data = ptn(17**6)
|
||||
|
||||
# All at once
|
||||
res = K12.new(data=data).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_ptn_c_1(self):
|
||||
tv = """FA B6 58 DB 63 E9 4A 24 61 88 BF 7A F6 9A 13 30
|
||||
45 F4 6E E9 84 C5 6E 3C 33 28 CA AF 1A A1 A5 83"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
custom = ptn(1)
|
||||
|
||||
# All at once
|
||||
res = K12.new(custom=custom).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_ptn_c_41(self):
|
||||
tv = """D8 48 C5 06 8C ED 73 6F 44 62 15 9B 98 67 FD 4C
|
||||
20 B8 08 AC C3 D5 BC 48 E0 B0 6B A0 A3 76 2E C4"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
custom = ptn(41)
|
||||
|
||||
# All at once
|
||||
res = K12.new(data=b'\xFF', custom=custom).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_ptn_c_41_2(self):
|
||||
tv = """C3 89 E5 00 9A E5 71 20 85 4C 2E 8C 64 67 0A C0
|
||||
13 58 CF 4C 1B AF 89 44 7A 72 42 34 DC 7C ED 74"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
custom = ptn(41**2)
|
||||
|
||||
# All at once
|
||||
res = K12.new(data=b'\xFF' * 3, custom=custom).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_ptn_c_41_3(self):
|
||||
tv = """75 D2 F8 6A 2E 64 45 66 72 6B 4F BC FC 56 57 B9
|
||||
DB CF 07 0C 7B 0D CA 06 45 0A B2 91 D7 44 3B CF"""
|
||||
|
||||
btv = txt2bin(tv)
|
||||
custom = ptn(41**3)
|
||||
|
||||
# All at once
|
||||
res = K12.new(data=b'\xFF' * 7, custom=custom).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
###
|
||||
|
||||
def test_1(self):
|
||||
tv = "fd608f91d81904a9916e78a18f65c157a78d63f93d8f6367db0524526a5ea2bb"
|
||||
|
||||
btv = txt2bin(tv)
|
||||
res = K12.new(data=b'', custom=ptn(100)).read(32)
|
||||
self.assertEqual(res, btv)
|
||||
|
||||
def test_2(self):
|
||||
tv4 = "5a4ec9a649f81916d4ce1553492962f7868abf8dd1ceb2f0cb3682ea95cda6a6"
|
||||
tv3 = "441688fe4fe4ae9425eb3105eb445eb2b3a6f67b66eff8e74ebfbc49371f6d4c"
|
||||
tv2 = "17269a57759af0214c84a0fd9bc851f4d95f80554cfed4e7da8a6ee1ff080131"
|
||||
tv1 = "33826990c09dc712ba7224f0d9be319e2720de95a4c1afbd2211507dae1c703a"
|
||||
tv0 = "9f4d3aba908ddc096e4d3a71da954f917b9752f05052b9d26d916a6fbc75bf3e"
|
||||
|
||||
res = K12.new(data=b'A' * (8192 - 4), custom=b'B').read(32)
|
||||
self.assertEqual(res, txt2bin(tv4))
|
||||
|
||||
res = K12.new(data=b'A' * (8192 - 3), custom=b'B').read(32)
|
||||
self.assertEqual(res, txt2bin(tv3))
|
||||
|
||||
res = K12.new(data=b'A' * (8192 - 2), custom=b'B').read(32)
|
||||
self.assertEqual(res, txt2bin(tv2))
|
||||
|
||||
res = K12.new(data=b'A' * (8192 - 1), custom=b'B').read(32)
|
||||
self.assertEqual(res, txt2bin(tv1))
|
||||
|
||||
res = K12.new(data=b'A' * (8192 - 0), custom=b'B').read(32)
|
||||
self.assertEqual(res, txt2bin(tv0))
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
tests += list_test_cases(KangarooTwelveTest)
|
||||
tests += list_test_cases(KangarooTwelveTV)
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def suite():
|
||||
return unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/MD2.py: Self-test for the MD2 hash function
|
||||
#
|
||||
# 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.Hash.MD2"""
|
||||
|
||||
from Crypto.Util.py3compat import *
|
||||
|
||||
# This is a list of (expected_result, input[, description]) tuples.
|
||||
test_data = [
|
||||
# Test vectors from RFC 1319
|
||||
('8350e5a3e24c153df2275c9f80692773', '', "'' (empty string)"),
|
||||
('32ec01ec4a6dac72c0ab96fb34c0b5d1', 'a'),
|
||||
('da853b0d3f88d99b30283a69e6ded6bb', 'abc'),
|
||||
('ab4f496bfb2a530b219ff33031fe06b0', 'message digest'),
|
||||
|
||||
('4e8ddff3650292ab5a4108c3aa47940b', 'abcdefghijklmnopqrstuvwxyz',
|
||||
'a-z'),
|
||||
|
||||
('da33def2a42df13975352846c30338cd',
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
|
||||
'A-Z, a-z, 0-9'),
|
||||
|
||||
('d5976f79d83d3a0dc9806c3c66f3efd8',
|
||||
'1234567890123456789012345678901234567890123456'
|
||||
+ '7890123456789012345678901234567890',
|
||||
"'1234567890' * 8"),
|
||||
]
|
||||
|
||||
def get_tests(config={}):
|
||||
from Crypto.Hash import MD2
|
||||
from .common import make_hash_tests
|
||||
return make_hash_tests(MD2, "MD2", test_data,
|
||||
digest_size=16,
|
||||
oid="1.2.840.113549.2.2")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||
@@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/MD4.py: Self-test for the MD4 hash function
|
||||
#
|
||||
# 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.Hash.MD4"""
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
from Crypto.Util.py3compat import *
|
||||
|
||||
# This is a list of (expected_result, input[, description]) tuples.
|
||||
test_data = [
|
||||
# Test vectors from RFC 1320
|
||||
('31d6cfe0d16ae931b73c59d7e0c089c0', '', "'' (empty string)"),
|
||||
('bde52cb31de33e46245e05fbdbd6fb24', 'a'),
|
||||
('a448017aaf21d8525fc10ae87aa6729d', 'abc'),
|
||||
('d9130a8164549fe818874806e1c7014b', 'message digest'),
|
||||
|
||||
('d79e1c308aa5bbcdeea8ed63df412da9', 'abcdefghijklmnopqrstuvwxyz',
|
||||
'a-z'),
|
||||
|
||||
('043f8582f241db351ce627e153e7f0e4',
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
|
||||
'A-Z, a-z, 0-9'),
|
||||
|
||||
('e33b4ddc9c38f2199c3e7b164fcc0536',
|
||||
'1234567890123456789012345678901234567890123456'
|
||||
+ '7890123456789012345678901234567890',
|
||||
"'1234567890' * 8"),
|
||||
]
|
||||
|
||||
def get_tests(config={}):
|
||||
from Crypto.Hash import MD4
|
||||
from .common import make_hash_tests
|
||||
return make_hash_tests(MD4, "MD4", test_data,
|
||||
digest_size=16,
|
||||
oid="1.2.840.113549.2.4")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||
@@ -0,0 +1,94 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/MD5.py: Self-test for the MD5 hash function
|
||||
#
|
||||
# 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.Hash.MD5"""
|
||||
|
||||
from Crypto.Util.py3compat import *
|
||||
from Crypto.Hash import MD5
|
||||
from binascii import unhexlify
|
||||
import unittest
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
|
||||
|
||||
# This is a list of (expected_result, input[, description]) tuples.
|
||||
test_data = [
|
||||
# Test vectors from RFC 1321
|
||||
('d41d8cd98f00b204e9800998ecf8427e', '', "'' (empty string)"),
|
||||
('0cc175b9c0f1b6a831c399e269772661', 'a'),
|
||||
('900150983cd24fb0d6963f7d28e17f72', 'abc'),
|
||||
('f96b697d7cb7938d525a2f31aaf161d0', 'message digest'),
|
||||
|
||||
('c3fcd3d76192e4007dfb496cca67e13b', 'abcdefghijklmnopqrstuvwxyz',
|
||||
'a-z'),
|
||||
|
||||
('d174ab98d277d9f5a5611c2c9f419d9f',
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
|
||||
'A-Z, a-z, 0-9'),
|
||||
|
||||
('57edf4a22be3c955ac49da2e2107b67a',
|
||||
'1234567890123456789012345678901234567890123456'
|
||||
+ '7890123456789012345678901234567890',
|
||||
"'1234567890' * 8"),
|
||||
|
||||
# https://www.cosic.esat.kuleuven.be/nessie/testvectors/hash/md5/Md5-128.unverified.test-vectors
|
||||
('57EDF4A22BE3C955AC49DA2E2107B67A', '1234567890' * 8, 'Set 1, vector #7'),
|
||||
('7707D6AE4E027C70EEA2A935C2296F21', 'a'*1000000, 'Set 1, vector #8'),
|
||||
]
|
||||
|
||||
|
||||
class Md5IterTest(unittest.TestCase):
|
||||
|
||||
def runTest(self):
|
||||
message = b("\x00") * 16
|
||||
result1 = "4AE71336E44BF9BF79D2752E234818A5".lower()
|
||||
result2 = "1A83F51285E4D89403D00C46EF8508FE".lower()
|
||||
|
||||
h = MD5.new(message)
|
||||
message = h.digest()
|
||||
self.assertEqual(h.hexdigest(), result1)
|
||||
|
||||
for _ in range(99999):
|
||||
h = MD5.new(message)
|
||||
message = h.digest()
|
||||
|
||||
self.assertEqual(h.hexdigest(), result2)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
from .common import make_hash_tests
|
||||
|
||||
tests = make_hash_tests(MD5, "MD5", test_data,
|
||||
digest_size=16,
|
||||
oid="1.2.840.113549.2.5")
|
||||
if config.get('slow_tests'):
|
||||
tests += [ Md5IterTest() ]
|
||||
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:
|
||||
@@ -0,0 +1,542 @@
|
||||
#
|
||||
# SelfTest/Hash/test_Poly1305.py: Self-test for the Poly1305 module
|
||||
#
|
||||
# ===================================================================
|
||||
#
|
||||
# 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.
|
||||
# ===================================================================
|
||||
|
||||
"""Self-test suite for Crypto.Hash._Poly1305"""
|
||||
|
||||
import json
|
||||
import unittest
|
||||
from binascii import unhexlify, hexlify
|
||||
|
||||
from .common import make_mac_tests
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
|
||||
from Crypto.Hash import Poly1305
|
||||
from Crypto.Cipher import AES, ChaCha20
|
||||
|
||||
from Crypto.Util.py3compat import tobytes
|
||||
from Crypto.Util.strxor import strxor_c
|
||||
|
||||
# This is a list of (r+s keypair, data, result, description, keywords) tuples.
|
||||
test_data_basic = [
|
||||
(
|
||||
"85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b",
|
||||
hexlify(b"Cryptographic Forum Research Group").decode(),
|
||||
"a8061dc1305136c6c22b8baf0c0127a9",
|
||||
"RFC7539"
|
||||
),
|
||||
(
|
||||
"746869732069732033322d62797465206b657920666f7220506f6c7931333035",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"49ec78090e481ec6c26b33b91ccc0307",
|
||||
"https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-00#section-7 A",
|
||||
),
|
||||
(
|
||||
"746869732069732033322d62797465206b657920666f7220506f6c7931333035",
|
||||
"48656c6c6f20776f726c6421",
|
||||
"a6f745008f81c916a20dcc74eef2b2f0",
|
||||
"https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-00#section-7 B",
|
||||
),
|
||||
(
|
||||
"746869732069732033322d62797465206b657920666f7220506f6c7931333035",
|
||||
"",
|
||||
"6b657920666f7220506f6c7931333035",
|
||||
"Generated with pure Python",
|
||||
),
|
||||
(
|
||||
"746869732069732033322d62797465206b657920666f7220506f6c7931333035",
|
||||
"FF",
|
||||
"f7e4e0ef4c46d106219da3d1bdaeb3ff",
|
||||
"Generated with pure Python",
|
||||
),
|
||||
(
|
||||
"746869732069732033322d62797465206b657920666f7220506f6c7931333035",
|
||||
"FF00",
|
||||
"7471eceeb22988fc936da1d6e838b70e",
|
||||
"Generated with pure Python",
|
||||
),
|
||||
(
|
||||
"746869732069732033322d62797465206b657920666f7220506f6c7931333035",
|
||||
"AA" * 17,
|
||||
"32590bc07cb2afaccca3f67f122975fe",
|
||||
"Generated with pure Python",
|
||||
),
|
||||
(
|
||||
"00" * 32,
|
||||
"00" * 64,
|
||||
"00" * 16,
|
||||
"RFC7539 A.3 #1",
|
||||
),
|
||||
(
|
||||
"0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e",
|
||||
hexlify(
|
||||
b"Any submission t"
|
||||
b"o the IETF inten"
|
||||
b"ded by the Contr"
|
||||
b"ibutor for publi"
|
||||
b"cation as all or"
|
||||
b" part of an IETF"
|
||||
b" Internet-Draft "
|
||||
b"or RFC and any s"
|
||||
b"tatement made wi"
|
||||
b"thin the context"
|
||||
b" of an IETF acti"
|
||||
b"vity is consider"
|
||||
b"ed an \"IETF Cont"
|
||||
b"ribution\". Such "
|
||||
b"statements inclu"
|
||||
b"de oral statemen"
|
||||
b"ts in IETF sessi"
|
||||
b"ons, as well as "
|
||||
b"written and elec"
|
||||
b"tronic communica"
|
||||
b"tions made at an"
|
||||
b"y time or place,"
|
||||
b" which are addre"
|
||||
b"ssed to").decode(),
|
||||
"36e5f6b5c5e06070f0efca96227a863e",
|
||||
"RFC7539 A.3 #2",
|
||||
),
|
||||
(
|
||||
"36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000",
|
||||
hexlify(
|
||||
b"Any submission t"
|
||||
b"o the IETF inten"
|
||||
b"ded by the Contr"
|
||||
b"ibutor for publi"
|
||||
b"cation as all or"
|
||||
b" part of an IETF"
|
||||
b" Internet-Draft "
|
||||
b"or RFC and any s"
|
||||
b"tatement made wi"
|
||||
b"thin the context"
|
||||
b" of an IETF acti"
|
||||
b"vity is consider"
|
||||
b"ed an \"IETF Cont"
|
||||
b"ribution\". Such "
|
||||
b"statements inclu"
|
||||
b"de oral statemen"
|
||||
b"ts in IETF sessi"
|
||||
b"ons, as well as "
|
||||
b"written and elec"
|
||||
b"tronic communica"
|
||||
b"tions made at an"
|
||||
b"y time or place,"
|
||||
b" which are addre"
|
||||
b"ssed to").decode(),
|
||||
"f3477e7cd95417af89a6b8794c310cf0",
|
||||
"RFC7539 A.3 #3",
|
||||
),
|
||||
(
|
||||
"1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0",
|
||||
"2754776173206272696c6c69672c2061"
|
||||
"6e642074686520736c6974687920746f"
|
||||
"7665730a446964206779726520616e64"
|
||||
"2067696d626c6520696e207468652077"
|
||||
"6162653a0a416c6c206d696d73792077"
|
||||
"6572652074686520626f726f676f7665"
|
||||
"732c0a416e6420746865206d6f6d6520"
|
||||
"7261746873206f757467726162652e",
|
||||
"4541669a7eaaee61e708dc7cbcc5eb62",
|
||||
"RFC7539 A.3 #4",
|
||||
),
|
||||
(
|
||||
"02" + "00" * 31,
|
||||
"FF" * 16,
|
||||
"03" + "00" * 15,
|
||||
"RFC7539 A.3 #5",
|
||||
),
|
||||
(
|
||||
"02" + "00" * 15 + "FF" * 16,
|
||||
"02" + "00" * 15,
|
||||
"03" + "00" * 15,
|
||||
"RFC7539 A.3 #6",
|
||||
),
|
||||
(
|
||||
"01" + "00" * 31,
|
||||
"FF" * 16 + "F0" + "FF" * 15 + "11" + "00" * 15,
|
||||
"05" + "00" * 15,
|
||||
"RFC7539 A.3 #7",
|
||||
),
|
||||
(
|
||||
"01" + "00" * 31,
|
||||
"FF" * 16 + "FB" + "FE" * 15 + "01" * 16,
|
||||
"00" * 16,
|
||||
"RFC7539 A.3 #8",
|
||||
),
|
||||
(
|
||||
"02" + "00" * 31,
|
||||
"FD" + "FF" * 15,
|
||||
"FA" + "FF" * 15,
|
||||
"RFC7539 A.3 #9",
|
||||
),
|
||||
(
|
||||
"01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00"
|
||||
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
||||
"E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00"
|
||||
"33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00"
|
||||
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
|
||||
"01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
||||
"14 00 00 00 00 00 00 00 55 00 00 00 00 00 00 00",
|
||||
"RFC7539 A.3 #10",
|
||||
),
|
||||
(
|
||||
"01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00"
|
||||
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
||||
"E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00"
|
||||
"33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00"
|
||||
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
|
||||
"13" + "00" * 15,
|
||||
"RFC7539 A.3 #11",
|
||||
),
|
||||
]
|
||||
|
||||
# This is a list of (key(k+r), data, result, description, keywords) tuples.
|
||||
test_data_aes = [
|
||||
(
|
||||
"ec074c835580741701425b623235add6851fc40c3467ac0be05cc20404f3f700",
|
||||
"f3f6",
|
||||
"f4c633c3044fc145f84f335cb81953de",
|
||||
"http://cr.yp.to/mac/poly1305-20050329.pdf",
|
||||
{ 'cipher':AES, 'nonce':unhexlify("fb447350c4e868c52ac3275cf9d4327e") }
|
||||
),
|
||||
(
|
||||
"75deaa25c09f208e1dc4ce6b5cad3fbfa0f3080000f46400d0c7e9076c834403",
|
||||
"",
|
||||
"dd3fab2251f11ac759f0887129cc2ee7",
|
||||
"http://cr.yp.to/mac/poly1305-20050329.pdf",
|
||||
{ 'cipher':AES, 'nonce':unhexlify("61ee09218d29b0aaed7e154a2c5509cc") }
|
||||
),
|
||||
(
|
||||
"6acb5f61a7176dd320c5c1eb2edcdc7448443d0bb0d21109c89a100b5ce2c208",
|
||||
"663cea190ffb83d89593f3f476b6bc24"
|
||||
"d7e679107ea26adb8caf6652d0656136",
|
||||
"0ee1c16bb73f0f4fd19881753c01cdbe",
|
||||
"http://cr.yp.to/mac/poly1305-20050329.pdf",
|
||||
{ 'cipher':AES, 'nonce':unhexlify("ae212a55399729595dea458bc621ff0e") }
|
||||
),
|
||||
(
|
||||
"e1a5668a4d5b66a5f68cc5424ed5982d12976a08c4426d0ce8a82407c4f48207",
|
||||
"ab0812724a7f1e342742cbed374d94d1"
|
||||
"36c6b8795d45b3819830f2c04491faf0"
|
||||
"990c62e48b8018b2c3e4a0fa3134cb67"
|
||||
"fa83e158c994d961c4cb21095c1bf9",
|
||||
"5154ad0d2cb26e01274fc51148491f1b",
|
||||
"http://cr.yp.to/mac/poly1305-20050329.pdf",
|
||||
{ 'cipher':AES, 'nonce':unhexlify("9ae831e743978d3a23527c7128149e3a") }
|
||||
),
|
||||
]
|
||||
|
||||
test_data_chacha20 = [
|
||||
(
|
||||
"00" * 32,
|
||||
"FF" * 15,
|
||||
"13cc5bbadc36b03a5163928f0bcb65aa",
|
||||
"RFC7539 A.4 #1",
|
||||
{ 'cipher':ChaCha20, 'nonce':unhexlify("00" * 12) }
|
||||
),
|
||||
(
|
||||
"00" * 31 + "01",
|
||||
"FF" * 15,
|
||||
"0baf33c1d6df211bdd50a6767e98e00a",
|
||||
"RFC7539 A.4 #2",
|
||||
{ 'cipher':ChaCha20, 'nonce':unhexlify("00" * 11 + "02") }
|
||||
),
|
||||
(
|
||||
"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",
|
||||
"FF" * 15,
|
||||
"e8b4c6db226cd8939e65e02eebf834ce",
|
||||
"RFC7539 A.4 #3",
|
||||
{ 'cipher':ChaCha20, 'nonce':unhexlify("00" * 11 + "02") }
|
||||
),
|
||||
(
|
||||
"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",
|
||||
"f3 33 88 86 00 00 00 00 00 00 4e 91 00 00 00 00"
|
||||
"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 00 00 00 00 00 00 00"
|
||||
"0c 00 00 00 00 00 00 00 09 01 00 00 00 00 00 00",
|
||||
"ee ad 9d 67 89 0c bb 22 39 23 36 fe a1 85 1f 38",
|
||||
"RFC7539 A.5",
|
||||
{ 'cipher':ChaCha20, 'nonce':unhexlify("000000000102030405060708") }
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class Poly1305Test_AES(unittest.TestCase):
|
||||
|
||||
key = b'\x11' * 32
|
||||
|
||||
def test_new_positive(self):
|
||||
|
||||
data = b'r' * 100
|
||||
|
||||
h1 = Poly1305.new(key=self.key, cipher=AES)
|
||||
self.assertEqual(h1.digest_size, 16)
|
||||
self.assertEqual(len(h1.nonce), 16)
|
||||
d1 = h1.update(data).digest()
|
||||
self.assertEqual(len(d1), 16)
|
||||
|
||||
h2 = Poly1305.new(key=self.key, nonce=h1.nonce, data=data, cipher=AES)
|
||||
d2 = h2.digest()
|
||||
self.assertEqual(h1.nonce, h2.nonce)
|
||||
self.assertEqual(d1, d2)
|
||||
|
||||
def test_new_negative(self):
|
||||
from Crypto.Cipher import DES3
|
||||
|
||||
self.assertRaises(ValueError, Poly1305.new, key=self.key[:31], cipher=AES)
|
||||
self.assertRaises(ValueError, Poly1305.new, key=self.key, cipher=DES3)
|
||||
self.assertRaises(ValueError, Poly1305.new, key=self.key, nonce=b'1' * 15, cipher=AES)
|
||||
self.assertRaises(TypeError, Poly1305.new, key=u"2" * 32, cipher=AES)
|
||||
self.assertRaises(TypeError, Poly1305.new, key=self.key, data=u"2" * 100, cipher=AES)
|
||||
|
||||
def test_update(self):
|
||||
pieces = [b"\x0A" * 200, b"\x14" * 300]
|
||||
h1 = Poly1305.new(key=self.key, cipher=AES)
|
||||
h1.update(pieces[0]).update(pieces[1])
|
||||
d1 = h1.digest()
|
||||
|
||||
h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce)
|
||||
h2.update(pieces[0] + pieces[1])
|
||||
d2 = h2.digest()
|
||||
self.assertEqual(d1, d2)
|
||||
|
||||
def test_update_negative(self):
|
||||
h = Poly1305.new(key=self.key, cipher=AES)
|
||||
self.assertRaises(TypeError, h.update, u"string")
|
||||
|
||||
def test_digest(self):
|
||||
h = Poly1305.new(key=self.key, cipher=AES)
|
||||
digest = h.digest()
|
||||
|
||||
# hexdigest does not change the state
|
||||
self.assertEqual(h.digest(), digest)
|
||||
# digest returns a byte string
|
||||
self.assertTrue(isinstance(digest, type(b"digest")))
|
||||
|
||||
def test_update_after_digest(self):
|
||||
msg=b"rrrrttt"
|
||||
|
||||
# Normally, update() cannot be done after digest()
|
||||
h = Poly1305.new(key=self.key, data=msg[:4], cipher=AES)
|
||||
h.digest()
|
||||
self.assertRaises(TypeError, h.update, msg[4:])
|
||||
|
||||
def test_hex_digest(self):
|
||||
mac = Poly1305.new(key=self.key, cipher=AES)
|
||||
digest = mac.digest()
|
||||
hexdigest = mac.hexdigest()
|
||||
|
||||
# hexdigest is equivalent to digest
|
||||
self.assertEqual(hexlify(digest), tobytes(hexdigest))
|
||||
# hexdigest does not change the state
|
||||
self.assertEqual(mac.hexdigest(), hexdigest)
|
||||
# hexdigest returns a string
|
||||
self.assertTrue(isinstance(hexdigest, type("digest")))
|
||||
|
||||
def test_verify(self):
|
||||
h = Poly1305.new(key=self.key, cipher=AES)
|
||||
mac = h.digest()
|
||||
h.verify(mac)
|
||||
wrong_mac = strxor_c(mac, 255)
|
||||
self.assertRaises(ValueError, h.verify, wrong_mac)
|
||||
|
||||
def test_hexverify(self):
|
||||
h = Poly1305.new(key=self.key, cipher=AES)
|
||||
mac = h.hexdigest()
|
||||
h.hexverify(mac)
|
||||
self.assertRaises(ValueError, h.hexverify, "4556")
|
||||
|
||||
def test_bytearray(self):
|
||||
|
||||
data = b"\x00\x01\x02"
|
||||
h0 = Poly1305.new(key=self.key, data=data, cipher=AES)
|
||||
d_ref = h0.digest()
|
||||
|
||||
# Data and key can be a bytearray (during initialization)
|
||||
key_ba = bytearray(self.key)
|
||||
data_ba = bytearray(data)
|
||||
|
||||
h1 = Poly1305.new(key=self.key, data=data, cipher=AES, nonce=h0.nonce)
|
||||
h2 = Poly1305.new(key=key_ba, data=data_ba, cipher=AES, nonce=h0.nonce)
|
||||
key_ba[:1] = b'\xFF'
|
||||
data_ba[:1] = b'\xEE'
|
||||
|
||||
self.assertEqual(h1.digest(), d_ref)
|
||||
self.assertEqual(h2.digest(), d_ref)
|
||||
|
||||
# Data can be a bytearray (during operation)
|
||||
data_ba = bytearray(data)
|
||||
|
||||
h1 = Poly1305.new(key=self.key, cipher=AES)
|
||||
h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce)
|
||||
h1.update(data)
|
||||
h2.update(data_ba)
|
||||
data_ba[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
def test_memoryview(self):
|
||||
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
def get_mv_ro(data):
|
||||
return memoryview(data)
|
||||
|
||||
def get_mv_rw(data):
|
||||
return memoryview(bytearray(data))
|
||||
|
||||
for get_mv in (get_mv_ro, get_mv_rw):
|
||||
|
||||
# Data and key can be a memoryview (during initialization)
|
||||
key_mv = get_mv(self.key)
|
||||
data_mv = get_mv(data)
|
||||
|
||||
h1 = Poly1305.new(key=self.key, data=data, cipher=AES)
|
||||
h2 = Poly1305.new(key=key_mv, data=data_mv, cipher=AES,
|
||||
nonce=h1.nonce)
|
||||
if not data_mv.readonly:
|
||||
data_mv[:1] = b'\xFF'
|
||||
key_mv[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
# Data can be a memoryview (during operation)
|
||||
data_mv = get_mv(data)
|
||||
|
||||
h1 = Poly1305.new(key=self.key, cipher=AES)
|
||||
h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce)
|
||||
h1.update(data)
|
||||
h2.update(data_mv)
|
||||
if not data_mv.readonly:
|
||||
data_mv[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
|
||||
class Poly1305Test_ChaCha20(unittest.TestCase):
|
||||
|
||||
key = b'\x11' * 32
|
||||
|
||||
def test_new_positive(self):
|
||||
data = b'r' * 100
|
||||
|
||||
h1 = Poly1305.new(key=self.key, cipher=ChaCha20)
|
||||
self.assertEqual(h1.digest_size, 16)
|
||||
self.assertEqual(len(h1.nonce), 12)
|
||||
|
||||
h2 = Poly1305.new(key=self.key, cipher=ChaCha20, nonce = b'8' * 8)
|
||||
self.assertEqual(len(h2.nonce), 8)
|
||||
self.assertEqual(h2.nonce, b'8' * 8)
|
||||
|
||||
def test_new_negative(self):
|
||||
|
||||
self.assertRaises(ValueError, Poly1305.new, key=self.key, nonce=b'1' * 7, cipher=ChaCha20)
|
||||
|
||||
|
||||
#
|
||||
# make_mac_tests() expect a new() function with signature new(key, data,
|
||||
# **kwargs), and we need to adapt Poly1305's, as it only uses keywords
|
||||
#
|
||||
class Poly1305_New(object):
|
||||
|
||||
@staticmethod
|
||||
def new(key, *data, **kwds):
|
||||
_kwds = dict(kwds)
|
||||
if len(data) == 1:
|
||||
_kwds['data'] = data[0]
|
||||
_kwds['key'] = key
|
||||
return Poly1305.new(**_kwds)
|
||||
|
||||
|
||||
class Poly1305_Basic(object):
|
||||
|
||||
@staticmethod
|
||||
def new(key, *data, **kwds):
|
||||
from Crypto.Hash.Poly1305 import Poly1305_MAC
|
||||
|
||||
if len(data) == 1:
|
||||
msg = data[0]
|
||||
else:
|
||||
msg = None
|
||||
|
||||
return Poly1305_MAC(key[:16], key[16:], msg)
|
||||
|
||||
|
||||
class Poly1305AES_MC(unittest.TestCase):
|
||||
|
||||
def runTest(self):
|
||||
tag = unhexlify(b"fb447350c4e868c52ac3275cf9d4327e")
|
||||
|
||||
msg = b''
|
||||
for msg_len in range(5000 + 1):
|
||||
key = tag + strxor_c(tag, 0xFF)
|
||||
nonce = tag[::-1]
|
||||
if msg_len > 0:
|
||||
msg = msg + tobytes(tag[0])
|
||||
auth = Poly1305.new(key=key, nonce=nonce, cipher=AES, data=msg)
|
||||
tag = auth.digest()
|
||||
|
||||
# Compare against output of original DJB's poly1305aes-20050218
|
||||
self.assertEqual("CDFA436DDD629C7DC20E1128530BAED2", auth.hexdigest().upper())
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = make_mac_tests(Poly1305_Basic, "Poly1305", test_data_basic)
|
||||
tests += make_mac_tests(Poly1305_New, "Poly1305", test_data_aes)
|
||||
tests += make_mac_tests(Poly1305_New, "Poly1305", test_data_chacha20)
|
||||
tests += [ Poly1305AES_MC() ]
|
||||
tests += list_test_cases(Poly1305Test_AES)
|
||||
tests += list_test_cases(Poly1305Test_ChaCha20)
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -0,0 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/test_RIPEMD160.py: Self-test for the RIPEMD-160 hash function
|
||||
#
|
||||
# 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.Hash.RIPEMD160"""
|
||||
|
||||
from Crypto.Util.py3compat import *
|
||||
|
||||
# This is a list of (expected_result, input[, description]) tuples.
|
||||
test_data = [
|
||||
# Test vectors downloaded 2008-09-12 from
|
||||
# http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
|
||||
('9c1185a5c5e9fc54612808977ee8f548b2258d31', '', "'' (empty string)"),
|
||||
('0bdc9d2d256b3ee9daae347be6f4dc835a467ffe', 'a'),
|
||||
('8eb208f7e05d987a9b044a8e98c6b087f15a0bfc', 'abc'),
|
||||
('5d0689ef49d2fae572b881b123a85ffa21595f36', 'message digest'),
|
||||
|
||||
('f71c27109c692c1b56bbdceb5b9d2865b3708dbc',
|
||||
'abcdefghijklmnopqrstuvwxyz',
|
||||
'a-z'),
|
||||
|
||||
('12a053384a9c0c88e405a06c27dcf49ada62eb2b',
|
||||
'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq',
|
||||
'abcdbcd...pnopq'),
|
||||
|
||||
('b0e20b6e3116640286ed3a87a5713079b21f5189',
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
|
||||
'A-Z, a-z, 0-9'),
|
||||
|
||||
('9b752e45573d4b39f4dbd3323cab82bf63326bfb',
|
||||
'1234567890' * 8,
|
||||
"'1234567890' * 8"),
|
||||
|
||||
('52783243c1697bdbe16d37f97f68f08325dc1528',
|
||||
'a' * 10**6,
|
||||
'"a" * 10**6'),
|
||||
]
|
||||
|
||||
def get_tests(config={}):
|
||||
from Crypto.Hash import RIPEMD160
|
||||
from .common import make_hash_tests
|
||||
return make_hash_tests(RIPEMD160, "RIPEMD160", test_data,
|
||||
digest_size=20,
|
||||
oid="1.3.36.3.2.1")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||
@@ -0,0 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/SHA1.py: Self-test for the SHA-1 hash function
|
||||
#
|
||||
# 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.Hash.SHA"""
|
||||
|
||||
from binascii import hexlify
|
||||
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
|
||||
# Test vectors from various sources
|
||||
# This is a list of (expected_result, input[, description]) tuples.
|
||||
test_data_various = [
|
||||
# FIPS PUB 180-2, A.1 - "One-Block Message"
|
||||
('a9993e364706816aba3e25717850c26c9cd0d89d', 'abc'),
|
||||
|
||||
# FIPS PUB 180-2, A.2 - "Multi-Block Message"
|
||||
('84983e441c3bd26ebaae4aa1f95129e5e54670f1',
|
||||
'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'),
|
||||
|
||||
# FIPS PUB 180-2, A.3 - "Long Message"
|
||||
# ('34aa973cd4c4daa4f61eeb2bdbad27316534016f',
|
||||
# 'a' * 10**6,
|
||||
# '"a" * 10**6'),
|
||||
|
||||
# RFC 3174: Section 7.3, "TEST4" (multiple of 512 bits)
|
||||
('dea356a2cddd90c7a7ecedc5ebb563934f460452',
|
||||
'01234567' * 80,
|
||||
'"01234567" * 80'),
|
||||
]
|
||||
|
||||
def get_tests(config={}):
|
||||
from Crypto.Hash import SHA1
|
||||
from .common import make_hash_tests
|
||||
|
||||
tests = []
|
||||
|
||||
test_vectors = load_test_vectors(("Hash", "SHA1"),
|
||||
"SHA1ShortMsg.rsp",
|
||||
"KAT SHA-1",
|
||||
{ "len" : lambda x: int(x) } ) or []
|
||||
|
||||
test_data = test_data_various[:]
|
||||
for tv in test_vectors:
|
||||
try:
|
||||
if tv.startswith('['):
|
||||
continue
|
||||
except AttributeError:
|
||||
pass
|
||||
if tv.len == 0:
|
||||
tv.msg = b""
|
||||
test_data.append((hexlify(tv.md), tv.msg, tv.desc))
|
||||
|
||||
tests = make_hash_tests(SHA1, "SHA1", test_data,
|
||||
digest_size=20,
|
||||
oid="1.3.14.3.2.26")
|
||||
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:
|
||||
@@ -0,0 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/test_SHA224.py: Self-test for the SHA-224 hash function
|
||||
#
|
||||
# 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.Hash.SHA224"""
|
||||
|
||||
# Test vectors from various sources
|
||||
# This is a list of (expected_result, input[, description]) tuples.
|
||||
test_data = [
|
||||
|
||||
# RFC 3874: Section 3.1, "Test Vector #1
|
||||
('23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7', 'abc'),
|
||||
|
||||
# RFC 3874: Section 3.2, "Test Vector #2
|
||||
('75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525', 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'),
|
||||
|
||||
# RFC 3874: Section 3.3, "Test Vector #3
|
||||
('20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67', 'a' * 10**6, "'a' * 10**6"),
|
||||
|
||||
# Examples from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm
|
||||
('d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f', ''),
|
||||
|
||||
('49b08defa65e644cbf8a2dd9270bdededabc741997d1dadd42026d7b',
|
||||
'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'),
|
||||
|
||||
('58911e7fccf2971a7d07f93162d8bd13568e71aa8fc86fc1fe9043d1',
|
||||
'Frank jagt im komplett verwahrlosten Taxi quer durch Bayern'),
|
||||
|
||||
]
|
||||
|
||||
def get_tests(config={}):
|
||||
from Crypto.Hash import SHA224
|
||||
from .common import make_hash_tests
|
||||
return make_hash_tests(SHA224, "SHA224", test_data,
|
||||
digest_size=28,
|
||||
oid='2.16.840.1.101.3.4.2.4')
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||
@@ -0,0 +1,94 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/test_SHA256.py: Self-test for the SHA-256 hash function
|
||||
#
|
||||
# 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.Hash.SHA256"""
|
||||
|
||||
import unittest
|
||||
from Crypto.Util.py3compat import *
|
||||
|
||||
class LargeSHA256Test(unittest.TestCase):
|
||||
def runTest(self):
|
||||
"""SHA256: 512/520 MiB test"""
|
||||
from Crypto.Hash import SHA256
|
||||
zeros = bchr(0x00) * (1024*1024)
|
||||
|
||||
h = SHA256.new(zeros)
|
||||
for i in range(511):
|
||||
h.update(zeros)
|
||||
|
||||
# This test vector is from PyCrypto's old testdata.py file.
|
||||
self.assertEqual('9acca8e8c22201155389f65abbf6bc9723edc7384ead80503839f49dcc56d767', h.hexdigest()) # 512 MiB
|
||||
|
||||
for i in range(8):
|
||||
h.update(zeros)
|
||||
|
||||
# This test vector is from PyCrypto's old testdata.py file.
|
||||
self.assertEqual('abf51ad954b246009dfe5a50ecd582fd5b8f1b8b27f30393853c3ef721e7fa6e', h.hexdigest()) # 520 MiB
|
||||
|
||||
def get_tests(config={}):
|
||||
# Test vectors from FIPS PUB 180-2
|
||||
# This is a list of (expected_result, input[, description]) tuples.
|
||||
test_data = [
|
||||
# FIPS PUB 180-2, B.1 - "One-Block Message"
|
||||
('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad',
|
||||
'abc'),
|
||||
|
||||
# FIPS PUB 180-2, B.2 - "Multi-Block Message"
|
||||
('248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1',
|
||||
'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'),
|
||||
|
||||
# FIPS PUB 180-2, B.3 - "Long Message"
|
||||
('cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0',
|
||||
'a' * 10**6,
|
||||
'"a" * 10**6'),
|
||||
|
||||
# Test for an old PyCrypto bug.
|
||||
('f7fd017a3c721ce7ff03f3552c0813adcc48b7f33f07e5e2ba71e23ea393d103',
|
||||
'This message is precisely 55 bytes long, to test a bug.',
|
||||
'Length = 55 (mod 64)'),
|
||||
|
||||
# Example from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm
|
||||
('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', ''),
|
||||
|
||||
('d32b568cd1b96d459e7291ebf4b25d007f275c9f13149beeb782fac0716613f8',
|
||||
'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'),
|
||||
]
|
||||
|
||||
from Crypto.Hash import SHA256
|
||||
from .common import make_hash_tests
|
||||
tests = make_hash_tests(SHA256, "SHA256", test_data,
|
||||
digest_size=32,
|
||||
oid="2.16.840.1.101.3.4.2.1")
|
||||
|
||||
if config.get('slow_tests'):
|
||||
tests += [LargeSHA256Test()]
|
||||
|
||||
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:
|
||||
@@ -0,0 +1,61 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/test_SHA.py: Self-test for the SHA-384 hash function
|
||||
#
|
||||
# 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.Hash.SHA384"""
|
||||
|
||||
# Test vectors from various sources
|
||||
# This is a list of (expected_result, input[, description]) tuples.
|
||||
test_data = [
|
||||
|
||||
# RFC 4634: Section Page 8.4, "Test 1"
|
||||
('cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7', 'abc'),
|
||||
|
||||
# RFC 4634: Section Page 8.4, "Test 2.2"
|
||||
('09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'),
|
||||
|
||||
# RFC 4634: Section Page 8.4, "Test 3"
|
||||
('9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985', 'a' * 10**6, "'a' * 10**6"),
|
||||
|
||||
# Taken from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm
|
||||
('38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b', ''),
|
||||
|
||||
# Example from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm
|
||||
('71e8383a4cea32d6fd6877495db2ee353542f46fa44bc23100bca48f3366b84e809f0708e81041f427c6d5219a286677',
|
||||
'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'),
|
||||
|
||||
]
|
||||
|
||||
def get_tests(config={}):
|
||||
from Crypto.Hash import SHA384
|
||||
from .common import make_hash_tests
|
||||
return make_hash_tests(SHA384, "SHA384", test_data,
|
||||
digest_size=48,
|
||||
oid='2.16.840.1.101.3.4.2.2')
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||
@@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/test_SHA3_224.py: Self-test for the SHA-3/224 hash function
|
||||
#
|
||||
# ===================================================================
|
||||
# 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.Hash.SHA3_224"""
|
||||
|
||||
import unittest
|
||||
from binascii import hexlify
|
||||
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
from Crypto.Hash import SHA3_224 as SHA3
|
||||
from Crypto.Util.py3compat import b
|
||||
|
||||
|
||||
class APITest(unittest.TestCase):
|
||||
|
||||
def test_update_after_digest(self):
|
||||
msg=b("rrrrttt")
|
||||
|
||||
# Normally, update() cannot be done after digest()
|
||||
h = SHA3.new(data=msg[:4])
|
||||
dig1 = h.digest()
|
||||
self.assertRaises(TypeError, h.update, msg[4:])
|
||||
dig2 = SHA3.new(data=msg).digest()
|
||||
|
||||
# With the proper flag, it is allowed
|
||||
h = SHA3.new(data=msg[:4], update_after_digest=True)
|
||||
self.assertEqual(h.digest(), dig1)
|
||||
# ... and the subsequent digest applies to the entire message
|
||||
# up to that point
|
||||
h.update(msg[4:])
|
||||
self.assertEqual(h.digest(), dig2)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
from .common import make_hash_tests
|
||||
|
||||
tests = []
|
||||
|
||||
test_vectors = load_test_vectors(("Hash", "SHA3"),
|
||||
"ShortMsgKAT_SHA3-224.txt",
|
||||
"KAT SHA-3 224",
|
||||
{ "len" : lambda x: int(x) } ) or []
|
||||
|
||||
test_data = []
|
||||
for tv in test_vectors:
|
||||
if tv.len == 0:
|
||||
tv.msg = b("")
|
||||
test_data.append((hexlify(tv.md), tv.msg, tv.desc))
|
||||
|
||||
tests += make_hash_tests(SHA3, "SHA3_224", test_data,
|
||||
digest_size=SHA3.digest_size,
|
||||
oid="2.16.840.1.101.3.4.2.7")
|
||||
tests += list_test_cases(APITest)
|
||||
return tests
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -0,0 +1,80 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/test_SHA3_256.py: Self-test for the SHA-3/256 hash function
|
||||
#
|
||||
# ===================================================================
|
||||
# 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.Hash.SHA3_256"""
|
||||
|
||||
import unittest
|
||||
from binascii import hexlify
|
||||
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
from Crypto.Hash import SHA3_256 as SHA3
|
||||
from Crypto.Util.py3compat import b
|
||||
|
||||
|
||||
class APITest(unittest.TestCase):
|
||||
|
||||
def test_update_after_digest(self):
|
||||
msg=b("rrrrttt")
|
||||
|
||||
# Normally, update() cannot be done after digest()
|
||||
h = SHA3.new(data=msg[:4])
|
||||
dig1 = h.digest()
|
||||
self.assertRaises(TypeError, h.update, msg[4:])
|
||||
dig2 = SHA3.new(data=msg).digest()
|
||||
|
||||
# With the proper flag, it is allowed
|
||||
h = SHA3.new(data=msg[:4], update_after_digest=True)
|
||||
self.assertEqual(h.digest(), dig1)
|
||||
# ... and the subsequent digest applies to the entire message
|
||||
# up to that point
|
||||
h.update(msg[4:])
|
||||
self.assertEqual(h.digest(), dig2)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
from .common import make_hash_tests
|
||||
|
||||
tests = []
|
||||
|
||||
test_vectors = load_test_vectors(("Hash", "SHA3"),
|
||||
"ShortMsgKAT_SHA3-256.txt",
|
||||
"KAT SHA-3 256",
|
||||
{ "len" : lambda x: int(x) } ) or []
|
||||
|
||||
test_data = []
|
||||
for tv in test_vectors:
|
||||
if tv.len == 0:
|
||||
tv.msg = b("")
|
||||
test_data.append((hexlify(tv.md), tv.msg, tv.desc))
|
||||
|
||||
|
||||
tests += make_hash_tests(SHA3, "SHA3_256", test_data,
|
||||
digest_size=SHA3.digest_size,
|
||||
oid="2.16.840.1.101.3.4.2.8")
|
||||
tests += list_test_cases(APITest)
|
||||
return tests
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/test_SHA3_384.py: Self-test for the SHA-3/384 hash function
|
||||
#
|
||||
# ===================================================================
|
||||
# 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.Hash.SHA3_384"""
|
||||
|
||||
import unittest
|
||||
from binascii import hexlify
|
||||
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
from Crypto.Hash import SHA3_384 as SHA3
|
||||
from Crypto.Util.py3compat import b
|
||||
|
||||
|
||||
class APITest(unittest.TestCase):
|
||||
|
||||
def test_update_after_digest(self):
|
||||
msg=b("rrrrttt")
|
||||
|
||||
# Normally, update() cannot be done after digest()
|
||||
h = SHA3.new(data=msg[:4])
|
||||
dig1 = h.digest()
|
||||
self.assertRaises(TypeError, h.update, msg[4:])
|
||||
dig2 = SHA3.new(data=msg).digest()
|
||||
|
||||
# With the proper flag, it is allowed
|
||||
h = SHA3.new(data=msg[:4], update_after_digest=True)
|
||||
self.assertEqual(h.digest(), dig1)
|
||||
# ... and the subsequent digest applies to the entire message
|
||||
# up to that point
|
||||
h.update(msg[4:])
|
||||
self.assertEqual(h.digest(), dig2)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
from .common import make_hash_tests
|
||||
|
||||
tests = []
|
||||
|
||||
test_vectors = load_test_vectors(("Hash", "SHA3"),
|
||||
"ShortMsgKAT_SHA3-384.txt",
|
||||
"KAT SHA-3 384",
|
||||
{ "len" : lambda x: int(x) } ) or []
|
||||
|
||||
test_data = []
|
||||
for tv in test_vectors:
|
||||
if tv.len == 0:
|
||||
tv.msg = b("")
|
||||
test_data.append((hexlify(tv.md), tv.msg, tv.desc))
|
||||
|
||||
tests += make_hash_tests(SHA3, "SHA3_384", test_data,
|
||||
digest_size=SHA3.digest_size,
|
||||
oid="2.16.840.1.101.3.4.2.9")
|
||||
tests += list_test_cases(APITest)
|
||||
return tests
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/test_SHA3_512.py: Self-test for the SHA-3/512 hash function
|
||||
#
|
||||
# ===================================================================
|
||||
# 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.Hash.SHA3_512"""
|
||||
|
||||
import unittest
|
||||
from binascii import hexlify
|
||||
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
from Crypto.Hash import SHA3_512 as SHA3
|
||||
from Crypto.Util.py3compat import b
|
||||
|
||||
|
||||
class APITest(unittest.TestCase):
|
||||
|
||||
def test_update_after_digest(self):
|
||||
msg=b("rrrrttt")
|
||||
|
||||
# Normally, update() cannot be done after digest()
|
||||
h = SHA3.new(data=msg[:4])
|
||||
dig1 = h.digest()
|
||||
self.assertRaises(TypeError, h.update, msg[4:])
|
||||
dig2 = SHA3.new(data=msg).digest()
|
||||
|
||||
# With the proper flag, it is allowed
|
||||
h = SHA3.new(data=msg[:4], update_after_digest=True)
|
||||
self.assertEqual(h.digest(), dig1)
|
||||
# ... and the subsequent digest applies to the entire message
|
||||
# up to that point
|
||||
h.update(msg[4:])
|
||||
self.assertEqual(h.digest(), dig2)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
from .common import make_hash_tests
|
||||
|
||||
tests = []
|
||||
|
||||
test_vectors = load_test_vectors(("Hash", "SHA3"),
|
||||
"ShortMsgKAT_SHA3-512.txt",
|
||||
"KAT SHA-3 512",
|
||||
{ "len" : lambda x: int(x) } ) or []
|
||||
|
||||
test_data = []
|
||||
for tv in test_vectors:
|
||||
if tv.len == 0:
|
||||
tv.msg = b("")
|
||||
test_data.append((hexlify(tv.md), tv.msg, tv.desc))
|
||||
|
||||
tests += make_hash_tests(SHA3, "SHA3_512", test_data,
|
||||
digest_size=SHA3.digest_size,
|
||||
oid="2.16.840.1.101.3.4.2.10")
|
||||
tests += list_test_cases(APITest)
|
||||
return tests
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -0,0 +1,140 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# SelfTest/Hash/test_SHA512.py: Self-test for the SHA-512 hash function
|
||||
#
|
||||
# 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.Hash.SHA512"""
|
||||
|
||||
from binascii import hexlify
|
||||
|
||||
from Crypto.Hash import SHA512
|
||||
from .common import make_hash_tests
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
|
||||
# Test vectors from various sources
|
||||
# This is a list of (expected_result, input[, description]) tuples.
|
||||
test_data_512_other = [
|
||||
|
||||
# RFC 4634: Section Page 8.4, "Test 1"
|
||||
('ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f', 'abc'),
|
||||
|
||||
# RFC 4634: Section Page 8.4, "Test 2.1"
|
||||
('8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'),
|
||||
|
||||
# RFC 4634: Section Page 8.4, "Test 3"
|
||||
('e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b', 'a' * 10**6, "'a' * 10**6"),
|
||||
|
||||
# Taken from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm
|
||||
('cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', ''),
|
||||
|
||||
('af9ed2de700433b803240a552b41b5a472a6ef3fe1431a722b2063c75e9f07451f67a28e37d09cde769424c96aea6f8971389db9e1993d6c565c3c71b855723c', 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'),
|
||||
]
|
||||
|
||||
|
||||
def get_tests_SHA512():
|
||||
|
||||
test_vectors = load_test_vectors(("Hash", "SHA2"),
|
||||
"SHA512ShortMsg.rsp",
|
||||
"KAT SHA-512",
|
||||
{"len": lambda x: int(x)}) or []
|
||||
|
||||
test_data = test_data_512_other[:]
|
||||
for tv in test_vectors:
|
||||
try:
|
||||
if tv.startswith('['):
|
||||
continue
|
||||
except AttributeError:
|
||||
pass
|
||||
if tv.len == 0:
|
||||
tv.msg = b""
|
||||
test_data.append((hexlify(tv.md), tv.msg, tv.desc))
|
||||
|
||||
tests = make_hash_tests(SHA512, "SHA512", test_data,
|
||||
digest_size=64,
|
||||
oid="2.16.840.1.101.3.4.2.3")
|
||||
return tests
|
||||
|
||||
|
||||
def get_tests_SHA512_224():
|
||||
|
||||
test_vectors = load_test_vectors(("Hash", "SHA2"),
|
||||
"SHA512_224ShortMsg.rsp",
|
||||
"KAT SHA-512/224",
|
||||
{"len": lambda x: int(x)}) or []
|
||||
|
||||
test_data = []
|
||||
for tv in test_vectors:
|
||||
try:
|
||||
if tv.startswith('['):
|
||||
continue
|
||||
except AttributeError:
|
||||
pass
|
||||
if tv.len == 0:
|
||||
tv.msg = b""
|
||||
test_data.append((hexlify(tv.md), tv.msg, tv.desc))
|
||||
|
||||
tests = make_hash_tests(SHA512, "SHA512/224", test_data,
|
||||
digest_size=28,
|
||||
oid="2.16.840.1.101.3.4.2.5",
|
||||
extra_params={ "truncate" : "224" })
|
||||
return tests
|
||||
|
||||
|
||||
def get_tests_SHA512_256():
|
||||
|
||||
test_vectors = load_test_vectors(("Hash", "SHA2"),
|
||||
"SHA512_256ShortMsg.rsp",
|
||||
"KAT SHA-512/256",
|
||||
{"len": lambda x: int(x)}) or []
|
||||
|
||||
test_data = []
|
||||
for tv in test_vectors:
|
||||
try:
|
||||
if tv.startswith('['):
|
||||
continue
|
||||
except AttributeError:
|
||||
pass
|
||||
if tv.len == 0:
|
||||
tv.msg = b""
|
||||
test_data.append((hexlify(tv.md), tv.msg, tv.desc))
|
||||
|
||||
tests = make_hash_tests(SHA512, "SHA512/256", test_data,
|
||||
digest_size=32,
|
||||
oid="2.16.840.1.101.3.4.2.6",
|
||||
extra_params={ "truncate" : "256" })
|
||||
return tests
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
|
||||
tests = []
|
||||
tests += get_tests_SHA512()
|
||||
tests += get_tests_SHA512_224()
|
||||
tests += get_tests_SHA512_256()
|
||||
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:
|
||||
@@ -0,0 +1,143 @@
|
||||
# ===================================================================
|
||||
#
|
||||
# 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.
|
||||
# ===================================================================
|
||||
|
||||
"""Self-test suite for Crypto.Hash.SHAKE128 and SHAKE256"""
|
||||
|
||||
import unittest
|
||||
from binascii import hexlify, unhexlify
|
||||
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
|
||||
from Crypto.Hash import SHAKE128, SHAKE256
|
||||
from Crypto.Util.py3compat import b, bchr, bord, tobytes
|
||||
|
||||
class SHAKETest(unittest.TestCase):
|
||||
|
||||
def test_new_positive(self):
|
||||
|
||||
xof1 = self.shake.new()
|
||||
xof2 = self.shake.new(data=b("90"))
|
||||
xof3 = self.shake.new().update(b("90"))
|
||||
|
||||
self.assertNotEqual(xof1.read(10), xof2.read(10))
|
||||
xof3.read(10)
|
||||
self.assertEqual(xof2.read(10), xof3.read(10))
|
||||
|
||||
def test_update(self):
|
||||
pieces = [bchr(10) * 200, bchr(20) * 300]
|
||||
h = self.shake.new()
|
||||
h.update(pieces[0]).update(pieces[1])
|
||||
digest = h.read(10)
|
||||
h = self.shake.new()
|
||||
h.update(pieces[0] + pieces[1])
|
||||
self.assertEqual(h.read(10), digest)
|
||||
|
||||
def test_update_negative(self):
|
||||
h = self.shake.new()
|
||||
self.assertRaises(TypeError, h.update, u"string")
|
||||
|
||||
def test_digest(self):
|
||||
h = self.shake.new()
|
||||
digest = h.read(90)
|
||||
|
||||
# read returns a byte string of the right length
|
||||
self.assertTrue(isinstance(digest, type(b("digest"))))
|
||||
self.assertEqual(len(digest), 90)
|
||||
|
||||
def test_update_after_read(self):
|
||||
mac = self.shake.new()
|
||||
mac.update(b("rrrr"))
|
||||
mac.read(90)
|
||||
self.assertRaises(TypeError, mac.update, b("ttt"))
|
||||
|
||||
|
||||
class SHAKE128Test(SHAKETest):
|
||||
shake = SHAKE128
|
||||
|
||||
|
||||
class SHAKE256Test(SHAKETest):
|
||||
shake = SHAKE256
|
||||
|
||||
|
||||
class SHAKEVectors(unittest.TestCase):
|
||||
pass
|
||||
|
||||
|
||||
test_vectors_128 = load_test_vectors(("Hash", "SHA3"),
|
||||
"ShortMsgKAT_SHAKE128.txt",
|
||||
"Short Messages KAT SHAKE128",
|
||||
{ "len" : lambda x: int(x) } ) or []
|
||||
|
||||
for idx, tv in enumerate(test_vectors_128):
|
||||
if tv.len == 0:
|
||||
data = b("")
|
||||
else:
|
||||
data = tobytes(tv.msg)
|
||||
|
||||
def new_test(self, data=data, result=tv.md):
|
||||
hobj = SHAKE128.new(data=data)
|
||||
digest = hobj.read(len(result))
|
||||
self.assertEqual(digest, result)
|
||||
|
||||
setattr(SHAKEVectors, "test_128_%d" % idx, new_test)
|
||||
|
||||
|
||||
test_vectors_256 = load_test_vectors(("Hash", "SHA3"),
|
||||
"ShortMsgKAT_SHAKE256.txt",
|
||||
"Short Messages KAT SHAKE256",
|
||||
{ "len" : lambda x: int(x) } ) or []
|
||||
|
||||
for idx, tv in enumerate(test_vectors_256):
|
||||
if tv.len == 0:
|
||||
data = b("")
|
||||
else:
|
||||
data = tobytes(tv.msg)
|
||||
|
||||
def new_test(self, data=data, result=tv.md):
|
||||
hobj = SHAKE256.new(data=data)
|
||||
digest = hobj.read(len(result))
|
||||
self.assertEqual(digest, result)
|
||||
|
||||
setattr(SHAKEVectors, "test_256_%d" % idx, new_test)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
tests += list_test_cases(SHAKE128Test)
|
||||
tests += list_test_cases(SHAKE256Test)
|
||||
tests += list_test_cases(SHAKEVectors)
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -0,0 +1,293 @@
|
||||
import unittest
|
||||
from binascii import unhexlify, hexlify
|
||||
|
||||
from Crypto.Util.py3compat import tobytes
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
|
||||
from Crypto.Hash import TupleHash128, TupleHash256
|
||||
|
||||
|
||||
class TupleHashTest(unittest.TestCase):
|
||||
|
||||
def new(self, *args, **kwargs):
|
||||
return self.TupleHash.new(*args, **kwargs)
|
||||
|
||||
def test_new_positive(self):
|
||||
|
||||
h = self.new()
|
||||
for new_func in self.TupleHash.new, h.new:
|
||||
|
||||
for dbits in range(64, 1024 + 1, 8):
|
||||
hobj = new_func(digest_bits=dbits)
|
||||
self.assertEqual(hobj.digest_size * 8, dbits)
|
||||
|
||||
for dbytes in range(8, 128 + 1):
|
||||
hobj = new_func(digest_bytes=dbytes)
|
||||
self.assertEqual(hobj.digest_size, dbytes)
|
||||
|
||||
hobj = h.new()
|
||||
self.assertEqual(hobj.digest_size, self.default_bytes)
|
||||
|
||||
def test_new_negative(self):
|
||||
|
||||
h = self.new()
|
||||
for new_func in self.TupleHash.new, h.new:
|
||||
self.assertRaises(TypeError, new_func,
|
||||
digest_bytes=self.minimum_bytes,
|
||||
digest_bits=self.minimum_bits)
|
||||
self.assertRaises(ValueError, new_func, digest_bytes=0)
|
||||
self.assertRaises(ValueError, new_func,
|
||||
digest_bits=self.minimum_bits + 7)
|
||||
self.assertRaises(ValueError, new_func,
|
||||
digest_bits=self.minimum_bits - 8)
|
||||
self.assertRaises(ValueError, new_func,
|
||||
digest_bits=self.minimum_bytes - 1)
|
||||
|
||||
def test_default_digest_size(self):
|
||||
digest = self.new().digest()
|
||||
self.assertEqual(len(digest), self.default_bytes)
|
||||
|
||||
def test_update(self):
|
||||
h = self.new()
|
||||
h.update(b'')
|
||||
h.digest()
|
||||
|
||||
h = self.new()
|
||||
h.update(b'')
|
||||
h.update(b'STRING1')
|
||||
h.update(b'STRING2')
|
||||
mac1 = h.digest()
|
||||
|
||||
h = self.new()
|
||||
h.update(b'STRING1')
|
||||
h.update(b'STRING2')
|
||||
mac2 = h.digest()
|
||||
|
||||
self.assertNotEqual(mac1, mac2)
|
||||
|
||||
def test_update_negative(self):
|
||||
h = self.new()
|
||||
self.assertRaises(TypeError, h.update, u"string")
|
||||
self.assertRaises(TypeError, h.update, None)
|
||||
|
||||
def test_digest(self):
|
||||
h = self.new()
|
||||
digest = h.digest()
|
||||
|
||||
# hexdigest does not change the state
|
||||
self.assertEqual(h.digest(), digest)
|
||||
# digest returns a byte string
|
||||
self.assertTrue(isinstance(digest, type(b"digest")))
|
||||
|
||||
def test_update_after_digest(self):
|
||||
msg = b"rrrrttt"
|
||||
|
||||
# Normally, update() cannot be done after digest()
|
||||
h = self.new()
|
||||
h.update(msg)
|
||||
dig1 = h.digest()
|
||||
self.assertRaises(TypeError, h.update, dig1)
|
||||
|
||||
def test_hex_digest(self):
|
||||
mac = self.new()
|
||||
digest = mac.digest()
|
||||
hexdigest = mac.hexdigest()
|
||||
|
||||
# hexdigest is equivalent to digest
|
||||
self.assertEqual(hexlify(digest), tobytes(hexdigest))
|
||||
# hexdigest does not change the state
|
||||
self.assertEqual(mac.hexdigest(), hexdigest)
|
||||
# hexdigest returns a string
|
||||
self.assertTrue(isinstance(hexdigest, type("digest")))
|
||||
|
||||
def test_bytearray(self):
|
||||
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
# Data can be a bytearray (during operation)
|
||||
data_ba = bytearray(data)
|
||||
|
||||
h1 = self.new()
|
||||
h2 = self.new()
|
||||
h1.update(data)
|
||||
h2.update(data_ba)
|
||||
data_ba[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
def test_memoryview(self):
|
||||
|
||||
data = b"\x00\x01\x02"
|
||||
|
||||
def get_mv_ro(data):
|
||||
return memoryview(data)
|
||||
|
||||
def get_mv_rw(data):
|
||||
return memoryview(bytearray(data))
|
||||
|
||||
for get_mv in (get_mv_ro, get_mv_rw):
|
||||
|
||||
# Data can be a memoryview (during operation)
|
||||
data_mv = get_mv(data)
|
||||
|
||||
h1 = self.new()
|
||||
h2 = self.new()
|
||||
h1.update(data)
|
||||
h2.update(data_mv)
|
||||
if not data_mv.readonly:
|
||||
data_mv[:1] = b'\xFF'
|
||||
|
||||
self.assertEqual(h1.digest(), h2.digest())
|
||||
|
||||
|
||||
class TupleHash128Test(TupleHashTest):
|
||||
|
||||
TupleHash = TupleHash128
|
||||
|
||||
minimum_bytes = 8
|
||||
default_bytes = 64
|
||||
|
||||
minimum_bits = 64
|
||||
default_bits = 512
|
||||
|
||||
|
||||
class TupleHash256Test(TupleHashTest):
|
||||
|
||||
TupleHash = TupleHash256
|
||||
|
||||
minimum_bytes = 8
|
||||
default_bytes = 64
|
||||
|
||||
minimum_bits = 64
|
||||
default_bits = 512
|
||||
|
||||
|
||||
class NISTExampleTestVectors(unittest.TestCase):
|
||||
|
||||
# http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/TupleHash_samples.pdf
|
||||
test_data = [
|
||||
(
|
||||
(
|
||||
"00 01 02",
|
||||
"10 11 12 13 14 15",
|
||||
),
|
||||
"",
|
||||
"C5 D8 78 6C 1A FB 9B 82 11 1A B3 4B 65 B2 C0 04"
|
||||
"8F A6 4E 6D 48 E2 63 26 4C E1 70 7D 3F FC 8E D1",
|
||||
"KMAC128 Sample #1 NIST",
|
||||
TupleHash128
|
||||
),
|
||||
(
|
||||
(
|
||||
"00 01 02",
|
||||
"10 11 12 13 14 15",
|
||||
),
|
||||
"My Tuple App",
|
||||
"75 CD B2 0F F4 DB 11 54 E8 41 D7 58 E2 41 60 C5"
|
||||
"4B AE 86 EB 8C 13 E7 F5 F4 0E B3 55 88 E9 6D FB",
|
||||
"KMAC128 Sample #2 NIST",
|
||||
TupleHash128
|
||||
),
|
||||
(
|
||||
(
|
||||
"00 01 02",
|
||||
"10 11 12 13 14 15",
|
||||
"20 21 22 23 24 25 26 27 28",
|
||||
),
|
||||
"My Tuple App",
|
||||
"E6 0F 20 2C 89 A2 63 1E DA 8D 4C 58 8C A5 FD 07"
|
||||
"F3 9E 51 51 99 8D EC CF 97 3A DB 38 04 BB 6E 84",
|
||||
"KMAC128 Sample #3 NIST",
|
||||
TupleHash128
|
||||
),
|
||||
(
|
||||
(
|
||||
"00 01 02",
|
||||
"10 11 12 13 14 15",
|
||||
),
|
||||
"",
|
||||
"CF B7 05 8C AC A5 E6 68 F8 1A 12 A2 0A 21 95 CE"
|
||||
"97 A9 25 F1 DB A3 E7 44 9A 56 F8 22 01 EC 60 73"
|
||||
"11 AC 26 96 B1 AB 5E A2 35 2D F1 42 3B DE 7B D4"
|
||||
"BB 78 C9 AE D1 A8 53 C7 86 72 F9 EB 23 BB E1 94",
|
||||
"KMAC256 Sample #4 NIST",
|
||||
TupleHash256
|
||||
),
|
||||
(
|
||||
(
|
||||
"00 01 02",
|
||||
"10 11 12 13 14 15",
|
||||
),
|
||||
"My Tuple App",
|
||||
"14 7C 21 91 D5 ED 7E FD 98 DB D9 6D 7A B5 A1 16"
|
||||
"92 57 6F 5F E2 A5 06 5F 3E 33 DE 6B BA 9F 3A A1"
|
||||
"C4 E9 A0 68 A2 89 C6 1C 95 AA B3 0A EE 1E 41 0B"
|
||||
"0B 60 7D E3 62 0E 24 A4 E3 BF 98 52 A1 D4 36 7E",
|
||||
"KMAC256 Sample #5 NIST",
|
||||
TupleHash256
|
||||
),
|
||||
(
|
||||
(
|
||||
"00 01 02",
|
||||
"10 11 12 13 14 15",
|
||||
"20 21 22 23 24 25 26 27 28",
|
||||
),
|
||||
"My Tuple App",
|
||||
"45 00 0B E6 3F 9B 6B FD 89 F5 47 17 67 0F 69 A9"
|
||||
"BC 76 35 91 A4 F0 5C 50 D6 88 91 A7 44 BC C6 E7"
|
||||
"D6 D5 B5 E8 2C 01 8D A9 99 ED 35 B0 BB 49 C9 67"
|
||||
"8E 52 6A BD 8E 85 C1 3E D2 54 02 1D B9 E7 90 CE",
|
||||
"KMAC256 Sample #6 NIST",
|
||||
TupleHash256
|
||||
),
|
||||
|
||||
|
||||
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
td = []
|
||||
for tv_in in self.test_data:
|
||||
tv_out = [None] * len(tv_in)
|
||||
|
||||
tv_out[0] = []
|
||||
for string in tv_in[0]:
|
||||
tv_out[0].append(unhexlify(string.replace(" ", "")))
|
||||
|
||||
tv_out[1] = tobytes(tv_in[1]) # Custom
|
||||
tv_out[2] = unhexlify(tv_in[2].replace(" ", ""))
|
||||
tv_out[3] = tv_in[3]
|
||||
tv_out[4] = tv_in[4]
|
||||
td.append(tv_out)
|
||||
self.test_data = td
|
||||
|
||||
def runTest(self):
|
||||
|
||||
for data, custom, digest, text, module in self.test_data:
|
||||
hd1 = module.new(custom=custom, digest_bytes=len(digest))
|
||||
hd2 = module.new(custom=custom, digest_bytes=len(digest))
|
||||
|
||||
# Call update() for each element
|
||||
for string in data:
|
||||
hd1.update(string)
|
||||
|
||||
# One single update for all elements
|
||||
hd2.update(*data)
|
||||
|
||||
self.assertEqual(hd1.digest(), digest, msg=text)
|
||||
self.assertEqual(hd2.digest(), digest, msg=text)
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
|
||||
tests += list_test_cases(TupleHash128Test)
|
||||
tests += list_test_cases(TupleHash256Test)
|
||||
tests.append(NISTExampleTestVectors())
|
||||
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def suite():
|
||||
return unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -0,0 +1,178 @@
|
||||
# ===================================================================
|
||||
# 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.
|
||||
# ===================================================================
|
||||
|
||||
"""Self-test suite for Crypto.Hash.cSHAKE128 and cSHAKE256"""
|
||||
|
||||
import unittest
|
||||
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
|
||||
from Crypto.Hash import cSHAKE128, cSHAKE256, SHAKE128, SHAKE256
|
||||
from Crypto.Util.py3compat import b, bchr, tobytes
|
||||
|
||||
|
||||
class cSHAKETest(unittest.TestCase):
|
||||
|
||||
def test_left_encode(self):
|
||||
from Crypto.Hash.cSHAKE128 import _left_encode
|
||||
self.assertEqual(_left_encode(0), b'\x01\x00')
|
||||
self.assertEqual(_left_encode(1), b'\x01\x01')
|
||||
self.assertEqual(_left_encode(256), b'\x02\x01\x00')
|
||||
|
||||
def test_bytepad(self):
|
||||
from Crypto.Hash.cSHAKE128 import _bytepad
|
||||
self.assertEqual(_bytepad(b'', 4), b'\x01\x04\x00\x00')
|
||||
self.assertEqual(_bytepad(b'A', 4), b'\x01\x04A\x00')
|
||||
self.assertEqual(_bytepad(b'AA', 4), b'\x01\x04AA')
|
||||
self.assertEqual(_bytepad(b'AAA', 4), b'\x01\x04AAA\x00\x00\x00')
|
||||
self.assertEqual(_bytepad(b'AAAA', 4), b'\x01\x04AAAA\x00\x00')
|
||||
self.assertEqual(_bytepad(b'AAAAA', 4), b'\x01\x04AAAAA\x00')
|
||||
self.assertEqual(_bytepad(b'AAAAAA', 4), b'\x01\x04AAAAAA')
|
||||
self.assertEqual(_bytepad(b'AAAAAAA', 4), b'\x01\x04AAAAAAA\x00\x00\x00')
|
||||
|
||||
def test_new_positive(self):
|
||||
|
||||
xof1 = self.cshake.new()
|
||||
xof2 = self.cshake.new(data=b("90"))
|
||||
xof3 = self.cshake.new().update(b("90"))
|
||||
|
||||
self.assertNotEqual(xof1.read(10), xof2.read(10))
|
||||
xof3.read(10)
|
||||
self.assertEqual(xof2.read(10), xof3.read(10))
|
||||
|
||||
xof1 = self.cshake.new()
|
||||
ref = xof1.read(10)
|
||||
xof2 = self.cshake.new(custom=b(""))
|
||||
xof3 = self.cshake.new(custom=b("foo"))
|
||||
|
||||
self.assertEqual(ref, xof2.read(10))
|
||||
self.assertNotEqual(ref, xof3.read(10))
|
||||
|
||||
xof1 = self.cshake.new(custom=b("foo"))
|
||||
xof2 = self.cshake.new(custom=b("foo"), data=b("90"))
|
||||
xof3 = self.cshake.new(custom=b("foo")).update(b("90"))
|
||||
|
||||
self.assertNotEqual(xof1.read(10), xof2.read(10))
|
||||
xof3.read(10)
|
||||
self.assertEqual(xof2.read(10), xof3.read(10))
|
||||
|
||||
def test_update(self):
|
||||
pieces = [bchr(10) * 200, bchr(20) * 300]
|
||||
h = self.cshake.new()
|
||||
h.update(pieces[0]).update(pieces[1])
|
||||
digest = h.read(10)
|
||||
h = self.cshake.new()
|
||||
h.update(pieces[0] + pieces[1])
|
||||
self.assertEqual(h.read(10), digest)
|
||||
|
||||
def test_update_negative(self):
|
||||
h = self.cshake.new()
|
||||
self.assertRaises(TypeError, h.update, u"string")
|
||||
|
||||
def test_digest(self):
|
||||
h = self.cshake.new()
|
||||
digest = h.read(90)
|
||||
|
||||
# read returns a byte string of the right length
|
||||
self.assertTrue(isinstance(digest, type(b("digest"))))
|
||||
self.assertEqual(len(digest), 90)
|
||||
|
||||
def test_update_after_read(self):
|
||||
mac = self.cshake.new()
|
||||
mac.update(b("rrrr"))
|
||||
mac.read(90)
|
||||
self.assertRaises(TypeError, mac.update, b("ttt"))
|
||||
|
||||
def test_shake(self):
|
||||
# When no customization string is passed, results must match SHAKE
|
||||
for digest_len in range(64):
|
||||
xof1 = self.cshake.new(b'TEST')
|
||||
xof2 = self.shake.new(b'TEST')
|
||||
self.assertEqual(xof1.read(digest_len), xof2.read(digest_len))
|
||||
|
||||
|
||||
class cSHAKE128Test(cSHAKETest):
|
||||
cshake = cSHAKE128
|
||||
shake = SHAKE128
|
||||
|
||||
|
||||
class cSHAKE256Test(cSHAKETest):
|
||||
cshake = cSHAKE256
|
||||
shake = SHAKE256
|
||||
|
||||
|
||||
class cSHAKEVectors(unittest.TestCase):
|
||||
pass
|
||||
|
||||
|
||||
vector_files = [("ShortMsgSamples_cSHAKE128.txt", "Short Message Samples cSHAKE128", "128_cshake", cSHAKE128),
|
||||
("ShortMsgSamples_cSHAKE256.txt", "Short Message Samples cSHAKE256", "256_cshake", cSHAKE256),
|
||||
("CustomMsgSamples_cSHAKE128.txt", "Custom Message Samples cSHAKE128", "custom_128_cshake", cSHAKE128),
|
||||
("CustomMsgSamples_cSHAKE256.txt", "Custom Message Samples cSHAKE256", "custom_256_cshake", cSHAKE256),
|
||||
]
|
||||
|
||||
for file, descr, tag, test_class in vector_files:
|
||||
|
||||
test_vectors = load_test_vectors(("Hash", "SHA3"), file, descr,
|
||||
{"len": lambda x: int(x),
|
||||
"nlen": lambda x: int(x),
|
||||
"slen": lambda x: int(x)}) or []
|
||||
|
||||
for idx, tv in enumerate(test_vectors):
|
||||
if getattr(tv, "len", 0) == 0:
|
||||
data = b("")
|
||||
else:
|
||||
data = tobytes(tv.msg)
|
||||
assert(tv.len == len(tv.msg)*8)
|
||||
if getattr(tv, "nlen", 0) != 0:
|
||||
raise ValueError("Unsupported cSHAKE test vector")
|
||||
if getattr(tv, "slen", 0) == 0:
|
||||
custom = b("")
|
||||
else:
|
||||
custom = tobytes(tv.s)
|
||||
assert(tv.slen == len(tv.s)*8)
|
||||
|
||||
def new_test(self, data=data, result=tv.md, custom=custom, test_class=test_class):
|
||||
hobj = test_class.new(data=data, custom=custom)
|
||||
digest = hobj.read(len(result))
|
||||
self.assertEqual(digest, result)
|
||||
|
||||
setattr(cSHAKEVectors, "test_%s_%d" % (tag, idx), new_test)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
tests += list_test_cases(cSHAKE128Test)
|
||||
tests += list_test_cases(cSHAKE256Test)
|
||||
tests += list_test_cases(cSHAKEVectors)
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -0,0 +1,250 @@
|
||||
# ===================================================================
|
||||
#
|
||||
# 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.
|
||||
# ===================================================================
|
||||
|
||||
"""Self-test suite for Crypto.Hash.keccak"""
|
||||
|
||||
import unittest
|
||||
from binascii import hexlify, unhexlify
|
||||
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
|
||||
from Crypto.Hash import keccak
|
||||
from Crypto.Util.py3compat import b, tobytes, bchr
|
||||
|
||||
class KeccakTest(unittest.TestCase):
|
||||
|
||||
def test_new_positive(self):
|
||||
|
||||
for digest_bits in (224, 256, 384, 512):
|
||||
hobj = keccak.new(digest_bits=digest_bits)
|
||||
self.assertEqual(hobj.digest_size, digest_bits // 8)
|
||||
|
||||
hobj2 = hobj.new()
|
||||
self.assertEqual(hobj2.digest_size, digest_bits // 8)
|
||||
|
||||
for digest_bytes in (28, 32, 48, 64):
|
||||
hobj = keccak.new(digest_bytes=digest_bytes)
|
||||
self.assertEqual(hobj.digest_size, digest_bytes)
|
||||
|
||||
hobj2 = hobj.new()
|
||||
self.assertEqual(hobj2.digest_size, digest_bytes)
|
||||
|
||||
def test_new_positive2(self):
|
||||
|
||||
digest1 = keccak.new(data=b("\x90"), digest_bytes=64).digest()
|
||||
digest2 = keccak.new(digest_bytes=64).update(b("\x90")).digest()
|
||||
self.assertEqual(digest1, digest2)
|
||||
|
||||
def test_new_negative(self):
|
||||
|
||||
# keccak.new needs digest size
|
||||
self.assertRaises(TypeError, keccak.new)
|
||||
|
||||
h = keccak.new(digest_bits=512)
|
||||
|
||||
# Either bits or bytes can be specified
|
||||
self.assertRaises(TypeError, keccak.new,
|
||||
digest_bytes=64,
|
||||
digest_bits=512)
|
||||
|
||||
# Range
|
||||
self.assertRaises(ValueError, keccak.new, digest_bytes=0)
|
||||
self.assertRaises(ValueError, keccak.new, digest_bytes=1)
|
||||
self.assertRaises(ValueError, keccak.new, digest_bytes=65)
|
||||
self.assertRaises(ValueError, keccak.new, digest_bits=0)
|
||||
self.assertRaises(ValueError, keccak.new, digest_bits=1)
|
||||
self.assertRaises(ValueError, keccak.new, digest_bits=513)
|
||||
|
||||
def test_update(self):
|
||||
pieces = [bchr(10) * 200, bchr(20) * 300]
|
||||
h = keccak.new(digest_bytes=64)
|
||||
h.update(pieces[0]).update(pieces[1])
|
||||
digest = h.digest()
|
||||
h = keccak.new(digest_bytes=64)
|
||||
h.update(pieces[0] + pieces[1])
|
||||
self.assertEqual(h.digest(), digest)
|
||||
|
||||
def test_update_negative(self):
|
||||
h = keccak.new(digest_bytes=64)
|
||||
self.assertRaises(TypeError, h.update, u"string")
|
||||
|
||||
def test_digest(self):
|
||||
h = keccak.new(digest_bytes=64)
|
||||
digest = h.digest()
|
||||
|
||||
# hexdigest does not change the state
|
||||
self.assertEqual(h.digest(), digest)
|
||||
# digest returns a byte string
|
||||
self.assertTrue(isinstance(digest, type(b("digest"))))
|
||||
|
||||
def test_hex_digest(self):
|
||||
mac = keccak.new(digest_bits=512)
|
||||
digest = mac.digest()
|
||||
hexdigest = mac.hexdigest()
|
||||
|
||||
# hexdigest is equivalent to digest
|
||||
self.assertEqual(hexlify(digest), tobytes(hexdigest))
|
||||
# hexdigest does not change the state
|
||||
self.assertEqual(mac.hexdigest(), hexdigest)
|
||||
# hexdigest returns a string
|
||||
self.assertTrue(isinstance(hexdigest, type("digest")))
|
||||
|
||||
def test_update_after_digest(self):
|
||||
msg=b("rrrrttt")
|
||||
|
||||
# Normally, update() cannot be done after digest()
|
||||
h = keccak.new(digest_bits=512, data=msg[:4])
|
||||
dig1 = h.digest()
|
||||
self.assertRaises(TypeError, h.update, msg[4:])
|
||||
dig2 = keccak.new(digest_bits=512, data=msg).digest()
|
||||
|
||||
# With the proper flag, it is allowed
|
||||
h = keccak.new(digest_bits=512, data=msg[:4], update_after_digest=True)
|
||||
self.assertEqual(h.digest(), dig1)
|
||||
# ... and the subsequent digest applies to the entire message
|
||||
# up to that point
|
||||
h.update(msg[4:])
|
||||
self.assertEqual(h.digest(), dig2)
|
||||
|
||||
|
||||
class KeccakVectors(unittest.TestCase):
|
||||
pass
|
||||
|
||||
# TODO: add ExtremelyLong tests
|
||||
|
||||
|
||||
test_vectors_224 = load_test_vectors(("Hash", "keccak"),
|
||||
"ShortMsgKAT_224.txt",
|
||||
"Short Messages KAT 224",
|
||||
{"len": lambda x: int(x)}) or []
|
||||
|
||||
test_vectors_224 += load_test_vectors(("Hash", "keccak"),
|
||||
"LongMsgKAT_224.txt",
|
||||
"Long Messages KAT 224",
|
||||
{"len": lambda x: int(x)}) or []
|
||||
|
||||
for idx, tv in enumerate(test_vectors_224):
|
||||
if tv.len == 0:
|
||||
data = b("")
|
||||
else:
|
||||
data = tobytes(tv.msg)
|
||||
|
||||
def new_test(self, data=data, result=tv.md):
|
||||
hobj = keccak.new(digest_bits=224, data=data)
|
||||
self.assertEqual(hobj.digest(), result)
|
||||
|
||||
setattr(KeccakVectors, "test_224_%d" % idx, new_test)
|
||||
|
||||
# ---
|
||||
|
||||
test_vectors_256 = load_test_vectors(("Hash", "keccak"),
|
||||
"ShortMsgKAT_256.txt",
|
||||
"Short Messages KAT 256",
|
||||
{ "len" : lambda x: int(x) } ) or []
|
||||
|
||||
test_vectors_256 += load_test_vectors(("Hash", "keccak"),
|
||||
"LongMsgKAT_256.txt",
|
||||
"Long Messages KAT 256",
|
||||
{ "len" : lambda x: int(x) } ) or []
|
||||
|
||||
for idx, tv in enumerate(test_vectors_256):
|
||||
if tv.len == 0:
|
||||
data = b("")
|
||||
else:
|
||||
data = tobytes(tv.msg)
|
||||
|
||||
def new_test(self, data=data, result=tv.md):
|
||||
hobj = keccak.new(digest_bits=256, data=data)
|
||||
self.assertEqual(hobj.digest(), result)
|
||||
|
||||
setattr(KeccakVectors, "test_256_%d" % idx, new_test)
|
||||
|
||||
|
||||
# ---
|
||||
|
||||
test_vectors_384 = load_test_vectors(("Hash", "keccak"),
|
||||
"ShortMsgKAT_384.txt",
|
||||
"Short Messages KAT 384",
|
||||
{"len": lambda x: int(x)}) or []
|
||||
|
||||
test_vectors_384 += load_test_vectors(("Hash", "keccak"),
|
||||
"LongMsgKAT_384.txt",
|
||||
"Long Messages KAT 384",
|
||||
{"len": lambda x: int(x)}) or []
|
||||
|
||||
for idx, tv in enumerate(test_vectors_384):
|
||||
if tv.len == 0:
|
||||
data = b("")
|
||||
else:
|
||||
data = tobytes(tv.msg)
|
||||
|
||||
def new_test(self, data=data, result=tv.md):
|
||||
hobj = keccak.new(digest_bits=384, data=data)
|
||||
self.assertEqual(hobj.digest(), result)
|
||||
|
||||
setattr(KeccakVectors, "test_384_%d" % idx, new_test)
|
||||
|
||||
# ---
|
||||
|
||||
test_vectors_512 = load_test_vectors(("Hash", "keccak"),
|
||||
"ShortMsgKAT_512.txt",
|
||||
"Short Messages KAT 512",
|
||||
{"len": lambda x: int(x)}) or []
|
||||
|
||||
test_vectors_512 += load_test_vectors(("Hash", "keccak"),
|
||||
"LongMsgKAT_512.txt",
|
||||
"Long Messages KAT 512",
|
||||
{"len": lambda x: int(x)}) or []
|
||||
|
||||
for idx, tv in enumerate(test_vectors_512):
|
||||
if tv.len == 0:
|
||||
data = b("")
|
||||
else:
|
||||
data = tobytes(tv.msg)
|
||||
|
||||
def new_test(self, data=data, result=tv.md):
|
||||
hobj = keccak.new(digest_bits=512, data=data)
|
||||
self.assertEqual(hobj.digest(), result)
|
||||
|
||||
setattr(KeccakVectors, "test_512_%d" % idx, new_test)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
tests += list_test_cases(KeccakTest)
|
||||
tests += list_test_cases(KeccakVectors)
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
@@ -0,0 +1,47 @@
|
||||
#
|
||||
# SelfTest/IO/__init__.py: Self-test for input/output module
|
||||
#
|
||||
# ===================================================================
|
||||
#
|
||||
# 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.
|
||||
# ===================================================================
|
||||
|
||||
"""Self-test for I/O"""
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
from Crypto.SelfTest.IO import test_PKCS8; tests += test_PKCS8.get_tests(config=config)
|
||||
from Crypto.SelfTest.IO import test_PBES; tests += test_PBES.get_tests(config=config)
|
||||
return tests
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
|
||||
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user