feat: initial commit - Phase 1 & 2 core features

This commit is contained in:
hiderfong
2026-04-22 17:07:33 +08:00
commit 1773bda06b
25005 changed files with 6252106 additions and 0 deletions
@@ -0,0 +1,64 @@
# -*- 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"""
import sys
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)
if sys.version_info >= (3, 9):
from Crypto.SelfTest.Cipher import test_KW
tests += test_KW.get_tests(config=config)
return tests
if __name__ == '__main__':
import unittest
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -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:
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,970 @@
# ===================================================================
#
# 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
from Crypto.Cipher._mode_ccm import CCMMessageTooLongError
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)
def test_message_too_long(self):
nonce = b'N' * 13
self.assertRaises(CCMMessageTooLongError,
AES.new,
self.key_128,
AES.MODE_CCM,
nonce=nonce,
assoc_len=20,
msg_len=0x10000)
nonce = b'N' * 7
self.assertRaises(CCMMessageTooLongError,
AES.new,
self.key_128,
AES.MODE_CCM,
nonce=nonce,
assoc_len=20,
msg_len=2**64)
nonce = b'N' * 13
cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=nonce)
self.assertRaises(CCMMessageTooLongError,
cipher.encrypt,
b'C' * 0x10000)
nonce = b'N' * 13
cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=nonce)
self.assertRaises(CCMMessageTooLongError,
cipher.decrypt,
b'C' * 0x10000)
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,175 @@
import unittest
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.SelfTest.loader import load_test_vectors_wycheproof
from Crypto.Cipher import AES
class KW_Tests(unittest.TestCase):
# From RFC3394
tvs = [
("000102030405060708090A0B0C0D0E0F",
"00112233445566778899AABBCCDDEEFF",
"1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5"),
("000102030405060708090A0B0C0D0E0F1011121314151617",
"00112233445566778899AABBCCDDEEFF",
"96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D"),
("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
"00112233445566778899AABBCCDDEEFF",
"64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7"),
("000102030405060708090A0B0C0D0E0F1011121314151617",
"00112233445566778899AABBCCDDEEFF0001020304050607",
"031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2"),
("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
"00112233445566778899AABBCCDDEEFF0001020304050607",
"A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1"),
("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
"00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F",
"28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21"),
]
def test_rfc3394(self):
for tv in self.tvs:
kek, pt, ct = [bytes.fromhex(x) for x in tv]
cipher = AES.new(kek, AES.MODE_KW)
ct2 = cipher.seal(pt)
self.assertEqual(ct, ct2)
cipher = AES.new(kek, AES.MODE_KW)
pt2 = cipher.unseal(ct)
self.assertEqual(pt, pt2)
def test_neg1(self):
cipher = AES.new(b'-' * 16, AES.MODE_KW)
with self.assertRaises(ValueError):
cipher.seal(b'')
with self.assertRaises(ValueError):
cipher.seal(b'8' * 17)
def test_neg2(self):
cipher = AES.new(b'-' * 16, AES.MODE_KW)
ct = bytearray(cipher.seal(b'7' * 16))
cipher = AES.new(b'-' * 16, AES.MODE_KW)
cipher.unseal(ct)
cipher = AES.new(b'-' * 16, AES.MODE_KW)
ct[0] ^= 0xFF
with self.assertRaises(ValueError):
cipher.unseal(ct)
class KW_Wycheproof(unittest.TestCase):
def setUp(self):
self.vectors = load_test_vectors_wycheproof(("Cipher", "wycheproof"),
"kw_test.json",
"Wycheproof tests for KW")
def test_wycheproof(self):
if not self.vectors:
self.skipTest("No test vectors available")
for vector in self.vectors:
with self.subTest(testId=vector.id):
cipher = AES.new(vector.key, AES.MODE_KW)
try:
cipher.seal(vector.msg)
except ValueError:
if vector.valid:
raise
continue
cipher = AES.new(vector.key, AES.MODE_KW)
try:
pt = cipher.unseal(vector.ct)
except ValueError:
if vector.valid:
raise
continue
self.assertEqual(pt, vector.msg)
class KWP_Tests(unittest.TestCase):
tvs = [
("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8",
"c37b7e6492584340bed12207808941155068f738",
"138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a"),
("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8",
"466f7250617369",
"afbeb0f07dfbf5419200f2ccb50bb24f"),
]
def test_rfc5649(self):
for tv in self.tvs:
kek, pt, ct = [bytes.fromhex(x) for x in tv]
cipher = AES.new(kek, AES.MODE_KWP)
ct2 = cipher.seal(pt)
self.assertEqual(ct, ct2)
cipher = AES.new(kek, AES.MODE_KWP)
pt2 = cipher.unseal(ct)
self.assertEqual(pt, pt2)
class KWP_Wycheproof(unittest.TestCase):
def setUp(self):
self.vectors = load_test_vectors_wycheproof(("Cipher", "wycheproof"),
"kwp_test.json",
"Wycheproof tests for KWP")
def test_wycheproof(self):
if not self.vectors:
self.skipTest("No test vectors available")
for vector in self.vectors:
with self.subTest(testId=vector.id):
cipher = AES.new(vector.key, AES.MODE_KWP)
try:
cipher.seal(vector.msg)
except ValueError:
if vector.valid and not vector.warning:
raise
continue
cipher = AES.new(vector.key, AES.MODE_KWP)
try:
pt = cipher.unseal(vector.ct)
except ValueError:
if vector.valid and not vector.warning:
raise
continue
self.assertEqual(pt, vector.msg)
def get_tests(config={}):
tests = []
tests += list_test_cases(KW_Tests)
tests += list_test_cases(KWP_Tests)
tests += list_test_cases(KW_Wycheproof)
tests += list_test_cases(KWP_Wycheproof)
return tests
if __name__ == '__main__':
def suite():
return 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,62 @@
# -*- 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)
from Crypto.SelfTest.Hash import test_TurboSHAKE; tests += test_TurboSHAKE.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:
@@ -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')
@@ -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')
@@ -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')
@@ -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,367 @@
# ===================================================================
# 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]
class KangarooTwelveTV(unittest.TestCase):
# https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KangarooTwelve.txt
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)
# https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/
def test_ptn_8191(self):
tv = """1B 57 76 36 F7 23 64 3E 99 0C C7 D6 A6 59 83 74
36 FD 6A 10 36 26 60 0E B8 30 1C D1 DB E5 53 D6"""
btv = txt2bin(tv)
# All at once
res = K12.new(data=ptn(8191)).read(32)
self.assertEqual(res, btv)
def test_ptn_8192(self):
tv = """48 F2 56 F6 77 2F 9E DF B6 A8 B6 61 EC 92 DC 93
B9 5E BD 05 A0 8A 17 B3 9A E3 49 08 70 C9 26 C3"""
btv = txt2bin(tv)
# All at once
res = K12.new(data=ptn(8192)).read(32)
self.assertEqual(res, btv)
def test_ptn_8192_8189(self):
tv = """3E D1 2F 70 FB 05 DD B5 86 89 51 0A B3 E4 D2 3C
6C 60 33 84 9A A0 1E 1D 8C 22 0A 29 7F ED CD 0B"""
btv = txt2bin(tv)
# All at once
res = K12.new(data=ptn(8192), custom=ptn(8189)).read(32)
self.assertEqual(res, btv)
def test_ptn_8192_8190(self):
tv = """6A 7C 1B 6A 5C D0 D8 C9 CA 94 3A 4A 21 6C C6 46
04 55 9A 2E A4 5F 78 57 0A 15 25 3D 67 BA 00 AE"""
btv = txt2bin(tv)
# All at once
res = K12.new(data=ptn(8192), custom=ptn(8190)).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,151 @@
# ===================================================================
#
# 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"))
def test_copy(self):
mac = self.shake.new()
mac.update(b("rrrr"))
mac2 = mac.copy()
x1 = mac.read(90)
x2 = mac2.read(90)
self.assertEqual(x1, x2)
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,302 @@
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)
h = self.new()
h.update(b'STRING1', b'STRING2')
self.assertEqual(mac2, h.digest())
h = self.new()
t = b'STRING1', b'STRING2'
h.update(*t)
self.assertEqual(mac2, h.digest())
def test_update_negative(self):
h = self.new()
self.assertRaises(TypeError, h.update, u"string")
self.assertRaises(TypeError, h.update, None)
self.assertRaises(TypeError, h.update, (b'STRING1', b'STRING2'))
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,468 @@
"""Self-test suite for Crypto.Hash.TurboSHAKE128 and TurboSHAKE256"""
import unittest
from binascii import unhexlify
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Hash import TurboSHAKE128, TurboSHAKE256
from Crypto.Util.py3compat import bchr
class TurboSHAKETest(unittest.TestCase):
def test_new_positive(self):
xof1 = self.TurboSHAKE.new()
xof1.update(b'90')
xof2 = self.TurboSHAKE.new(domain=0x1F)
xof2.update(b'90')
xof3 = self.TurboSHAKE.new(data=b'90')
out1 = xof1.read(128)
out2 = xof2.read(128)
out3 = xof3.read(128)
self.assertEqual(out1, out2)
self.assertEqual(out1, out3)
def test_new_domain(self):
xof1 = self.TurboSHAKE.new(domain=0x1D)
xof2 = self.TurboSHAKE.new(domain=0x20)
self.assertNotEqual(xof1.read(128), xof2.read(128))
def test_update(self):
pieces = [bchr(10) * 200, bchr(20) * 300]
xof1 = self.TurboSHAKE.new()
xof1.update(pieces[0]).update(pieces[1])
digest1 = xof1.read(10)
xof2 = self.TurboSHAKE.new()
xof2.update(pieces[0] + pieces[1])
digest2 = xof2.read(10)
self.assertEqual(digest1, digest2)
def test_update_negative(self):
xof1 = self.TurboSHAKE.new()
self.assertRaises(TypeError, xof1.update, u"string")
def test_read(self):
xof1 = self.TurboSHAKE.new()
digest = xof1.read(90)
# read returns a byte string of the right length
self.assertTrue(isinstance(digest, bytes))
self.assertEqual(len(digest), 90)
def test_update_after_read(self):
xof1 = self.TurboSHAKE.new()
xof1.update(b"rrrr")
xof1.read(90)
self.assertRaises(TypeError, xof1.update, b"ttt")
def test_new(self):
xof1 = self.TurboSHAKE.new(domain=0x07)
xof1.update(b'90')
digest1 = xof1.read(100)
xof2 = xof1.new()
xof2.update(b'90')
digest2 = xof2.read(100)
self.assertEqual(digest1, digest2)
self.assertRaises(TypeError, xof1.new, domain=0x07)
class TurboSHAKE128Test(TurboSHAKETest):
TurboSHAKE = TurboSHAKE128
class TurboSHAKE256Test(TurboSHAKETest):
TurboSHAKE = TurboSHAKE256
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]
class TurboSHAKE128TV(unittest.TestCase):
def test_zero_1(self):
tv = """1E 41 5F 1C 59 83 AF F2 16 92 17 27 7D 17 BB 53
8C D9 45 A3 97 DD EC 54 1F 1C E4 1A F2 C1 B7 4C"""
btv = txt2bin(tv)
res = TurboSHAKE128.new().read(32)
self.assertEqual(res, btv)
def test_zero_2(self):
tv = """1E 41 5F 1C 59 83 AF F2 16 92 17 27 7D 17 BB 53
8C D9 45 A3 97 DD EC 54 1F 1C E4 1A F2 C1 B7 4C
3E 8C CA E2 A4 DA E5 6C 84 A0 4C 23 85 C0 3C 15
E8 19 3B DF 58 73 73 63 32 16 91 C0 54 62 C8 DF"""
btv = txt2bin(tv)
res = TurboSHAKE128.new().read(64)
self.assertEqual(res, btv)
def test_zero_3(self):
tv = """A3 B9 B0 38 59 00 CE 76 1F 22 AE D5 48 E7 54 DA
10 A5 24 2D 62 E8 C6 58 E3 F3 A9 23 A7 55 56 07"""
btv = txt2bin(tv)
res = TurboSHAKE128.new().read(10032)[-32:]
self.assertEqual(res, btv)
def test_ptn_1(self):
tv = """55 CE DD 6F 60 AF 7B B2 9A 40 42 AE 83 2E F3 F5
8D B7 29 9F 89 3E BB 92 47 24 7D 85 69 58 DA A9"""
btv = txt2bin(tv)
res = TurboSHAKE128.new(data=ptn(1)).read(32)
self.assertEqual(res, btv)
def test_ptn_17(self):
tv = """9C 97 D0 36 A3 BA C8 19 DB 70 ED E0 CA 55 4E C6
E4 C2 A1 A4 FF BF D9 EC 26 9C A6 A1 11 16 12 33"""
btv = txt2bin(tv)
res = TurboSHAKE128.new(data=ptn(17)).read(32)
self.assertEqual(res, btv)
def test_ptn_17_2(self):
tv = """96 C7 7C 27 9E 01 26 F7 FC 07 C9 B0 7F 5C DA E1
E0 BE 60 BD BE 10 62 00 40 E7 5D 72 23 A6 24 D2"""
btv = txt2bin(tv)
res = TurboSHAKE128.new(data=ptn(17**2)).read(32)
self.assertEqual(res, btv)
def test_ptn_17_3(self):
tv = """D4 97 6E B5 6B CF 11 85 20 58 2B 70 9F 73 E1 D6
85 3E 00 1F DA F8 0E 1B 13 E0 D0 59 9D 5F B3 72"""
btv = txt2bin(tv)
res = TurboSHAKE128.new(data=ptn(17**3)).read(32)
self.assertEqual(res, btv)
def test_ptn_17_4(self):
tv = """DA 67 C7 03 9E 98 BF 53 0C F7 A3 78 30 C6 66 4E
14 CB AB 7F 54 0F 58 40 3B 1B 82 95 13 18 EE 5C"""
btv = txt2bin(tv)
data = ptn(17**4)
# All at once
res = TurboSHAKE128.new(data=data).read(32)
self.assertEqual(res, btv)
# Byte by byte
xof = TurboSHAKE128.new()
for x in data:
xof.update(bchr(x))
res = xof.read(32)
self.assertEqual(res, btv)
# Chunks of various prime sizes
for chunk_size in (13, 17, 19, 23, 31):
xof = TurboSHAKE128.new()
for x in chunked(data, chunk_size):
xof.update(x)
res = xof.read(32)
self.assertEqual(res, btv)
def test_ptn_17_5(self):
tv = """B9 7A 90 6F BF 83 EF 7C 81 25 17 AB F3 B2 D0 AE
A0 C4 F6 03 18 CE 11 CF 10 39 25 12 7F 59 EE CD"""
btv = txt2bin(tv)
data = ptn(17**5)
# All at once
res = TurboSHAKE128.new(data=data).read(32)
self.assertEqual(res, btv)
# Chunks
xof = TurboSHAKE128.new()
for chunk in chunked(data, 8192):
xof.update(chunk)
res = xof.read(32)
self.assertEqual(res, btv)
def test_ptn_17_6(self):
tv = """35 CD 49 4A DE DE D2 F2 52 39 AF 09 A7 B8 EF 0C
4D 1C A4 FE 2D 1A C3 70 FA 63 21 6F E7 B4 C2 B1"""
btv = txt2bin(tv)
data = ptn(17**6)
res = TurboSHAKE128.new(data=data).read(32)
self.assertEqual(res, btv)
def test_ffffff_d01(self):
tv = """BF 32 3F 94 04 94 E8 8E E1 C5 40 FE 66 0B E8 A0
C9 3F 43 D1 5E C0 06 99 84 62 FA 99 4E ED 5D AB"""
btv = txt2bin(tv)
res = TurboSHAKE128.new(data=b"\xff\xff\xff", domain=0x01).read(32)
self.assertEqual(res, btv)
def test_ff_d06(self):
tv = """8E C9 C6 64 65 ED 0D 4A 6C 35 D1 35 06 71 8D 68
7A 25 CB 05 C7 4C CA 1E 42 50 1A BD 83 87 4A 67"""
btv = txt2bin(tv)
res = TurboSHAKE128.new(data=b'\xFF', domain=0x06).read(32)
self.assertEqual(res, btv)
def test_ffffff_d07(self):
tv = """B6 58 57 60 01 CA D9 B1 E5 F3 99 A9 F7 77 23 BB
A0 54 58 04 2D 68 20 6F 72 52 68 2D BA 36 63 ED"""
btv = txt2bin(tv)
res = TurboSHAKE128.new(data=b'\xFF' * 3, domain=0x07).read(32)
self.assertEqual(res, btv)
def test_ffffffffffff_d0b(self):
tv = """8D EE AA 1A EC 47 CC EE 56 9F 65 9C 21 DF A8 E1
12 DB 3C EE 37 B1 81 78 B2 AC D8 05 B7 99 CC 37"""
btv = txt2bin(tv)
res = TurboSHAKE128.new(data=b'\xFF' * 7, domain=0x0B).read(32)
self.assertEqual(res, btv)
def test_ff_d30(self):
tv = """55 31 22 E2 13 5E 36 3C 32 92 BE D2 C6 42 1F A2
32 BA B0 3D AA 07 C7 D6 63 66 03 28 65 06 32 5B"""
btv = txt2bin(tv)
res = TurboSHAKE128.new(data=b'\xFF', domain=0x30).read(32)
self.assertEqual(res, btv)
def test_ffffff_d7f(self):
tv = """16 27 4C C6 56 D4 4C EF D4 22 39 5D 0F 90 53 BD
A6 D2 8E 12 2A BA 15 C7 65 E5 AD 0E 6E AF 26 F9"""
btv = txt2bin(tv)
res = TurboSHAKE128.new(data=b'\xFF' * 3, domain=0x7F).read(32)
self.assertEqual(res, btv)
class TurboSHAKE256TV(unittest.TestCase):
def test_zero_1(self):
tv = """36 7A 32 9D AF EA 87 1C 78 02 EC 67 F9 05 AE 13
C5 76 95 DC 2C 66 63 C6 10 35 F5 9A 18 F8 E7 DB
11 ED C0 E1 2E 91 EA 60 EB 6B 32 DF 06 DD 7F 00
2F BA FA BB 6E 13 EC 1C C2 0D 99 55 47 60 0D B0"""
btv = txt2bin(tv)
res = TurboSHAKE256.new().read(64)
self.assertEqual(res, btv)
def test_zero_2(self):
tv = """AB EF A1 16 30 C6 61 26 92 49 74 26 85 EC 08 2F
20 72 65 DC CF 2F 43 53 4E 9C 61 BA 0C 9D 1D 75"""
btv = txt2bin(tv)
res = TurboSHAKE256.new().read(10032)[-32:]
self.assertEqual(res, btv)
def test_ptn_1(self):
tv = """3E 17 12 F9 28 F8 EA F1 05 46 32 B2 AA 0A 24 6E
D8 B0 C3 78 72 8F 60 BC 97 04 10 15 5C 28 82 0E
90 CC 90 D8 A3 00 6A A2 37 2C 5C 5E A1 76 B0 68
2B F2 2B AE 74 67 AC 94 F7 4D 43 D3 9B 04 82 E2"""
btv = txt2bin(tv)
res = TurboSHAKE256.new(data=ptn(1)).read(64)
self.assertEqual(res, btv)
def test_ptn_17(self):
tv = """B3 BA B0 30 0E 6A 19 1F BE 61 37 93 98 35 92 35
78 79 4E A5 48 43 F5 01 10 90 FA 2F 37 80 A9 E5
CB 22 C5 9D 78 B4 0A 0F BF F9 E6 72 C0 FB E0 97
0B D2 C8 45 09 1C 60 44 D6 87 05 4D A5 D8 E9 C7"""
btv = txt2bin(tv)
res = TurboSHAKE256.new(data=ptn(17)).read(64)
self.assertEqual(res, btv)
def test_ptn_17_2(self):
tv = """66 B8 10 DB 8E 90 78 04 24 C0 84 73 72 FD C9 57
10 88 2F DE 31 C6 DF 75 BE B9 D4 CD 93 05 CF CA
E3 5E 7B 83 E8 B7 E6 EB 4B 78 60 58 80 11 63 16
FE 2C 07 8A 09 B9 4A D7 B8 21 3C 0A 73 8B 65 C0"""
btv = txt2bin(tv)
res = TurboSHAKE256.new(data=ptn(17**2)).read(64)
self.assertEqual(res, btv)
def test_ptn_17_3(self):
tv = """C7 4E BC 91 9A 5B 3B 0D D1 22 81 85 BA 02 D2 9E
F4 42 D6 9D 3D 42 76 A9 3E FE 0B F9 A1 6A 7D C0
CD 4E AB AD AB 8C D7 A5 ED D9 66 95 F5 D3 60 AB
E0 9E 2C 65 11 A3 EC 39 7D A3 B7 6B 9E 16 74 FB"""
btv = txt2bin(tv)
res = TurboSHAKE256.new(data=ptn(17**3)).read(64)
self.assertEqual(res, btv)
def test_ptn_17_4(self):
tv = """02 CC 3A 88 97 E6 F4 F6 CC B6 FD 46 63 1B 1F 52
07 B6 6C 6D E9 C7 B5 5B 2D 1A 23 13 4A 17 0A FD
AC 23 4E AB A9 A7 7C FF 88 C1 F0 20 B7 37 24 61
8C 56 87 B3 62 C4 30 B2 48 CD 38 64 7F 84 8A 1D"""
btv = txt2bin(tv)
data = ptn(17**4)
# All at once
res = TurboSHAKE256.new(data=data).read(64)
self.assertEqual(res, btv)
# Byte by byte
xof = TurboSHAKE256.new()
for x in data:
xof.update(bchr(x))
res = xof.read(64)
self.assertEqual(res, btv)
# Chunks of various prime sizes
for chunk_size in (13, 17, 19, 23, 31):
xof = TurboSHAKE256.new()
for x in chunked(data, chunk_size):
xof.update(x)
res = xof.read(64)
self.assertEqual(res, btv)
def test_ptn_17_5(self):
tv = """AD D5 3B 06 54 3E 58 4B 58 23 F6 26 99 6A EE 50
FE 45 ED 15 F2 02 43 A7 16 54 85 AC B4 AA 76 B4
FF DA 75 CE DF 6D 8C DC 95 C3 32 BD 56 F4 B9 86
B5 8B B1 7D 17 78 BF C1 B1 A9 75 45 CD F4 EC 9F"""
btv = txt2bin(tv)
data = ptn(17**5)
# All at once
res = TurboSHAKE256.new(data=data).read(64)
self.assertEqual(res, btv)
# Chunks
xof = TurboSHAKE256.new()
for chunk in chunked(data, 8192):
xof.update(chunk)
res = xof.read(64)
self.assertEqual(res, btv)
def test_ptn_17_6(self):
tv = """9E 11 BC 59 C2 4E 73 99 3C 14 84 EC 66 35 8E F7
1D B7 4A EF D8 4E 12 3F 78 00 BA 9C 48 53 E0 2C
FE 70 1D 9E 6B B7 65 A3 04 F0 DC 34 A4 EE 3B A8
2C 41 0F 0D A7 0E 86 BF BD 90 EA 87 7C 2D 61 04"""
btv = txt2bin(tv)
data = ptn(17**6)
res = TurboSHAKE256.new(data=data).read(64)
self.assertEqual(res, btv)
def test_ffffff_d01(self):
tv = """D2 1C 6F BB F5 87 FA 22 82 F2 9A EA 62 01 75 FB
02 57 41 3A F7 8A 0B 1B 2A 87 41 9C E0 31 D9 33
AE 7A 4D 38 33 27 A8 A1 76 41 A3 4F 8A 1D 10 03
AD 7D A6 B7 2D BA 84 BB 62 FE F2 8F 62 F1 24 24"""
btv = txt2bin(tv)
res = TurboSHAKE256.new(data=b"\xff\xff\xff", domain=0x01).read(64)
self.assertEqual(res, btv)
def test_ff_d06(self):
tv = """73 8D 7B 4E 37 D1 8B 7F 22 AD 1B 53 13 E3 57 E3
DD 7D 07 05 6A 26 A3 03 C4 33 FA 35 33 45 52 80
F4 F5 A7 D4 F7 00 EF B4 37 FE 6D 28 14 05 E0 7B
E3 2A 0A 97 2E 22 E6 3A DC 1B 09 0D AE FE 00 4B"""
btv = txt2bin(tv)
res = TurboSHAKE256.new(data=b'\xFF', domain=0x06).read(64)
self.assertEqual(res, btv)
def test_ffffff_d07(self):
tv = """18 B3 B5 B7 06 1C 2E 67 C1 75 3A 00 E6 AD 7E D7
BA 1C 90 6C F9 3E FB 70 92 EA F2 7F BE EB B7 55
AE 6E 29 24 93 C1 10 E4 8D 26 00 28 49 2B 8E 09
B5 50 06 12 B8 F2 57 89 85 DE D5 35 7D 00 EC 67"""
btv = txt2bin(tv)
res = TurboSHAKE256.new(data=b'\xFF' * 3, domain=0x07).read(64)
self.assertEqual(res, btv)
def test_ffffffffffff_d0b(self):
tv = """BB 36 76 49 51 EC 97 E9 D8 5F 7E E9 A6 7A 77 18
FC 00 5C F4 25 56 BE 79 CE 12 C0 BD E5 0E 57 36
D6 63 2B 0D 0D FB 20 2D 1B BB 8F FE 3D D7 4C B0
08 34 FA 75 6C B0 34 71 BA B1 3A 1E 2C 16 B3 C0"""
btv = txt2bin(tv)
res = TurboSHAKE256.new(data=b'\xFF' * 7, domain=0x0B).read(64)
self.assertEqual(res, btv)
def test_ff_d30(self):
tv = """F3 FE 12 87 3D 34 BC BB 2E 60 87 79 D6 B7 0E 7F
86 BE C7 E9 0B F1 13 CB D4 FD D0 C4 E2 F4 62 5E
14 8D D7 EE 1A 52 77 6C F7 7F 24 05 14 D9 CC FC
3B 5D DA B8 EE 25 5E 39 EE 38 90 72 96 2C 11 1A"""
btv = txt2bin(tv)
res = TurboSHAKE256.new(data=b'\xFF', domain=0x30).read(64)
self.assertEqual(res, btv)
def test_ffffff_d7f(self):
tv = """AB E5 69 C1 F7 7E C3 40 F0 27 05 E7 D3 7C 9A B7
E1 55 51 6E 4A 6A 15 00 21 D7 0B 6F AC 0B B4 0C
06 9F 9A 98 28 A0 D5 75 CD 99 F9 BA E4 35 AB 1A
CF 7E D9 11 0B A9 7C E0 38 8D 07 4B AC 76 87 76"""
btv = txt2bin(tv)
res = TurboSHAKE256.new(data=b'\xFF' * 3, domain=0x7F).read(64)
self.assertEqual(res, btv)
def get_tests(config={}):
tests = []
tests += list_test_cases(TurboSHAKE128Test)
tests += list_test_cases(TurboSHAKE256Test)
tests += list_test_cases(TurboSHAKE128TV)
tests += list_test_cases(TurboSHAKE256TV)
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')
@@ -0,0 +1,118 @@
#
# SelfTest/IO/test_PBES.py: Self-test for the _PBES 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-tests for Crypto.IO._PBES module"""
import unittest
from Crypto.IO._PBES import PBES2
class TestPBES2(unittest.TestCase):
def setUp(self):
self.ref = b"Test data"
self.passphrase = b"Passphrase"
def test1(self):
ct = PBES2.encrypt(self.ref, self.passphrase,
'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC')
pt = PBES2.decrypt(ct, self.passphrase)
self.assertEqual(self.ref, pt)
def test2(self):
ct = PBES2.encrypt(self.ref, self.passphrase,
'PBKDF2WithHMAC-SHA224AndAES128-CBC')
pt = PBES2.decrypt(ct, self.passphrase)
self.assertEqual(self.ref, pt)
def test3(self):
ct = PBES2.encrypt(self.ref, self.passphrase,
'PBKDF2WithHMAC-SHA256AndAES192-CBC')
pt = PBES2.decrypt(ct, self.passphrase)
self.assertEqual(self.ref, pt)
def test4(self):
ct = PBES2.encrypt(self.ref, self.passphrase,
'PBKDF2WithHMAC-SHA384AndAES256-CBC')
pt = PBES2.decrypt(ct, self.passphrase)
self.assertEqual(self.ref, pt)
def test5(self):
ct = PBES2.encrypt(self.ref, self.passphrase,
'PBKDF2WithHMAC-SHA512AndAES128-GCM')
pt = PBES2.decrypt(ct, self.passphrase)
self.assertEqual(self.ref, pt)
def test6(self):
ct = PBES2.encrypt(self.ref, self.passphrase,
'PBKDF2WithHMAC-SHA512-224AndAES192-GCM')
pt = PBES2.decrypt(ct, self.passphrase)
self.assertEqual(self.ref, pt)
def test7(self):
ct = PBES2.encrypt(self.ref, self.passphrase,
'PBKDF2WithHMAC-SHA3-256AndAES256-GCM')
pt = PBES2.decrypt(ct, self.passphrase)
self.assertEqual(self.ref, pt)
def test8(self):
ct = PBES2.encrypt(self.ref, self.passphrase,
'scryptAndAES128-CBC')
pt = PBES2.decrypt(ct, self.passphrase)
self.assertEqual(self.ref, pt)
def test9(self):
ct = PBES2.encrypt(self.ref, self.passphrase,
'scryptAndAES192-CBC')
pt = PBES2.decrypt(ct, self.passphrase)
self.assertEqual(self.ref, pt)
def test10(self):
ct = PBES2.encrypt(self.ref, self.passphrase,
'scryptAndAES256-CBC')
pt = PBES2.decrypt(ct, self.passphrase)
self.assertEqual(self.ref, pt)
def get_tests(config={}):
from Crypto.SelfTest.st_common import list_test_cases
listTests = []
listTests += list_test_cases(TestPBES2)
return listTests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,459 @@
#
# SelfTest/IO/test_PKCS8.py: Self-test for the PKCS8 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-tests for Crypto.IO.PKCS8 module"""
import unittest
from binascii import unhexlify
from Crypto.Util.py3compat import *
from Crypto.IO import PKCS8
from Crypto.Util.asn1 import DerNull
oid_key = '1.2.840.113549.1.1.1'
# Original RSA key (in DER format)
# hexdump -v -e '32/1 "%02x" "\n"' key.der
clear_key="""
308201ab020100025a00b94a7f7075ab9e79e8196f47be707781e80dd965cf16
0c951a870b71783b6aaabbd550c0e65e5a3dfe15b8620009f6d7e5efec42a3f0
6fe20faeebb0c356e79cdec6db4dd427e82d8ae4a5b90996227b8ba54ccfc4d2
5c08050203010001025a00afa09c70d528299b7552fe766b5d20f9a221d66938
c3b68371d48515359863ff96f0978d700e08cd6fd3d8a3f97066fc2e0d5f78eb
3a50b8e17ba297b24d1b8e9cdfd18d608668198d724ad15863ef0329195dee89
3f039395022d0ebe0518df702a8b25954301ec60a97efdcec8eaa4f2e76ca7e8
8dfbc3f7e0bb83f9a0e8dc47c0f8c746e9df6b022d0c9195de13f09b7be1fdd7
1f56ae7d973e08bd9fd2c3dfd8936bb05be9cc67bd32d663c7f00d70932a0be3
c24f022d0ac334eb6cabf1933633db007b763227b0d9971a9ea36aca8b669ec9
4fcf16352f6b3dcae28e4bd6137db4ddd3022d0400a09f15ee7b351a2481cb03
09920905c236d09c87afd3022f3afc2a19e3b746672b635238956ee7e6dd62d5
022d0cd88ed14fcfbda5bbf0257f700147137bbab9c797af7df866704b889aa3
7e2e93df3ff1a0fd3490111dcdbc4c
"""
# Same key as above, wrapped in PKCS#8 but w/o password
#
# openssl pkcs8 -topk8 -inform DER -nocrypt -in key.der -outform DER -out keyp8.der
# hexdump -v -e '32/1 "%02x" "\n"' keyp8.der
wrapped_clear_key="""
308201c5020100300d06092a864886f70d0101010500048201af308201ab0201
00025a00b94a7f7075ab9e79e8196f47be707781e80dd965cf160c951a870b71
783b6aaabbd550c0e65e5a3dfe15b8620009f6d7e5efec42a3f06fe20faeebb0
c356e79cdec6db4dd427e82d8ae4a5b90996227b8ba54ccfc4d25c0805020301
0001025a00afa09c70d528299b7552fe766b5d20f9a221d66938c3b68371d485
15359863ff96f0978d700e08cd6fd3d8a3f97066fc2e0d5f78eb3a50b8e17ba2
97b24d1b8e9cdfd18d608668198d724ad15863ef0329195dee893f039395022d
0ebe0518df702a8b25954301ec60a97efdcec8eaa4f2e76ca7e88dfbc3f7e0bb
83f9a0e8dc47c0f8c746e9df6b022d0c9195de13f09b7be1fdd71f56ae7d973e
08bd9fd2c3dfd8936bb05be9cc67bd32d663c7f00d70932a0be3c24f022d0ac3
34eb6cabf1933633db007b763227b0d9971a9ea36aca8b669ec94fcf16352f6b
3dcae28e4bd6137db4ddd3022d0400a09f15ee7b351a2481cb0309920905c236
d09c87afd3022f3afc2a19e3b746672b635238956ee7e6dd62d5022d0cd88ed1
4fcfbda5bbf0257f700147137bbab9c797af7df866704b889aa37e2e93df3ff1
a0fd3490111dcdbc4c
"""
###
#
# The key above will now be encrypted with different algorithms.
# The password is always 'TestTest'.
#
# Each item in the wrapped_enc_keys list contains:
# * wrap algorithm
# * iteration count
# * Salt
# * IV
# * Expected result
###
wrapped_enc_keys = []
#
# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -outform DER -out keyenc.der -v2 des3
# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
#
wrapped_enc_keys.append((
'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC',
2048,
"47EA7227D8B22E2F", # IV
"E3F7A838AB911A4D", # Salt
"""
30820216304006092a864886f70d01050d3033301b06092a864886f70d01050c
300e0408e3f7a838ab911a4d02020800301406082a864886f70d0307040847ea
7227d8b22e2f048201d0ea388b374d2d0e4ceb7a5139f850fdff274884a6e6c0
64326e09d00dbba9018834edb5a51a6ae3d1806e6e91eebf33788ce71fee0637
a2ebf58859dd32afc644110c390274a6128b50c39b8d907823810ec471bada86
6f5b75d8ea04ad310fad2e73621696db8e426cd511ee93ec1714a1a7db45e036
4bf20d178d1f16bbb250b32c2d200093169d588de65f7d99aad9ddd0104b44f1
326962e1520dfac3c2a800e8a14f678dff2b3d0bb23f69da635bf2a643ac934e
219a447d2f4460b67149e860e54f365da130763deefa649c72b0dcd48966a2d3
4a477444782e3e66df5a582b07bbb19778a79bd355074ce331f4a82eb966b0c4
52a09eab6116f2722064d314ae433b3d6e81d2436e93fdf446112663cde93b87
9c8be44beb45f18e2c78fee9b016033f01ecda51b9b142091fa69f65ab784d2c
5ad8d34be6f7f1464adfc1e0ef3f7848f40d3bdea4412758f2fcb655c93d8f4d
f6fa48fc5aa4b75dd1c017ab79ac9d737233a6d668f5364ccf47786debd37334
9c10c9e6efbe78430a61f71c89948aa32cdc3cc7338cf994147819ce7ab23450
c8f7d9b94c3bb377d17a3fa204b601526317824b142ff6bc843fa7815ece89c0
839573f234dac8d80cc571a045353d61db904a4398d8ef3df5ac
"""
))
#
# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -outform DER -out keyenc.der
# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
#
wrapped_enc_keys.append((
'skip encryption', # pbeWithMD5AndDES-CBC, only decoding is supported
-1,
"",
"",
"""
308201f1301b06092a864886f70d010503300e0408f9b990c89af1d41b020208
00048201d0c6267fe8592903891933d559e71a7ca68b2e39150f19daca0f7921
52f97e249d72f670d5140e9150433310ed7c7ee51927693fd39884cb9551cea5
a7b746f7edf199f8787d4787a35dad930d7db057b2118851211b645ac8b90fa6
b0e7d49ac8567cbd5fff226e87aa9129a0f52c45e9307752e8575c3b0ff756b7
31fda6942d15ecb6b27ea19370ccc79773f47891e80d22b440d81259c4c28eac
e0ca839524116bcf52d8c566e49a95ddb0e5493437279a770a39fd333f3fca91
55884fad0ba5aaf273121f893059d37dd417da7dcfd0d6fa7494968f13b2cc95
65633f2c891340193e5ec00e4ee0b0e90b3b93da362a4906360845771ade1754
9df79140be5993f3424c012598eadd3e7c7c0b4db2c72cf103d7943a5cf61420
93370b9702386c3dd4eb0a47f34b579624a46a108b2d13921fa1b367495fe345
6aa128aa70f8ca80ae13eb301e96c380724ce67c54380bbea2316c1faf4d058e
b4ca2e23442047606b9bc4b3bf65b432cb271bea4eb35dd3eb360d3be8612a87
a50e96a2264490aeabdc07c6e78e5dbf4fe3388726d0e2a228346bf3c2907d68
2a6276b22ae883fb30fa611f4e4193e7a08480fcd7db48308bacbd72bf4807aa
11fd394859f97d22982f7fe890b2e2a0f7e7ffb693
"""
))
#
# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
# -outform DER -out keyenc.der -v1 PBE-SHA1-RC2-64
# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
#
wrapped_enc_keys.append((
'skip encryption', # pbeWithSHA1AndRC2-CBC, only decoding is supported
-1,
"",
"",
"""
308201f1301b06092a864886f70d01050b300e04083ee943bdae185008020208
00048201d0e4614d9371d3ff10ceabc2f6a7a13a0f449f9a714144e46518ea55
e3e6f0cde24031d01ef1f37ec40081449ef01914faf45983dde0d2bc496712de
8dd15a5527dff4721d9016c13f34fb93e3ce68577e30146266d71b539f854e56
753a192cf126ed4812734d86f81884374f1100772f78d0646e9946407637c565
d070acab413c55952f7237437f2e48cae7fa0ff8d370de2bf446dd08049a3663
d9c813ac197468c02e2b687e7ca994cf7f03f01b6eca87dbfed94502c2094157
ea39f73fe4e591df1a68b04d19d9adab90bb9898467c1464ad20bf2b8fb9a5ff
d3ec91847d1c67fd768a4b9cfb46572eccc83806601372b6fad0243f58f623b7
1c5809dea0feb8278fe27e5560eed8448dc93f5612f546e5dd7c5f6404365eb2
5bf3396814367ae8b15c5c432b57eaed1f882c05c7f6517ee9e42b87b7b8d071
9d6125d1b52f7b2cca1f6bd5f584334bf90bce1a7d938274cafe27b68e629698
b16e27ae528db28593af9adcfccbebb3b9e1f2af5cd5531b51968389caa6c091
e7de1f1b96f0d258e54e540d961a7c0ef51fda45d6da5fddd33e9bbfd3a5f8d7
d7ab2e971de495cddbc86d38444fee9f0ac097b00adaf7802dabe0cff5b43b45
4f26b7b547016f89be52676866189911c53e2f2477"""
))
#
# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
# -outform DER -out keyenc.der -v1 PBE-MD5-RC2-64
# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
#
wrapped_enc_keys.append((
'skip encryption', # pbeWithMD5AndRC2-CBC, only decoding is supported
-1,
"",
"",
"""
308201f1301b06092a864886f70d010506300e0408f5cd2fee56d9b4b8020208
00048201d086454942d6166a19d6b108465bd111e7080911f573d54b1369c676
df28600e84936bfec04f91023ff16499e2e07178c340904f12ffa6886ab66228
32bf43c2bff5a0ed14e765918cf5fc543ad49566246f7eb3fc044fa5a9c25f40
8fc8c8296b91658d3bb1067c0aba008c4fefd9e2bcdbbbd63fdc8085482bccf4
f150cec9a084259ad441a017e5d81a1034ef2484696a7a50863836d0eeda45cd
8cee8ecabfed703f8d9d4bbdf3a767d32a0ccdc38550ee2928d7fe3fa27eda5b
5c7899e75ad55d076d2c2d3c37d6da3d95236081f9671dab9a99afdb1cbc890e
332d1a91105d9a8ce08b6027aa07367bd1daec3059cb51f5d896124da16971e4
0ca4bcadb06c854bdf39f42dd24174011414e51626d198775eff3449a982df7b
ace874e77e045eb6d7c3faef0750792b29a068a6291f7275df1123fac5789c51
27ace42836d81633faf9daf38f6787fff0394ea484bbcd465b57d4dbee3cf8df
b77d1db287b3a6264c466805be5a4fe85cfbca180699859280f2dd8e2c2c10b5
7a7d2ac670c6039d41952fbb0e4f99b560ebe1d020e1b96d02403283819c00cc
529c51f0b0101555e4c58002ba3c6e3c12e3fde1aec94382792e96d9666a2b33
3dc397b22ecab67ee38a552fec29a1d4ff8719c748"""
))
#
# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
# -outform DER -out keyenc.der -v1 PBE-SHA1-DES
# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
#
wrapped_enc_keys.append((
'skip encryption', # pbeWithSHA1AndDES-CBC, only decoding is supported
-1,
"",
"",
"""
308201f1301b06092a864886f70d01050a300e04089bacc9cf1e8f734e020208
00048201d03e502f3ceafe8fd19ab2939576bfdded26d719b2441db1459688f5
9673218b41ec1f739edf1e460bd927bc28470c87b2d4fc8ea02ba17b47a63c49
c5c1bee40529dadfd3ef8b4472c730bc136678c78abfb34670ec9d7dcd17ee3f
892f93f2629e6e0f4b24ecb9f954069bf722f466dece3913bb6abbd2c471d9a5
c5eea89b14aaccda43d30b0dd0f6eb6e9850d9747aa8aa8414c383ad01c374ee
26d3552abec9ba22669cc9622ccf2921e3d0c8ecd1a70e861956de0bec6104b5
b649ac994970c83f8a9e84b14a7dff7843d4ca3dd4af87cea43b5657e15ae0b5
a940ce5047f006ab3596506600724764f23757205fe374fee04911336d655acc
03e159ec27789191d1517c4f3f9122f5242d44d25eab8f0658cafb928566ca0e
8f6589aa0c0ab13ca7a618008ae3eafd4671ee8fe0b562e70b3623b0e2a16eee
97fd388087d2e03530c9fe7db6e52eccc7c48fd701ede35e08922861a9508d12
bc8bbf24f0c6bee6e63dbcb489b603d4c4a78ce45bf2eab1d5d10456c42a65a8
3a606f4e4b9b46eb13b57f2624b651859d3d2d5192b45dbd5a2ead14ff20ca76
48f321309aa56d8c0c4a192b580821cc6c70c75e6f19d1c5414da898ec4dd39d
b0eb93d6ba387a80702dfd2db610757ba340f63230
"""
))
#
# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
# -outform DER -out keyenc.der -v2 aes128
# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
#
wrapped_enc_keys.append((
'PBKDF2WithHMAC-SHA1AndAES128-CBC',
2048,
"4F66EE5D3BCD531FE6EBF4B4E73016B8", # IV
"479F25156176C53A", # Salt
"""
3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c
300e0408479f25156176c53a02020800301d060960864801650304010204104f
66ee5d3bcd531fe6ebf4b4e73016b8048201d0e33cfa560423f589d097d21533
3b880a5ebac5b2ac58b4e73b0d787aee7764f034fe34ca1d1bd845c0a7c3316f
afbfb2129e03dcaf5a5031394206492828dacef1e04639bee5935e0f46114202
10bc6c37182f4889be11c5d0486c398f4be952e5740f65de9d8edeb275e2b406
e19bc29ad5ebb97fa536344fc3d84c7e755696f12b810898de4e6f069b8a81c8
0aab0d45d7d062303aaa4a10c2ce84fdb5a03114039cfe138e38bb15b2ced717
93549cdad85e730b14d9e2198b663dfdc8d04a4349eb3de59b076ad40b116d4a
25ed917c576bc7c883c95ef0f1180e28fc9981bea069594c309f1aa1b253ceab
a2f0313bb1372bcb51a745056be93d77a1f235a762a45e8856512d436b2ca0f7
dd60fbed394ba28978d2a2b984b028529d0a58d93aba46c6bbd4ac1e4013cbaa
63b00988bc5f11ccc40141c346762d2b28f64435d4be98ec17c1884985e3807e
e550db606600993efccf6de0dfc2d2d70b5336a3b018fa415d6bdd59f5777118
16806b7bc17c4c7e20ad7176ebfa5a1aa3f6bc10f04b77afd443944642ac9cca
d740e082b4a3bbb8bafdd34a0b3c5f2f3c2aceccccdccd092b78994b845bfa61
706c3b9df5165ed1dbcbf1244fe41fc9bf993f52f7658e2f87e1baaeacb0f562
9d905c
"""
))
#
# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
# -outform DER -out keyenc.der -v2 aes192
# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
#
wrapped_enc_keys.append((
'PBKDF2WithHMAC-SHA1AndAES192-CBC',
2048,
"5CFC2A4FF7B63201A4A8A5B021148186", # IV
"D718541C264944CE", # Salt
"""
3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c
300e0408d718541c264944ce02020800301d060960864801650304011604105c
fc2a4ff7b63201a4a8a5b021148186048201d08e74aaa21b8bcfb15b9790fe95
b0e09ddb0f189b6fb1682fdb9f122b804650ddec3c67a1df093a828b3e5fbcc6
286abbcc5354c482fd796d972e919ca8a5eba1eaa2293af1d648013ddad72106
75622264dfba55dafdda39e338f058f1bdb9846041ffff803797d3fdf3693135
8a192729ea8346a7e5e58e925a2e2e4af0818581859e8215d87370eb4194a5ff
bae900857d4c591dbc651a241865a817eaede9987c9f9ae4f95c0bf930eea88c
4d7596e535ffb7ca369988aba75027a96b9d0bc9c8b0b75f359067fd145a378b
02aaa15e9db7a23176224da48a83249005460cc6e429168657f2efa8b1af7537
d7d7042f2d683e8271b21d591090963eeb57aea6172f88da139e1614d6a7d1a2
1002d5a7a93d6d21156e2b4777f6fc069287a85a1538c46b7722ccde591ab55c
630e1ceeb1ac42d1b41f3f654e9da86b5efced43775ea68b2594e50e4005e052
0fe753c0898120c2c07265367ff157f6538a1e4080d6f9d1ca9eb51939c9574e
f2e4e1e87c1434affd5808563cddd376776dbbf790c6a40028f311a8b58dafa2
0970ed34acd6e3e89d063987893b2b9570ddb8cc032b05a723bba9444933ebf3
c624204be72f4190e0245197d0cb772bec933fd8442445f9a28bd042d5a3a1e9
9a8a07
"""
))
#
# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
# -outform DER -out keyenc.der -v2 aes192
# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
#
wrapped_enc_keys.append((
'PBKDF2WithHMAC-SHA1AndAES256-CBC',
2048,
"323351F94462AC563E053A056252C2C4", # IV
"02A6CD0D12E727B5", # Salt
"""
3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c
300e040802a6cd0d12e727b502020800301d060960864801650304012a041032
3351f94462ac563e053a056252c2c4048201d07f4ef1c7be21aae738a20c5632
b8bdbbb9083b6e7f68822267b1f481fd27fdafd61a90660de6e4058790e4c912
bf3f319a7c37e6eb3d956daaa143865020d554bf6215e8d7492359aaeef45d6e
d85a686ed26c0bf7c18d071d827a86f0b73e1db0c0e7f3d42201544093302a90
551ad530692468c47ac15c69500b8ca67d4a17b64d15cecc035ae50b768a36cf
07c395afa091e9e6f86f665455fbdc1b21ad79c0908b73da5de75a9b43508d5d
44dc97a870cd3cd9f01ca24452e9b11c1b4982946702cfcbfda5b2fcc0203fb5
0b52a115760bd635c94d4c95ac2c640ee9a04ffaf6ccff5a8d953dd5d88ca478
c377811c521f2191639c643d657a9e364af88bb7c14a356c2b0b4870a23c2f54
d41f8157afff731471dccc6058b15e1151bcf84b39b5e622a3a1d65859c912a5
591b85e034a1f6af664f030a6bfc8c3d20c70f32b54bcf4da9c2da83cef49cf8
e9a74f0e5d358fe50b88acdce6a9db9a7ad61536212fc5f877ebfc7957b8bda4
b1582a0f10d515a20ee06cf768db9c977aa6fbdca7540d611ff953012d009dac
e8abd059f8e8ffea637c9c7721f817aaf0bb23403e26a0ef0ff0e2037da67d41
af728481f53443551a9bff4cea023164e9622b5441a309e1f4bff98e5bf76677
8d7cd9
"""
))
# hexdump -v -e '32/1 "%02x" "\n"' botan_scrypt.der
botan_scrypt = """
3081f1305206092a864886f70d01050d3045302806092b06010401da47040b30
1b040c316c5c7a847276a838a668280202200002010102010102012030190609
60864801650304012e040c293e9bcddc0d59d64e060cb604819ab92318063480
16148081a3123bb092b636ec0cc3b964628e181504c13eaf94987e6fb9f171d4
9c45baeeb79c1d805d5a762d9bfd6d1995669df60a2cd0174b6d204693964de7
05bc3fdc3a4ce5db01f30a994c82b0aac786e4f8655138c952f1cf2cc6093f90
b5e5ca507beb539ff497b7b6370ba7f31f4928d3385dbe8bcd2395813ba1324e
6795e81a8518aff0f0a9e01396539f937b8b7b08
"""
# hexdump -v -e '32/1 "%02x" "\n"' botan_pbkdf2.der
botan_pbkdf2 = """
3081f3305e06092a864886f70d01050d3051303006092a864886f70d01050c30
23040cc91c89b368db578d2ec4c32002020fa0020118300c06082a864886f70d
02090500301d060960864801650304011604102a7147289e7c914a7d8257e4a1
a2135b048190a648955fc96ecae56dcb4d0ab19edc5b7ef1219c88c7c3b2d0ed
b21e25d2559447f53e20b90b2f20e72456d943561c4925aad6067a4c720afb3d
691e14dfffa10ef77898e21d134f19136d35088a7aac508b296fd00d5742ad69
8c693293b6a591e3660b130d718724d23d696f4da9bf4031475fafb682d7955c
996363f37032e10ac85afebb7cc1cbfc0e5d4c60a4c2
"""
def txt2bin(inputs):
s = b('').join([b(x) for x in inputs if not (x in '\n\r\t ')])
return unhexlify(s)
class Rng:
def __init__(self, output):
self.output=output
self.idx=0
def __call__(self, n):
output = self.output[self.idx:self.idx+n]
self.idx += n
return output
class PKCS8_Decrypt(unittest.TestCase):
def setUp(self):
self.oid_key = oid_key
self.clear_key = txt2bin(clear_key)
self.wrapped_clear_key = txt2bin(wrapped_clear_key)
self.wrapped_enc_keys = []
for t in wrapped_enc_keys:
self.wrapped_enc_keys.append((
t[0],
t[1],
txt2bin(t[2]),
txt2bin(t[3]),
txt2bin(t[4])
))
### NO ENCRYTION
def test1(self):
"""Verify unwrapping w/o encryption"""
res1, res2, res3 = PKCS8.unwrap(self.wrapped_clear_key)
self.assertEqual(res1, self.oid_key)
self.assertEqual(res2, self.clear_key)
def test2(self):
"""Verify wrapping w/o encryption"""
wrapped = PKCS8.wrap(self.clear_key, self.oid_key)
res1, res2, res3 = PKCS8.unwrap(wrapped)
self.assertEqual(res1, self.oid_key)
self.assertEqual(res2, self.clear_key)
## ENCRYPTION
def test3(self):
"""Verify unwrapping with encryption"""
for t in self.wrapped_enc_keys:
res1, res2, res3 = PKCS8.unwrap(t[4], b"TestTest")
self.assertEqual(res1, self.oid_key)
self.assertEqual(res2, self.clear_key)
def test4(self):
"""Verify wrapping with encryption"""
for t in self.wrapped_enc_keys:
if t[0] == 'skip encryption':
continue
rng = Rng(t[2]+t[3])
params = { 'iteration_count':t[1] }
wrapped = PKCS8.wrap(
self.clear_key,
self.oid_key,
b("TestTest"),
protection=t[0],
prot_params=params,
key_params=DerNull(),
randfunc=rng)
self.assertEqual(wrapped, t[4])
def test_import_botan_keys(self):
botan_scrypt_der = txt2bin(botan_scrypt)
key1 = PKCS8.unwrap(botan_scrypt_der,
b'your_password')
botan_pbkdf2_der = txt2bin(botan_pbkdf2)
key2 = PKCS8.unwrap(botan_pbkdf2_der,
b'your_password')
self.assertEqual(key1, key2)
def get_tests(config={}):
from Crypto.SelfTest.st_common import list_test_cases
listTests = []
listTests += list_test_cases(PKCS8_Decrypt)
return listTests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,51 @@
#
# SelfTest/Math/__init__.py: Self-test for math 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 Math"""
def get_tests(config={}):
tests = []
from Crypto.SelfTest.Math import test_Numbers
from Crypto.SelfTest.Math import test_Primality
from Crypto.SelfTest.Math import test_modexp
from Crypto.SelfTest.Math import test_modmult
tests += test_Numbers.get_tests(config=config)
tests += test_Primality.get_tests(config=config)
tests += test_modexp.get_tests(config=config)
tests += test_modmult.get_tests(config=config)
return tests
if __name__ == '__main__':
import unittest
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,838 @@
#
# SelfTest/Math/test_Numbers.py: Self-test for Numbers 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 Math.Numbers"""
import sys
import unittest
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Util.py3compat import *
from Crypto.Math._IntegerNative import IntegerNative
class TestIntegerBase(unittest.TestCase):
def setUp(self):
raise NotImplementedError("To be implemented")
def Integers(self, *arg):
return map(self.Integer, arg)
def test_init_and_equality(self):
Integer = self.Integer
v1 = Integer(23)
v2 = Integer(v1)
v3 = Integer(-9)
self.assertRaises(ValueError, Integer, 1.0)
v4 = Integer(10**10)
v5 = Integer(-10**10)
v6 = Integer(0xFFFF)
v7 = Integer(0xFFFFFFFF)
v8 = Integer(0xFFFFFFFFFFFFFFFF)
self.assertEqual(v1, v1)
self.assertEqual(v1, 23)
self.assertEqual(v1, v2)
self.assertEqual(v3, -9)
self.assertEqual(v4, 10 ** 10)
self.assertEqual(v5, -10 ** 10)
self.assertEqual(v6, 0xFFFF)
self.assertEqual(v7, 0xFFFFFFFF)
self.assertEqual(v8, 0xFFFFFFFFFFFFFFFF)
self.assertFalse(v1 == v4)
# Init and comparison between Integer's
v6 = Integer(v1)
self.assertEqual(v1, v6)
self.assertFalse(Integer(0) == None)
def test_conversion_to_int(self):
v1, v2 = self.Integers(-23, 2 ** 1000)
self.assertEqual(int(v1), -23)
self.assertEqual(int(v2), 2 ** 1000)
def test_equality_with_ints(self):
v1, v2, v3 = self.Integers(23, -89, 2 ** 1000)
self.assertTrue(v1 == 23)
self.assertTrue(v2 == -89)
self.assertFalse(v1 == 24)
self.assertTrue(v3 == 2 ** 1000)
def test_conversion_to_str(self):
v1, v2, v3, v4 = self.Integers(20, 0, -20, 2 ** 1000)
self.assertTrue(str(v1) == "20")
self.assertTrue(str(v2) == "0")
self.assertTrue(str(v3) == "-20")
self.assertTrue(str(v4) == "10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376")
def test_repr(self):
v1, v2 = self.Integers(-1, 2**80)
self.assertEqual(repr(v1), "Integer(-1)")
self.assertEqual(repr(v2), "Integer(1208925819614629174706176)")
def test_conversion_to_bytes(self):
Integer = self.Integer
v0 = Integer(0)
self.assertEqual(b"\x00", v0.to_bytes())
v1 = Integer(0x17)
self.assertEqual(b"\x17", v1.to_bytes())
v2 = Integer(0xFFFE)
self.assertEqual(b"\xFF\xFE", v2.to_bytes())
self.assertEqual(b"\x00\xFF\xFE", v2.to_bytes(3))
self.assertRaises(ValueError, v2.to_bytes, 1)
self.assertEqual(b"\xFE\xFF", v2.to_bytes(byteorder='little'))
self.assertEqual(b"\xFE\xFF\x00", v2.to_bytes(3, byteorder='little'))
v3 = Integer(0xFF00AABBCCDDEE1122)
self.assertEqual(b"\xFF\x00\xAA\xBB\xCC\xDD\xEE\x11\x22", v3.to_bytes())
self.assertEqual(b"\x22\x11\xEE\xDD\xCC\xBB\xAA\x00\xFF",
v3.to_bytes(byteorder='little'))
self.assertEqual(b"\x00\xFF\x00\xAA\xBB\xCC\xDD\xEE\x11\x22",
v3.to_bytes(10))
self.assertEqual(b"\x22\x11\xEE\xDD\xCC\xBB\xAA\x00\xFF\x00",
v3.to_bytes(10, byteorder='little'))
self.assertRaises(ValueError, v3.to_bytes, 8)
v4 = Integer(-90)
self.assertRaises(ValueError, v4.to_bytes)
self.assertRaises(ValueError, v4.to_bytes, byteorder='bittle')
def test_conversion_from_bytes(self):
Integer = self.Integer
v1 = Integer.from_bytes(b"\x00")
self.assertTrue(isinstance(v1, Integer))
self.assertEqual(0, v1)
v2 = Integer.from_bytes(b"\x00\x01")
self.assertEqual(1, v2)
v3 = Integer.from_bytes(b"\xFF\xFF")
self.assertEqual(0xFFFF, v3)
v4 = Integer.from_bytes(b"\x00\x01", 'big')
self.assertEqual(1, v4)
v5 = Integer.from_bytes(b"\x00\x01", byteorder='big')
self.assertEqual(1, v5)
v6 = Integer.from_bytes(b"\x00\x01", byteorder='little')
self.assertEqual(0x0100, v6)
self.assertRaises(ValueError, Integer.from_bytes, b'\x09', 'bittle')
def test_inequality(self):
# Test Integer!=Integer and Integer!=int
v1, v2, v3, v4 = self.Integers(89, 89, 90, -8)
self.assertTrue(v1 != v3)
self.assertTrue(v1 != 90)
self.assertFalse(v1 != v2)
self.assertFalse(v1 != 89)
self.assertTrue(v1 != v4)
self.assertTrue(v4 != v1)
self.assertTrue(self.Integer(0) != None)
def test_less_than(self):
# Test Integer<Integer and Integer<int
v1, v2, v3, v4, v5 = self.Integers(13, 13, 14, -8, 2 ** 10)
self.assertTrue(v1 < v3)
self.assertTrue(v1 < 14)
self.assertFalse(v1 < v2)
self.assertFalse(v1 < 13)
self.assertTrue(v4 < v1)
self.assertFalse(v1 < v4)
self.assertTrue(v1 < v5)
self.assertFalse(v5 < v1)
def test_less_than_or_equal(self):
# Test Integer<=Integer and Integer<=int
v1, v2, v3, v4, v5 = self.Integers(13, 13, 14, -4, 2 ** 10)
self.assertTrue(v1 <= v1)
self.assertTrue(v1 <= 13)
self.assertTrue(v1 <= v2)
self.assertTrue(v1 <= 14)
self.assertTrue(v1 <= v3)
self.assertFalse(v1 <= v4)
self.assertTrue(v1 <= v5)
self.assertFalse(v5 <= v1)
def test_more_than(self):
# Test Integer>Integer and Integer>int
v1, v2, v3, v4, v5 = self.Integers(13, 13, 14, -8, 2 ** 10)
self.assertTrue(v3 > v1)
self.assertTrue(v3 > 13)
self.assertFalse(v1 > v1)
self.assertFalse(v1 > v2)
self.assertFalse(v1 > 13)
self.assertTrue(v1 > v4)
self.assertFalse(v4 > v1)
self.assertTrue(v5 > v1)
self.assertFalse(v1 > v5)
def test_more_than_or_equal(self):
# Test Integer>=Integer and Integer>=int
v1, v2, v3, v4 = self.Integers(13, 13, 14, -4)
self.assertTrue(v3 >= v1)
self.assertTrue(v3 >= 13)
self.assertTrue(v1 >= v2)
self.assertTrue(v1 >= v1)
self.assertTrue(v1 >= 13)
self.assertFalse(v4 >= v1)
def test_bool(self):
v1, v2, v3, v4 = self.Integers(0, 10, -9, 2 ** 10)
self.assertFalse(v1)
self.assertFalse(bool(v1))
self.assertTrue(v2)
self.assertTrue(bool(v2))
self.assertTrue(v3)
self.assertTrue(v4)
def test_is_negative(self):
v1, v2, v3, v4, v5 = self.Integers(-3 ** 100, -3, 0, 3, 3**100)
self.assertTrue(v1.is_negative())
self.assertTrue(v2.is_negative())
self.assertFalse(v4.is_negative())
self.assertFalse(v5.is_negative())
def test_addition(self):
# Test Integer+Integer and Integer+int
v1, v2, v3 = self.Integers(7, 90, -7)
self.assertTrue(isinstance(v1 + v2, self.Integer))
self.assertEqual(v1 + v2, 97)
self.assertEqual(v1 + 90, 97)
self.assertEqual(v1 + v3, 0)
self.assertEqual(v1 + (-7), 0)
self.assertEqual(v1 + 2 ** 10, 2 ** 10 + 7)
def test_subtraction(self):
# Test Integer-Integer and Integer-int
v1, v2, v3 = self.Integers(7, 90, -7)
self.assertTrue(isinstance(v1 - v2, self.Integer))
self.assertEqual(v2 - v1, 83)
self.assertEqual(v2 - 7, 83)
self.assertEqual(v2 - v3, 97)
self.assertEqual(v1 - (-7), 14)
self.assertEqual(v1 - 2 ** 10, 7 - 2 ** 10)
def test_multiplication(self):
# Test Integer-Integer and Integer-int
v1, v2, v3, v4 = self.Integers(4, 5, -2, 2 ** 10)
self.assertTrue(isinstance(v1 * v2, self.Integer))
self.assertEqual(v1 * v2, 20)
self.assertEqual(v1 * 5, 20)
self.assertEqual(v1 * -2, -8)
self.assertEqual(v1 * 2 ** 10, 4 * (2 ** 10))
def test_floor_div(self):
v1, v2, v3 = self.Integers(3, 8, 2 ** 80)
self.assertTrue(isinstance(v1 // v2, self.Integer))
self.assertEqual(v2 // v1, 2)
self.assertEqual(v2 // 3, 2)
self.assertEqual(v2 // -3, -3)
self.assertEqual(v3 // 2 ** 79, 2)
self.assertRaises(ZeroDivisionError, lambda: v1 // 0)
def test_remainder(self):
# Test Integer%Integer and Integer%int
v1, v2, v3 = self.Integers(23, 5, -4)
self.assertTrue(isinstance(v1 % v2, self.Integer))
self.assertEqual(v1 % v2, 3)
self.assertEqual(v1 % 5, 3)
self.assertEqual(v3 % 5, 1)
self.assertEqual(v1 % 2 ** 10, 23)
self.assertRaises(ZeroDivisionError, lambda: v1 % 0)
self.assertRaises(ValueError, lambda: v1 % -6)
def test_simple_exponentiation(self):
v1, v2, v3 = self.Integers(4, 3, -2)
self.assertTrue(isinstance(v1 ** v2, self.Integer))
self.assertEqual(v1 ** v2, 64)
self.assertEqual(pow(v1, v2), 64)
self.assertEqual(v1 ** 3, 64)
self.assertEqual(pow(v1, 3), 64)
self.assertEqual(v3 ** 2, 4)
self.assertEqual(v3 ** 3, -8)
self.assertRaises(ValueError, pow, v1, -3)
def test_modular_exponentiation(self):
v1, v2, v3 = self.Integers(23, 5, 17)
self.assertTrue(isinstance(pow(v1, v2, v3), self.Integer))
self.assertEqual(pow(v1, v2, v3), 7)
self.assertEqual(pow(v1, 5, v3), 7)
self.assertEqual(pow(v1, v2, 17), 7)
self.assertEqual(pow(v1, 5, 17), 7)
self.assertEqual(pow(v1, 0, 17), 1)
self.assertEqual(pow(v1, 1, 2 ** 80), 23)
self.assertEqual(pow(v1, 2 ** 80, 89298), 17689)
self.assertRaises(ZeroDivisionError, pow, v1, 5, 0)
self.assertRaises(ValueError, pow, v1, 5, -4)
self.assertRaises(ValueError, pow, v1, -3, 8)
def test_inplace_exponentiation(self):
v1 = self.Integer(4)
v1.inplace_pow(2)
self.assertEqual(v1, 16)
v1 = self.Integer(4)
v1.inplace_pow(2, 15)
self.assertEqual(v1, 1)
def test_abs(self):
v1, v2, v3, v4, v5 = self.Integers(-2 ** 100, -2, 0, 2, 2 ** 100)
self.assertEqual(abs(v1), 2 ** 100)
self.assertEqual(abs(v2), 2)
self.assertEqual(abs(v3), 0)
self.assertEqual(abs(v4), 2)
self.assertEqual(abs(v5), 2 ** 100)
def test_sqrt(self):
v1, v2, v3, v4 = self.Integers(-2, 0, 49, 10**100)
self.assertRaises(ValueError, v1.sqrt)
self.assertEqual(v2.sqrt(), 0)
self.assertEqual(v3.sqrt(), 7)
self.assertEqual(v4.sqrt(), 10**50)
def test_sqrt_module(self):
# Invalid modulus (non positive)
self.assertRaises(ValueError, self.Integer(5).sqrt, 0)
self.assertRaises(ValueError, self.Integer(5).sqrt, -1)
# Simple cases
assert self.Integer(0).sqrt(5) == 0
assert self.Integer(1).sqrt(5) in (1, 4)
# Test with all quadratic residues in several fields
for p in (11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53):
for i in range(0, p):
square = i**2 % p
res = self.Integer(square).sqrt(p)
assert res in (i, p - i)
# 2 is a non-quadratic reside in Z_11
self.assertRaises(ValueError, self.Integer(2).sqrt, 11)
# 10 is not a prime
self.assertRaises(ValueError, self.Integer(4).sqrt, 10)
# 5 is square residue of 4 and 7
assert self.Integer(5 - 11).sqrt(11) in (4, 7)
assert self.Integer(5 + 11).sqrt(11) in (4, 7)
def test_in_place_add(self):
v1, v2 = self.Integers(10, 20)
v1 += v2
self.assertEqual(v1, 30)
v1 += 10
self.assertEqual(v1, 40)
v1 += -1
self.assertEqual(v1, 39)
v1 += 2 ** 1000
self.assertEqual(v1, 39 + 2 ** 1000)
def test_in_place_sub(self):
v1, v2 = self.Integers(10, 20)
v1 -= v2
self.assertEqual(v1, -10)
v1 -= -100
self.assertEqual(v1, 90)
v1 -= 90000
self.assertEqual(v1, -89910)
v1 -= -100000
self.assertEqual(v1, 10090)
def test_in_place_mul(self):
v1, v2 = self.Integers(3, 5)
v1 *= v2
self.assertEqual(v1, 15)
v1 *= 2
self.assertEqual(v1, 30)
v1 *= -2
self.assertEqual(v1, -60)
v1 *= 2 ** 1000
self.assertEqual(v1, -60 * (2 ** 1000))
def test_in_place_modulus(self):
v1, v2 = self.Integers(20, 7)
v1 %= v2
self.assertEqual(v1, 6)
v1 %= 2 ** 1000
self.assertEqual(v1, 6)
v1 %= 2
self.assertEqual(v1, 0)
def t():
v3 = self.Integer(9)
v3 %= 0
self.assertRaises(ZeroDivisionError, t)
def test_and(self):
v1, v2, v3 = self.Integers(0xF4, 0x31, -0xF)
self.assertTrue(isinstance(v1 & v2, self.Integer))
self.assertEqual(v1 & v2, 0x30)
self.assertEqual(v1 & 0x31, 0x30)
self.assertEqual(v1 & v3, 0xF0)
self.assertEqual(v1 & -0xF, 0xF0)
self.assertEqual(v3 & -0xF, -0xF)
self.assertEqual(v2 & (2 ** 1000 + 0x31), 0x31)
def test_or(self):
v1, v2, v3 = self.Integers(0x40, 0x82, -0xF)
self.assertTrue(isinstance(v1 | v2, self.Integer))
self.assertEqual(v1 | v2, 0xC2)
self.assertEqual(v1 | 0x82, 0xC2)
self.assertEqual(v2 | v3, -0xD)
self.assertEqual(v2 | 2 ** 1000, 2 ** 1000 + 0x82)
def test_right_shift(self):
v1, v2, v3 = self.Integers(0x10, 1, -0x10)
self.assertEqual(v1 >> 0, v1)
self.assertTrue(isinstance(v1 >> v2, self.Integer))
self.assertEqual(v1 >> v2, 0x08)
self.assertEqual(v1 >> 1, 0x08)
self.assertRaises(ValueError, lambda: v1 >> -1)
self.assertEqual(v1 >> (2 ** 1000), 0)
self.assertEqual(v3 >> 1, -0x08)
self.assertEqual(v3 >> (2 ** 1000), -1)
def test_in_place_right_shift(self):
v1, v2, v3 = self.Integers(0x10, 1, -0x10)
v1 >>= 0
self.assertEqual(v1, 0x10)
v1 >>= 1
self.assertEqual(v1, 0x08)
v1 >>= v2
self.assertEqual(v1, 0x04)
v3 >>= 1
self.assertEqual(v3, -0x08)
def l():
v4 = self.Integer(0x90)
v4 >>= -1
self.assertRaises(ValueError, l)
def m1():
v4 = self.Integer(0x90)
v4 >>= 2 ** 1000
return v4
self.assertEqual(0, m1())
def m2():
v4 = self.Integer(-1)
v4 >>= 2 ** 1000
return v4
self.assertEqual(-1, m2())
def _test_left_shift(self):
v1, v2, v3 = self.Integers(0x10, 1, -0x10)
self.assertEqual(v1 << 0, v1)
self.assertTrue(isinstance(v1 << v2, self.Integer))
self.assertEqual(v1 << v2, 0x20)
self.assertEqual(v1 << 1, 0x20)
self.assertEqual(v3 << 1, -0x20)
self.assertRaises(ValueError, lambda: v1 << -1)
self.assertRaises(ValueError, lambda: v1 << (2 ** 1000))
def test_in_place_left_shift(self):
v1, v2, v3 = self.Integers(0x10, 1, -0x10)
v1 <<= 0
self.assertEqual(v1, 0x10)
v1 <<= 1
self.assertEqual(v1, 0x20)
v1 <<= v2
self.assertEqual(v1, 0x40)
v3 <<= 1
self.assertEqual(v3, -0x20)
def l():
v4 = self.Integer(0x90)
v4 <<= -1
self.assertRaises(ValueError, l)
def m():
v4 = self.Integer(0x90)
v4 <<= 2 ** 1000
self.assertRaises(ValueError, m)
def test_get_bit(self):
v1, v2, v3 = self.Integers(0x102, -3, 1)
self.assertEqual(v1.get_bit(0), 0)
self.assertEqual(v1.get_bit(1), 1)
self.assertEqual(v1.get_bit(v3), 1)
self.assertEqual(v1.get_bit(8), 1)
self.assertEqual(v1.get_bit(9), 0)
self.assertRaises(ValueError, v1.get_bit, -1)
self.assertEqual(v1.get_bit(2 ** 1000), 0)
self.assertRaises(ValueError, v2.get_bit, -1)
self.assertRaises(ValueError, v2.get_bit, 0)
self.assertRaises(ValueError, v2.get_bit, 1)
self.assertRaises(ValueError, v2.get_bit, 2 * 1000)
def test_odd_even(self):
v1, v2, v3, v4, v5 = self.Integers(0, 4, 17, -4, -17)
self.assertTrue(v1.is_even())
self.assertTrue(v2.is_even())
self.assertFalse(v3.is_even())
self.assertTrue(v4.is_even())
self.assertFalse(v5.is_even())
self.assertFalse(v1.is_odd())
self.assertFalse(v2.is_odd())
self.assertTrue(v3.is_odd())
self.assertFalse(v4.is_odd())
self.assertTrue(v5.is_odd())
def test_size_in_bits(self):
v1, v2, v3, v4 = self.Integers(0, 1, 0x100, -90)
self.assertEqual(v1.size_in_bits(), 1)
self.assertEqual(v2.size_in_bits(), 1)
self.assertEqual(v3.size_in_bits(), 9)
self.assertRaises(ValueError, v4.size_in_bits)
def test_size_in_bytes(self):
v1, v2, v3, v4, v5, v6 = self.Integers(0, 1, 0xFF, 0x1FF, 0x10000, -9)
self.assertEqual(v1.size_in_bytes(), 1)
self.assertEqual(v2.size_in_bytes(), 1)
self.assertEqual(v3.size_in_bytes(), 1)
self.assertEqual(v4.size_in_bytes(), 2)
self.assertEqual(v5.size_in_bytes(), 3)
self.assertRaises(ValueError, v6.size_in_bits)
def test_perfect_square(self):
self.assertFalse(self.Integer(-9).is_perfect_square())
self.assertTrue(self.Integer(0).is_perfect_square())
self.assertTrue(self.Integer(1).is_perfect_square())
self.assertFalse(self.Integer(2).is_perfect_square())
self.assertFalse(self.Integer(3).is_perfect_square())
self.assertTrue(self.Integer(4).is_perfect_square())
self.assertTrue(self.Integer(39*39).is_perfect_square())
self.assertFalse(self.Integer(39*39+1).is_perfect_square())
for x in range(100, 1000):
self.assertFalse(self.Integer(x**2+1).is_perfect_square())
self.assertTrue(self.Integer(x**2).is_perfect_square())
def test_fail_if_divisible_by(self):
v1, v2, v3 = self.Integers(12, -12, 4)
# No failure expected
v1.fail_if_divisible_by(7)
v2.fail_if_divisible_by(7)
v2.fail_if_divisible_by(2 ** 80)
# Failure expected
self.assertRaises(ValueError, v1.fail_if_divisible_by, 4)
self.assertRaises(ValueError, v1.fail_if_divisible_by, v3)
def test_multiply_accumulate(self):
v1, v2, v3 = self.Integers(4, 3, 2)
v1.multiply_accumulate(v2, v3)
self.assertEqual(v1, 10)
v1.multiply_accumulate(v2, 2)
self.assertEqual(v1, 16)
v1.multiply_accumulate(3, v3)
self.assertEqual(v1, 22)
v1.multiply_accumulate(1, -2)
self.assertEqual(v1, 20)
v1.multiply_accumulate(-2, 1)
self.assertEqual(v1, 18)
v1.multiply_accumulate(1, 2 ** 1000)
self.assertEqual(v1, 18 + 2 ** 1000)
v1.multiply_accumulate(2 ** 1000, 1)
self.assertEqual(v1, 18 + 2 ** 1001)
def test_set(self):
v1, v2 = self.Integers(3, 6)
v1.set(v2)
self.assertEqual(v1, 6)
v1.set(9)
self.assertEqual(v1, 9)
v1.set(-2)
self.assertEqual(v1, -2)
v1.set(2 ** 1000)
self.assertEqual(v1, 2 ** 1000)
def test_inverse(self):
v1, v2, v3, v4, v5, v6 = self.Integers(2, 5, -3, 0, 723872, 3433)
self.assertTrue(isinstance(v1.inverse(v2), self.Integer))
self.assertEqual(v1.inverse(v2), 3)
self.assertEqual(v1.inverse(5), 3)
self.assertEqual(v3.inverse(5), 3)
self.assertEqual(v5.inverse(92929921), 58610507)
self.assertEqual(v6.inverse(9912), 5353)
self.assertRaises(ValueError, v2.inverse, 10)
self.assertRaises(ValueError, v1.inverse, -3)
self.assertRaises(ValueError, v4.inverse, 10)
self.assertRaises(ZeroDivisionError, v2.inverse, 0)
def test_inplace_inverse(self):
v1, v2 = self.Integers(2, 5)
v1.inplace_inverse(v2)
self.assertEqual(v1, 3)
def test_gcd(self):
v1, v2, v3, v4 = self.Integers(6, 10, 17, -2)
self.assertTrue(isinstance(v1.gcd(v2), self.Integer))
self.assertEqual(v1.gcd(v2), 2)
self.assertEqual(v1.gcd(10), 2)
self.assertEqual(v1.gcd(v3), 1)
self.assertEqual(v1.gcd(-2), 2)
self.assertEqual(v4.gcd(6), 2)
def test_lcm(self):
v1, v2, v3, v4, v5 = self.Integers(6, 10, 17, -2, 0)
self.assertTrue(isinstance(v1.lcm(v2), self.Integer))
self.assertEqual(v1.lcm(v2), 30)
self.assertEqual(v1.lcm(10), 30)
self.assertEqual(v1.lcm(v3), 102)
self.assertEqual(v1.lcm(-2), 6)
self.assertEqual(v4.lcm(6), 6)
self.assertEqual(v1.lcm(0), 0)
self.assertEqual(v5.lcm(0), 0)
def test_jacobi_symbol(self):
data = (
(1001, 1, 1),
(19, 45, 1),
(8, 21, -1),
(5, 21, 1),
(610, 987, -1),
(1001, 9907, -1),
(5, 3439601197, -1)
)
js = self.Integer.jacobi_symbol
# Jacobi symbol is always 1 for k==1 or n==1
for k in range(1, 30):
self.assertEqual(js(k, 1), 1)
for n in range(1, 30, 2):
self.assertEqual(js(1, n), 1)
# Fail if n is not positive odd
self.assertRaises(ValueError, js, 6, -2)
self.assertRaises(ValueError, js, 6, -1)
self.assertRaises(ValueError, js, 6, 0)
self.assertRaises(ValueError, js, 0, 0)
self.assertRaises(ValueError, js, 6, 2)
self.assertRaises(ValueError, js, 6, 4)
self.assertRaises(ValueError, js, 6, 6)
self.assertRaises(ValueError, js, 6, 8)
for tv in data:
self.assertEqual(js(tv[0], tv[1]), tv[2])
self.assertEqual(js(self.Integer(tv[0]), tv[1]), tv[2])
self.assertEqual(js(tv[0], self.Integer(tv[1])), tv[2])
def test_jacobi_symbol_wikipedia(self):
# Test vectors from https://en.wikipedia.org/wiki/Jacobi_symbol
tv = [
(3, [(1, 1), (2, -1), (3, 0), (4, 1), (5, -1), (6, 0), (7, 1), (8, -1), (9, 0), (10, 1), (11, -1), (12, 0), (13, 1), (14, -1), (15, 0), (16, 1), (17, -1), (18, 0), (19, 1), (20, -1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, -1), (27, 0), (28, 1), (29, -1), (30, 0)]),
(5, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 0), (6, 1), (7, -1), (8, -1), (9, 1), (10, 0), (11, 1), (12, -1), (13, -1), (14, 1), (15, 0), (16, 1), (17, -1), (18, -1), (19, 1), (20, 0), (21, 1), (22, -1), (23, -1), (24, 1), (25, 0), (26, 1), (27, -1), (28, -1), (29, 1), (30, 0)]),
(7, [(1, 1), (2, 1), (3, -1), (4, 1), (5, -1), (6, -1), (7, 0), (8, 1), (9, 1), (10, -1), (11, 1), (12, -1), (13, -1), (14, 0), (15, 1), (16, 1), (17, -1), (18, 1), (19, -1), (20, -1), (21, 0), (22, 1), (23, 1), (24, -1), (25, 1), (26, -1), (27, -1), (28, 0), (29, 1), (30, 1)]),
(9, [(1, 1), (2, 1), (3, 0), (4, 1), (5, 1), (6, 0), (7, 1), (8, 1), (9, 0), (10, 1), (11, 1), (12, 0), (13, 1), (14, 1), (15, 0), (16, 1), (17, 1), (18, 0), (19, 1), (20, 1), (21, 0), (22, 1), (23, 1), (24, 0), (25, 1), (26, 1), (27, 0), (28, 1), (29, 1), (30, 0)]),
(11, [(1, 1), (2, -1), (3, 1), (4, 1), (5, 1), (6, -1), (7, -1), (8, -1), (9, 1), (10, -1), (11, 0), (12, 1), (13, -1), (14, 1), (15, 1), (16, 1), (17, -1), (18, -1), (19, -1), (20, 1), (21, -1), (22, 0), (23, 1), (24, -1), (25, 1), (26, 1), (27, 1), (28, -1), (29, -1), (30, -1)]),
(13, [(1, 1), (2, -1), (3, 1), (4, 1), (5, -1), (6, -1), (7, -1), (8, -1), (9, 1), (10, 1), (11, -1), (12, 1), (13, 0), (14, 1), (15, -1), (16, 1), (17, 1), (18, -1), (19, -1), (20, -1), (21, -1), (22, 1), (23, 1), (24, -1), (25, 1), (26, 0), (27, 1), (28, -1), (29, 1), (30, 1)]),
(15, [(1, 1), (2, 1), (3, 0), (4, 1), (5, 0), (6, 0), (7, -1), (8, 1), (9, 0), (10, 0), (11, -1), (12, 0), (13, -1), (14, -1), (15, 0), (16, 1), (17, 1), (18, 0), (19, 1), (20, 0), (21, 0), (22, -1), (23, 1), (24, 0), (25, 0), (26, -1), (27, 0), (28, -1), (29, -1), (30, 0)]),
(17, [(1, 1), (2, 1), (3, -1), (4, 1), (5, -1), (6, -1), (7, -1), (8, 1), (9, 1), (10, -1), (11, -1), (12, -1), (13, 1), (14, -1), (15, 1), (16, 1), (17, 0), (18, 1), (19, 1), (20, -1), (21, 1), (22, -1), (23, -1), (24, -1), (25, 1), (26, 1), (27, -1), (28, -1), (29, -1), (30, 1)]),
(19, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 1), (6, 1), (7, 1), (8, -1), (9, 1), (10, -1), (11, 1), (12, -1), (13, -1), (14, -1), (15, -1), (16, 1), (17, 1), (18, -1), (19, 0), (20, 1), (21, -1), (22, -1), (23, 1), (24, 1), (25, 1), (26, 1), (27, -1), (28, 1), (29, -1), (30, 1)]),
(21, [(1, 1), (2, -1), (3, 0), (4, 1), (5, 1), (6, 0), (7, 0), (8, -1), (9, 0), (10, -1), (11, -1), (12, 0), (13, -1), (14, 0), (15, 0), (16, 1), (17, 1), (18, 0), (19, -1), (20, 1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, 1), (27, 0), (28, 0), (29, -1), (30, 0)]),
(23, [(1, 1), (2, 1), (3, 1), (4, 1), (5, -1), (6, 1), (7, -1), (8, 1), (9, 1), (10, -1), (11, -1), (12, 1), (13, 1), (14, -1), (15, -1), (16, 1), (17, -1), (18, 1), (19, -1), (20, -1), (21, -1), (22, -1), (23, 0), (24, 1), (25, 1), (26, 1), (27, 1), (28, -1), (29, 1), (30, -1)]),
(25, [(1, 1), (2, 1), (3, 1), (4, 1), (5, 0), (6, 1), (7, 1), (8, 1), (9, 1), (10, 0), (11, 1), (12, 1), (13, 1), (14, 1), (15, 0), (16, 1), (17, 1), (18, 1), (19, 1), (20, 0), (21, 1), (22, 1), (23, 1), (24, 1), (25, 0), (26, 1), (27, 1), (28, 1), (29, 1), (30, 0)]),
(27, [(1, 1), (2, -1), (3, 0), (4, 1), (5, -1), (6, 0), (7, 1), (8, -1), (9, 0), (10, 1), (11, -1), (12, 0), (13, 1), (14, -1), (15, 0), (16, 1), (17, -1), (18, 0), (19, 1), (20, -1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, -1), (27, 0), (28, 1), (29, -1), (30, 0)]),
(29, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 1), (6, 1), (7, 1), (8, -1), (9, 1), (10, -1), (11, -1), (12, -1), (13, 1), (14, -1), (15, -1), (16, 1), (17, -1), (18, -1), (19, -1), (20, 1), (21, -1), (22, 1), (23, 1), (24, 1), (25, 1), (26, -1), (27, -1), (28, 1), (29, 0), (30, 1)]),
]
js = self.Integer.jacobi_symbol
for n, kj in tv:
for k, j in kj:
self.assertEqual(js(k, n), j)
def test_hex(self):
v1, = self.Integers(0x10)
self.assertEqual(hex(v1), "0x10")
def test_mult_modulo_bytes(self):
modmult = self.Integer._mult_modulo_bytes
res = modmult(4, 5, 19)
self.assertEqual(res, b'\x01')
res = modmult(4 - 19, 5, 19)
self.assertEqual(res, b'\x01')
res = modmult(4, 5 - 19, 19)
self.assertEqual(res, b'\x01')
res = modmult(4 + 19, 5, 19)
self.assertEqual(res, b'\x01')
res = modmult(4, 5 + 19, 19)
self.assertEqual(res, b'\x01')
modulus = 2**512 - 1 # 64 bytes
t1 = 13**100
t2 = 17**100
expect = b"\xfa\xb2\x11\x87\xc3(y\x07\xf8\xf1n\xdepq\x0b\xca\xf3\xd3B,\xef\xf2\xfbf\xcc)\x8dZ*\x95\x98r\x96\xa8\xd5\xc3}\xe2q:\xa2'z\xf48\xde%\xef\t\x07\xbc\xc4[C\x8bUE2\x90\xef\x81\xaa:\x08"
self.assertEqual(expect, modmult(t1, t2, modulus))
self.assertRaises(ZeroDivisionError, modmult, 4, 5, 0)
self.assertRaises(ValueError, modmult, 4, 5, -1)
self.assertRaises(ValueError, modmult, 4, 5, 4)
class TestIntegerInt(TestIntegerBase):
def setUp(self):
self.Integer = IntegerNative
class testIntegerRandom(unittest.TestCase):
def test_random_exact_bits(self):
for _ in range(1000):
a = IntegerNative.random(exact_bits=8)
self.assertFalse(a < 128)
self.assertFalse(a >= 256)
for bits_value in range(1024, 1024 + 8):
a = IntegerNative.random(exact_bits=bits_value)
self.assertFalse(a < 2**(bits_value - 1))
self.assertFalse(a >= 2**bits_value)
def test_random_max_bits(self):
flag = False
for _ in range(1000):
a = IntegerNative.random(max_bits=8)
flag = flag or a < 128
self.assertFalse(a>=256)
self.assertTrue(flag)
for bits_value in range(1024, 1024 + 8):
a = IntegerNative.random(max_bits=bits_value)
self.assertFalse(a >= 2**bits_value)
def test_random_bits_custom_rng(self):
class CustomRNG(object):
def __init__(self):
self.counter = 0
def __call__(self, size):
self.counter += size
return bchr(0) * size
custom_rng = CustomRNG()
a = IntegerNative.random(exact_bits=32, randfunc=custom_rng)
self.assertEqual(custom_rng.counter, 4)
def test_random_range(self):
func = IntegerNative.random_range
for x in range(200):
a = func(min_inclusive=1, max_inclusive=15)
self.assertTrue(1 <= a <= 15)
for x in range(200):
a = func(min_inclusive=1, max_exclusive=15)
self.assertTrue(1 <= a < 15)
self.assertRaises(ValueError, func, min_inclusive=1, max_inclusive=2,
max_exclusive=3)
self.assertRaises(ValueError, func, max_inclusive=2, max_exclusive=3)
def get_tests(config={}):
tests = []
tests += list_test_cases(TestIntegerInt)
try:
from Crypto.Math._IntegerGMP import IntegerGMP
class TestIntegerGMP(TestIntegerBase):
def setUp(self):
self.Integer = IntegerGMP
tests += list_test_cases(TestIntegerGMP)
except (ImportError, OSError) as e:
if sys.platform == "win32":
sys.stdout.write("Skipping GMP tests on Windows\n")
else:
sys.stdout.write("Skipping GMP tests (%s)\n" % str(e) )
try:
from Crypto.Math._IntegerCustom import IntegerCustom
class TestIntegerCustomModexp(TestIntegerBase):
def setUp(self):
self.Integer = IntegerCustom
tests += list_test_cases(TestIntegerCustomModexp)
except (ImportError, OSError) as e:
sys.stdout.write("Skipping custom modexp tests (%s)\n" % str(e) )
tests += list_test_cases(testIntegerRandom)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,118 @@
#
# SelfTest/Math/test_Primality.py: Self-test for Primality 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 Math.Numbers"""
import unittest
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Util.py3compat import *
from Crypto.Math.Numbers import Integer
from Crypto.Math.Primality import (
PROBABLY_PRIME, COMPOSITE,
miller_rabin_test, lucas_test,
test_probable_prime,
generate_probable_prime,
generate_probable_safe_prime,
)
class TestPrimality(unittest.TestCase):
primes = (1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 2**127-1, 175637383534939453397801320455508570374088202376942372758907369518414308188137781042871856139027160010343454418881888953150175357127346872102307696660678617989191485418582475696230580407111841072614783095326672517315988762029036079794994990250662362650625650262324085116467511357592728695033227611029693067539)
composites = (0, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 7*23, (2**19-1)*(2**67-1), 9746347772161,)
def test_miller_rabin(self):
for prime in self.primes:
self.assertEqual(miller_rabin_test(prime, 3), PROBABLY_PRIME)
for composite in self.composites:
self.assertEqual(miller_rabin_test(composite, 3), COMPOSITE)
self.assertRaises(ValueError, miller_rabin_test, -1, 3)
def test_lucas(self):
for prime in self.primes:
res = lucas_test(prime)
self.assertEqual(res, PROBABLY_PRIME)
for composite in self.composites:
res = lucas_test(composite)
self.assertEqual(res, COMPOSITE)
self.assertRaises(ValueError, lucas_test, -1)
def test_is_prime(self):
primes = (170141183460469231731687303715884105727,
19175002942688032928599,
1363005552434666078217421284621279933627102780881053358473,
2 ** 521 - 1)
for p in primes:
self.assertEqual(test_probable_prime(p), PROBABLY_PRIME)
not_primes = (
4754868377601046732119933839981363081972014948522510826417784001,
1334733877147062382486934807105197899496002201113849920496510541601,
260849323075371835669784094383812120359260783810157225730623388382401,
)
for np in not_primes:
self.assertEqual(test_probable_prime(np), COMPOSITE)
from Crypto.Util.number import sieve_base
for p in sieve_base[:100]:
res = test_probable_prime(p)
self.assertEqual(res, PROBABLY_PRIME)
def test_generate_prime_bit_size(self):
p = generate_probable_prime(exact_bits=512)
self.assertEqual(p.size_in_bits(), 512)
def test_generate_prime_filter(self):
def ending_with_one(number):
return number % 10 == 1
for x in range(20):
q = generate_probable_prime(exact_bits=160,
prime_filter=ending_with_one)
self.assertEqual(q % 10, 1)
def test_generate_safe_prime(self):
p = generate_probable_safe_prime(exact_bits=161)
self.assertEqual(p.size_in_bits(), 161)
def get_tests(config={}):
tests = []
tests += list_test_cases(TestPrimality)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,201 @@
#
# SelfTest/Math/test_modexp.py: Self-test for module exponentiation
#
# ===================================================================
#
# Copyright (c) 2017, 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 for the custom module exponentiation"""
import unittest
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Util.number import long_to_bytes, bytes_to_long
from Crypto.Util.py3compat import *
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
create_string_buffer,
get_raw_buffer,
c_size_t,
c_ulonglong)
from Crypto.Hash import SHAKE128
from Crypto.Math.Numbers import Integer
from Crypto.Math._IntegerCustom import _raw_montgomery
from Crypto.Random.random import StrongRandom
def create_rng(tag):
rng = StrongRandom(SHAKE128.new(data=tag))
return rng
class ExceptionModulus(ValueError):
pass
def monty_pow(base, exp, modulus):
max_len = len(long_to_bytes(max(base, exp, modulus)))
base_b, exp_b, modulus_b = [ long_to_bytes(x, max_len) for x in
(base, exp, modulus) ]
out = create_string_buffer(max_len)
error = _raw_montgomery.monty_pow(
out,
base_b,
exp_b,
modulus_b,
c_size_t(max_len),
c_ulonglong(32)
)
if error == 17:
raise ExceptionModulus()
if error:
raise ValueError("monty_pow failed with error: %d" % error)
result = bytes_to_long(get_raw_buffer(out))
return result
exponent1 = 0x2ce0af628901460a419a08ef950d498b9fd6f271a1a52ac293b86fe5c60efe8e8ba93fa1ebe1eb3d614d2e7b328cb60a2591440e163441a190ecf101ceec245f600fffdcf3f5b3a17a7baeacb96a424db1d7ec985e8ec998bb479fecfffed6a75f9a90fc97062fd973303bce855ad7b8d8272a94025e8532be9aabd54a183f303538d2a7e621b4131d59e823a4625f39bd7d518d7784f7c3a8f19061da74974ff42fa1c063dec2db97d461e291a7d6e721708a5229de166c1246363372854e27f3f08ae274bc16bfd205b028a4d81386494433d516dfbb35f495acba5e4e1d1843cb3c3129b6642a85fc7244ce5845fac071c7f622e4ee12ac43fabeeaa0cd01
modulus1 = 0xd66691b20071be4d66d4b71032b37fa007cfabf579fcb91e50bfc2753b3f0ce7be74e216aef7e26d4ae180bc20d7bd3ea88a6cbf6f87380e613c8979b5b043b200a8ff8856a3b12875e36e98a7569f3852d028e967551000b02c19e9fa52e83115b89309aabb1e1cf1e2cb6369d637d46775ce4523ea31f64ad2794cbc365dd8a35e007ed3b57695877fbf102dbeb8b3212491398e494314e93726926e1383f8abb5889bea954eb8c0ca1c62c8e9d83f41888095c5e645ed6d32515fe0c58c1368cad84694e18da43668c6f43e61d7c9bca633ddcda7aef5b79bc396d4a9f48e2a9abe0836cc455e435305357228e93d25aaed46b952defae0f57339bf26f5a9
class TestModExp(unittest.TestCase):
def test_small(self):
self.assertEqual(1, monty_pow(11,12,19))
def test_large_1(self):
base = 0xfffffffffffffffffffffffffffffffffffffffffffffffffff
expected = pow(base, exponent1, modulus1)
result = monty_pow(base, exponent1, modulus1)
self.assertEqual(result, expected)
def test_zero_exp(self):
base = 0xfffffffffffffffffffffffffffffffffffffffffffffffffff
result = monty_pow(base, 0, modulus1)
self.assertEqual(result, 1)
def test_zero_base(self):
result = monty_pow(0, exponent1, modulus1)
self.assertEqual(result, 0)
def test_zero_modulus(self):
base = 0xfffffffffffffffffffffffffffffffffffffffffffffffff
self.assertRaises(ExceptionModulus, monty_pow, base, exponent1, 0)
self.assertRaises(ExceptionModulus, monty_pow, 0, 0, 0)
def test_larger_exponent(self):
base = modulus1 - 0xFFFFFFF
expected = pow(base, modulus1<<64, modulus1)
result = monty_pow(base, modulus1<<64, modulus1)
self.assertEqual(result, expected)
def test_even_modulus(self):
base = modulus1 >> 4
self.assertRaises(ExceptionModulus, monty_pow, base, exponent1, modulus1-1)
def test_several_lengths(self):
prng = SHAKE128.new().update(b('Test'))
for length in range(1, 100):
modulus2 = Integer.from_bytes(prng.read(length)) | 1
base = Integer.from_bytes(prng.read(length)) % modulus2
exponent2 = Integer.from_bytes(prng.read(length))
expected = pow(base, exponent2, modulus2)
result = monty_pow(base, exponent2, modulus2)
self.assertEqual(result, expected)
def test_variable_exponent(self):
prng = create_rng(b('Test variable exponent'))
for i in range(20):
for j in range(7):
modulus = prng.getrandbits(8*30) | 1
base = prng.getrandbits(8*30) % modulus
exponent = prng.getrandbits(i*8+j)
expected = pow(base, exponent, modulus)
result = monty_pow(base, exponent, modulus)
self.assertEqual(result, expected)
exponent ^= (1 << (i*8+j)) - 1
expected = pow(base, exponent, modulus)
result = monty_pow(base, exponent, modulus)
self.assertEqual(result, expected)
def test_stress_63(self):
prng = create_rng(b('Test 63'))
length = 63
for _ in range(2000):
modulus = prng.getrandbits(8*length) | 1
base = prng.getrandbits(8*length) % modulus
exponent = prng.getrandbits(8*length)
expected = pow(base, exponent, modulus)
result = monty_pow(base, exponent, modulus)
self.assertEqual(result, expected)
def test_stress_64(self):
prng = create_rng(b('Test 64'))
length = 64
for _ in range(2000):
modulus = prng.getrandbits(8*length) | 1
base = prng.getrandbits(8*length) % modulus
exponent = prng.getrandbits(8*length)
expected = pow(base, exponent, modulus)
result = monty_pow(base, exponent, modulus)
self.assertEqual(result, expected)
def test_stress_65(self):
prng = create_rng(b('Test 65'))
length = 65
for _ in range(2000):
modulus = prng.getrandbits(8*length) | 1
base = prng.getrandbits(8*length) % modulus
exponent = prng.getrandbits(8*length)
expected = pow(base, exponent, modulus)
result = monty_pow(base, exponent, modulus)
self.assertEqual(result, expected)
def get_tests(config={}):
tests = []
tests += list_test_cases(TestModExp)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,120 @@
#
# SelfTest/Math/test_modmult.py: Self-test for custom modular multiplication
#
# ===================================================================
#
# Copyright (c) 2023, 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 for the custom modular multiplication"""
import unittest
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Util.number import long_to_bytes, bytes_to_long
from Crypto.Util._raw_api import (create_string_buffer,
get_raw_buffer,
c_size_t)
from Crypto.Math._IntegerCustom import _raw_montgomery
class ExceptionModulus(ValueError):
pass
def monty_mult(term1, term2, modulus):
if term1 >= modulus:
term1 %= modulus
if term2 >= modulus:
term2 %= modulus
modulus_b = long_to_bytes(modulus)
numbers_len = len(modulus_b)
term1_b = long_to_bytes(term1, numbers_len)
term2_b = long_to_bytes(term2, numbers_len)
out = create_string_buffer(numbers_len)
error = _raw_montgomery.monty_multiply(
out,
term1_b,
term2_b,
modulus_b,
c_size_t(numbers_len)
)
if error == 17:
raise ExceptionModulus()
if error:
raise ValueError("monty_multiply() failed with error: %d" % error)
return get_raw_buffer(out)
modulus1 = 0xd66691b20071be4d66d4b71032b37fa007cfabf579fcb91e50bfc2753b3f0ce7be74e216aef7e26d4ae180bc20d7bd3ea88a6cbf6f87380e613c8979b5b043b200a8ff8856a3b12875e36e98a7569f3852d028e967551000b02c19e9fa52e83115b89309aabb1e1cf1e2cb6369d637d46775ce4523ea31f64ad2794cbc365dd8a35e007ed3b57695877fbf102dbeb8b3212491398e494314e93726926e1383f8abb5889bea954eb8c0ca1c62c8e9d83f41888095c5e645ed6d32515fe0c58c1368cad84694e18da43668c6f43e61d7c9bca633ddcda7aef5b79bc396d4a9f48e2a9abe0836cc455e435305357228e93d25aaed46b952defae0f57339bf26f5a9
class TestModMultiply(unittest.TestCase):
def test_small(self):
self.assertEqual(b"\x01", monty_mult(5, 6, 29))
def test_large(self):
numbers_len = (modulus1.bit_length() + 7) // 8
t1 = modulus1 // 2
t2 = modulus1 - 90
expect = b'\x00' * (numbers_len - 1) + b'\x2d'
self.assertEqual(expect, monty_mult(t1, t2, modulus1))
def test_zero_term(self):
numbers_len = (modulus1.bit_length() + 7) // 8
expect = b'\x00' * numbers_len
self.assertEqual(expect, monty_mult(0x100, 0, modulus1))
self.assertEqual(expect, monty_mult(0, 0x100, modulus1))
def test_larger_term(self):
t1 = 2**2047
expect_int = 0x8edf4071f78e3d7ba622cdbbbef74612e301d69186776ae6bf87ff38c320d9aebaa64889c2f67de2324e6bccd2b10ad89e91fd21ba4bb523904d033eff5e70e62f01a84f41fa90a4f248ef249b82e1d2729253fdfc2a3b5b740198123df8bfbf7057d03e15244ad5f26eb9a099763b5c5972121ec076b0bf899f59bd95f7cc129abddccf24217bce52ca0f3a44c9ccc504765dbb89734205f3ae6a8cc560494a60ea84b27d8e00fa24bdd5b4f1d4232edb61e47d3d984c1fa50a3820a2e580fbc3fc8bc11e99df53b9efadf5a40ac75d384e400905aa6f1d88950cd53b1c54dc2222115ad84a27260fa4d978155c1434c551de1ee7361a17a2f79d4388f78a5d
res = bytes_to_long(monty_mult(t1, t1, modulus1))
self.assertEqual(res, expect_int)
def get_tests(config={}):
tests = []
tests += list_test_cases(TestModMultiply)
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,45 @@
# SelfTest/Protocol/__init__.py: Self-tests for Crypto.Protocol
#
# 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.
# ===================================================================
import sys
"""Self-test for Crypto.Protocol"""
def get_tests(config={}):
tests = []
from Crypto.SelfTest.Protocol import test_rfc1751; tests += test_rfc1751.get_tests(config=config)
from Crypto.SelfTest.Protocol import test_KDF; tests += test_KDF.get_tests(config=config)
from Crypto.SelfTest.Protocol import test_ecdh; tests += test_ecdh.get_tests(config=config)
from Crypto.SelfTest.Protocol import test_SecretSharing
tests += test_SecretSharing.get_tests(config=config)
if sys.version_info >= (3, 9):
from Crypto.SelfTest.Protocol import test_HPKE
tests += test_HPKE.get_tests(config=config)
return tests
if __name__ == '__main__':
import unittest
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,491 @@
import os
import json
import unittest
from binascii import unhexlify
from Crypto.Protocol import HPKE
from Crypto.Protocol.HPKE import DeserializeError
from Crypto.PublicKey import ECC
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Protocol import DH
from Crypto.Hash import SHA256, SHA384, SHA512
class HPKE_Tests(unittest.TestCase):
key1 = ECC.generate(curve='p256')
key2 = ECC.generate(curve='p256')
# name, size of enc
curves = {
'p256': 65,
'p384': 97,
'p521': 133,
'curve25519': 32,
'curve448': 56,
}
def round_trip(self, curve, aead_id):
key1 = ECC.generate(curve=curve)
aead_id = aead_id
encryptor = HPKE.new(receiver_key=key1.public_key(),
aead_id=aead_id)
self.assertEqual(len(encryptor.enc), self.curves[curve])
# First message
ct = encryptor.seal(b'ABC', auth_data=b'DEF')
decryptor = HPKE.new(receiver_key=key1,
aead_id=aead_id,
enc=encryptor.enc)
pt = decryptor.unseal(ct, auth_data=b'DEF')
self.assertEqual(b'ABC', pt)
# Second message
ct2 = encryptor.seal(b'GHI')
pt2 = decryptor.unseal(ct2)
self.assertEqual(b'GHI', pt2)
def test_round_trip(self):
for curve in self.curves.keys():
for aead_id in HPKE.AEAD:
self.round_trip(curve, aead_id)
def test_psk(self):
aead_id = HPKE.AEAD.AES128_GCM
HPKE.new(receiver_key=self.key1.public_key(),
aead_id=aead_id,
psk=(b'a', b'c' * 32))
def test_info(self):
aead_id = HPKE.AEAD.AES128_GCM
HPKE.new(receiver_key=self.key1.public_key(),
aead_id=aead_id,
info=b'baba')
def test_neg_unsupported_curve(self):
key3 = ECC.generate(curve='p224')
with self.assertRaises(ValueError) as cm:
HPKE.new(receiver_key=key3.public_key(),
aead_id=HPKE.AEAD.AES128_GCM)
self.assertIn("Unsupported curve", str(cm.exception))
def test_neg_too_many_private_keys(self):
with self.assertRaises(ValueError) as cm:
HPKE.new(receiver_key=self.key1,
sender_key=self.key2,
aead_id=HPKE.AEAD.AES128_GCM)
self.assertIn("Exactly 1 private key", str(cm.exception))
def test_neg_curve_mismatch(self):
key3 = ECC.generate(curve='p384')
with self.assertRaises(ValueError) as cm:
HPKE.new(receiver_key=self.key1.public_key(),
sender_key=key3,
aead_id=HPKE.AEAD.AES128_GCM)
self.assertIn("but recipient key", str(cm.exception))
def test_neg_psk(self):
with self.assertRaises(ValueError) as cm:
HPKE.new(receiver_key=self.key1.public_key(),
psk=(b'', b'G' * 32),
aead_id=HPKE.AEAD.AES128_GCM)
with self.assertRaises(ValueError) as cm:
HPKE.new(receiver_key=self.key1.public_key(),
psk=(b'JJJ', b''),
aead_id=HPKE.AEAD.AES128_GCM)
with self.assertRaises(ValueError) as cm:
HPKE.new(receiver_key=self.key1.public_key(),
psk=(b'JJJ', b'Y' * 31),
aead_id=HPKE.AEAD.AES128_GCM)
self.assertIn("at least 32", str(cm.exception))
def test_neg_wrong_enc(self):
wrong_enc = b'\xFF' + b'8' * 64
with self.assertRaises(DeserializeError):
HPKE.new(receiver_key=self.key1,
aead_id=HPKE.AEAD.AES128_GCM,
enc=wrong_enc)
with self.assertRaises(ValueError) as cm:
HPKE.new(receiver_key=self.key1.public_key(),
enc=self.key1.public_key().export_key(format='raw'),
aead_id=HPKE.AEAD.AES128_GCM)
self.assertIn("'enc' cannot be an input", str(cm.exception))
with self.assertRaises(ValueError) as cm:
HPKE.new(receiver_key=self.key1,
aead_id=HPKE.AEAD.AES128_GCM)
self.assertIn("'enc' required", str(cm.exception))
def test_neg_unseal_wrong_ct(self):
decryptor = HPKE.new(receiver_key=self.key1,
aead_id=HPKE.AEAD.CHACHA20_POLY1305,
enc=self.key2.public_key().export_key(format='raw'))
with self.assertRaises(ValueError):
decryptor.unseal(b'XYZ' * 20)
def test_neg_unseal_no_auth_data(self):
aead_id = HPKE.AEAD.CHACHA20_POLY1305
encryptor = HPKE.new(receiver_key=self.key1.public_key(),
aead_id=aead_id)
ct = encryptor.seal(b'ABC', auth_data=b'DEF')
decryptor = HPKE.new(receiver_key=self.key1,
aead_id=aead_id,
enc=encryptor.enc)
with self.assertRaises(ValueError):
decryptor.unseal(ct)
def test_x25519_mode_0(self):
# RFC x9180, A.1.1.1, seq 0 and 1
keyR_hex = "4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8"
keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex))
pt_hex = "4265617574792069732074727574682c20747275746820626561757479"
pt = bytes.fromhex(pt_hex)
ct0_hex = "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a"
ct0 = bytes.fromhex(ct0_hex)
enc_hex = "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431"
enc = bytes.fromhex(enc_hex)
aad0_hex = "436f756e742d30"
aad0 = bytes.fromhex(aad0_hex)
aad1_hex = "436f756e742d31"
aad1 = bytes.fromhex(aad1_hex)
info_hex = "4f6465206f6e2061204772656369616e2055726e"
info = bytes.fromhex(info_hex)
ct1_hex = "af2d7e9ac9ae7e270f46ba1f975be53c09f8d875bdc8535458c2494e8a6eab251c03d0c22a56b8ca42c2063b84"
ct1 = bytes.fromhex(ct1_hex)
aead_id = HPKE.AEAD.AES128_GCM
decryptor = HPKE.new(receiver_key=keyR,
aead_id=aead_id,
info=info,
enc=enc)
pt_X0 = decryptor.unseal(ct0, aad0)
self.assertEqual(pt_X0, pt)
pt_X1 = decryptor.unseal(ct1, aad1)
self.assertEqual(pt_X1, pt)
def test_x25519_mode_1(self):
# RFC x9180, A.1.2.1, seq 0 and 1
keyR_hex = "c5eb01eb457fe6c6f57577c5413b931550a162c71a03ac8d196babbd4e5ce0fd"
keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex))
psk_id_hex = "456e6e796e20447572696e206172616e204d6f726961"
psk_id = bytes.fromhex(psk_id_hex)
psk_hex = "0247fd33b913760fa1fa51e1892d9f307fbe65eb171e8132c2af18555a738b82"
psk = bytes.fromhex(psk_hex)
pt_hex = "4265617574792069732074727574682c20747275746820626561757479"
pt = bytes.fromhex(pt_hex)
ct0_hex = "e52c6fed7f758d0cf7145689f21bc1be6ec9ea097fef4e959440012f4feb73fb611b946199e681f4cfc34db8ea"
ct0 = bytes.fromhex(ct0_hex)
enc_hex = "0ad0950d9fb9588e59690b74f1237ecdf1d775cd60be2eca57af5a4b0471c91b"
enc = bytes.fromhex(enc_hex)
aad0_hex = "436f756e742d30"
aad0 = bytes.fromhex(aad0_hex)
aad1_hex = "436f756e742d31"
aad1 = bytes.fromhex(aad1_hex)
info_hex = "4f6465206f6e2061204772656369616e2055726e"
info = bytes.fromhex(info_hex)
ct1_hex = "49f3b19b28a9ea9f43e8c71204c00d4a490ee7f61387b6719db765e948123b45b61633ef059ba22cd62437c8ba"
ct1 = bytes.fromhex(ct1_hex)
aead_id = HPKE.AEAD.AES128_GCM
decryptor = HPKE.new(receiver_key=keyR,
aead_id=aead_id,
info=info,
psk=(psk_id, psk),
enc=enc)
pt_X0 = decryptor.unseal(ct0, aad0)
self.assertEqual(pt_X0, pt)
pt_X1 = decryptor.unseal(ct1, aad1)
self.assertEqual(pt_X1, pt)
def test_x25519_mode_2(self):
# RFC x9180, A.1.3.1, seq 0 and 1
keyR_hex = "fdea67cf831f1ca98d8e27b1f6abeb5b7745e9d35348b80fa407ff6958f9137e"
keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex))
keyS_hex = "dc4a146313cce60a278a5323d321f051c5707e9c45ba21a3479fecdf76fc69dd"
keyS = DH.import_x25519_private_key(bytes.fromhex(keyS_hex))
pt_hex = "4265617574792069732074727574682c20747275746820626561757479"
pt = bytes.fromhex(pt_hex)
ct0_hex = "5fd92cc9d46dbf8943e72a07e42f363ed5f721212cd90bcfd072bfd9f44e06b80fd17824947496e21b680c141b"
ct0 = bytes.fromhex(ct0_hex)
enc_hex = "23fb952571a14a25e3d678140cd0e5eb47a0961bb18afcf85896e5453c312e76"
enc = bytes.fromhex(enc_hex)
aad0_hex = "436f756e742d30"
aad0 = bytes.fromhex(aad0_hex)
aad1_hex = "436f756e742d31"
aad1 = bytes.fromhex(aad1_hex)
info_hex = "4f6465206f6e2061204772656369616e2055726e"
info = bytes.fromhex(info_hex)
ct1_hex = "d3736bb256c19bfa93d79e8f80b7971262cb7c887e35c26370cfed62254369a1b52e3d505b79dd699f002bc8ed"
ct1 = bytes.fromhex(ct1_hex)
aead_id = HPKE.AEAD.AES128_GCM
decryptor = HPKE.new(receiver_key=keyR,
sender_key=keyS.public_key(),
aead_id=aead_id,
info=info,
enc=enc)
pt_X0 = decryptor.unseal(ct0, aad0)
self.assertEqual(pt_X0, pt)
pt_X1 = decryptor.unseal(ct1, aad1)
self.assertEqual(pt_X1, pt)
def test_x25519_mode_3(self):
# RFC x9180, A.1.4.1, seq 0 and 1
keyR_hex = "cb29a95649dc5656c2d054c1aa0d3df0493155e9d5da6d7e344ed8b6a64a9423"
keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex))
keyS_hex = "fc1c87d2f3832adb178b431fce2ac77c7ca2fd680f3406c77b5ecdf818b119f4"
keyS = DH.import_x25519_private_key(bytes.fromhex(keyS_hex))
psk_id_hex = "456e6e796e20447572696e206172616e204d6f726961"
psk_id = bytes.fromhex(psk_id_hex)
psk_hex = "0247fd33b913760fa1fa51e1892d9f307fbe65eb171e8132c2af18555a738b82"
psk = bytes.fromhex(psk_hex)
pt_hex = "4265617574792069732074727574682c20747275746820626561757479"
pt = bytes.fromhex(pt_hex)
ct0_hex = "a84c64df1e11d8fd11450039d4fe64ff0c8a99fca0bd72c2d4c3e0400bc14a40f27e45e141a24001697737533e"
ct0 = bytes.fromhex(ct0_hex)
enc_hex = "820818d3c23993492cc5623ab437a48a0a7ca3e9639c140fe1e33811eb844b7c"
enc = bytes.fromhex(enc_hex)
aad0_hex = "436f756e742d30"
aad0 = bytes.fromhex(aad0_hex)
aad1_hex = "436f756e742d31"
aad1 = bytes.fromhex(aad1_hex)
info_hex = "4f6465206f6e2061204772656369616e2055726e"
info = bytes.fromhex(info_hex)
ct1_hex = "4d19303b848f424fc3c3beca249b2c6de0a34083b8e909b6aa4c3688505c05ffe0c8f57a0a4c5ab9da127435d9"
ct1 = bytes.fromhex(ct1_hex)
aead_id = HPKE.AEAD.AES128_GCM
decryptor = HPKE.new(receiver_key=keyR,
sender_key=keyS.public_key(),
aead_id=aead_id,
psk=(psk_id, psk),
info=info,
enc=enc)
pt_X0 = decryptor.unseal(ct0, aad0)
self.assertEqual(pt_X0, pt)
pt_X1 = decryptor.unseal(ct1, aad1)
self.assertEqual(pt_X1, pt)
class HPKE_TestVectors(unittest.TestCase):
def setUp(self):
self.vectors = []
try:
import pycryptodome_test_vectors # type: ignore
init_dir = os.path.dirname(pycryptodome_test_vectors.__file__)
full_file_name = os.path.join(init_dir, "Protocol", "wycheproof", "HPKE-test-vectors.json")
with open(full_file_name, "r") as f:
self.vectors = json.load(f)
except (FileNotFoundError, ImportError):
print("\nWarning: skipping extended tests for HPKE (install pycryptodome-test-vectors)")
def import_private_key(self, key_hex, kem_id):
key_bin = unhexlify(key_hex)
if kem_id == 0x0010:
return ECC.construct(curve='p256', d=int.from_bytes(key_bin,
byteorder="big"))
elif kem_id == 0x0011:
return ECC.construct(curve='p384', d=int.from_bytes(key_bin,
byteorder="big"))
elif kem_id == 0x0012:
return ECC.construct(curve='p521', d=int.from_bytes(key_bin,
byteorder="big"))
elif kem_id == 0x0020:
return DH.import_x25519_private_key(key_bin)
elif kem_id == 0x0021:
return DH.import_x448_private_key(key_bin)
def test_hpke_encap(self):
"""Test HPKE encapsulation using test vectors."""
if not self.vectors:
self.skipTest("No test vectors available")
for idx, vector in enumerate(self.vectors):
kem_id = vector["kem_id"]
kdf_id = vector["kdf_id"]
aead_id = vector["aead_id"]
# No export-only pseudo-cipher
if aead_id == 0xffff:
continue
# We support only one KDF per curve
supported_combi = {
(0x10, 0x1): SHA256,
(0x11, 0x2): SHA384,
(0x12, 0x3): SHA512,
(0x20, 0x1): SHA256,
(0x21, 0x3): SHA512,
}
hashmod = supported_combi.get((kem_id, kdf_id))
if hashmod is None:
continue
with self.subTest(idx=idx, kem_id=kem_id, aead_id=aead_id):
receiver_pub = self.import_private_key(vector["skRm"],
kem_id).public_key()
sender_priv = None
if "skSm" in vector:
sender_priv = self.import_private_key(vector["skSm"],
kem_id)
encap_key = self.import_private_key(vector["skEm"], kem_id)
shared_secret, enc = HPKE.HPKE_Cipher._encap(receiver_pub,
kem_id,
hashmod,
sender_priv,
encap_key)
self.assertEqual(enc.hex(), vector["enc"])
self.assertEqual(shared_secret,
unhexlify(vector["shared_secret"]))
print(".", end="", flush=True)
def test_hpke_unseal(self):
"""Test HPKE encryption and decryption using test vectors."""
if not self.vectors:
self.skipTest("No test vectors available")
for idx, vector in enumerate(self.vectors):
kem_id = vector["kem_id"]
kdf_id = vector["kdf_id"]
aead_id = vector["aead_id"]
# No export-only pseudo-cipher
if aead_id == 0xffff:
continue
# We support only one KDF per curve
supported_combi = (
(0x10, 0x1),
(0x11, 0x2),
(0x12, 0x3),
(0x20, 0x1),
(0x21, 0x3),
)
if (kem_id, kdf_id) not in supported_combi:
continue
with self.subTest(idx=idx, kem_id=kem_id, aead_id=aead_id):
receiver_priv = self.import_private_key(vector["skRm"],
kem_id)
sender_pub = None
if "skSm" in vector:
sender_priv = self.import_private_key(vector["skSm"],
kem_id)
sender_pub = sender_priv.public_key()
encap_key = unhexlify(vector["enc"])
psk = None
if "psk_id" in vector:
psk = unhexlify(vector["psk_id"]), unhexlify(vector["psk"])
receiver_hpke = HPKE.new(receiver_key=receiver_priv,
aead_id=HPKE.AEAD(aead_id),
enc=encap_key,
sender_key=sender_pub,
psk=psk,
info=unhexlify(vector["info"]))
for encryption in vector['encryptions']:
plaintext = unhexlify(encryption["pt"])
ciphertext = unhexlify(encryption["ct"])
aad = unhexlify(encryption["aad"])
# Decrypt (unseal)
decrypted = receiver_hpke.unseal(ciphertext, aad)
self.assertEqual(decrypted, plaintext, "Decryption failed")
print(".", end="", flush=True)
def get_tests(config={}):
tests = []
tests += list_test_cases(HPKE_Tests)
if config.get('slow_tests'):
tests += list_test_cases(HPKE_TestVectors)
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,809 @@
# -*- coding: utf-8 -*-
#
# SelfTest/Protocol/test_KDF.py: Self-test for key derivation functions
#
# ===================================================================
# 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 re
import unittest
from binascii import unhexlify
from Crypto.Util.py3compat import b, bchr
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof
from Crypto.Hash import SHA1, HMAC, SHA256, MD5, SHA224, SHA384, SHA512
from Crypto.Cipher import AES, DES3
from Crypto.Protocol.KDF import (PBKDF1, PBKDF2, _S2V, HKDF, scrypt,
bcrypt, bcrypt_check,
SP800_108_Counter)
from Crypto.Protocol.KDF import _bcrypt_decode
def t2b(t):
if t is None:
return None
t2 = t.replace(" ", "").replace("\n", "")
return unhexlify(b(t2))
class TestVector(object):
pass
class PBKDF1_Tests(unittest.TestCase):
# List of tuples with test data.
# Each tuple is made up by:
# Item #0: a pass phrase
# Item #1: salt (8 bytes encoded in hex)
# Item #2: output key length
# Item #3: iterations to use
# Item #4: expected result (encoded in hex)
_testData = (
# From http://www.di-mgt.com.au/cryptoKDFs.html#examplespbkdf
("password", "78578E5A5D63CB06", 16, 1000, "DC19847E05C64D2FAF10EBFB4A3D2A20"),
)
def test1(self):
v = self._testData[0]
res = PBKDF1(v[0], t2b(v[1]), v[2], v[3], SHA1)
self.assertEqual(res, t2b(v[4]))
class PBKDF2_Tests(unittest.TestCase):
# List of tuples with test data.
# Each tuple is made up by:
# Item #0: a pass phrase
# Item #1: salt (encoded in hex)
# Item #2: output key length
# Item #3: iterations to use
# Item #4: hash module
# Item #5: expected result (encoded in hex)
_testData = (
# From http://www.di-mgt.com.au/cryptoKDFs.html#examplespbkdf
("password","78578E5A5D63CB06",24,2048, SHA1, "BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"),
# From RFC 6050
("password","73616c74", 20, 1, SHA1, "0c60c80f961f0e71f3a9b524af6012062fe037a6"),
("password","73616c74", 20, 2, SHA1, "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"),
("password","73616c74", 20, 4096, SHA1, "4b007901b765489abead49d926f721d065a429c1"),
("passwordPASSWORDpassword","73616c7453414c5473616c7453414c5473616c7453414c5473616c7453414c5473616c74",
25, 4096, SHA1, "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"),
( 'pass\x00word',"7361006c74",16,4096, SHA1, "56fa6aa75548099dcc37d7f03425e0c3"),
# From draft-josefsson-scrypt-kdf-01, Chapter 10
( 'passwd', '73616c74', 64, 1, SHA256, "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783"),
( 'Password', '4e61436c', 64, 80000, SHA256, "4ddcd8f60b98be21830cee5ef22701f9641a4418d04c0414aeff08876b34ab56a1d425a1225833549adb841b51c9b3176a272bdebba1d078478f62b397f33c8d"),
)
def test1(self):
# Test only for HMAC-SHA1 as PRF
def prf_SHA1(p,s):
return HMAC.new(p,s,SHA1).digest()
def prf_SHA256(p,s):
return HMAC.new(p,s,SHA256).digest()
for i in range(len(self._testData)):
v = self._testData[i]
password = v[0]
salt = t2b(v[1])
out_len = v[2]
iters = v[3]
hash_mod = v[4]
expected = t2b(v[5])
if hash_mod is SHA1:
res = PBKDF2(password, salt, out_len, iters)
self.assertEqual(res, expected)
res = PBKDF2(password, salt, out_len, iters, prf_SHA1)
self.assertEqual(res, expected)
else:
res = PBKDF2(password, salt, out_len, iters, prf_SHA256)
self.assertEqual(res, expected)
def test2(self):
# Verify that prf and hmac_hash_module are mutual exclusive
def prf_SHA1(p,s):
return HMAC.new(p,s,SHA1).digest()
self.assertRaises(ValueError, PBKDF2, b("xxx"), b("yyy"), 16, 100,
prf=prf_SHA1, hmac_hash_module=SHA1)
def test3(self):
# Verify that hmac_hash_module works like prf
password = b("xxx")
salt = b("yyy")
for hashmod in (MD5, SHA1, SHA224, SHA256, SHA384, SHA512):
pr1 = PBKDF2(password, salt, 16, 100,
prf=lambda p, s: HMAC.new(p,s,hashmod).digest())
pr2 = PBKDF2(password, salt, 16, 100, hmac_hash_module=hashmod)
self.assertEqual(pr1, pr2)
def test4(self):
# Verify that PBKDF2 can take bytes or strings as password or salt
k1 = PBKDF2("xxx", b("yyy"), 16, 10)
k2 = PBKDF2(b("xxx"), b("yyy"), 16, 10)
self.assertEqual(k1, k2)
k1 = PBKDF2(b("xxx"), "yyy", 16, 10)
k2 = PBKDF2(b("xxx"), b("yyy"), 16, 10)
self.assertEqual(k1, k2)
class S2V_Tests(unittest.TestCase):
# Sequence of test vectors.
# Each test vector is made up by:
# Item #0: a tuple of strings
# Item #1: an AES key
# Item #2: the result
# Item #3: the cipher module S2V is based on
# Everything is hex encoded
_testData = [
# RFC5297, A.1
(
( '101112131415161718191a1b1c1d1e1f2021222324252627',
'112233445566778899aabbccddee' ),
'fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0',
'85632d07c6e8f37f950acd320a2ecc93',
AES
),
# RFC5297, A.2
(
( '00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddcc'+
'bbaa99887766554433221100',
'102030405060708090a0',
'09f911029d74e35bd84156c5635688c0',
'7468697320697320736f6d6520706c61'+
'696e7465787420746f20656e63727970'+
'74207573696e67205349562d414553'),
'7f7e7d7c7b7a79787776757473727170',
'7bdb6e3b432667eb06f4d14bff2fbd0f',
AES
),
]
def test1(self):
"""Verify correctness of test vector"""
for tv in self._testData:
s2v = _S2V.new(t2b(tv[1]), tv[3])
for s in tv[0]:
s2v.update(t2b(s))
result = s2v.derive()
self.assertEqual(result, t2b(tv[2]))
def test2(self):
"""Verify that no more than 127(AES) and 63(TDES)
components are accepted."""
key = bchr(0) * 8 + bchr(255) * 8
for module in (AES, DES3):
s2v = _S2V.new(key, module)
max_comps = module.block_size*8-1
for i in range(max_comps):
s2v.update(b("XX"))
self.assertRaises(TypeError, s2v.update, b("YY"))
class HKDF_Tests(unittest.TestCase):
# Test vectors from RFC5869, Appendix A
# Each tuple is made up by:
# Item #0: hash module
# Item #1: secret
# Item #2: salt
# Item #3: context
# Item #4: expected result
_test_vector = (
(
SHA256,
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
"000102030405060708090a0b0c",
"f0f1f2f3f4f5f6f7f8f9",
42,
"3cb25f25faacd57a90434f64d0362f2a" +
"2d2d0a90cf1a5a4c5db02d56ecc4c5bf" +
"34007208d5b887185865"
),
(
SHA256,
"000102030405060708090a0b0c0d0e0f" +
"101112131415161718191a1b1c1d1e1f" +
"202122232425262728292a2b2c2d2e2f" +
"303132333435363738393a3b3c3d3e3f" +
"404142434445464748494a4b4c4d4e4f",
"606162636465666768696a6b6c6d6e6f" +
"707172737475767778797a7b7c7d7e7f" +
"808182838485868788898a8b8c8d8e8f" +
"909192939495969798999a9b9c9d9e9f" +
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" +
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" +
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" +
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef" +
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
82,
"b11e398dc80327a1c8e7f78c596a4934" +
"4f012eda2d4efad8a050cc4c19afa97c" +
"59045a99cac7827271cb41c65e590e09" +
"da3275600c2f09b8367793a9aca3db71" +
"cc30c58179ec3e87c14c01d5c1f3434f" +
"1d87"
),
(
SHA256,
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
None,
None,
42,
"8da4e775a563c18f715f802a063c5a31" +
"b8a11f5c5ee1879ec3454e5f3c738d2d" +
"9d201395faa4b61a96c8"
),
(
SHA1,
"0b0b0b0b0b0b0b0b0b0b0b",
"000102030405060708090a0b0c",
"f0f1f2f3f4f5f6f7f8f9",
42,
"085a01ea1b10f36933068b56efa5ad81" +
"a4f14b822f5b091568a9cdd4f155fda2" +
"c22e422478d305f3f896"
),
(
SHA1,
"000102030405060708090a0b0c0d0e0f" +
"101112131415161718191a1b1c1d1e1f" +
"202122232425262728292a2b2c2d2e2f" +
"303132333435363738393a3b3c3d3e3f" +
"404142434445464748494a4b4c4d4e4f",
"606162636465666768696a6b6c6d6e6f" +
"707172737475767778797a7b7c7d7e7f" +
"808182838485868788898a8b8c8d8e8f" +
"909192939495969798999a9b9c9d9e9f" +
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" +
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" +
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" +
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef" +
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
82,
"0bd770a74d1160f7c9f12cd5912a06eb" +
"ff6adcae899d92191fe4305673ba2ffe" +
"8fa3f1a4e5ad79f3f334b3b202b2173c" +
"486ea37ce3d397ed034c7f9dfeb15c5e" +
"927336d0441f4c4300e2cff0d0900b52" +
"d3b4"
),
(
SHA1,
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
"",
"",
42,
"0ac1af7002b3d761d1e55298da9d0506" +
"b9ae52057220a306e07b6b87e8df21d0" +
"ea00033de03984d34918"
),
(
SHA1,
"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
None,
"",
42,
"2c91117204d745f3500d636a62f64f0a" +
"b3bae548aa53d423b0d1f27ebba6f5e5" +
"673a081d70cce7acfc48"
)
)
def test1(self):
for tv in self._test_vector:
secret, salt, info, exp = [ t2b(tv[x]) for x in (1,2,3,5) ]
key_len, hashmod = [ tv[x] for x in (4,0) ]
output = HKDF(secret, key_len, salt, hashmod, 1, info)
self.assertEqual(output, exp)
def test2(self):
ref = HKDF(b("XXXXXX"), 12, b("YYYY"), SHA1)
# Same output, but this time split over 2 keys
key1, key2 = HKDF(b("XXXXXX"), 6, b("YYYY"), SHA1, 2)
self.assertEqual((ref[:6], ref[6:]), (key1, key2))
# Same output, but this time split over 3 keys
key1, key2, key3 = HKDF(b("XXXXXX"), 4, b("YYYY"), SHA1, 3)
self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3))
class scrypt_Tests(unittest.TestCase):
# Test vectors taken from
# https://tools.ietf.org/html/rfc7914
# - password
# - salt
# - N
# - r
# - p
data = (
(
"",
"",
16, # 2K
1,
1,
"""
77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97
f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42
fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17
e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06
"""
),
(
"password",
"NaCl",
1024, # 1M
8,
16,
"""
fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe
7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62
2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da
c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40
"""
),
(
"pleaseletmein",
"SodiumChloride",
16384, # 16M
8,
1,
"""
70 23 bd cb 3a fd 73 48 46 1c 06 cd 81 fd 38 eb
fd a8 fb ba 90 4f 8e 3e a9 b5 43 f6 54 5d a1 f2
d5 43 29 55 61 3f 0f cf 62 d4 97 05 24 2a 9a f9
e6 1e 85 dc 0d 65 1e 40 df cf 01 7b 45 57 58 87
"""
),
(
"pleaseletmein",
"SodiumChloride",
1048576, # 1G
8,
1,
"""
21 01 cb 9b 6a 51 1a ae ad db be 09 cf 70 f8 81
ec 56 8d 57 4a 2f fd 4d ab e5 ee 98 20 ad aa 47
8e 56 fd 8f 4b a5 d0 9f fa 1c 6d 92 7c 40 f4 c3
37 30 40 49 e8 a9 52 fb cb f4 5c 6f a7 7a 41 a4
"""
),
)
def setUp(self):
new_test_vectors = []
for tv in self.data:
new_tv = TestVector()
new_tv.P = b(tv[0])
new_tv.S = b(tv[1])
new_tv.N = tv[2]
new_tv.r = tv[3]
new_tv.p = tv[4]
new_tv.output = t2b(tv[5])
new_tv.dkLen = len(new_tv.output)
new_test_vectors.append(new_tv)
self.data = new_test_vectors
def test2(self):
for tv in self.data:
try:
output = scrypt(tv.P, tv.S, tv.dkLen, tv.N, tv.r, tv.p)
except ValueError as e:
if " 2 " in str(e) and tv.N >= 1048576:
import warnings
warnings.warn("Not enough memory to unit test scrypt() with N=1048576", RuntimeWarning)
continue
else:
raise e
self.assertEqual(output, tv.output)
def test3(self):
ref = scrypt(b("password"), b("salt"), 12, 16, 1, 1)
# Same output, but this time split over 2 keys
key1, key2 = scrypt(b("password"), b("salt"), 6, 16, 1, 1, 2)
self.assertEqual((ref[:6], ref[6:]), (key1, key2))
# Same output, but this time split over 3 keys
key1, key2, key3 = scrypt(b("password"), b("salt"), 4, 16, 1, 1, 3)
self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3))
class bcrypt_Tests(unittest.TestCase):
def test_negative_cases(self):
self.assertRaises(ValueError, bcrypt, b"1" * 73, 10)
self.assertRaises(ValueError, bcrypt, b"1" * 10, 3)
self.assertRaises(ValueError, bcrypt, b"1" * 10, 32)
self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"")
self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"1")
self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"1" * 17)
self.assertRaises(ValueError, bcrypt, b"1\x00" * 10, 4)
def test_bytearray_mismatch(self):
ref = bcrypt("pwd", 4)
bcrypt_check("pwd", ref)
bref = bytearray(ref)
bcrypt_check("pwd", bref)
wrong = ref[:-1] + bchr(bref[-1] ^ 0x01)
self.assertRaises(ValueError, bcrypt_check, "pwd", wrong)
wrong = b"x" + ref[1:]
self.assertRaises(ValueError, bcrypt_check, "pwd", wrong)
# https://github.com/patrickfav/bcrypt/wiki/Published-Test-Vectors
def test_empty_password(self):
# password, cost, salt, bcrypt hash
tvs = [
(b"", 4, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$04$zVHmKQtGGQob.b/Nc7l9NO8UlrYcW05FiuCj/SxsFO/ZtiN9.mNzy"),
(b"", 5, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$05$zVHmKQtGGQob.b/Nc7l9NOWES.1hkVBgy5IWImh9DOjKNU8atY4Iy"),
(b"", 6, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$06$zVHmKQtGGQob.b/Nc7l9NOjOl7l4oz3WSh5fJ6414Uw8IXRAUoiaO"),
(b"", 7, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$07$zVHmKQtGGQob.b/Nc7l9NOBsj1dQpBA1HYNGpIETIByoNX9jc.hOi"),
(b"", 8, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$08$zVHmKQtGGQob.b/Nc7l9NOiLTUh/9MDpX86/DLyEzyiFjqjBFePgO"),
]
for (idx, (password, cost, salt64, result)) in enumerate(tvs):
x = bcrypt(password, cost, salt=_bcrypt_decode(salt64))
self.assertEqual(x, result)
bcrypt_check(password, result)
def test_random_password_and_salt_short_pw(self):
# password, cost, salt, bcrypt hash
tvs = [
(b"<.S.2K(Zq'", 4, b"VYAclAMpaXY/oqAo9yUpku", b"$2a$04$VYAclAMpaXY/oqAo9yUpkuWmoYywaPzyhu56HxXpVltnBIfmO9tgu"),
(b"5.rApO%5jA", 5, b"kVNDrnYKvbNr5AIcxNzeIu", b"$2a$05$kVNDrnYKvbNr5AIcxNzeIuRcyIF5cZk6UrwHGxENbxP5dVv.WQM/G"),
(b"oW++kSrQW^", 6, b"QLKkRMH9Am6irtPeSKN5sO", b"$2a$06$QLKkRMH9Am6irtPeSKN5sObJGr3j47cO6Pdf5JZ0AsJXuze0IbsNm"),
(b"ggJ\\KbTnDG", 7, b"4H896R09bzjhapgCPS/LYu", b"$2a$07$4H896R09bzjhapgCPS/LYuMzAQluVgR5iu/ALF8L8Aln6lzzYXwbq"),
(b"49b0:;VkH/", 8, b"hfvO2retKrSrx5f2RXikWe", b"$2a$08$hfvO2retKrSrx5f2RXikWeFWdtSesPlbj08t/uXxCeZoHRWDz/xFe"),
(b">9N^5jc##'", 9, b"XZLvl7rMB3EvM0c1.JHivu", b"$2a$09$XZLvl7rMB3EvM0c1.JHivuIDPJWeNJPTVrpjZIEVRYYB/mF6cYgJK"),
(b"\\$ch)s4WXp", 10, b"aIjpMOLK5qiS9zjhcHR5TO", b"$2a$10$aIjpMOLK5qiS9zjhcHR5TOU7v2NFDmcsBmSFDt5EHOgp/jeTF3O/q"),
(b"RYoj\\_>2P7", 12, b"esIAHiQAJNNBrsr5V13l7.", b"$2a$12$esIAHiQAJNNBrsr5V13l7.RFWWJI2BZFtQlkFyiWXjou05GyuREZa"),
]
for (idx, (password, cost, salt64, result)) in enumerate(tvs):
x = bcrypt(password, cost, salt=_bcrypt_decode(salt64))
self.assertEqual(x, result)
bcrypt_check(password, result)
def test_random_password_and_salt_long_pw(self):
# password, cost, salt, bcrypt hash
tvs = [
(b"^Q&\"]A`%/A(BVGt>QaX0M-#<Q148&f", 4, b"vrRP5vQxyD4LrqiLd/oWRO", b"$2a$04$vrRP5vQxyD4LrqiLd/oWROgrrGINsw3gb4Ga5x2sn01jNmiLVECl6"),
(b"nZa!rRf\\U;OL;R?>1ghq_+\":Y0CRmY", 5, b"YuQvhokOGVnevctykUYpKu", b"$2a$05$YuQvhokOGVnevctykUYpKutZD2pWeGGYn3auyLOasguMY3/0BbIyq"),
(b"F%uN/j>[GuB7-jB'_Yj!Tnb7Y!u^6)", 6, b"5L3vpQ0tG9O7k5gQ8nAHAe", b"$2a$06$5L3vpQ0tG9O7k5gQ8nAHAe9xxQiOcOLh8LGcI0PLWhIznsDt.S.C6"),
(b"Z>BobP32ub\"Cfe*Q<<WUq3rc=[GJr-", 7, b"hp8IdLueqE6qFh1zYycUZ.", b"$2a$07$hp8IdLueqE6qFh1zYycUZ.twmUH8eSTPQAEpdNXKMlwms9XfKqfea"),
(b"Ik&8N['7*[1aCc1lOm8\\jWeD*H$eZM", 8, b"2ANDTYCB9m7vf0Prh7rSru", b"$2a$08$2ANDTYCB9m7vf0Prh7rSrupqpO3jJOkIz2oW/QHB4lCmK7qMytGV6"),
(b"O)=%3[E$*q+>-q-=tRSjOBh8\\mLNW.", 9, b"nArqOfdCsD9kIbVnAixnwe", b"$2a$09$nArqOfdCsD9kIbVnAixnwe6s8QvyPYWtQBpEXKir2OJF9/oNBsEFe"),
(b"/MH51`!BP&0tj3%YCA;Xk%e3S`o\\EI", 10, b"ePiAc.s.yoBi3B6p1iQUCe", b"$2a$10$ePiAc.s.yoBi3B6p1iQUCezn3mraLwpVJ5XGelVyYFKyp5FZn/y.u"),
(b"ptAP\"mcg6oH.\";c0U2_oll.OKi<!ku", 12, b"aroG/pwwPj1tU5fl9a9pkO", b"$2a$12$aroG/pwwPj1tU5fl9a9pkO4rydAmkXRj/LqfHZOSnR6LGAZ.z.jwa"),
]
for (idx, (password, cost, salt64, result)) in enumerate(tvs):
x = bcrypt(password, cost, salt=_bcrypt_decode(salt64))
self.assertEqual(x, result)
bcrypt_check(password, result)
def test_same_password_and_random_salt(self):
# password, cost, salt, bcrypt hash
tvs = [
(b"Q/A:k3DP;X@=<0\"hg&9c", 4, b"wbgDTvLMtyjQlNK7fjqwyO", b"$2a$04$wbgDTvLMtyjQlNK7fjqwyOakBoACQuYh11.VsKNarF4xUIOBWgD6S"),
(b"Q/A:k3DP;X@=<0\"hg&9c", 5, b"zbAaOmloOhxiKItjznRqru", b"$2a$05$zbAaOmloOhxiKItjznRqrunRqHlu3MAa7pMGv26Rr3WwyfGcwoRm6"),
(b"Q/A:k3DP;X@=<0\"hg&9c", 6, b"aOK0bWUvLI0qLkc3ti5jyu", b"$2a$06$aOK0bWUvLI0qLkc3ti5jyuAIQoqRzuqoK09kQqQ6Ou/YKDhW50/qa"),
]
for (idx, (password, cost, salt64, result)) in enumerate(tvs):
x = bcrypt(password, cost, salt=_bcrypt_decode(salt64))
self.assertEqual(x, result)
bcrypt_check(password, result)
def test_same_password_and_salt_increasing_cost_factor(self):
# password, cost, salt, bcrypt hash
tvs = [
(b"o<&+X'F4AQ8H,LU,N`&r", 4, b"BK5u.QHk1Driey7bvnFTH.", b"$2a$04$BK5u.QHk1Driey7bvnFTH.3smGwxd91PtoK2GxH5nZ7pcBsYX4lMq"),
(b"o<&+X'F4AQ8H,LU,N`&r", 5, b"BK5u.QHk1Driey7bvnFTH.", b"$2a$05$BK5u.QHk1Driey7bvnFTH.t5P.jZvFBMzDB1IY4PwkkRPOyVbEtFG"),
(b"o<&+X'F4AQ8H,LU,N`&r", 6, b"BK5u.QHk1Driey7bvnFTH.", b"$2a$06$BK5u.QHk1Driey7bvnFTH.6Ea1Z5db2p25CPXZbxb/3OyKQagg3pa"),
(b"o<&+X'F4AQ8H,LU,N`&r", 7, b"BK5u.QHk1Driey7bvnFTH.", b"$2a$07$BK5u.QHk1Driey7bvnFTH.sruuQi8Lhv/0LWKDvNp3AGFk7ltdkm6"),
(b"o<&+X'F4AQ8H,LU,N`&r", 8, b"BK5u.QHk1Driey7bvnFTH.", b"$2a$08$BK5u.QHk1Driey7bvnFTH.IE7KsaUzc4m7gzAMlyUPUeiYyACWe0q"),
(b"o<&+X'F4AQ8H,LU,N`&r", 9, b"BK5u.QHk1Driey7bvnFTH.", b"$2a$09$BK5u.QHk1Driey7bvnFTH.1v4Xj1dwkp44QNg0cVAoQt4FQMMrvnS"),
(b"o<&+X'F4AQ8H,LU,N`&r", 10, b"BK5u.QHk1Driey7bvnFTH.", b"$2a$10$BK5u.QHk1Driey7bvnFTH.ESINe9YntUMcVgFDfkC.Vbhc9vMhNX2"),
(b"o<&+X'F4AQ8H,LU,N`&r", 12, b"BK5u.QHk1Driey7bvnFTH.", b"$2a$12$BK5u.QHk1Driey7bvnFTH.QM1/nnGe/f5cTzb6XTTi/vMzcAnycqG"),
]
for (idx, (password, cost, salt64, result)) in enumerate(tvs):
x = bcrypt(password, cost, salt=_bcrypt_decode(salt64))
self.assertEqual(x, result)
bcrypt_check(password, result)
def test_long_passwords(self):
# password, cost, salt, bcrypt hash
tvs = [
(b"g*3Q45=\"8NNgpT&mbMJ$Omfr.#ZeW?FP=CE$#roHd?97uL0F-]`?u73c\"\\[.\"*)qU34@VG",
4, b"T2XJ5MOWvHQZRijl8LIKkO", b"$2a$04$T2XJ5MOWvHQZRijl8LIKkOQKIyX75KBfuLsuRYOJz5OjwBNF2lM8a"),
(b"\\M+*8;&QE=Ll[>5?Ui\"^ai#iQH7ZFtNMfs3AROnIncE9\"BNNoEgO[[*Yk8;RQ(#S,;I+aT",
5, b"wgkOlGNXIVE2fWkT3gyRoO", b"$2a$05$wgkOlGNXIVE2fWkT3gyRoOqWi4gbi1Wv2Q2Jx3xVs3apl1w.Wtj8C"),
(b"M.E1=dt<.L0Q&p;94NfGm_Oo23+Kpl@M5?WIAL.[@/:'S)W96G8N^AWb7_smmC]>7#fGoB",
6, b"W9zTCl35nEvUukhhFzkKMe", b"$2a$06$W9zTCl35nEvUukhhFzkKMekjT9/pj7M0lihRVEZrX3m8/SBNZRX7i"),
]
for (idx, (password, cost, salt64, result)) in enumerate(tvs):
x = bcrypt(password, cost, salt=_bcrypt_decode(salt64))
self.assertEqual(x, result)
bcrypt_check(password, result)
def test_increasing_password_length(self):
# password, cost, salt, bcrypt hash
tvs = [
(b"a", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.l4WvgHIVg17ZawDIrDM2IjlE64GDNQS"),
(b"aa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.AyUxBk.ThHlsLvRTH7IqcG7yVHJ3SXq"),
(b"aaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.BxOVac5xPB6XFdRc/ZrzM9FgZkqmvbW"),
(b"aaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.Qbr209bpCtfl5hN7UQlG/L4xiD3AKau"),
(b"aaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.oWszihPjDZI0ypReKsaDOW1jBl7oOii"),
(b"aaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ./k.Xxn9YiqtV/sxh3EHbnOHd0Qsq27K"),
(b"aaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.PYJqRFQbgRbIjMd5VNKmdKS4sBVOyDe"),
(b"aaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ..VMYfzaw1wP/SGxowpLeGf13fxCCt.q"),
(b"aaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.5B0p054nO5WgAD1n04XslDY/bqY9RJi"),
(b"aaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.INBTgqm7sdlBJDg.J5mLMSRK25ri04y"),
(b"aaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.s3y7CdFD0OR5p6rsZw/eZ.Dla40KLfm"),
(b"aaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.Jx742Djra6Q7PqJWnTAS.85c28g.Siq"),
(b"aaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.oKMXW3EZcPHcUV0ib5vDBnh9HojXnLu"),
(b"aaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.w6nIjWpDPNSH5pZUvLjC1q25ONEQpeS"),
(b"aaaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.k1b2/r9A/hxdwKEKurg6OCn4MwMdiGq"),
(b"aaaaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.3prCNHVX1Ws.7Hm2bJxFUnQOX9f7DFa"),
]
for (idx, (password, cost, salt64, result)) in enumerate(tvs):
x = bcrypt(password, cost, salt=_bcrypt_decode(salt64))
self.assertEqual(x, result)
bcrypt_check(password, result)
def test_non_ascii_characters(self):
# password, cost, salt, bcrypt hash
tvs = [
("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 4, b"D3qS2aoTVyqM7z8v8crLm.", b"$2a$04$D3qS2aoTVyqM7z8v8crLm.3nKt4CzBZJbyFB.ZebmfCvRw7BGs.Xm"),
("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 5, b"VA1FujiOCMPkUHQ8kF7IaO", b"$2a$05$VA1FujiOCMPkUHQ8kF7IaOg7NGaNvpxwWzSluQutxEVmbZItRTsAa"),
("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 6, b"TXiaNrPeBSz5ugiQlehRt.", b"$2a$06$TXiaNrPeBSz5ugiQlehRt.gwpeDQnXWteQL4z2FulouBr6G7D9KUi"),
("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 4, b"YTn1Qlvps8e1odqMn6G5x.", b"$2a$04$YTn1Qlvps8e1odqMn6G5x.85pqKql6w773EZJAExk7/BatYAI4tyO"),
("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 5, b"C.8k5vJKD2NtfrRI9o17DO", b"$2a$05$C.8k5vJKD2NtfrRI9o17DOfIW0XnwItA529vJnh2jzYTb1QdoY0py"),
("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 6, b"xqfRPj3RYAgwurrhcA6uRO", b"$2a$06$xqfRPj3RYAgwurrhcA6uROtGlXDp/U6/gkoDYHwlubtcVcNft5.vW"),
("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 4, b"y8vGgMmr9EdyxP9rmMKjH.", b"$2a$04$y8vGgMmr9EdyxP9rmMKjH.wv2y3r7yRD79gykQtmb3N3zrwjKsyay"),
("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 5, b"iYH4XIKAOOm/xPQs7xKP1u", b"$2a$05$iYH4XIKAOOm/xPQs7xKP1upD0cWyMn3Jf0ZWiizXbEkVpS41K1dcO"),
("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 6, b"wCOob.D0VV8twafNDB2ape", b"$2a$06$wCOob.D0VV8twafNDB2apegiGD5nqF6Y1e6K95q6Y.R8C4QGd265q"),
("ΔημοσιεύθηκεστηνΕφημερίδατης", 4, b"E5SQtS6P4568MDXW7cyUp.", b"$2a$04$E5SQtS6P4568MDXW7cyUp.18wfDisKZBxifnPZjAI1d/KTYMfHPYO"),
("АБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмН", 4, b"03e26gQFHhQwRNf81/ww9.", b"$2a$04$03e26gQFHhQwRNf81/ww9.p1UbrNwxpzWjLuT.zpTLH4t/w5WhAhC"),
("нОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮю", 4, b"PHNoJwpXCfe32nUtLv2Upu", b"$2a$04$PHNoJwpXCfe32nUtLv2UpuhJXOzd4k7IdFwnEpYwfJVCZ/f/.8Pje"),
("電电電島岛島兔兔兎龜龟亀國国国區区区", 4, b"wU4/0i1TmNl2u.1jIwBX.u", b"$2a$04$wU4/0i1TmNl2u.1jIwBX.uZUaOL3Rc5ID7nlQRloQh6q5wwhV/zLW"),
("诶比伊艾弗豆贝尔维吾艾尺开艾丝维贼德", 4, b"P4kreGLhCd26d4WIy7DJXu", b"$2a$04$P4kreGLhCd26d4WIy7DJXusPkhxLvBouzV6OXkL5EB0jux0osjsry"),
]
for (idx, (password, cost, salt64, result)) in enumerate(tvs):
x = bcrypt(password, cost, salt=_bcrypt_decode(salt64))
self.assertEqual(x, result)
bcrypt_check(password, result)
def test_special_case_salt(self):
# password, cost, salt, bcrypt hash
tvs = [
("-O_=*N!2JP", 4, b"......................", b"$2a$04$......................JjuKLOX9OOwo5PceZZXSkaLDvdmgb82"),
("7B[$Q<4b>U", 5, b"......................", b"$2a$05$......................DRiedDQZRL3xq5A5FL8y7/6NM8a2Y5W"),
(">d5-I_8^.h", 6, b"......................", b"$2a$06$......................5Mq1Ng8jgDY.uHNU4h5p/x6BedzNH2W"),
(")V`/UM/]1t", 4, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$04$.OC/.OC/.OC/.OC/.OC/.OQIvKRDAam.Hm5/IaV/.hc7P8gwwIbmi"),
(":@t2.bWuH]", 5, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$05$.OC/.OC/.OC/.OC/.OC/.ONDbUvdOchUiKmQORX6BlkPofa/QxW9e"),
("b(#KljF5s\"", 6, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$06$.OC/.OC/.OC/.OC/.OC/.OHfTd9e7svOu34vi1PCvOcAEq07ST7.K"),
("@3YaJ^Xs]*", 4, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$04$eGA.eGA.eGA.eGA.eGA.e.stcmvh.R70m.0jbfSFVxlONdj1iws0C"),
("'\"5\\!k*C(p", 5, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$05$eGA.eGA.eGA.eGA.eGA.e.vR37mVSbfdHwu.F0sNMvgn8oruQRghy"),
("edEu7C?$'W", 6, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$06$eGA.eGA.eGA.eGA.eGA.e.tSq0FN8MWHQXJXNFnHTPQKtA.n2a..G"),
("N7dHmg\\PI^", 4, b"999999999999999999999u", b"$2a$04$999999999999999999999uCZfA/pLrlyngNDMq89r1uUk.bQ9icOu"),
("\"eJuHh!)7*", 5, b"999999999999999999999u", b"$2a$05$999999999999999999999uj8Pfx.ufrJFAoWFLjapYBS5vVEQQ/hK"),
("ZeDRJ:_tu:", 6, b"999999999999999999999u", b"$2a$06$999999999999999999999u6RB0P9UmbdbQgjoQFEJsrvrKe.BoU6q"),
]
for (idx, (password, cost, salt64, result)) in enumerate(tvs):
x = bcrypt(password, cost, salt=_bcrypt_decode(salt64))
self.assertEqual(x, result)
bcrypt_check(password, result)
class TestVectorsHKDFWycheproof(unittest.TestCase):
def __init__(self, wycheproof_warnings):
unittest.TestCase.__init__(self)
self._wycheproof_warnings = wycheproof_warnings
self._id = "None"
def add_tests(self, filename):
def filter_algo(root):
algo_name = root['algorithm']
if algo_name == "HKDF-SHA-1":
return SHA1
elif algo_name == "HKDF-SHA-256":
return SHA256
elif algo_name == "HKDF-SHA-384":
return SHA384
elif algo_name == "HKDF-SHA-512":
return SHA512
else:
raise ValueError("Unknown algorithm " + algo_name)
def filter_size(unit):
return int(unit['size'])
result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
filename,
"Wycheproof HMAC (%s)" % filename,
root_tag={'hash_module': filter_algo},
unit_tag={'size': filter_size})
return result
def setUp(self):
self.tv = []
self.add_tests("hkdf_sha1_test.json")
self.add_tests("hkdf_sha256_test.json")
self.add_tests("hkdf_sha384_test.json")
self.add_tests("hkdf_sha512_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_verify(self, tv):
self._id = "Wycheproof HKDF Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
try:
key = HKDF(tv.ikm, tv.size, tv.salt, tv.hash_module, 1, tv.info)
except ValueError:
assert not tv.valid
else:
if key != tv.okm:
assert not tv.valid
else:
assert tv.valid
self.warn(tv)
def runTest(self):
for tv in self.tv:
self.test_verify(tv)
def load_hash_by_name(hash_name):
return __import__("Crypto.Hash." + hash_name, globals(), locals(), ["new"])
class SP800_108_Counter_Tests(unittest.TestCase):
def test_negative_zeroes(self):
def prf(s, x):
return HMAC.new(s, x, SHA256).digest()
try:
_ = SP800_108_Counter(b'0' * 16, 1, prf, label=b'A\x00B')
except ValueError:
self.fail('SP800_108_Counter failed with zero in label')
self.assertRaises(ValueError, SP800_108_Counter, b'0' * 16, 1, prf,
context=b'A\x00B')
def test_multiple_keys(self):
def prf(s, x):
return HMAC.new(s, x, SHA256).digest()
key = b'0' * 16
expected = SP800_108_Counter(key, 2*3*23, prf)
for r in (1, 2, 3, 23):
dks = SP800_108_Counter(key, r, prf, 138//r)
self.assertEqual(len(dks), 138//r)
self.assertEqual(len(dks[0]), r)
self.assertEqual(b''.join(dks), expected)
def add_tests_sp800_108_counter(cls):
test_vectors_sp800_108_counter = load_test_vectors(("Protocol", ),
"KDF_SP800_108_COUNTER.txt",
"NIST SP 800 108 KDF Counter Mode",
{'count': lambda x: int(x)},
) or []
mac_type = None
for idx, tv in enumerate(test_vectors_sp800_108_counter):
if isinstance(tv, str):
res = re.match(r"\[HMAC-(SHA-[0-9]+)\]", tv)
if res:
hash_name = res.group(1).replace("-", "")
hash_module = load_hash_by_name(hash_name)
mac_type = "hmac"
continue
res = re.match(r"\[CMAC-AES-128\]", tv)
if res:
mac_type = "cmac"
continue
assert res
if mac_type == "hmac":
def prf(s, x, hash_module=hash_module):
return HMAC.new(s, x, hash_module).digest()
elif mac_type == "cmac":
def prf(s, x, hash_module=hash_module):
return CMAC.new(s, x, AES).digest()
continue
def kdf_test(self, prf=prf, kin=tv.kin, label=tv.label,
context=tv.context, kout=tv.kout, count=tv.count):
result = SP800_108_Counter(kin, len(kout), prf, 1, label, context)
assert(len(result) == len(kout))
self.assertEqual(result, kout)
setattr(cls, "test_kdf_sp800_108_counter_%d" % idx, kdf_test)
add_tests_sp800_108_counter(SP800_108_Counter_Tests)
def get_tests(config={}):
wycheproof_warnings = config.get('wycheproof_warnings')
if not config.get('slow_tests'):
PBKDF2_Tests._testData = PBKDF2_Tests._testData[:3]
scrypt_Tests.data = scrypt_Tests.data[:3]
tests = []
tests += list_test_cases(PBKDF1_Tests)
tests += list_test_cases(PBKDF2_Tests)
tests += list_test_cases(S2V_Tests)
tests += list_test_cases(HKDF_Tests)
tests += [TestVectorsHKDFWycheproof(wycheproof_warnings)]
tests += list_test_cases(scrypt_Tests)
tests += list_test_cases(bcrypt_Tests)
tests += list_test_cases(SP800_108_Counter_Tests)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,290 @@
#
# SelfTest/Protocol/test_secret_sharing.py: Self-test for secret sharing protocols
#
# ===================================================================
#
# 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.
# ===================================================================
from unittest import main, TestCase, TestSuite
from binascii import unhexlify, hexlify
from Crypto.Util.py3compat import *
from Crypto.Hash import SHAKE128
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Protocol.SecretSharing import Shamir, _Element, \
_mult_gf2, _div_gf2
class GF2_Tests(TestCase):
def test_mult_gf2(self):
# Prove mult by zero
x = _mult_gf2(0,0)
self.assertEqual(x, 0)
# Prove mult by unity
x = _mult_gf2(34, 1)
self.assertEqual(x, 34)
z = 3 # (x+1)
y = _mult_gf2(z, z)
self.assertEqual(y, 5) # (x+1)^2 = x^2 + 1
y = _mult_gf2(y, z)
self.assertEqual(y, 15) # (x+1)^3 = x^3 + x^2 + x + 1
y = _mult_gf2(y, z)
self.assertEqual(y, 17) # (x+1)^4 = x^4 + 1
# Prove linearity works
comps = [1, 4, 128, 2**34]
sum_comps = 1+4+128+2**34
y = 908
z = _mult_gf2(sum_comps, y)
w = 0
for x in comps:
w ^= _mult_gf2(x, y)
self.assertEqual(w, z)
def test_div_gf2(self):
from Crypto.Util.number import size as deg
x, y = _div_gf2(567, 7)
self.assertTrue(deg(y) < deg(7))
w = _mult_gf2(x, 7) ^ y
self.assertEqual(567, w)
x, y = _div_gf2(7, 567)
self.assertEqual(x, 0)
self.assertEqual(y, 7)
class Element_Tests(TestCase):
def test1(self):
# Test encondings
e = _Element(256)
self.assertEqual(int(e), 256)
self.assertEqual(e.encode(), bchr(0)*14 + b("\x01\x00"))
e = _Element(bchr(0)*14 + b("\x01\x10"))
self.assertEqual(int(e), 0x110)
self.assertEqual(e.encode(), bchr(0)*14 + b("\x01\x10"))
# Only 16 byte string are a valid encoding
self.assertRaises(ValueError, _Element, bchr(0))
def test2(self):
# Test addition
e = _Element(0x10)
f = _Element(0x0A)
self.assertEqual(int(e+f), 0x1A)
def test3(self):
# Test multiplication
zero = _Element(0)
one = _Element(1)
two = _Element(2)
x = _Element(6) * zero
self.assertEqual(int(x), 0)
x = _Element(6) * one
self.assertEqual(int(x), 6)
x = _Element(2**127) * two
self.assertEqual(int(x), 1 + 2 + 4 + 128)
def test4(self):
# Test inversion
one = _Element(1)
x = one.inverse()
self.assertEqual(int(x), 1)
x = _Element(82323923)
y = x.inverse()
self.assertEqual(int(x * y), 1)
class Shamir_Tests(TestCase):
def test1(self):
# Test splitting
shares = Shamir.split(2, 3, bchr(90)*16)
self.assertEqual(len(shares), 3)
for index in range(3):
self.assertEqual(shares[index][0], index+1)
self.assertEqual(len(shares[index][1]), 16)
def test2(self):
# Test recombine
from itertools import permutations
# Generated by ssss (index, secret, shares)
# in hex mode, without "diffusion" mode
test_vectors = (
(2, "d9fe73909bae28b3757854c0af7ad405",
"1-594ae8964294174d95c33756d2504170",
"2-d897459d29da574eb40e93ec552ffe6e",
"3-5823de9bf0e068b054b5f07a28056b1b",
"4-db2c1f8bff46d748f795da995bd080cb"),
(2, "bf4f902d9a7efafd1f3ffd9291fd5de9",
"1-557bd3b0748064b533469722d1cc7935",
"2-6b2717164783c66d47cd28f2119f14d0",
"3-8113548ba97d58256bb4424251ae300c",
"4-179e9e5a218483ddaeda57539139cf04"),
(3, "ec96aa5c14c9faa699354cf1da74e904",
"1-64579fbf1908d66f7239bf6e2b4e41e1",
"2-6cd9428df8017b52322561e8c672ae3e",
"3-e418776ef5c0579bd9299277374806dd",
"4-ab3f77a0107398d23b323e581bb43f5d",
"5-23fe42431db2b41bd03ecdc7ea8e97ac"),
(3, "44cf249b68b80fcdc27b47be60c2c145",
"1-d6515a3905cd755119b86e311c801e31",
"2-16693d9ac9f10c254036ced5f8917fa3",
"3-84f74338a48476b99bf5e75a84d3a0d1",
"4-3fe8878dc4a5d35811cf3cbcd33dbe52",
"5-ad76f92fa9d0a9c4ca0c1533af7f6132"),
(5, "5398717c982db935d968eebe53a47f5a",
"1-be7be2dd4c068e7ef576aaa1b1c11b01",
"2-f821f5848441cb98b3eb467e2733ee21",
"3-25ee52f53e203f6e29a0297b5ab486b5",
"4-fc9fb58ef74dab947fbf9acd9d5d83cd",
"5-b1949cce46d81552e65f248d3f74cc5c",
"6-d64797f59977c4d4a7956ad916da7699",
"7-ab608a6546a8b9af8820ff832b1135c7"),
(5, "4a78db90fbf35da5545d2fb728e87596",
"1-08daf9a25d8aa184cfbf02b30a0ed6a0",
"2-dda28261e36f0b14168c2cf153fb734e",
"3-e9fdec5505d674a57f9836c417c1ecaa",
"4-4dce5636ae06dee42d2c82e65f06c735",
"5-3963dc118afc2ba798fa1d452b28ef00",
"6-6dfe6ff5b09e94d2f84c382b12f42424",
"7-6faea9d4d4a4e201bf6c90b9000630c3"),
(10, "eccbf6d66d680b49b073c4f1ddf804aa",
"01-7d8ac32fe4ae209ead1f3220fda34466",
"02-f9144e76988aad647d2e61353a6e96d5",
"03-b14c3b80179203363922d60760271c98",
"04-770bb2a8c28f6cee89e00f4d5cc7f861",
"05-6e3d7073ea368334ef67467871c66799",
"06-248792bc74a98ce024477c13c8fb5f8d",
"07-fcea4640d2db820c0604851e293d2487",
"08-2776c36fb714bb1f8525a0be36fc7dba",
"09-6ee7ac8be773e473a4bf75ee5f065762",
"10-33657fc073354cf91d4a68c735aacfc8",
"11-7645c65094a5868bf225c516fdee2d0c",
"12-840485aacb8226631ecd9c70e3018086"),
(10, "377e63bdbb5f7d4dc58a483d035212bb",
"01-32c53260103be431c843b1a633afe3bd",
"02-0107eb16cb8695084d452d2cc50bc7d6",
"03-df1e5c66cd755287fb0446faccd72a06",
"04-361bbcd5d40797f49dfa1898652da197",
"05-160d3ad1512f7dec7fd9344aed318591",
"06-659af6d95df4f25beca4fb9bfee3b7e8",
"07-37f3b208977bad50b3724566b72bfa9d",
"08-6c1de2dfc69c2986142c26a8248eb316",
"09-5e19220837a396bd4bc8cd685ff314c3",
"10-86e7b864fb0f3d628e46d50c1ba92f1c",
"11-065d0082c80b1aea18f4abe0c49df72e",
"12-84a09430c1d20ea9f388f3123c3733a3"),
)
def get_share(p):
pos = p.find('-')
return int(p[:pos]), unhexlify(p[pos + 1:])
for tv in test_vectors:
k = tv[0]
secret = unhexlify(tv[1])
max_perms = 10
for perm, shares_idx in enumerate(permutations(range(2, len(tv)), k)):
if perm > max_perms:
break
shares = [ get_share(tv[x]) for x in shares_idx ]
result = Shamir.combine(shares, True)
self.assertEqual(secret, result)
def test3(self):
# Loopback split/recombine
rng = SHAKE128.new(b"test3")
for _ in range(100):
secret = rng.read(16)
shares = Shamir.split(2, 3, secret)
secret2 = Shamir.combine(shares[:2])
self.assertEqual(secret, secret2)
secret3 = Shamir.combine([ shares[0], shares[2] ])
self.assertEqual(secret, secret3)
def test4(self):
# Loopback split/recombine (SSSS)
rng = SHAKE128.new(b"test4")
for _ in range(10):
secret = rng.read(16)
shares = Shamir.split(2, 3, secret, ssss=True)
secret2 = Shamir.combine(shares[:2], ssss=True)
self.assertEqual(secret, secret2)
for _ in range(10):
secret = rng.read(16)
shares = Shamir.split(3, 7, secret, ssss=True)
secret2 = Shamir.combine([shares[3], shares[4], shares[6]], ssss=True)
self.assertEqual(secret, secret2)
def test5(self):
# Detect duplicate shares
secret = unhexlify(b("000102030405060708090a0b0c0d0e0f"))
shares = Shamir.split(2, 3, secret)
self.assertRaises(ValueError, Shamir.combine, (shares[0], shares[0]))
def get_tests(config={}):
tests = []
tests += list_test_cases(GF2_Tests)
tests += list_test_cases(Element_Tests)
tests += list_test_cases(Shamir_Tests)
return tests
if __name__ == '__main__':
suite = lambda: TestSuite(get_tests())
main(defaultTest='suite')
@@ -0,0 +1,770 @@
import re
import base64
import unittest
from binascii import hexlify, unhexlify
from Crypto.Util.py3compat import bord
from Crypto.Hash import SHA256
from Crypto.PublicKey import ECC
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof
from Crypto.Protocol import DH
from Crypto.Protocol.DH import (key_agreement,
import_x25519_public_key,
import_x25519_private_key,
import_x448_public_key,
import_x448_private_key)
class FIPS_ECDH_Tests_KAT(unittest.TestCase):
pass
test_vectors_verify = load_test_vectors(("Protocol", ),
"KAS_ECC_CDH_PrimitiveTest.txt",
"ECC CDH Primitive (SP800-56A Section 5.7.1.2)",
{
'qcavsx': lambda x: int(x, 16),
'qcavsy': lambda x: int(x, 16),
'diut': lambda x: int(x, 16),
'qiutx': lambda x: int(x, 16),
'qiuty': lambda x: int(x, 16),
}) or []
for idx, tv in enumerate(test_vectors_verify):
# Stand-alone header with curve name
if isinstance(tv, str):
res = re.match(r"\[([A-Za-z0-9-]+)\]", tv)
assert res
curve_name = res.group(1)
continue
public_key = ECC.construct(curve=curve_name,
point_x=tv.qcavsx,
point_y=tv.qcavsy)
private_key = ECC.construct(curve=curve_name,
d=tv.diut)
exp_response = tv.ziut
def ecdh_test(self,
public_key=public_key,
private_key=private_key,
exp_response=exp_response):
z = key_agreement(
static_pub=public_key,
static_priv=private_key,
kdf=lambda x: x)
self.assertEqual(z, exp_response)
def ecdh_test_rev(self,
public_key=public_key,
private_key=private_key,
exp_response=exp_response):
z = key_agreement(
static_pub=public_key,
static_priv=private_key,
kdf=lambda x: x)
self.assertEqual(z, exp_response)
setattr(FIPS_ECDH_Tests_KAT, "test_verify_positive_%d" % idx, ecdh_test)
if idx == 1:
setattr(FIPS_ECDH_Tests_KAT, "test_verify_positive_rev_%d" % idx, ecdh_test_rev)
class TestVectorsECDHWycheproof(unittest.TestCase):
desc = "Wycheproof ECDH tests"
def add_tests(self, filename):
def curve(g):
return g['curve']
def private(u):
return int(u['private'], 16)
result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
filename,
"Wycheproof ECDH (%s)"
% filename,
group_tag={'curve': curve},
unit_tag={'private': private},
)
self.tv += result
def setUp(self):
self.tv = []
self.desc = None
self.add_tests("ecdh_secp224r1_ecpoint_test.json")
self.add_tests("ecdh_secp256r1_ecpoint_test.json")
self.add_tests("ecdh_secp384r1_ecpoint_test.json")
self.add_tests("ecdh_secp521r1_ecpoint_test.json")
self.add_tests("ecdh_secp224r1_test.json")
self.add_tests("ecdh_secp256r1_test.json")
self.add_tests("ecdh_secp384r1_test.json")
self.add_tests("ecdh_secp521r1_test.json")
def shortDescription(self):
return self.desc
def test_verify(self, tv):
if len(tv.public) == 0:
return
try:
if bord(tv.public[0]) == 4: # SEC1
public_key = ECC.import_key(tv.public, curve_name=tv.curve)
else:
public_key = ECC.import_key(tv.public)
except ValueError:
assert tv.warning or not tv.valid
return
private_key = ECC.construct(curve=tv.curve, d=tv.private)
try:
z = key_agreement(static_pub=public_key,
static_priv=private_key,
kdf=lambda x: x)
except ValueError:
assert not tv.valid
except TypeError as e:
assert not tv.valid
assert "incompatible curve" in str(e)
else:
self.assertEqual(z, tv.shared)
assert tv.valid
def runTest(self):
for tv in self.tv:
self.desc = "Wycheproof ECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
self.test_verify(tv)
class ECDH_Tests(unittest.TestCase):
static_priv = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg9VHFVKh2a1aVFifH\n+BiyNaRa2kttEg3165Ye/dJxJ7KhRANCAARImIEXro5ZOcyWU2mq/+d79FEZXtTA\nbKkz1aICQXihQdCMzRNbeNtC9LFLzhu1slRKJ2xsDAlw9r6w6vwtkRzr\n-----END PRIVATE KEY-----')
static_pub = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgHhmv8zmZ+Nw8fsZd\ns8tlZflyfw2NE1CRS9DWr3Y3O46hRANCAAS3hZVUCbk+uk3w4S/YOraEVGG+WYpk\nNO/vrwzufUUks2GV2OnBQESe0EBk4Jq8gn4ij8Lvs3rZX2yT+XfeATYd\n-----END PRIVATE KEY-----').public_key()
eph_priv = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGPdJmFFFKzLPspIr\nE1T2cEjeIf4ajS9CpneP0e2b3AyhRANCAAQBexAA5BYDcXHs2KOksTYUsst4HhPt\nkp0zkgI2virc3OGJFNGPaCCPfFCQJHwLRaEpiq3SoQlgoBwSc8ZPsl3y\n-----END PRIVATE KEY-----')
eph_pub = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQghaVZXElSEGEojFKF\nOU0JCpxWUWHvWQUR81gwWrOp76ShRANCAATi1Ib2K+YR3AckD8wxypWef7pw5PRw\ntBaB3RDPyE7IjHZC6yu1DbcXoCdtaw+F5DM+4zpl59n5ZaIy/Yl1BdIy\n-----END PRIVATE KEY-----')
def test_1(self):
# C(0, 2s)
kdf = lambda x: SHA256.new(x).digest()
z = key_agreement(
kdf=kdf,
static_pub=self.static_pub,
static_priv=self.static_priv)
self.assertEqual(hexlify(z),
b"3960a1101d1193cbaffef4cc7202ebff783c22c6d2e0d5d530ffc66dc197ea9c")
def test_2(self):
# C(2e, 2s)
kdf = lambda x: SHA256.new(x).digest()
z = key_agreement(
kdf=kdf,
static_pub=self.static_pub,
static_priv=self.static_priv,
eph_pub=self.eph_pub,
eph_priv=self.eph_priv)
self.assertEqual(hexlify(z),
b"7447b733d40c8fab2c633b3dc61e4a8c742f3a6af7e16fb0cc486f5bdb5d6ba2")
def test_3(self):
# C(1e, 2s)
kdf = lambda x: SHA256.new(x).digest()
z = key_agreement(
kdf=kdf,
static_pub=self.static_pub,
static_priv=self.static_priv,
eph_priv=self.eph_priv)
self.assertEqual(hexlify(z),
b"9e977ae45f33bf67f285d064d83e6632bcafe3a7d33fe571233bab4794ace759")
def test_4(self):
# C(1e, 2s)
kdf = lambda x: SHA256.new(x).digest()
z = key_agreement(
kdf=kdf,
static_pub=self.static_pub,
static_priv=self.static_priv,
eph_pub=self.eph_pub)
self.assertEqual(hexlify(z),
b"c9532df6aa7e9dbe5fe85da31ee25ff19c179c88691ec4b8328cc2036dcdadf2")
def test_5(self):
# C(2e, 1s) is not supported
kdf = lambda x: SHA256.new(x).digest()
self.assertRaises(ValueError,
key_agreement,
kdf=kdf,
static_priv=self.static_priv,
eph_pub=self.eph_pub,
eph_priv=self.eph_priv)
def test_6(self):
# C(2e, 1s) is not supported
kdf = lambda x: SHA256.new(x).digest()
self.assertRaises(ValueError,
key_agreement,
kdf=kdf,
static_pub=self.static_pub,
eph_pub=self.eph_pub,
eph_priv=self.eph_priv)
def test_7(self):
# C(2e, 0)
kdf = lambda x: SHA256.new(x).digest()
z = key_agreement(
kdf=kdf,
eph_pub=self.eph_pub,
eph_priv=self.eph_priv)
self.assertEqual(hexlify(z),
b"feb257ebe063078b1391aac07913283d7b642ad7df61b46dfc9cd6f420bb896a")
def test_8(self):
# C(1e, 1s)
kdf = lambda x: SHA256.new(x).digest()
z = key_agreement(
kdf=kdf,
static_priv=self.static_priv,
eph_pub=self.eph_pub)
self.assertEqual(hexlify(z),
b"ee4dc995117476ed57fd17ff0ed44e9f0466d46b929443bc0db9380317583b04")
def test_9(self):
# C(1e, 1s)
kdf = lambda x: SHA256.new(x).digest()
z = key_agreement(
kdf=kdf,
static_pub=self.static_pub,
eph_priv=self.eph_priv)
self.assertEqual(hexlify(z),
b"2351cc2014f7c40468fa072b5d30f706eeaeef7507311cd8e59bab3b43f03c51")
def test_10(self):
# No private (local) keys
kdf = lambda x: SHA256.new(x).digest()
self.assertRaises(ValueError,
key_agreement,
kdf=kdf,
static_pub=self.static_pub,
eph_pub=self.eph_pub)
def test_11(self):
# No public (peer) keys
kdf = lambda x: SHA256.new(x).digest()
self.assertRaises(ValueError,
key_agreement,
kdf=kdf,
static_priv=self.static_priv,
eph_priv=self.eph_priv)
def test_12(self):
# failure if kdf is missing
self.assertRaises(ValueError,
key_agreement,
static_pub=self.static_pub,
static_priv=self.static_priv)
class X25519_Tests(unittest.TestCase):
def test_rfc7748_1(self):
tvs = (
("a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
"e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c",
"c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552"),
("4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d",
"e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493",
"95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957"),
)
for tv1, tv2, tv3 in tvs:
priv_key = DH.import_x25519_private_key(unhexlify(tv1))
pub_key = DH.import_x25519_public_key(unhexlify(tv2))
result = key_agreement(static_pub=pub_key,
static_priv=priv_key,
kdf=lambda x: x)
self.assertEqual(result, unhexlify(tv3))
def test_rfc7748_2(self):
k = unhexlify("0900000000000000000000000000000000000000000000000000000000000000")
priv_key = DH.import_x25519_private_key(k)
pub_key = DH.import_x25519_public_key(k)
result = key_agreement(static_pub=pub_key,
static_priv=priv_key,
kdf=lambda x: x)
self.assertEqual(
result,
unhexlify("422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079")
)
for _ in range(999):
priv_key = DH.import_x25519_private_key(result)
pub_key = DH.import_x25519_public_key(k)
k = result
result = key_agreement(static_pub=pub_key,
static_priv=priv_key,
kdf=lambda x: x)
self.assertEqual(
result,
unhexlify("684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51")
)
def test_rfc7748_3(self):
tv1 = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"
tv2 = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"
tv3 = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"
tv4 = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"
tv5 = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
alice_priv_key = DH.import_x25519_private_key(unhexlify(tv1))
alice_pub_key = DH.import_x25519_public_key(unhexlify(tv2))
bob_priv_key = DH.import_x25519_private_key(unhexlify(tv3))
bob_pub_key = DH.import_x25519_public_key(unhexlify(tv4))
secret = unhexlify(tv5)
result1 = key_agreement(static_pub=alice_pub_key,
static_priv=bob_priv_key,
kdf=lambda x: x)
result2 = key_agreement(static_pub=bob_pub_key,
static_priv=alice_priv_key,
kdf=lambda x: x)
self.assertEqual(result1, secret)
self.assertEqual(result2, secret)
def test_weak(self):
weak_keys = (
"0000000000000000000000000000000000000000000000000000000000000000",
"0100000000000000000000000000000000000000000000000000000000000000",
"e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800",
"5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157",
"ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
# The implementation will accept these value, but only because
# it will set the MSB to zero (as required by RFC7748, Section 5),
# therefore leading to another public key (and to a point which is
# not of low order anymore).
# "cdeb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880",
# "4c9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f11d7",
# "d9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
# "daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
# "dbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
)
for x in weak_keys:
self.assertRaises(ValueError,
DH.import_x25519_public_key,
unhexlify(x))
class X448_Tests(unittest.TestCase):
def test_rfc7748_1(self):
tvs = (
("3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3",
"06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086",
"ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f"),
("203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f",
"0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db",
"884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d"),
)
for tv1, tv2, tv3 in tvs:
priv_key = DH.import_x448_private_key(unhexlify(tv1))
pub_key = DH.import_x448_public_key(unhexlify(tv2))
result = key_agreement(static_pub=pub_key,
static_priv=priv_key,
kdf=lambda x: x)
self.assertEqual(result, unhexlify(tv3))
def test_rfc7748_2(self):
k = unhexlify("0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
priv_key = DH.import_x448_private_key(k)
pub_key = DH.import_x448_public_key(k)
result = key_agreement(static_pub=pub_key,
static_priv=priv_key,
kdf=lambda x: x)
self.assertEqual(
result,
unhexlify("3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113")
)
for _ in range(999):
priv_key = DH.import_x448_private_key(result)
pub_key = DH.import_x448_public_key(k)
k = result
result = key_agreement(static_pub=pub_key,
static_priv=priv_key,
kdf=lambda x: x)
self.assertEqual(
result,
unhexlify("aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38")
)
def test_rfc7748_3(self):
tv1 = "9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b"
tv2 = "9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0"
tv3 = "1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d"
tv4 = "3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609"
tv5 = "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d"
alice_priv_key = DH.import_x448_private_key(unhexlify(tv1))
alice_pub_key = DH.import_x448_public_key(unhexlify(tv2))
bob_priv_key = DH.import_x448_private_key(unhexlify(tv3))
bob_pub_key = DH.import_x448_public_key(unhexlify(tv4))
secret = unhexlify(tv5)
result1 = key_agreement(static_pub=alice_pub_key,
static_priv=bob_priv_key,
kdf=lambda x: x)
result2 = key_agreement(static_pub=bob_pub_key,
static_priv=alice_priv_key,
kdf=lambda x: x)
self.assertEqual(result1, secret)
self.assertEqual(result2, secret)
def test_weak(self):
weak_keys = (
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"fefffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
)
for x in weak_keys:
self.assertRaises(ValueError,
DH.import_x448_public_key,
unhexlify(x))
class TestVectorsX25519Wycheproof(unittest.TestCase):
desc = "Wycheproof X25519 tests"
def add_tests_hex(self, filename):
def encoding(g):
return g['type']
def private(u):
return unhexlify(u['private'])
result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
filename,
"Wycheproof ECDH (%s)"
% filename,
group_tag={'encoding': encoding},
unit_tag={'private': private}
)
self.tv += result
def add_tests_ascii(self, filename):
def encoding(g):
return g['type']
def public(u):
return u['public']
def private(u):
return u['private']
result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
filename,
"Wycheproof ECDH (%s)"
% filename,
group_tag={'encoding': encoding},
unit_tag={'public': public,
'private': private}
)
self.tv += result
def setUp(self):
self.tv = []
self.desc = None
self.add_tests_hex("x25519_test.json")
self.add_tests_hex("x25519_asn_test.json")
self.add_tests_ascii("x25519_pem_test.json")
self.add_tests_ascii("x25519_jwk_test.json")
def shortDescription(self):
return self.desc
def test_verify(self, tv):
if tv.encoding == "XdhComp":
try:
public_key = import_x25519_public_key(tv.public)
except ValueError as e:
assert tv.valid
assert tv.warning
assert "LowOrderPublic" in tv.flags
assert "Invalid Curve25519" in str(e)
return
private_key = import_x25519_private_key(tv.private)
elif tv.encoding in ("XdhAsnComp", "XdhPemComp"):
try:
public_key = ECC.import_key(tv.public)
private_key = ECC.import_key(tv.private)
except ECC.UnsupportedEccFeature as e:
assert not tv.valid
assert "Unsupported ECC" in str(e)
return
except ValueError:
assert tv.valid
assert tv.warning
assert "LowOrderPublic" in tv.flags
return
elif tv.encoding == "XdhJwkComp":
if 'y' in tv.public:
return
if 'x' not in tv.public:
return
if 'x' not in tv.private:
return
if tv.public.get('kty') != 'OKP':
return
if tv.public.get('crv') != 'X25519':
return
if tv.private.get('crv') != 'X25519':
return
def base64url_decode(input_str):
input_str = input_str.replace('-', '+').replace('_', '/')
padding = 4 - (len(input_str) % 4)
if padding != 4:
input_str += '=' * padding
decoded_bytes = base64.b64decode(input_str)
return decoded_bytes
jwk_public = base64url_decode(tv.public['x'])
jwk_private = base64url_decode(tv.private['d'])
try:
public_key = import_x25519_public_key(jwk_public)
private_key = import_x25519_private_key(jwk_private)
except ValueError as e:
if tv.valid:
assert tv.warning
assert "LowOrderPublic" in tv.flags
assert "Invalid Curve25519" in str(e)
return
else:
assert "Incorrect length" in str(e)
return
except ValueError:
assert tv.valid
else:
raise ValueError("Unknown encoding", tv.encoding)
try:
z = key_agreement(static_pub=public_key,
static_priv=private_key,
kdf=lambda x: x)
except ValueError:
assert not tv.valid
except TypeError as e:
assert not tv.valid
assert "incompatible curve" in str(e)
else:
self.assertEqual(z, tv.shared)
assert tv.valid
def runTest(self):
for tv in self.tv:
self.desc = "Wycheproof XECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
self.test_verify(tv)
class TestVectorsX448Wycheproof(unittest.TestCase):
desc = "Wycheproof X448 tests"
def add_tests_hex(self, filename):
def encoding(g):
return g['type']
def private(u):
return unhexlify(u['private'])
result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
filename,
"Wycheproof ECDH (%s)"
% filename,
group_tag={'encoding': encoding},
unit_tag={'private': private}
)
self.tv += result
def add_tests_ascii(self, filename):
def encoding(g):
return g['type']
def public(u):
return u['public']
def private(u):
return u['private']
result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
filename,
"Wycheproof ECDH (%s)"
% filename,
group_tag={'encoding': encoding},
unit_tag={'public': public,
'private': private}
)
self.tv += result
def setUp(self):
self.tv = []
self.desc = None
self.add_tests_hex("x448_test.json")
self.add_tests_hex("x448_asn_test.json")
self.add_tests_ascii("x448_pem_test.json")
self.add_tests_ascii("x448_jwk_test.json")
def shortDescription(self):
return self.desc
def test_verify(self, tv):
if tv.encoding == "XdhComp":
try:
public_key = import_x448_public_key(tv.public)
except ValueError as e:
assert tv.valid
assert tv.warning
if len(tv.public) == 56:
assert "LowOrderPublic" in tv.flags
assert "Invalid Curve448" in str(e)
else:
assert "Incorrect Curve448" in str(e)
return
private_key = import_x448_private_key(tv.private)
elif tv.encoding in ("XdhAsnComp", "XdhPemComp"):
try:
public_key = ECC.import_key(tv.public)
private_key = ECC.import_key(tv.private)
except ECC.UnsupportedEccFeature as e:
assert not tv.valid
assert "Unsupported ECC" in str(e)
return
except ValueError as e:
assert tv.valid
assert tv.warning
assert "LowOrderPublic" in tv.flags or "NonCanonicalPublic" in tv.flags
return
elif tv.encoding == "XdhJwkComp":
if 'y' in tv.public:
return
if 'x' not in tv.public:
return
if 'x' not in tv.private:
return
if tv.public.get('kty') != 'OKP':
return
if tv.public.get('crv') != 'X448':
return
if tv.private.get('crv') != 'X448':
return
def base64url_decode(input_str):
input_str = input_str.replace('-', '+').replace('_', '/')
padding = 4 - (len(input_str) % 4)
if padding != 4:
input_str += '=' * padding
decoded_bytes = base64.b64decode(input_str)
return decoded_bytes
jwk_public = base64url_decode(tv.public['x'])
jwk_private = base64url_decode(tv.private['d'])
try:
public_key = import_x448_public_key(jwk_public)
private_key = import_x448_private_key(jwk_private)
except ValueError as e:
if tv.valid:
assert tv.warning
if len(tv.public['x']) == 75:
assert "LowOrderPublic" in tv.flags or \
"NonCanonicalPublic" in tv.flags
assert "Invalid Curve448" in str(e)
else:
assert "Incorrect Curve448" in str(e)
return
else:
assert "Incorrect length" in str(e)
return
except ValueError:
assert tv.valid
else:
raise ValueError("Unknown encoding", tv.encoding)
try:
z = key_agreement(static_pub=public_key,
static_priv=private_key,
kdf=lambda x: x)
except ValueError:
assert not tv.valid
except TypeError as e:
assert not tv.valid
assert "incompatible curve" in str(e)
else:
self.assertEqual(z, tv.shared)
assert tv.valid
def runTest(self):
for tv in self.tv:
self.desc = "Wycheproof XECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
self.test_verify(tv)
def get_tests(config={}):
tests = []
tests += list_test_cases(FIPS_ECDH_Tests_KAT)
tests += [TestVectorsECDHWycheproof()]
tests += list_test_cases(ECDH_Tests)
tests += list_test_cases(X25519_Tests)
tests += list_test_cases(X448_Tests)
tests += [TestVectorsX25519Wycheproof()]
tests += [TestVectorsX448Wycheproof()]
slow_tests = config.get('slow_tests')
if slow_tests:
pass
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,62 @@
#
# Test script for Crypto.Util.RFC1751.
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew Kuchling and others
#
# ===================================================================
# 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.
# ===================================================================
__revision__ = "$Id$"
import binascii
import unittest
from Crypto.Util import RFC1751
from Crypto.Util.py3compat import *
test_data = [('EB33F77EE73D4053', 'TIDE ITCH SLOW REIN RULE MOT'),
('CCAC2AED591056BE4F90FD441C534766',
'RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE'),
('EFF81F9BFBC65350920CDD7416DE8009',
'TROD MUTE TAIL WARM CHAR KONG HAAG CITY BORE O TEAL AWL')
]
class RFC1751Test_k2e (unittest.TestCase):
def runTest (self):
"Check converting keys to English"
for key, words in test_data:
key=binascii.a2b_hex(b(key))
self.assertEqual(RFC1751.key_to_english(key), words)
class RFC1751Test_e2k (unittest.TestCase):
def runTest (self):
"Check converting English strings to keys"
for key, words in test_data:
key=binascii.a2b_hex(b(key))
self.assertEqual(RFC1751.english_to_key(words), key)
# class RFC1751Test
def get_tests(config={}):
return [RFC1751Test_k2e(), RFC1751Test_e2k()]
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
#
# SelfTest/PublicKey/__init__.py: Self-test for public key crypto
#
# 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 public-key crypto"""
import unittest
from Crypto.SelfTest.PublicKey import (test_DSA, test_RSA,
test_ECC_NIST,
test_ECC_Ed25519,
test_ECC_Curve25519,
test_ECC_Ed448,
test_ECC_Curve448,
test_import_DSA, test_import_RSA,
test_import_ECC, test_ElGamal,
test_import_Curve25519,
test_import_Curve448)
def get_tests(config={}):
tests = []
tests += test_DSA.get_tests(config=config)
tests += test_RSA.get_tests(config=config)
tests += test_ECC_NIST.get_tests(config=config)
tests += test_ECC_Ed25519.get_tests(config=config)
tests += test_ECC_Curve25519.get_tests(config=config)
tests += test_ECC_Ed448.get_tests(config=config)
tests += test_ECC_Curve448.get_tests(config=config)
tests += test_import_DSA.get_tests(config=config)
tests += test_import_RSA.get_tests(config=config)
tests += test_import_ECC.get_tests(config=config)
tests += test_import_Curve25519.get_tests(config=config)
tests += test_import_Curve448.get_tests(config=config)
tests += test_ElGamal.get_tests(config=config)
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,247 @@
# -*- coding: utf-8 -*-
#
# SelfTest/PublicKey/test_DSA.py: Self-test for the DSA primitive
#
# 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.PublicKey.DSA"""
import os
from Crypto.Util.py3compat import *
import unittest
from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
def _sws(s):
"""Remove whitespace from a text or byte string"""
if isinstance(s,str):
return "".join(s.split())
else:
return b("").join(s.split())
class DSATest(unittest.TestCase):
# Test vector from "Appendix 5. Example of the DSA" of
# "Digital Signature Standard (DSS)",
# U.S. Department of Commerce/National Institute of Standards and Technology
# FIPS 186-2 (+Change Notice), 2000 January 27.
# http://csrc.nist.gov/publications/fips/fips186-2/fips186-2-change1.pdf
y = _sws("""19131871 d75b1612 a819f29d 78d1b0d7 346f7aa7 7bb62a85
9bfd6c56 75da9d21 2d3a36ef 1672ef66 0b8c7c25 5cc0ec74
858fba33 f44c0669 9630a76b 030ee333""")
g = _sws("""626d0278 39ea0a13 413163a5 5b4cb500 299d5522 956cefcb
3bff10f3 99ce2c2e 71cb9de5 fa24babf 58e5b795 21925c9c
c42e9f6f 464b088c c572af53 e6d78802""")
p = _sws("""8df2a494 492276aa 3d25759b b06869cb eac0d83a fb8d0cf7
cbb8324f 0d7882e5 d0762fc5 b7210eaf c2e9adac 32ab7aac
49693dfb f83724c2 ec0736ee 31c80291""")
q = _sws("""c773218c 737ec8ee 993b4f2d ed30f48e dace915f""")
x = _sws("""2070b322 3dba372f de1c0ffc 7b2e3b49 8b260614""")
k = _sws("""358dad57 1462710f 50e254cf 1a376b2b deaadfbf""")
k_inverse = _sws("""0d516729 8202e49b 4116ac10 4fc3f415 ae52f917""")
m = b2a_hex(b("abc"))
m_hash = _sws("""a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d""")
r = _sws("""8bac1ab6 6410435c b7181f95 b16ab97c 92b341c0""")
s = _sws("""41e2345f 1f56df24 58f426d1 55b4ba2d b6dcd8c8""")
def setUp(self):
global DSA, Random, bytes_to_long, size
from Crypto.PublicKey import DSA
from Crypto import Random
from Crypto.Util.number import bytes_to_long, inverse, size
self.dsa = DSA
def test_generate_1arg(self):
"""DSA (default implementation) generated key (1 argument)"""
dsaObj = self.dsa.generate(1024)
self._check_private_key(dsaObj)
pub = dsaObj.public_key()
self._check_public_key(pub)
def test_generate_2arg(self):
"""DSA (default implementation) generated key (2 arguments)"""
dsaObj = self.dsa.generate(1024, Random.new().read)
self._check_private_key(dsaObj)
pub = dsaObj.public_key()
self._check_public_key(pub)
def test_construct_4tuple(self):
"""DSA (default implementation) constructed key (4-tuple)"""
(y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)]
dsaObj = self.dsa.construct((y, g, p, q))
self._test_verification(dsaObj)
def test_construct_5tuple(self):
"""DSA (default implementation) constructed key (5-tuple)"""
(y, g, p, q, x) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q, self.x)]
dsaObj = self.dsa.construct((y, g, p, q, x))
self._test_signing(dsaObj)
self._test_verification(dsaObj)
def test_construct_bad_key4(self):
(y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)]
tup = (y, g, p+1, q)
self.assertRaises(ValueError, self.dsa.construct, tup)
tup = (y, g, p, q+1)
self.assertRaises(ValueError, self.dsa.construct, tup)
tup = (y, 1, p, q)
self.assertRaises(ValueError, self.dsa.construct, tup)
def test_construct_bad_key5(self):
(y, g, p, q, x) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q, self.x)]
tup = (y, g, p, q, x+1)
self.assertRaises(ValueError, self.dsa.construct, tup)
tup = (y, g, p, q, q+10)
self.assertRaises(ValueError, self.dsa.construct, tup)
def _check_private_key(self, dsaObj):
# Check capabilities
self.assertEqual(1, dsaObj.has_private())
self.assertEqual(1, dsaObj.can_sign())
self.assertEqual(0, dsaObj.can_encrypt())
# Sanity check key data
self.assertEqual(1, dsaObj.p > dsaObj.q) # p > q
self.assertEqual(160, size(dsaObj.q)) # size(q) == 160 bits
self.assertEqual(0, (dsaObj.p - 1) % dsaObj.q) # q is a divisor of p-1
self.assertEqual(dsaObj.y, pow(dsaObj.g, dsaObj.x, dsaObj.p)) # y == g**x mod p
self.assertEqual(1, 0 < dsaObj.x < dsaObj.q) # 0 < x < q
def _check_public_key(self, dsaObj):
k = bytes_to_long(a2b_hex(self.k))
m_hash = bytes_to_long(a2b_hex(self.m_hash))
# Check capabilities
self.assertEqual(0, dsaObj.has_private())
self.assertEqual(1, dsaObj.can_sign())
self.assertEqual(0, dsaObj.can_encrypt())
# Check that private parameters are all missing
self.assertEqual(0, hasattr(dsaObj, 'x'))
# Sanity check key data
self.assertEqual(1, dsaObj.p > dsaObj.q) # p > q
self.assertEqual(160, size(dsaObj.q)) # size(q) == 160 bits
self.assertEqual(0, (dsaObj.p - 1) % dsaObj.q) # q is a divisor of p-1
# Public-only key objects should raise an error when .sign() is called
self.assertRaises(TypeError, dsaObj._sign, m_hash, k)
# Check __eq__ and __ne__
self.assertEqual(dsaObj.public_key() == dsaObj.public_key(),True) # assert_
self.assertEqual(dsaObj.public_key() != dsaObj.public_key(),False) # assertFalse
self.assertEqual(dsaObj.public_key(), dsaObj.publickey())
def _test_signing(self, dsaObj):
k = bytes_to_long(a2b_hex(self.k))
m_hash = bytes_to_long(a2b_hex(self.m_hash))
r = bytes_to_long(a2b_hex(self.r))
s = bytes_to_long(a2b_hex(self.s))
(r_out, s_out) = dsaObj._sign(m_hash, k)
self.assertEqual((r, s), (r_out, s_out))
def _test_verification(self, dsaObj):
m_hash = bytes_to_long(a2b_hex(self.m_hash))
r = bytes_to_long(a2b_hex(self.r))
s = bytes_to_long(a2b_hex(self.s))
self.assertTrue(dsaObj._verify(m_hash, (r, s)))
self.assertFalse(dsaObj._verify(m_hash + 1, (r, s)))
def test_repr(self):
(y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)]
dsaObj = self.dsa.construct((y, g, p, q))
repr(dsaObj)
class DSADomainTest(unittest.TestCase):
def test_domain1(self):
"""Verify we can generate new keys in a given domain"""
dsa_key_1 = DSA.generate(1024)
domain_params = dsa_key_1.domain()
dsa_key_2 = DSA.generate(1024, domain=domain_params)
self.assertEqual(dsa_key_1.p, dsa_key_2.p)
self.assertEqual(dsa_key_1.q, dsa_key_2.q)
self.assertEqual(dsa_key_1.g, dsa_key_2.g)
self.assertEqual(dsa_key_1.domain(), dsa_key_2.domain())
def _get_weak_domain(self):
from Crypto.Math.Numbers import Integer
from Crypto.Math import Primality
p = Integer(4)
while p.size_in_bits() != 1024 or Primality.test_probable_prime(p) != Primality.PROBABLY_PRIME:
q1 = Integer.random(exact_bits=80)
q2 = Integer.random(exact_bits=80)
q = q1 * q2
z = Integer.random(exact_bits=1024-160)
p = z * q + 1
h = Integer(2)
g = 1
while g == 1:
g = pow(h, z, p)
h += 1
return (p, q, g)
def test_generate_error_weak_domain(self):
"""Verify that domain parameters with composite q are rejected"""
domain_params = self._get_weak_domain()
self.assertRaises(ValueError, DSA.generate, 1024, domain=domain_params)
def test_construct_error_weak_domain(self):
"""Verify that domain parameters with composite q are rejected"""
from Crypto.Math.Numbers import Integer
p, q, g = self._get_weak_domain()
y = pow(g, 89, p)
self.assertRaises(ValueError, DSA.construct, (y, g, p, q))
def get_tests(config={}):
tests = []
tests += list_test_cases(DSATest)
tests += list_test_cases(DSADomainTest)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
# vim:set ts=4 sw=4 sts=4 expandtab:
@@ -0,0 +1,283 @@
# ===================================================================
#
# Copyright (c) 2024, 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.Math.Numbers import Integer
from Crypto.Hash import SHAKE128
from Crypto.PublicKey import ECC
from Crypto.PublicKey.ECC import EccKey, EccXPoint, _curves
# Test vectors for scalar multiplication using point with X=9 as base
# generated with nickovs' Python-only code https://gist.github.com/nickovs/cc3c22d15f239a2640c185035c06f8a3
# The order is 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
# Each tuple is (exponent, X-coordinate)
scalar_base9_test = [
(1, 9),
(2, 0x20d342d51873f1b7d9750c687d1571148f3f5ced1e350b5c5cae469cdd684efb),
(3, 0x1c12bc1a6d57abe645534d91c21bba64f8824e67621c0859c00a03affb713c12),
(4, 0x79ce98b7e0689d7de7d1d074a15b315ffe1805dfcd5d2a230fee85e4550013ef),
(6, 0x26954ccdc99ebf34f8f1dde5e6bb080685fec73640494c28f9fe0bfa8c794531),
(9, 0x192b929197d07748db44600da41bab7499b1c2e6e2f87c6f0e337980668164ba),
(129, 0x7332096a738900085e721103fce2cbf13aee50fef0788ea0d669008eb09ceab7),
(255, 0x1534582fc2b1cea45e8cb776547e209da4fd54a9e473b50c5b8c6b0ae023a9b3),
(256, 0x4300017536976a742ec8747f7505cd6bc80e610d669acab1a1eed36f680d98e8),
(257, 0x6c410611cb484c9016adfb884d37a0e682e075daca1d46f45bb7a4afed10b125),
(0x10101, 0xa679e9d7e043bf76c03362576e2c88abe9093c5d4f6b4a202c64a8397467cf),
(0xAA55CC, 0x2cc02f84c067e3586f4278326689be163e606d69ccae505bb09488e11f295887),
(0x1B29A0E579E0A000567, 0x50c38a72d7bfd7864c8b9083fa123e8d359068e6b491a019a885036e073f6604),
(0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + 1, 9),
]
class TestEccPoint_Curve25519(unittest.TestCase):
v1 = 0x09fa78b39b00a72930bcd8039be789a0997830bb99f79aeeb93493715390b4e8
v2 = 0x15210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493
def test_init(self):
EccXPoint(9, "curve25519")
EccXPoint(2**255 - 19 + 5, "curve25519")
def test_curve_attribute(self):
point = EccXPoint(9, "curve25519")
self.assertEqual(point.curve, "Curve25519")
def test_init_fail(self):
self.assertRaises(ValueError, EccXPoint, 3*(2**255 - 19), "curve25519")
self.assertRaises(ValueError, EccXPoint, 9, "curve25518")
def test_equal_set(self):
point1 = EccXPoint(self.v1, "curve25519")
point2 = EccXPoint(self.v2, "curve25519")
self.assertEqual(point1, point1)
self.assertNotEqual(point1, point2)
point2.set(point1)
self.assertEqual(point1.x, point2.x)
def test_copy(self):
point1 = EccXPoint(self.v1, "curve25519")
point2 = point1.copy()
self.assertEqual(point1.x, point2.x)
def test_pai(self):
point1 = EccXPoint(self.v1, "curve25519")
pai = point1.point_at_infinity()
self.assertTrue(pai.point_at_infinity())
point2 = EccXPoint(None, "curve25519")
self.assertTrue(point2.point_at_infinity())
def test_scalar_multiply(self):
base = EccXPoint(9, "curve25519")
pointH = 0 * base
self.assertTrue(pointH.point_at_infinity())
pointH = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed * base
self.assertTrue(pointH.point_at_infinity())
pointH = base * 1
self.assertEqual(pointH.x, 9)
for d, result in scalar_base9_test:
pointH = d * base
self.assertEqual(pointH.x, result)
def test_sizes(self):
point = EccXPoint(9, "curve25519")
self.assertEqual(point.size_in_bits(), 255)
self.assertEqual(point.size_in_bytes(), 32)
class TestEccKey_Curve25519(unittest.TestCase):
def test_private_key(self):
# RFC7748 Section 6.1 - Alice
alice_priv = unhexlify("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a")
alice_pub = unhexlify("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a")
alice_pub_x = Integer.from_bytes(alice_pub, byteorder='little')
key = EccKey(curve="Curve25519", seed=alice_priv)
self.assertEqual(key.seed, alice_priv)
self.assertTrue(key.has_private())
self.assertEqual(key.pointQ.x, alice_pub_x)
# RFC7748 Section 6.1 - Bob
bob_priv = unhexlify("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb")
bob_pub = unhexlify("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f")
bob_pub_x = Integer.from_bytes(bob_pub, byteorder='little')
key = EccKey(curve="Curve25519", seed=bob_priv)
self.assertEqual(key.seed, bob_priv)
self.assertTrue(key.has_private())
self.assertEqual(key.pointQ.x, bob_pub_x)
# Other names
key = EccKey(curve="curve25519", seed=alice_priv)
# Must not accept d parameter
self.assertRaises(ValueError, EccKey, curve="curve25519", d=1)
def test_public_key(self):
point = EccXPoint(_curves['curve25519'].Gx,
curve='curve25519')
key = EccKey(curve="curve25519", point=point)
self.assertFalse(key.has_private())
self.assertEqual(key.pointQ, point)
def test_public_key_derived(self):
priv_key = EccKey(curve="curve25519", seed=b'H'*32)
pub_key = priv_key.public_key()
self.assertFalse(pub_key.has_private())
self.assertEqual(priv_key.pointQ, pub_key.pointQ)
def test_invalid_seed(self):
self.assertRaises(ValueError, lambda: EccKey(curve="curve25519", seed=b'H' * 31))
def test_equality(self):
private_key = ECC.construct(seed=b'H'*32, curve="Curve25519")
private_key2 = ECC.construct(seed=b'H'*32, curve="curve25519")
private_key3 = ECC.construct(seed=b'C'*32, curve="Curve25519")
public_key = private_key.public_key()
public_key2 = private_key2.public_key()
public_key3 = private_key3.public_key()
self.assertEqual(private_key, private_key2)
self.assertNotEqual(private_key, private_key3)
self.assertEqual(public_key, public_key2)
self.assertNotEqual(public_key, public_key3)
self.assertNotEqual(public_key, private_key)
def test_name_consistency(self):
key = ECC.generate(curve='curve25519')
self.assertIn("curve='Curve25519'", repr(key))
self.assertEqual(key.curve, 'Curve25519')
self.assertEqual(key.public_key().curve, 'Curve25519')
class TestEccModule_Curve25519(unittest.TestCase):
def test_generate(self):
key = ECC.generate(curve="Curve25519")
self.assertTrue(key.has_private())
point = EccXPoint(_curves['Curve25519'].Gx, curve="Curve25519") * key.d
self.assertEqual(key.pointQ, point)
# Always random
key2 = ECC.generate(curve="Curve25519")
self.assertNotEqual(key, key2)
# Other names
ECC.generate(curve="curve25519")
# Random source
key1 = ECC.generate(curve="Curve25519", randfunc=SHAKE128.new().read)
key2 = ECC.generate(curve="Curve25519", randfunc=SHAKE128.new().read)
self.assertEqual(key1, key2)
def test_construct(self):
seed = unhexlify("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a")
point_hex = unhexlify("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a")
Px = Integer.from_bytes(point_hex, byteorder='little')
point = EccXPoint(Px, curve="Curve25519")
# Private key only
key = ECC.construct(curve="Curve25519", seed=seed)
self.assertEqual(key.pointQ, point)
self.assertTrue(key.has_private())
# Public key only
key = ECC.construct(curve="Curve25519", point_x=Px)
self.assertEqual(key.pointQ, point)
self.assertFalse(key.has_private())
# Private and public key
key = ECC.construct(curve="Curve25519", seed=seed, point_x=Px)
self.assertEqual(key.pointQ, point)
self.assertTrue(key.has_private())
# Other names
key = ECC.construct(curve="curve25519", seed=seed)
def test_negative_construct(self):
coordG = dict(point_x=_curves['curve25519'].Gx)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519", d=2, **coordG)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519", seed=b'H'*31)
# Verify you cannot construct weak keys (small-order points)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=0)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=1)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=325606250916557431795983626356110631294008115727848805560023387167927233504)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=39382357235489614581723060781553021112529911719440698176882885853963445705823)
p = 2**255 - 19
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=p-1)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=p)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=p+1)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=p+325606250916557431795983626356110631294008115727848805560023387167927233504)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=p+39382357235489614581723060781553021112529911719440698176882885853963445705823)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=p*2-1)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=p*2)
self.assertRaises(ValueError, ECC.construct, curve="Curve25519",
point_x=p*2+1)
def get_tests(config={}):
tests = []
tests += list_test_cases(TestEccPoint_Curve25519)
tests += list_test_cases(TestEccKey_Curve25519)
tests += list_test_cases(TestEccModule_Curve25519)
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,246 @@
# This file is licensed under the BSD 2-Clause License.
# See https://opensource.org/licenses/BSD-2-Clause for details.
import unittest
from binascii import unhexlify
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Math.Numbers import Integer
from Crypto.Hash import SHAKE128
from Crypto.PublicKey import ECC
from Crypto.PublicKey.ECC import EccKey, EccXPoint, _curves
CURVE448_P = 2**448 - 2**224 - 1
CURVE448_ORDER = 2**446 - 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d
# Test vectors for scalar multiplication using point with X=5 as base
# Each tuple is (exponent, X-coordinate)
scalar_base5_test = [
(1, 5),
(2, 0x6391322257cae3d49aef4665d8bd5cccac9abefb511e83d75f3c766616266fc1bf3747f1da00ed7125e8f0255a1208087d32a4bc1c743cb6),
(3, 0x1fbe4b3584cab86170c14b9325840b8a2429b61fb93c42492c002a2807a4e7ea63138ea59bf95652ce9a7d13d0321c7511e3314d0553f34c),
(4, 0x93b44a7b78726ba8d0b048bd7144074f8bdad24ef9d0a6c8264f6c00b135ffcea11545e80d18364acc8ebfbcc45358e0da5fd5e5146e2b1),
(6, 0x693d165f453bd62871e5e53845f33e9e5b18b24d79c1f9102608aa7ba6f18ac24864012171d64c90b698f5ce5631cd02cee4e4336b1ad88c),
(9, 0xb970d576e7d9aa427dbf7cb9b7dd65170721d04ee060c9ea8d499dc361d4cfde1ceb19068eae853bac8f5d92827bdbf3d94c22de2fb42dae),
(129, 0x9fbdb50a1450438fe656aa32aa1bb2548d077d5c3a5d327689093a2996a4f94eacd1fb4f90315edb2afe41908a759f0d6db83fa791df80db),
(255, 0x31bc3e9385dfd12e1238927061eb0c911466da394e459bf058ba3b08260a258a3c392b0f85ddbd23828657137b88577a85b83774139fab9e),
(256, 0x735c7f30e6872e5e4215c0147c8a112d697f668c9bd0f92f5f1e4e6badc128a0b654e697cd4bae2144d54e726b54c1fa63a09b00dd3c17f),
(257, 0x95c1b0ce01286dc047aeb5922a5e62b3effb5b9296273a5004eb456f592728dd494a6fb5996a2ea7011ae6423874a48c2927bfa62d8ce8b0),
(0x10101, 0x113bb172c9dc52ab45bd665dd9751ed44e33b8596f943c6cb2f8dd329160ece802960b3eb0d2c21ef3a3ac12c20fccbc2a271fc2f061c1b2),
(0xAA55CC, 0xcf42585d2e0b1e45c0bfd601c91af4b137d7faf139fc761178c7ded432417c307ee1759af2deec6a14dbaf6b868eb13a6039fbdde4b61898),
(0x1B29A0E579E0A000567, 0x7bd9ec9775a664f4d860d82d6be60895113a7c36f92db25583dbba5dc17f09c136ec27e14857bfd6a705311327030aa657dd036325fad330),
(CURVE448_ORDER + 1, 5),
]
class TestEccPoint_Curve448(unittest.TestCase):
v1 = 0x09fa78b39b00a72930bcd8039be789a0997830bb99f79aeeb93493715390b4e8
v2 = 0x15210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493
def test_init(self):
EccXPoint(5, "curve448")
EccXPoint(CURVE448_P - 5, "curve448")
def test_curve_attribute(self):
point = EccXPoint(5, "curve448")
self.assertEqual(point.curve, "Curve448")
def test_init_fail(self):
self.assertRaises(ValueError, EccXPoint, 3*CURVE448_P, "curve448")
self.assertRaises(ValueError, EccXPoint, 3, "curve449")
def test_equal_set(self):
point1 = EccXPoint(self.v1, "curve448")
point2 = EccXPoint(self.v2, "curve448")
self.assertEqual(point1, point1)
self.assertNotEqual(point1, point2)
point2.set(point1)
self.assertEqual(point1.x, point2.x)
def test_copy(self):
point1 = EccXPoint(self.v1, "curve448")
point2 = point1.copy()
self.assertEqual(point1.x, point2.x)
def test_pai(self):
point1 = EccXPoint(self.v1, "curve448")
pai = point1.point_at_infinity()
self.assertTrue(pai.point_at_infinity())
point2 = EccXPoint(None, "curve448")
self.assertTrue(point2.point_at_infinity())
def test_scalar_multiply(self):
base = EccXPoint(5, "curve448")
pointH = 0 * base
self.assertTrue(pointH.point_at_infinity())
pointH = CURVE448_ORDER * base
self.assertTrue(pointH.point_at_infinity())
pointH = base * 1
self.assertEqual(pointH.x, 5)
for d, result in scalar_base5_test:
pointH = d * base
self.assertEqual(pointH.x, result)
def test_sizes(self):
point = EccXPoint(5, "curve448")
self.assertEqual(point.size_in_bits(), 448)
self.assertEqual(point.size_in_bytes(), 56)
class TestEccKey_Curve448(unittest.TestCase):
def test_private_key(self):
# RFC7748 Section 6.2 - Alice
alice_priv = unhexlify("9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b")
alice_pub = unhexlify("9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0")
alice_pub_x = Integer.from_bytes(alice_pub, byteorder='little')
key = EccKey(curve="Curve448", seed=alice_priv)
self.assertEqual(key.seed, alice_priv)
self.assertTrue(key.has_private())
self.assertEqual(key.pointQ.x, alice_pub_x)
# RFC7748 Section 6.2 - Bob
bob_priv = unhexlify("1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d")
bob_pub = unhexlify("3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609")
bob_pub_x = Integer.from_bytes(bob_pub, byteorder='little')
key = EccKey(curve="Curve448", seed=bob_priv)
self.assertEqual(key.seed, bob_priv)
self.assertTrue(key.has_private())
self.assertEqual(key.pointQ.x, bob_pub_x)
# Other names
key = EccKey(curve="curve448", seed=alice_priv)
# Must not accept d parameter
self.assertRaises(ValueError, EccKey, curve="curve448", d=1)
def test_public_key(self):
point = EccXPoint(_curves['curve448'].Gx,
curve='curve448')
key = EccKey(curve="curve448", point=point)
self.assertFalse(key.has_private())
self.assertEqual(key.pointQ, point)
def test_public_key_derived(self):
priv_key = EccKey(curve="curve448", seed=b'H'*56)
pub_key = priv_key.public_key()
self.assertFalse(pub_key.has_private())
self.assertEqual(priv_key.pointQ, pub_key.pointQ)
def test_invalid_seed(self):
self.assertRaises(ValueError, lambda: EccKey(curve="curve448",
seed=b'H' * 55))
def test_equality(self):
private_key = ECC.construct(seed=b'H'*56, curve="Curve448")
private_key2 = ECC.construct(seed=b'H'*56, curve="curve448")
private_key3 = ECC.construct(seed=b'C'*56, curve="Curve448")
public_key = private_key.public_key()
public_key2 = private_key2.public_key()
public_key3 = private_key3.public_key()
self.assertEqual(private_key, private_key2)
self.assertNotEqual(private_key, private_key3)
self.assertEqual(public_key, public_key2)
self.assertNotEqual(public_key, public_key3)
self.assertNotEqual(public_key, private_key)
def test_name_consistency(self):
key = ECC.generate(curve='curve448')
self.assertIn("curve='Curve448'", repr(key))
self.assertEqual(key.curve, 'Curve448')
self.assertEqual(key.public_key().curve, 'Curve448')
class TestEccModule_Curve448(unittest.TestCase):
def test_generate(self):
key = ECC.generate(curve="Curve448")
self.assertTrue(key.has_private())
point = EccXPoint(_curves['Curve448'].Gx, curve="Curve448") * key.d
self.assertEqual(key.pointQ, point)
# Always random
key2 = ECC.generate(curve="Curve448")
self.assertNotEqual(key, key2)
# Other names
ECC.generate(curve="curve448")
# Random source
key1 = ECC.generate(curve="Curve448", randfunc=SHAKE128.new().read)
key2 = ECC.generate(curve="Curve448", randfunc=SHAKE128.new().read)
self.assertEqual(key1, key2)
def test_construct(self):
seed = unhexlify("9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b")
point_hex = unhexlify("9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0")
Px = Integer.from_bytes(point_hex, byteorder='little')
point = EccXPoint(Px, curve="Curve448")
# Private key only
key = ECC.construct(curve="Curve448", seed=seed)
self.assertEqual(key.pointQ, point)
self.assertTrue(key.has_private())
# Public key only
key = ECC.construct(curve="Curve448", point_x=Px)
self.assertEqual(key.pointQ, point)
self.assertFalse(key.has_private())
# Private and public key
key = ECC.construct(curve="Curve448", seed=seed, point_x=Px)
self.assertEqual(key.pointQ, point)
self.assertTrue(key.has_private())
# Other names
key = ECC.construct(curve="curve448", seed=seed)
def test_negative_construct(self):
coordG = dict(point_x=_curves['curve448'].Gx)
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
d=2, **coordG)
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
seed=b'H'*55)
# Verify you cannot construct weak keys (small-order points)
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
point_x=0)
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
point_x=1)
p = 2**448 - 2**224 - 1
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
point_x=p-1)
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
point_x=p)
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
point_x=p+1)
def get_tests(config={}):
tests = []
tests += list_test_cases(TestEccPoint_Curve448)
tests += list_test_cases(TestEccKey_Curve448)
tests += list_test_cases(TestEccModule_Curve448)
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,341 @@
# ===================================================================
#
# Copyright (c) 2022, 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
from Crypto.PublicKey import ECC
from Crypto.PublicKey.ECC import EccPoint, _curves, EccKey
from Crypto.Math.Numbers import Integer
from Crypto.Hash import SHAKE128
class TestEccPoint_Ed25519(unittest.TestCase):
Gxy = {"x": 15112221349535400772501151409588531511454012693041857206046113283949847762202,
"y": 46316835694926478169428394003475163141307993866256225615783033603165251855960}
G2xy = {"x": 24727413235106541002554574571675588834622768167397638456726423682521233608206,
"y": 15549675580280190176352668710449542251549572066445060580507079593062643049417}
G3xy = {"x": 46896733464454938657123544595386787789046198280132665686241321779790909858396,
"y": 8324843778533443976490377120369201138301417226297555316741202210403726505172}
pointG = EccPoint(Gxy['x'], Gxy['y'], curve="ed25519")
pointG2 = EccPoint(G2xy['x'], G2xy['y'], curve="ed25519")
pointG3 = EccPoint(G3xy['x'], G3xy['y'], curve="ed25519")
def test_curve_attribute(self):
self.assertEqual(self.pointG.curve, "Ed25519")
def test_init_xy(self):
EccPoint(self.Gxy['x'], self.Gxy['y'], curve="Ed25519")
# Neutral point
pai = EccPoint(0, 1, curve="Ed25519")
self.assertEqual(pai.x, 0)
self.assertEqual(pai.y, 1)
self.assertEqual(pai.xy, (0, 1))
# G
bp = self.pointG.copy()
self.assertEqual(bp.x, 15112221349535400772501151409588531511454012693041857206046113283949847762202)
self.assertEqual(bp.y, 46316835694926478169428394003475163141307993866256225615783033603165251855960)
self.assertEqual(bp.xy, (bp.x, bp.y))
# 2G
bp2 = self.pointG2.copy()
self.assertEqual(bp2.x, 24727413235106541002554574571675588834622768167397638456726423682521233608206)
self.assertEqual(bp2.y, 15549675580280190176352668710449542251549572066445060580507079593062643049417)
self.assertEqual(bp2.xy, (bp2.x, bp2.y))
# 5G
EccPoint(x=33467004535436536005251147249499675200073690106659565782908757308821616914995,
y=43097193783671926753355113395909008640284023746042808659097434958891230611693,
curve="Ed25519")
# Catch if point is not on the curve
self.assertRaises(ValueError, EccPoint, 34, 35, curve="Ed25519")
def test_set(self):
pointW = EccPoint(0, 1, curve="Ed25519")
pointW.set(self.pointG)
self.assertEqual(pointW.x, self.pointG.x)
self.assertEqual(pointW.y, self.pointG.y)
def test_copy(self):
pointW = self.pointG.copy()
self.assertEqual(pointW.x, self.pointG.x)
self.assertEqual(pointW.y, self.pointG.y)
def test_equal(self):
pointH = self.pointG.copy()
pointI = self.pointG2.copy()
self.assertEqual(self.pointG, pointH)
self.assertNotEqual(self.pointG, pointI)
def test_pai(self):
pai = EccPoint(0, 1, curve="Ed25519")
self.assertTrue(pai.is_point_at_infinity())
self.assertEqual(pai, pai.point_at_infinity())
def test_negate(self):
negG = -self.pointG
G100 = self.pointG * 100
sum_zero = G100 + negG * 100
self.assertTrue(sum_zero.is_point_at_infinity())
sum_99 = G100 + negG
expected = self.pointG * 99
self.assertEqual(sum_99, expected)
def test_addition(self):
self.assertEqual(self.pointG + self.pointG2, self.pointG3)
self.assertEqual(self.pointG2 + self.pointG, self.pointG3)
self.assertEqual(self.pointG2 + self.pointG.point_at_infinity(), self.pointG2)
self.assertEqual(self.pointG.point_at_infinity() + self.pointG2, self.pointG2)
G5 = self.pointG2 + self.pointG3
self.assertEqual(G5.x, 33467004535436536005251147249499675200073690106659565782908757308821616914995)
self.assertEqual(G5.y, 43097193783671926753355113395909008640284023746042808659097434958891230611693)
def test_inplace_addition(self):
pointH = self.pointG.copy()
pointH += self.pointG
self.assertEqual(pointH, self.pointG2)
pointH += self.pointG
self.assertEqual(pointH, self.pointG3)
pointH += self.pointG.point_at_infinity()
self.assertEqual(pointH, self.pointG3)
def test_doubling(self):
pointH = self.pointG.copy()
pointH.double()
self.assertEqual(pointH.x, self.pointG2.x)
self.assertEqual(pointH.y, self.pointG2.y)
# 2*0
pai = self.pointG.point_at_infinity()
pointR = pai.copy()
pointR.double()
self.assertEqual(pointR, pai)
def test_scalar_multiply(self):
d = 0
pointH = d * self.pointG
self.assertEqual(pointH.x, 0)
self.assertEqual(pointH.y, 1)
d = 1
pointH = d * self.pointG
self.assertEqual(pointH.x, self.pointG.x)
self.assertEqual(pointH.y, self.pointG.y)
d = 2
pointH = d * self.pointG
self.assertEqual(pointH.x, self.pointG2.x)
self.assertEqual(pointH.y, self.pointG2.y)
d = 3
pointH = d * self.pointG
self.assertEqual(pointH.x, self.pointG3.x)
self.assertEqual(pointH.y, self.pointG3.y)
d = 4
pointH = d * self.pointG
self.assertEqual(pointH.x, 14582954232372986451776170844943001818709880559417862259286374126315108956272)
self.assertEqual(pointH.y, 32483318716863467900234833297694612235682047836132991208333042722294373421359)
d = 5
pointH = d * self.pointG
self.assertEqual(pointH.x, 33467004535436536005251147249499675200073690106659565782908757308821616914995)
self.assertEqual(pointH.y, 43097193783671926753355113395909008640284023746042808659097434958891230611693)
d = 10
pointH = d * self.pointG
self.assertEqual(pointH.x, 43500613248243327786121022071801015118933854441360174117148262713429272820047)
self.assertEqual(pointH.y, 45005105423099817237495816771148012388779685712352441364231470781391834741548)
d = 20
pointH = d * self.pointG
self.assertEqual(pointH.x, 46694936775300686710656303283485882876784402425210400817529601134760286812591)
self.assertEqual(pointH.y, 8786390172762935853260670851718824721296437982862763585171334833968259029560)
d = 255
pointH = d * self.pointG
self.assertEqual(pointH.x, 36843863416400016952258312492144504209624961884991522125275155377549541182230)
self.assertEqual(pointH.y, 22327030283879720808995671630924669697661065034121040761798775626517750047180)
d = 256
pointH = d * self.pointG
self.assertEqual(pointH.x, 42740085206947573681423002599456489563927820004573071834350074001818321593686)
self.assertEqual(pointH.y, 6935684722522267618220753829624209639984359598320562595061366101608187623111)
def test_sizes(self):
self.assertEqual(self.pointG.size_in_bits(), 255)
self.assertEqual(self.pointG.size_in_bytes(), 32)
class TestEccKey_Ed25519(unittest.TestCase):
def test_private_key(self):
seed = unhexlify("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
Px = 38815646466658113194383306759739515082307681141926459231621296960732224964046
Py = 11903303657706407974989296177215005343713679411332034699907763981919547054807
key = EccKey(curve="Ed25519", seed=seed)
self.assertEqual(key.seed, seed)
self.assertEqual(key.d, 36144925721603087658594284515452164870581325872720374094707712194495455132720)
self.assertTrue(key.has_private())
self.assertEqual(key.pointQ.x, Px)
self.assertEqual(key.pointQ.y, Py)
point = EccPoint(Px, Py, "ed25519")
key = EccKey(curve="Ed25519", seed=seed, point=point)
self.assertEqual(key.d, 36144925721603087658594284515452164870581325872720374094707712194495455132720)
self.assertTrue(key.has_private())
self.assertEqual(key.pointQ, point)
# Other names
key = EccKey(curve="ed25519", seed=seed)
# Must not accept d parameter
self.assertRaises(ValueError, EccKey, curve="ed25519", d=1)
def test_public_key(self):
point = EccPoint(_curves['ed25519'].Gx, _curves['ed25519'].Gy, curve='ed25519')
key = EccKey(curve="ed25519", point=point)
self.assertFalse(key.has_private())
self.assertEqual(key.pointQ, point)
def test_public_key_derived(self):
priv_key = EccKey(curve="ed25519", seed=b'H'*32)
pub_key = priv_key.public_key()
self.assertFalse(pub_key.has_private())
self.assertEqual(priv_key.pointQ, pub_key.pointQ)
def test_invalid_seed(self):
self.assertRaises(ValueError, lambda: EccKey(curve="ed25519", seed=b'H' * 31))
def test_equality(self):
private_key = ECC.construct(seed=b'H'*32, curve="Ed25519")
private_key2 = ECC.construct(seed=b'H'*32, curve="ed25519")
private_key3 = ECC.construct(seed=b'C'*32, curve="Ed25519")
public_key = private_key.public_key()
public_key2 = private_key2.public_key()
public_key3 = private_key3.public_key()
self.assertEqual(private_key, private_key2)
self.assertNotEqual(private_key, private_key3)
self.assertEqual(public_key, public_key2)
self.assertNotEqual(public_key, public_key3)
self.assertNotEqual(public_key, private_key)
def test_name_consistency(self):
key = ECC.generate(curve='ed25519')
self.assertIn("curve='Ed25519'", repr(key))
self.assertEqual(key.curve, 'Ed25519')
self.assertEqual(key.public_key().curve, 'Ed25519')
class TestEccModule_Ed25519(unittest.TestCase):
def test_generate(self):
key = ECC.generate(curve="Ed25519")
self.assertTrue(key.has_private())
point = EccPoint(_curves['Ed25519'].Gx, _curves['Ed25519'].Gy, curve="Ed25519") * key.d
self.assertEqual(key.pointQ, point)
# Always random
key2 = ECC.generate(curve="Ed25519")
self.assertNotEqual(key, key2)
# Other names
ECC.generate(curve="Ed25519")
# Random source
key1 = ECC.generate(curve="Ed25519", randfunc=SHAKE128.new().read)
key2 = ECC.generate(curve="Ed25519", randfunc=SHAKE128.new().read)
self.assertEqual(key1, key2)
def test_construct(self):
seed = unhexlify("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
Px = 38815646466658113194383306759739515082307681141926459231621296960732224964046
Py = 11903303657706407974989296177215005343713679411332034699907763981919547054807
d = 36144925721603087658594284515452164870581325872720374094707712194495455132720
point = EccPoint(Px, Py, curve="Ed25519")
# Private key only
key = ECC.construct(curve="Ed25519", seed=seed)
self.assertEqual(key.pointQ, point)
self.assertTrue(key.has_private())
# Public key only
key = ECC.construct(curve="Ed25519", point_x=Px, point_y=Py)
self.assertEqual(key.pointQ, point)
self.assertFalse(key.has_private())
# Private and public key
key = ECC.construct(curve="Ed25519", seed=seed, point_x=Px, point_y=Py)
self.assertEqual(key.pointQ, point)
self.assertTrue(key.has_private())
# Other names
key = ECC.construct(curve="ed25519", seed=seed)
def test_negative_construct(self):
coord = dict(point_x=10, point_y=4)
coordG = dict(point_x=_curves['ed25519'].Gx, point_y=_curves['ed25519'].Gy)
self.assertRaises(ValueError, ECC.construct, curve="Ed25519", **coord)
self.assertRaises(ValueError, ECC.construct, curve="Ed25519", d=2, **coordG)
self.assertRaises(ValueError, ECC.construct, curve="Ed25519", seed=b'H'*31)
def get_tests(config={}):
tests = []
tests += list_test_cases(TestEccPoint_Ed25519)
tests += list_test_cases(TestEccKey_Ed25519)
tests += list_test_cases(TestEccModule_Ed25519)
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,336 @@
# ===================================================================
#
# Copyright (c) 2022, 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
from Crypto.PublicKey import ECC
from Crypto.PublicKey.ECC import EccPoint, _curves, EccKey
from Crypto.Math.Numbers import Integer
from Crypto.Hash import SHAKE128
class TestEccPoint_Ed448(unittest.TestCase):
Gxy = {"x": 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e,
"y": 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14}
G2xy = {"x": 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa955555555555555555555555555555555555555555555555555555555,
"y": 0xae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed}
G3xy = {"x": 0x865886b9108af6455bd64316cb6943332241b8b8cda82c7e2ba077a4a3fcfe8daa9cbf7f6271fd6e862b769465da8575728173286ff2f8f,
"y": 0xe005a8dbd5125cf706cbda7ad43aa6449a4a8d952356c3b9fce43c82ec4e1d58bb3a331bdb6767f0bffa9a68fed02dafb822ac13588ed6fc}
pointG = EccPoint(Gxy['x'], Gxy['y'], curve="ed448")
pointG2 = EccPoint(G2xy['x'], G2xy['y'], curve="ed448")
pointG3 = EccPoint(G3xy['x'], G3xy['y'], curve="ed448")
def test_curve_attribute(self):
self.assertEqual(self.pointG.curve, "Ed448")
def test_init_xy(self):
EccPoint(self.Gxy['x'], self.Gxy['y'], curve="Ed448")
# Neutral point
pai = EccPoint(0, 1, curve="Ed448")
self.assertEqual(pai.x, 0)
self.assertEqual(pai.y, 1)
self.assertEqual(pai.xy, (0, 1))
# G
bp = self.pointG.copy()
self.assertEqual(bp.x, 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e)
self.assertEqual(bp.y, 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14)
self.assertEqual(bp.xy, (bp.x, bp.y))
# 2G
bp2 = self.pointG2.copy()
self.assertEqual(bp2.x, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa955555555555555555555555555555555555555555555555555555555)
self.assertEqual(bp2.y, 0xae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed)
self.assertEqual(bp2.xy, (bp2.x, bp2.y))
# 5G
EccPoint(x=0x7a9f9335a48dcb0e2ba7601eedb50def80cbcf728562ada756d761e8958812808bc0d57a920c3c96f07b2d8cefc6f950d0a99d1092030034,
y=0xadfd751a2517edd3b9109ce4fd580ade260ca1823ab18fced86551f7b698017127d7a4ee59d2b33c58405512881f225443b4731472f435eb,
curve="Ed448")
# Catch if point is not on the curve
self.assertRaises(ValueError, EccPoint, 34, 35, curve="Ed448")
def test_set(self):
pointW = EccPoint(0, 1, curve="Ed448")
pointW.set(self.pointG)
self.assertEqual(pointW.x, self.pointG.x)
self.assertEqual(pointW.y, self.pointG.y)
def test_copy(self):
pointW = self.pointG.copy()
self.assertEqual(pointW.x, self.pointG.x)
self.assertEqual(pointW.y, self.pointG.y)
def test_equal(self):
pointH = self.pointG.copy()
pointI = self.pointG2.copy()
self.assertEqual(self.pointG, pointH)
self.assertNotEqual(self.pointG, pointI)
def test_pai(self):
pai = EccPoint(0, 1, curve="Ed448")
self.assertTrue(pai.is_point_at_infinity())
self.assertEqual(pai, pai.point_at_infinity())
def test_negate(self):
negG = -self.pointG
sum = self.pointG + negG
self.assertTrue(sum.is_point_at_infinity())
def test_addition(self):
self.assertEqual(self.pointG + self.pointG2, self.pointG3)
self.assertEqual(self.pointG2 + self.pointG, self.pointG3)
self.assertEqual(self.pointG2 + self.pointG.point_at_infinity(), self.pointG2)
self.assertEqual(self.pointG.point_at_infinity() + self.pointG2, self.pointG2)
G5 = self.pointG2 + self.pointG3
self.assertEqual(G5.x, 0x7a9f9335a48dcb0e2ba7601eedb50def80cbcf728562ada756d761e8958812808bc0d57a920c3c96f07b2d8cefc6f950d0a99d1092030034)
self.assertEqual(G5.y, 0xadfd751a2517edd3b9109ce4fd580ade260ca1823ab18fced86551f7b698017127d7a4ee59d2b33c58405512881f225443b4731472f435eb)
def test_inplace_addition(self):
pointH = self.pointG.copy()
pointH += self.pointG
self.assertEqual(pointH, self.pointG2)
pointH += self.pointG
self.assertEqual(pointH, self.pointG3)
pointH += self.pointG.point_at_infinity()
self.assertEqual(pointH, self.pointG3)
def test_doubling(self):
pointH = self.pointG.copy()
pointH.double()
self.assertEqual(pointH.x, self.pointG2.x)
self.assertEqual(pointH.y, self.pointG2.y)
# 2*0
pai = self.pointG.point_at_infinity()
pointR = pai.copy()
pointR.double()
self.assertEqual(pointR, pai)
def test_scalar_multiply(self):
d = 0
pointH = d * self.pointG
self.assertEqual(pointH.x, 0)
self.assertEqual(pointH.y, 1)
d = 1
pointH = d * self.pointG
self.assertEqual(pointH.x, self.pointG.x)
self.assertEqual(pointH.y, self.pointG.y)
d = 2
pointH = d * self.pointG
self.assertEqual(pointH.x, self.pointG2.x)
self.assertEqual(pointH.y, self.pointG2.y)
d = 3
pointH = d * self.pointG
self.assertEqual(pointH.x, self.pointG3.x)
self.assertEqual(pointH.y, self.pointG3.y)
d = 4
pointH = d * self.pointG
self.assertEqual(pointH.x, 0x49dcbc5c6c0cce2c1419a17226f929ea255a09cf4e0891c693fda4be70c74cc301b7bdf1515dd8ba21aee1798949e120e2ce42ac48ba7f30)
self.assertEqual(pointH.y, 0xd49077e4accde527164b33a5de021b979cb7c02f0457d845c90dc3227b8a5bc1c0d8f97ea1ca9472b5d444285d0d4f5b32e236f86de51839)
d = 5
pointH = d * self.pointG
self.assertEqual(pointH.x, 0x7a9f9335a48dcb0e2ba7601eedb50def80cbcf728562ada756d761e8958812808bc0d57a920c3c96f07b2d8cefc6f950d0a99d1092030034)
self.assertEqual(pointH.y, 0xadfd751a2517edd3b9109ce4fd580ade260ca1823ab18fced86551f7b698017127d7a4ee59d2b33c58405512881f225443b4731472f435eb)
d = 10
pointH = d * self.pointG
self.assertEqual(pointH.x, 0x77486f9d19f6411cdd35d30d1c3235f71936452c787e5c034134d3e8172278aca61622bc805761ce3dab65118a0122d73b403165d0ed303d)
self.assertEqual(pointH.y, 0x4d2fea0b026be11024f1f0fe7e94e618e8ac17381ada1d1bf7ee293a68ff5d0bf93c1997dc1aabdc0c7e6381428d85b6b1954a89e4cddf67)
d = 20
pointH = d * self.pointG
self.assertEqual(pointH.x, 0x3c236422354600fe6763defcc1503737e4ed89e262d0de3ec1e552020f2a56fe3b9e1e012d021072598c3c2821e18268bb8fb8339c0d1216)
self.assertEqual(pointH.y, 0xb555b9721f630ccb05fc466de4c74d3d2781e69eca88e1b040844f04cab39fd946f91c688fa42402bb38fb9c3e61231017020b219b4396e1)
d = 255
pointH = d * self.pointG
self.assertEqual(pointH.x, 0xbeb7f8388b05cd9c1aa2e3c0dcf31e2b563659361826225390e7748654f627d5c36cbe627e9019936b56d15d4dad7c337c09bac64ff4197f)
self.assertEqual(pointH.y, 0x1e37312b2dd4e9440c43c6e7725fc4fa3d11e582d4863f1d018e28f50c0efdb1f53f9b01ada7c87fa162b1f0d72401015d57613d25f1ad53)
d = 256
pointH = d * self.pointG
self.assertEqual(pointH.x, 0xf19c34feb56730e3e2be761ac0a2a2b24853b281dda019fc35a5ab58e3696beb39609ae756b0d20fb7ccf0d79aaf5f3bca2e4fdb25bfac1c)
self.assertEqual(pointH.y, 0x3beb69cc9111bffcaddc61d363ce6fe5dd44da4aadce78f52e92e985d5442344ced72c4611ed0daac9f4f5661eab73d7a12d25ce8a30241e)
def test_sizes(self):
self.assertEqual(self.pointG.size_in_bits(), 448)
self.assertEqual(self.pointG.size_in_bytes(), 56)
class TestEccKey_Ed448(unittest.TestCase):
def test_private_key(self):
seed = unhexlify("4adf5d37ac6785e83e99a924f92676d366a78690af59c92b6bdf14f9cdbcf26fdad478109607583d633b60078d61d51d81b7509c5433b0d4c9")
Px = 0x72a01eea003a35f9ac44231dc4aae2a382f351d80bf32508175b0855edcf389aa2bbf308dd961ce361a6e7c2091bc78957f6ebcf3002a617
Py = 0x9e0d08d84586e9aeefecacb41d049b831f1a3ee0c3eada63e34557b30702b50ab59fb372feff7c30b8cbb7dd51afbe88444ec56238722ec1
key = EccKey(curve="Ed448", seed=seed)
self.assertEqual(key.seed, seed)
self.assertEqual(key.d, 0xb07cf179604f83433186e5178760c759c15125ee54ff6f8dcde46e872b709ac82ed0bd0a4e036d774034dcb18a9fb11894657a1485895f80)
self.assertTrue(key.has_private())
self.assertEqual(key.pointQ.x, Px)
self.assertEqual(key.pointQ.y, Py)
point = EccPoint(Px, Py, "ed448")
key = EccKey(curve="Ed448", seed=seed, point=point)
self.assertEqual(key.d, 0xb07cf179604f83433186e5178760c759c15125ee54ff6f8dcde46e872b709ac82ed0bd0a4e036d774034dcb18a9fb11894657a1485895f80)
self.assertTrue(key.has_private())
self.assertEqual(key.pointQ, point)
# Other names
key = EccKey(curve="ed448", seed=seed)
# Must not accept d parameter
self.assertRaises(ValueError, EccKey, curve="ed448", d=1)
def test_public_key(self):
point = EccPoint(_curves['ed448'].Gx, _curves['ed448'].Gy, curve='ed448')
key = EccKey(curve="ed448", point=point)
self.assertFalse(key.has_private())
self.assertEqual(key.pointQ, point)
def test_public_key_derived(self):
priv_key = EccKey(curve="ed448", seed=b'H'*57)
pub_key = priv_key.public_key()
self.assertFalse(pub_key.has_private())
self.assertEqual(priv_key.pointQ, pub_key.pointQ)
def test_invalid_seed(self):
self.assertRaises(ValueError, lambda: EccKey(curve="ed448", seed=b'H' * 56))
def test_equality(self):
private_key = ECC.construct(seed=b'H'*57, curve="Ed448")
private_key2 = ECC.construct(seed=b'H'*57, curve="ed448")
private_key3 = ECC.construct(seed=b'C'*57, curve="Ed448")
public_key = private_key.public_key()
public_key2 = private_key2.public_key()
public_key3 = private_key3.public_key()
self.assertEqual(private_key, private_key2)
self.assertNotEqual(private_key, private_key3)
self.assertEqual(public_key, public_key2)
self.assertNotEqual(public_key, public_key3)
self.assertNotEqual(public_key, private_key)
def test_name_consistency(self):
key = ECC.generate(curve='ed448')
self.assertIn("curve='Ed448'", repr(key))
self.assertEqual(key.curve, 'Ed448')
self.assertEqual(key.public_key().curve, 'Ed448')
class TestEccModule_Ed448(unittest.TestCase):
def test_generate(self):
key = ECC.generate(curve="Ed448")
self.assertTrue(key.has_private())
point = EccPoint(_curves['Ed448'].Gx, _curves['Ed448'].Gy, curve="Ed448") * key.d
self.assertEqual(key.pointQ, point)
# Always random
key2 = ECC.generate(curve="Ed448")
self.assertNotEqual(key, key2)
# Other names
ECC.generate(curve="Ed448")
# Random source
key1 = ECC.generate(curve="Ed448", randfunc=SHAKE128.new().read)
key2 = ECC.generate(curve="Ed448", randfunc=SHAKE128.new().read)
self.assertEqual(key1, key2)
def test_construct(self):
seed = unhexlify("4adf5d37ac6785e83e99a924f92676d366a78690af59c92b6bdf14f9cdbcf26fdad478109607583d633b60078d61d51d81b7509c5433b0d4c9")
Px = 0x72a01eea003a35f9ac44231dc4aae2a382f351d80bf32508175b0855edcf389aa2bbf308dd961ce361a6e7c2091bc78957f6ebcf3002a617
Py = 0x9e0d08d84586e9aeefecacb41d049b831f1a3ee0c3eada63e34557b30702b50ab59fb372feff7c30b8cbb7dd51afbe88444ec56238722ec1
d = 0xb07cf179604f83433186e5178760c759c15125ee54ff6f8dcde46e872b709ac82ed0bd0a4e036d774034dcb18a9fb11894657a1485895f80
point = EccPoint(Px, Py, curve="Ed448")
# Private key only
key = ECC.construct(curve="Ed448", seed=seed)
self.assertEqual(key.pointQ, point)
self.assertTrue(key.has_private())
# Public key only
key = ECC.construct(curve="Ed448", point_x=Px, point_y=Py)
self.assertEqual(key.pointQ, point)
self.assertFalse(key.has_private())
# Private and public key
key = ECC.construct(curve="Ed448", seed=seed, point_x=Px, point_y=Py)
self.assertEqual(key.pointQ, point)
self.assertTrue(key.has_private())
# Other names
key = ECC.construct(curve="ed448", seed=seed)
def test_negative_construct(self):
coord = dict(point_x=10, point_y=4)
coordG = dict(point_x=_curves['ed448'].Gx, point_y=_curves['ed448'].Gy)
self.assertRaises(ValueError, ECC.construct, curve="Ed448", **coord)
self.assertRaises(ValueError, ECC.construct, curve="Ed448", d=2, **coordG)
self.assertRaises(ValueError, ECC.construct, curve="Ed448", seed=b'H'*58)
def get_tests(config={}):
tests = []
tests += list_test_cases(TestEccPoint_Ed448)
tests += list_test_cases(TestEccKey_Ed448)
tests += list_test_cases(TestEccModule_Ed448)
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,217 @@
# -*- coding: utf-8 -*-
#
# SelfTest/PublicKey/test_ElGamal.py: Self-test for the ElGamal primitive
#
# ===================================================================
# 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.PublicKey.ElGamal"""
__revision__ = "$Id$"
import unittest
from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
from Crypto import Random
from Crypto.PublicKey import ElGamal
from Crypto.Util.number import bytes_to_long
from Crypto.Util.py3compat import *
class ElGamalTest(unittest.TestCase):
#
# Test vectors
#
# There seem to be no real ElGamal test vectors available in the
# public domain. The following test vectors have been generated
# with libgcrypt 1.5.0.
#
# Encryption
tve=[
{
# 256 bits
'p' :'BA4CAEAAED8CBE952AFD2126C63EB3B345D65C2A0A73D2A3AD4138B6D09BD933',
'g' :'05',
'y' :'60D063600ECED7C7C55146020E7A31C4476E9793BEAED420FEC9E77604CAE4EF',
'x' :'1D391BA2EE3C37FE1BA175A69B2C73A11238AD77675932',
'k' :'F5893C5BAB4131264066F57AB3D8AD89E391A0B68A68A1',
'pt' :'48656C6C6F207468657265',
'ct1':'32BFD5F487966CEA9E9356715788C491EC515E4ED48B58F0F00971E93AAA5EC7',
'ct2':'7BE8FBFF317C93E82FCEF9BD515284BA506603FEA25D01C0CB874A31F315EE68'
},
{
# 512 bits
'p' :'F1B18AE9F7B4E08FDA9A04832F4E919D89462FD31BF12F92791A93519F75076D6CE3942689CDFF2F344CAFF0F82D01864F69F3AECF566C774CBACF728B81A227',
'g' :'07',
'y' :'688628C676E4F05D630E1BE39D0066178CA7AA83836B645DE5ADD359B4825A12B02EF4252E4E6FA9BEC1DB0BE90F6D7C8629CABB6E531F472B2664868156E20C',
'x' :'14E60B1BDFD33436C0DA8A22FDC14A2CCDBBED0627CE68',
'k' :'38DBF14E1F319BDA9BAB33EEEADCAF6B2EA5250577ACE7',
'pt' :'48656C6C6F207468657265',
'ct1':'290F8530C2CC312EC46178724F196F308AD4C523CEABB001FACB0506BFED676083FE0F27AC688B5C749AB3CB8A80CD6F7094DBA421FB19442F5A413E06A9772B',
'ct2':'1D69AAAD1DC50493FB1B8E8721D621D683F3BF1321BE21BC4A43E11B40C9D4D9C80DE3AAC2AB60D31782B16B61112E68220889D53C4C3136EE6F6CE61F8A23A0'
}
]
# Signature
tvs=[
{
# 256 bits
'p' :'D2F3C41EA66530838A704A48FFAC9334F4701ECE3A97CEE4C69DD01AE7129DD7',
'g' :'05',
'y' :'C3F9417DC0DAFEA6A05C1D2333B7A95E63B3F4F28CC962254B3256984D1012E7',
'x' :'165E4A39BE44D5A2D8B1332D416BC559616F536BC735BB',
'k' :'C7F0C794A7EAD726E25A47FF8928013680E73C51DD3D7D99BFDA8F492585928F',
'h' :'48656C6C6F207468657265',
'sig1':'35CA98133779E2073EF31165AFCDEB764DD54E96ADE851715495F9C635E1E7C2',
'sig2':'0135B88B1151279FE5D8078D4FC685EE81177EE9802AB123A73925FC1CB059A7',
},
{
# 512 bits
'p' :'E24CF3A4B8A6AF749DCA6D714282FE4AABEEE44A53BB6ED15FBE32B5D3C3EF9CC4124A2ECA331F3C1C1B667ACA3766825217E7B5F9856648D95F05330C6A19CF',
'g' :'0B',
'y' :'2AD3A1049CA5D4ED207B2431C79A8719BB4073D4A94E450EA6CEE8A760EB07ADB67C0D52C275EE85D7B52789061EE45F2F37D9B2AE522A51C28329766BFE68AC',
'x' :'16CBB4F46D9ECCF24FF9F7E63CAA3BD8936341555062AB',
'k' :'8A3D89A4E429FD2476D7D717251FB79BF900FFE77444E6BB8299DC3F84D0DD57ABAB50732AE158EA52F5B9E7D8813E81FD9F79470AE22F8F1CF9AEC820A78C69',
'h' :'48656C6C6F207468657265',
'sig1':'BE001AABAFFF976EC9016198FBFEA14CBEF96B000CCC0063D3324016F9E91FE80D8F9325812ED24DDB2B4D4CF4430B169880B3CE88313B53255BD4EC0378586F',
'sig2':'5E266F3F837BA204E3BBB6DBECC0611429D96F8C7CE8F4EFDF9D4CB681C2A954468A357BF4242CEC7418B51DFC081BCD21299EF5B5A0DDEF3A139A1817503DDE',
}
]
def test_generate_180(self):
self._test_random_key(180)
def test_encryption(self):
for tv in self.tve:
d = self.convert_tv(tv, True)
key = ElGamal.construct(d['key'])
ct = key._encrypt(d['pt'], d['k'])
self.assertEqual(ct[0], d['ct1'])
self.assertEqual(ct[1], d['ct2'])
def test_decryption(self):
for tv in self.tve:
d = self.convert_tv(tv, True)
key = ElGamal.construct(d['key'])
pt = key._decrypt((d['ct1'], d['ct2']))
self.assertEqual(pt, d['pt'])
def test_signing(self):
for tv in self.tvs:
d = self.convert_tv(tv, True)
key = ElGamal.construct(d['key'])
sig1, sig2 = key._sign(d['h'], d['k'])
self.assertEqual(sig1, d['sig1'])
self.assertEqual(sig2, d['sig2'])
def test_verification(self):
for tv in self.tvs:
d = self.convert_tv(tv, True)
key = ElGamal.construct(d['key'])
# Positive test
res = key._verify( d['h'], (d['sig1'],d['sig2']) )
self.assertTrue(res)
# Negative test
res = key._verify( d['h'], (d['sig1']+1,d['sig2']) )
self.assertFalse(res)
def test_bad_key3(self):
tup = tup0 = list(self.convert_tv(self.tvs[0], 1)['key'])[:3]
tup[0] += 1 # p += 1 (not prime)
self.assertRaises(ValueError, ElGamal.construct, tup)
tup = tup0
tup[1] = 1 # g = 1
self.assertRaises(ValueError, ElGamal.construct, tup)
tup = tup0
tup[2] = tup[0]*2 # y = 2*p
self.assertRaises(ValueError, ElGamal.construct, tup)
def test_bad_key4(self):
tup = tup0 = list(self.convert_tv(self.tvs[0], 1)['key'])
tup[3] += 1 # x += 1
self.assertRaises(ValueError, ElGamal.construct, tup)
def convert_tv(self, tv, as_longs=0):
"""Convert a test vector from textual form (hexadecimal ascii
to either integers or byte strings."""
key_comps = 'p','g','y','x'
tv2 = {}
for c in tv.keys():
tv2[c] = a2b_hex(tv[c])
if as_longs or c in key_comps or c in ('sig1','sig2'):
tv2[c] = bytes_to_long(tv2[c])
tv2['key']=[]
for c in key_comps:
tv2['key'] += [tv2[c]]
del tv2[c]
return tv2
def _test_random_key(self, bits):
elgObj = ElGamal.generate(bits, Random.new().read)
self._check_private_key(elgObj)
self._exercise_primitive(elgObj)
pub = elgObj.publickey()
self._check_public_key(pub)
self._exercise_public_primitive(elgObj)
def _check_private_key(self, elgObj):
# Check capabilities
self.assertTrue(elgObj.has_private())
# Sanity check key data
self.assertTrue(1<elgObj.g<(elgObj.p-1))
self.assertEqual(pow(elgObj.g, elgObj.p-1, elgObj.p), 1)
self.assertTrue(1<elgObj.x<(elgObj.p-1))
self.assertEqual(pow(elgObj.g, elgObj.x, elgObj.p), elgObj.y)
def _check_public_key(self, elgObj):
# Check capabilities
self.assertFalse(elgObj.has_private())
# Sanity check key data
self.assertTrue(1<elgObj.g<(elgObj.p-1))
self.assertEqual(pow(elgObj.g, elgObj.p-1, elgObj.p), 1)
def _exercise_primitive(self, elgObj):
# Test encryption/decryption
plaintext = 127218
ciphertext = elgObj._encrypt(plaintext, 123456789)
plaintextP = elgObj._decrypt(ciphertext)
self.assertEqual(plaintext, plaintextP)
# Test signature/verification
signature = elgObj._sign(plaintext, 987654321)
elgObj._verify(plaintext, signature)
def _exercise_public_primitive(self, elgObj):
plaintext = 92987276
ciphertext = elgObj._encrypt(plaintext, 123456789)
def get_tests(config={}):
tests = []
tests += list_test_cases(ElGamalTest)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,324 @@
# -*- coding: utf-8 -*-
#
# SelfTest/PublicKey/test_RSA.py: Self-test for the RSA primitive
#
# 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.PublicKey.RSA"""
__revision__ = "$Id$"
import os
import pickle
from pickle import PicklingError
from Crypto.Util.py3compat import *
import unittest
from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
class RSATest(unittest.TestCase):
# Test vectors from "RSA-OAEP and RSA-PSS test vectors (.zip file)"
# ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip
# See RSADSI's PKCS#1 page at
# http://www.rsa.com/rsalabs/node.asp?id=2125
# from oaep-int.txt
# TODO: PyCrypto treats the message as starting *after* the leading "00"
# TODO: That behaviour should probably be changed in the future.
plaintext = """
eb 7a 19 ac e9 e3 00 63 50 e3 29 50 4b 45 e2
ca 82 31 0b 26 dc d8 7d 5c 68 f1 ee a8 f5 52 67
c3 1b 2e 8b b4 25 1f 84 d7 e0 b2 c0 46 26 f5 af
f9 3e dc fb 25 c9 c2 b3 ff 8a e1 0e 83 9a 2d db
4c dc fe 4f f4 77 28 b4 a1 b7 c1 36 2b aa d2 9a
b4 8d 28 69 d5 02 41 21 43 58 11 59 1b e3 92 f9
82 fb 3e 87 d0 95 ae b4 04 48 db 97 2f 3a c1 4f
7b c2 75 19 52 81 ce 32 d2 f1 b7 6d 4d 35 3e 2d
"""
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
"""
modulus = """
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
"""
e = 0x11 # public exponent
prime_factor = """
c9 7f b1 f0 27 f4 53 f6 34 12 33 ea aa d1 d9 35
3f 6c 42 d0 88 66 b1 d0 5a 0f 20 35 02 8b 9d 86
98 40 b4 16 66 b4 2e 92 ea 0d a3 b4 32 04 b5 cf
ce 33 52 52 4d 04 16 a5 a4 41 e7 00 af 46 15 03
"""
def setUp(self):
global RSA, Random, bytes_to_long
from Crypto.PublicKey import RSA
from Crypto import Random
from Crypto.Util.number import bytes_to_long, inverse
self.n = bytes_to_long(a2b_hex(self.modulus))
self.p = bytes_to_long(a2b_hex(self.prime_factor))
# Compute q, d, and u from n, e, and p
self.q = self.n // self.p
self.d = inverse(self.e, (self.p-1)*(self.q-1))
self.u = inverse(self.p, self.q) # u = e**-1 (mod q)
self.rsa = RSA
def test_generate_1arg(self):
"""RSA (default implementation) generated key (1 argument)"""
rsaObj = self.rsa.generate(1024)
self._check_private_key(rsaObj)
self._exercise_primitive(rsaObj)
pub = rsaObj.public_key()
self._check_public_key(pub)
self._exercise_public_primitive(rsaObj)
def test_generate_2arg(self):
"""RSA (default implementation) generated key (2 arguments)"""
rsaObj = self.rsa.generate(1024, Random.new().read)
self._check_private_key(rsaObj)
self._exercise_primitive(rsaObj)
pub = rsaObj.public_key()
self._check_public_key(pub)
self._exercise_public_primitive(rsaObj)
def test_generate_3args(self):
rsaObj = self.rsa.generate(1024, Random.new().read,e=65537)
self._check_private_key(rsaObj)
self._exercise_primitive(rsaObj)
pub = rsaObj.public_key()
self._check_public_key(pub)
self._exercise_public_primitive(rsaObj)
self.assertEqual(65537,rsaObj.e)
def test_construct_2tuple(self):
"""RSA (default implementation) constructed key (2-tuple)"""
pub = self.rsa.construct((self.n, self.e))
self._check_public_key(pub)
self._check_encryption(pub)
def test_construct_3tuple(self):
"""RSA (default implementation) constructed key (3-tuple)"""
rsaObj = self.rsa.construct((self.n, self.e, self.d))
self._check_encryption(rsaObj)
self._check_decryption(rsaObj)
def test_construct_4tuple(self):
"""RSA (default implementation) constructed key (4-tuple)"""
rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p))
self._check_encryption(rsaObj)
self._check_decryption(rsaObj)
def test_construct_5tuple(self):
"""RSA (default implementation) constructed key (5-tuple)"""
rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q))
self._check_private_key(rsaObj)
self._check_encryption(rsaObj)
self._check_decryption(rsaObj)
def test_construct_6tuple(self):
"""RSA (default implementation) constructed key (6-tuple)"""
rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q, self.u))
self._check_private_key(rsaObj)
self._check_encryption(rsaObj)
self._check_decryption(rsaObj)
def test_construct_bad_key2(self):
tup = (self.n, 1)
self.assertRaises(ValueError, self.rsa.construct, tup)
# An even modulus is wrong
tup = (self.n+1, self.e)
self.assertRaises(ValueError, self.rsa.construct, tup)
def test_construct_bad_key3(self):
tup = (self.n, self.e, self.d+1)
self.assertRaises(ValueError, self.rsa.construct, tup)
def test_construct_bad_key5(self):
tup = (self.n, self.e, self.d, self.p, self.p)
self.assertRaises(ValueError, self.rsa.construct, tup)
tup = (self.p*self.p, self.e, self.p, self.p)
self.assertRaises(ValueError, self.rsa.construct, tup)
tup = (self.p*self.p, 3, self.p, self.q)
self.assertRaises(ValueError, self.rsa.construct, tup)
def test_construct_bad_key6(self):
tup = (self.n, self.e, self.d, self.p, self.q, 10)
self.assertRaises(ValueError, self.rsa.construct, tup)
from Crypto.Util.number import inverse
tup = (self.n, self.e, self.d, self.p, self.q, inverse(self.q, self.p))
self.assertRaises(ValueError, self.rsa.construct, tup)
def test_factoring(self):
rsaObj = self.rsa.construct([self.n, self.e, self.d])
self.assertTrue(rsaObj.p==self.p or rsaObj.p==self.q)
self.assertTrue(rsaObj.q==self.p or rsaObj.q==self.q)
self.assertTrue(rsaObj.q*rsaObj.p == self.n)
self.assertRaises(ValueError, self.rsa.construct, [self.n, self.e, self.n-1])
def test_repr(self):
rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q))
repr(rsaObj)
def test_serialization(self):
"""RSA keys are unpickable"""
rsa_key = self.rsa.generate(1024)
self.assertRaises(PicklingError, pickle.dumps, rsa_key)
def test_raw_rsa_boundary(self):
# The argument of every RSA raw operation (encrypt/decrypt) must be
# non-negative and no larger than the modulus
rsa_obj = self.rsa.generate(1024)
self.assertRaises(ValueError, rsa_obj._decrypt, rsa_obj.n)
self.assertRaises(ValueError, rsa_obj._decrypt_to_bytes, rsa_obj.n)
self.assertRaises(ValueError, rsa_obj._encrypt, rsa_obj.n)
self.assertRaises(ValueError, rsa_obj._decrypt, -1)
self.assertRaises(ValueError, rsa_obj._decrypt_to_bytes, -1)
self.assertRaises(ValueError, rsa_obj._encrypt, -1)
def test_size(self):
pub = self.rsa.construct((self.n, self.e))
self.assertEqual(pub.size_in_bits(), 1024)
self.assertEqual(pub.size_in_bytes(), 128)
def _check_private_key(self, rsaObj):
from Crypto.Math.Numbers import Integer
# Check capabilities
self.assertEqual(1, rsaObj.has_private())
# Sanity check key data
self.assertEqual(rsaObj.n, rsaObj.p * rsaObj.q) # n = pq
lcm = int(Integer(rsaObj.p-1).lcm(rsaObj.q-1))
self.assertEqual(1, rsaObj.d * rsaObj.e % lcm) # ed = 1 (mod LCM(p-1, q-1))
self.assertEqual(1, rsaObj.p * rsaObj.u % rsaObj.q) # pu = 1 (mod q)
self.assertEqual(1, rsaObj.p > 1) # p > 1
self.assertEqual(1, rsaObj.q > 1) # q > 1
self.assertEqual(1, rsaObj.e > 1) # e > 1
self.assertEqual(1, rsaObj.d > 1) # d > 1
self.assertEqual(rsaObj.u, rsaObj.invp)
self.assertEqual(1, rsaObj.q * rsaObj.invq % rsaObj.p)
def _check_public_key(self, rsaObj):
ciphertext = a2b_hex(self.ciphertext)
# Check capabilities
self.assertEqual(0, rsaObj.has_private())
# Check rsaObj.[ne] -> rsaObj.[ne] mapping
self.assertEqual(rsaObj.n, rsaObj.n)
self.assertEqual(rsaObj.e, rsaObj.e)
# Check that private parameters are all missing
self.assertEqual(0, hasattr(rsaObj, 'd'))
self.assertEqual(0, hasattr(rsaObj, 'p'))
self.assertEqual(0, hasattr(rsaObj, 'q'))
self.assertEqual(0, hasattr(rsaObj, 'u'))
# Sanity check key data
self.assertEqual(1, rsaObj.e > 1) # e > 1
# Public keys should not be able to sign or decrypt
self.assertRaises(TypeError, rsaObj._decrypt,
bytes_to_long(ciphertext))
self.assertRaises(TypeError, rsaObj._decrypt_to_bytes,
bytes_to_long(ciphertext))
# Check __eq__ and __ne__
self.assertEqual(rsaObj.public_key() == rsaObj.public_key(),True) # assert_
self.assertEqual(rsaObj.public_key() != rsaObj.public_key(),False) # assertFalse
self.assertEqual(rsaObj.publickey(), rsaObj.public_key())
def _exercise_primitive(self, rsaObj):
# Since we're using a randomly-generated key, we can't check the test
# vector, but we can make sure encryption and decryption are inverse
# operations.
ciphertext = bytes_to_long(a2b_hex(self.ciphertext))
# Test decryption
plaintext = rsaObj._decrypt(ciphertext)
# Test encryption (2 arguments)
new_ciphertext2 = rsaObj._encrypt(plaintext)
self.assertEqual(ciphertext, new_ciphertext2)
def _exercise_public_primitive(self, rsaObj):
plaintext = a2b_hex(self.plaintext)
# Test encryption (2 arguments)
new_ciphertext2 = rsaObj._encrypt(bytes_to_long(plaintext))
def _check_encryption(self, rsaObj):
plaintext = a2b_hex(self.plaintext)
ciphertext = a2b_hex(self.ciphertext)
# Test encryption
new_ciphertext2 = rsaObj._encrypt(bytes_to_long(plaintext))
self.assertEqual(bytes_to_long(ciphertext), new_ciphertext2)
def _check_decryption(self, rsaObj):
plaintext = bytes_to_long(a2b_hex(self.plaintext))
ciphertext = bytes_to_long(a2b_hex(self.ciphertext))
# Test plain decryption
new_plaintext = rsaObj._decrypt(ciphertext)
self.assertEqual(plaintext, new_plaintext)
def get_tests(config={}):
tests = []
tests += list_test_cases(RSATest)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
# vim:set ts=4 sw=4 sts=4 expandtab:
@@ -0,0 +1,385 @@
# ===================================================================
#
# Copyright (c) 2024, 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 os
import errno
import warnings
import unittest
from binascii import unhexlify
from unittest import SkipTest
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Util.py3compat import tostr, FileNotFoundError
from Crypto.Util.asn1 import DerSequence, DerBitString
from Crypto.Hash import SHAKE128
from Crypto.PublicKey import ECC
try:
import pycryptodome_test_vectors # type: ignore
test_vectors_available = True
except ImportError:
test_vectors_available = False
def load_file(file_name, mode="rb"):
results = None
try:
if not test_vectors_available:
raise FileNotFoundError(errno.ENOENT,
os.strerror(errno.ENOENT),
file_name)
dir_comps = ("PublicKey", "ECC")
init_dir = os.path.dirname(pycryptodome_test_vectors.__file__)
full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name)
with open(full_file_name, mode) as file_in:
results = file_in.read()
except FileNotFoundError:
warnings.warn("Warning: skipping extended tests for ECC",
UserWarning,
stacklevel=2)
if results is None:
raise SkipTest("Missing %s" % file_name)
return results
def compact(lines):
ext = b"".join(lines)
return unhexlify(tostr(ext).replace(" ", "").replace(":", ""))
def create_ref_keys_x25519():
key_lines = load_file("ecc_x25519.txt").splitlines()
seed = compact(key_lines[5:8])
key = ECC.construct(curve="Curve25519", seed=seed)
return (key, key.public_key())
def get_fixed_prng():
return SHAKE128.new().update(b"SEED").read
def extract_bitstring_from_spki(data):
seq = DerSequence()
seq.decode(data)
bs = DerBitString()
bs.decode(seq[1])
return bs.value
class TestImport(unittest.TestCase):
def test_empty(self):
self.assertRaises(ValueError, ECC.import_key, b"")
def test_mismatch(self):
# Private key with X448 Object ID but X25519 key
mismatch_hex = "302e020100300506032b656f042204207009906b64ec727d5cb5c23007bf0425b3fd79014c6cd62ca3dddfcf0f278f79"
mismatch = unhexlify(mismatch_hex)
self.assertRaises(ValueError, ECC.import_key, mismatch)
class TestImport_Curve25519(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(TestImport_Curve25519, self).__init__(*args, **kwargs)
self.ref_private, self.ref_public = create_ref_keys_x25519()
def test_import_public_der(self):
key_file = load_file("ecc_x25519_public.der")
key = ECC._import_subjectPublicKeyInfo(key_file)
self.assertEqual(self.ref_public, key)
key = ECC._import_der(key_file, None)
self.assertEqual(self.ref_public, key)
key = ECC.import_key(key_file)
self.assertEqual(self.ref_public, key)
def test_import_pkcs8_der(self):
key_file = load_file("ecc_x25519_private.der")
key = ECC._import_der(key_file, None)
self.assertEqual(self.ref_private, key)
key = ECC.import_key(key_file)
self.assertEqual(self.ref_private, key)
def test_import_private_pkcs8_encrypted_1(self):
key_file = load_file("ecc_x25519_private_p8.der")
key = ECC._import_der(key_file, "secret")
self.assertEqual(self.ref_private, key)
key = ECC.import_key(key_file, "secret")
self.assertEqual(self.ref_private, key)
def test_import_private_pkcs8_encrypted_2(self):
key_file = load_file("ecc_x25519_private_p8.pem")
key = ECC.import_key(key_file, "secret")
self.assertEqual(self.ref_private, key)
def test_import_private_pkcs8_encrypted_3(self):
key_file = load_file("ecc_x25519_private_p8_2.der")
key = ECC._import_der(key_file, "secret")
self.assertEqual(self.ref_private, key)
key = ECC.import_key(key_file, "secret")
self.assertEqual(self.ref_private, key)
def test_import_x509_der(self):
key_file = load_file("ecc_x25519_x509.der")
key = ECC._import_der(key_file, None)
self.assertEqual(self.ref_public, key)
key = ECC.import_key(key_file)
self.assertEqual(self.ref_public, key)
def test_import_public_pem(self):
key_file = load_file("ecc_x25519_public.pem")
key = ECC.import_key(key_file)
self.assertEqual(self.ref_public, key)
def test_import_private_pem(self):
key_file = load_file("ecc_x25519_private.pem")
key = ECC.import_key(key_file)
self.assertEqual(self.ref_private, key)
def test_import_private_pem_encrypted(self):
for algo in "des3", "aes128", "aes192", "aes256":
key_file = load_file("ecc_x25519_private_enc_%s.pem" % algo)
key = ECC.import_key(key_file, "secret")
self.assertEqual(self.ref_private, key)
key = ECC.import_key(tostr(key_file), b"secret")
self.assertEqual(self.ref_private, key)
def test_import_x509_pem(self):
key_file = load_file("ecc_x25519_x509.pem")
key = ECC.import_key(key_file)
self.assertEqual(self.ref_public, key)
class TestExport_Curve25519(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(TestExport_Curve25519, self).__init__(*args, **kwargs)
self.ref_private, self.ref_public = create_ref_keys_x25519()
def test_export_public_der(self):
key_file = load_file("ecc_x25519_public.der")
encoded = self.ref_public._export_subjectPublicKeyInfo(True)
self.assertEqual(key_file, encoded)
encoded = self.ref_public.export_key(format="DER")
self.assertEqual(key_file, encoded)
encoded = self.ref_public.export_key(format="DER", compress=False)
self.assertEqual(key_file, encoded)
def test_export_private_pkcs8_clear(self):
key_file = load_file("ecc_x25519_private.der")
encoded = self.ref_private._export_pkcs8()
self.assertEqual(key_file, encoded)
# ---
encoded = self.ref_private.export_key(format="DER")
self.assertEqual(key_file, encoded)
self.assertRaises(ValueError, self.ref_private.export_key,
format="DER", use_pkcs8=False)
def test_export_private_pkcs8_encrypted(self):
encoded = self.ref_private._export_pkcs8(passphrase="secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
# This should prove that the output is password-protected
self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None)
decoded = ECC._import_pkcs8(encoded, "secret")
self.assertEqual(self.ref_private, decoded)
# ---
encoded = self.ref_private.export_key(format="DER",
passphrase="secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
decoded = ECC.import_key(encoded, "secret")
self.assertEqual(self.ref_private, decoded)
# ---
encoded = self.ref_private.export_key(format="DER",
passphrase="secret",
protection="PBKDF2WithHMAC-SHA256AndAES128-CBC",
prot_params={'iteration_count': 123})
decoded = ECC.import_key(encoded, "secret")
self.assertEqual(self.ref_private, decoded)
def test_export_public_pem(self):
key_file_ref = load_file("ecc_x25519_public.pem", "rt").strip()
key_file = self.ref_public.export_key(format="PEM").strip()
self.assertEqual(key_file_ref, key_file)
def test_export_private_pem_clear(self):
key_file = load_file("ecc_x25519_private.pem", "rt").strip()
encoded = self.ref_private.export_key(format="PEM").strip()
self.assertEqual(key_file, encoded)
def test_export_private_pem_encrypted(self):
encoded = self.ref_private.export_key(format="PEM",
passphrase=b"secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
# This should prove that the output is password-protected
self.assertRaises(ValueError, ECC.import_key, encoded)
assert "ENCRYPTED PRIVATE KEY" in encoded
decoded = ECC.import_key(encoded, "secret")
self.assertEqual(self.ref_private, decoded)
def test_export_raw(self):
encoded = self.ref_public.export_key(format='raw')
self.assertEqual(len(encoded), 32)
self.assertEqual(encoded, unhexlify(b'ff7561ef60c9c8a757f6d6372ec14142c9be208d0e719136d8d3c715dfcf7e15'))
def test_prng(self):
# Test that password-protected containers use the provided PRNG
encoded1 = self.ref_private.export_key(format="PEM",
passphrase="secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
randfunc=get_fixed_prng())
encoded2 = self.ref_private.export_key(format="PEM",
passphrase="secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
randfunc=get_fixed_prng())
self.assertEqual(encoded1, encoded2)
def test_byte_or_string_passphrase(self):
encoded1 = self.ref_private.export_key(format="PEM",
passphrase="secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
randfunc=get_fixed_prng())
encoded2 = self.ref_private.export_key(format="PEM",
passphrase=b"secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
randfunc=get_fixed_prng())
self.assertEqual(encoded1, encoded2)
def test_error_params1(self):
# Unknown format
self.assertRaises(ValueError, self.ref_private.export_key, format="XXX")
# Missing 'protection' parameter when PKCS#8 is used
self.assertRaises(ValueError,
self.ref_private.export_key,
format="PEM",
passphrase="secret")
# Empty password
self.assertRaises(ValueError,
self.ref_private.export_key,
format="PEM",
passphrase="",
use_pkcs8=False)
self.assertRaises(ValueError,
self.ref_private.export_key,
format="PEM",
passphrase="",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
# No private keys with OpenSSH
self.assertRaises(ValueError,
self.ref_private.export_key,
format="OpenSSH",
passphrase="secret")
class TestImport_Curve25519_Weak(unittest.TestCase):
def test_weak_pem(self):
p = 2**255 - 19
weak_x = (0,
1,
325606250916557431795983626356110631294008115727848805560023387167927233504,
39382357235489614581723060781553021112529911719440698176882885853963445705823,
p - 1,
p,
p + 1,
p + 325606250916557431795983626356110631294008115727848805560023387167927233504,
p + 39382357235489614581723060781553021112529911719440698176882885853963445705823,
p * 2 - 1,
p * 2,
p * 2 + 1)
for x in weak_x:
low_order_point = ECC.EccXPoint(x, "curve25519")
weak_key = ECC.EccKey(point=low_order_point, curve="curve25519")
encoded = weak_key.export_key(format="PEM")
self.assertRaises(ValueError,
ECC.import_key,
encoded)
def get_tests(config={}):
tests = []
try:
tests += list_test_cases(TestImport)
tests += list_test_cases(TestImport_Curve25519)
tests += list_test_cases(TestExport_Curve25519)
tests += list_test_cases(TestImport_Curve25519_Weak)
except SkipTest:
pass
return tests
if __name__ == '__main__':
def suit():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,351 @@
# This file is licensed under the BSD 2-Clause License.
# See https://opensource.org/licenses/BSD-2-Clause for details.
import os
import errno
import warnings
import unittest
from binascii import unhexlify
from unittest import SkipTest
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Util.py3compat import tostr, FileNotFoundError
from Crypto.Util.asn1 import DerSequence, DerBitString
from Crypto.Hash import SHAKE128
from Crypto.PublicKey import ECC
try:
import pycryptodome_test_vectors # type: ignore
test_vectors_available = True
except ImportError:
test_vectors_available = False
def load_file(file_name, mode="rb"):
results = None
try:
if not test_vectors_available:
raise FileNotFoundError(errno.ENOENT,
os.strerror(errno.ENOENT),
file_name)
dir_comps = ("PublicKey", "ECC")
init_dir = os.path.dirname(pycryptodome_test_vectors.__file__)
full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name)
with open(full_file_name, mode) as file_in:
results = file_in.read()
except FileNotFoundError:
warnings.warn("Warning: skipping extended tests for ECC",
UserWarning,
stacklevel=2)
if results is None:
raise SkipTest("Missing %s" % file_name)
return results
def compact(lines):
ext = b"".join(lines)
return unhexlify(tostr(ext).replace(" ", "").replace(":", ""))
def create_ref_keys_x448():
key_lines = load_file("ecc_x448.txt").splitlines()
seed = compact(key_lines[6:10])
key = ECC.construct(curve="Curve448", seed=seed)
return (key, key.public_key())
def get_fixed_prng():
return SHAKE128.new().update(b"SEED").read
def extract_bitstring_from_spki(data):
seq = DerSequence()
seq.decode(data)
bs = DerBitString()
bs.decode(seq[1])
return bs.value
class TestImport(unittest.TestCase):
def test_empty(self):
self.assertRaises(ValueError, ECC.import_key, b"")
def test_mismatch(self):
# Private key with X448 Object ID but X448 key
mismatch_hex = "302e020100300506032b656f042204207009906b64ec727d5cb5c23007bf0425b3fd79014c6cd62ca3dddfcf0f278f79"
mismatch = unhexlify(mismatch_hex)
self.assertRaises(ValueError, ECC.import_key, mismatch)
class TestImport_Curve448(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(TestImport_Curve448, self).__init__(*args, **kwargs)
self.ref_private, self.ref_public = create_ref_keys_x448()
def test_import_public_der(self):
key_file = load_file("ecc_x448_public.der")
key = ECC._import_subjectPublicKeyInfo(key_file)
self.assertEqual(self.ref_public, key)
key = ECC._import_der(key_file, None)
self.assertEqual(self.ref_public, key)
key = ECC.import_key(key_file)
self.assertEqual(self.ref_public, key)
def test_import_pkcs8_der(self):
key_file = load_file("ecc_x448_private.der")
key = ECC._import_der(key_file, None)
self.assertEqual(self.ref_private, key)
key = ECC.import_key(key_file)
self.assertEqual(self.ref_private, key)
def test_import_private_pkcs8_encrypted_1(self):
key_file = load_file("ecc_x448_private_p8.der")
key = ECC._import_der(key_file, "secret")
self.assertEqual(self.ref_private, key)
key = ECC.import_key(key_file, "secret")
self.assertEqual(self.ref_private, key)
def test_import_private_pkcs8_encrypted_2(self):
key_file = load_file("ecc_x448_private_p8.pem")
key = ECC.import_key(key_file, "secret")
self.assertEqual(self.ref_private, key)
def test_import_private_pkcs8_encrypted_3(self):
key_file = load_file("ecc_x448_private_p8_2.der")
key = ECC._import_der(key_file, "secret")
self.assertEqual(self.ref_private, key)
key = ECC.import_key(key_file, "secret")
self.assertEqual(self.ref_private, key)
def test_import_x509_der(self):
key_file = load_file("ecc_x448_x509.der")
key = ECC._import_der(key_file, None)
self.assertEqual(self.ref_public, key)
key = ECC.import_key(key_file)
self.assertEqual(self.ref_public, key)
def test_import_public_pem(self):
key_file = load_file("ecc_x448_public.pem")
key = ECC.import_key(key_file)
self.assertEqual(self.ref_public, key)
def test_import_private_pem(self):
key_file = load_file("ecc_x448_private.pem")
key = ECC.import_key(key_file)
self.assertEqual(self.ref_private, key)
def test_import_private_pem_encrypted(self):
for algo in "des3", "aes128", "aes192", "aes256":
key_file = load_file("ecc_x448_private_enc_%s.pem" % algo)
key = ECC.import_key(key_file, "secret")
self.assertEqual(self.ref_private, key)
key = ECC.import_key(tostr(key_file), b"secret")
self.assertEqual(self.ref_private, key)
def test_import_x509_pem(self):
key_file = load_file("ecc_x448_x509.pem")
key = ECC.import_key(key_file)
self.assertEqual(self.ref_public, key)
class TestExport_Curve448(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(TestExport_Curve448, self).__init__(*args, **kwargs)
self.ref_private, self.ref_public = create_ref_keys_x448()
def test_export_public_der(self):
key_file = load_file("ecc_x448_public.der")
encoded = self.ref_public._export_subjectPublicKeyInfo(True)
self.assertEqual(key_file, encoded)
encoded = self.ref_public.export_key(format="DER")
self.assertEqual(key_file, encoded)
encoded = self.ref_public.export_key(format="DER", compress=False)
self.assertEqual(key_file, encoded)
def test_export_private_pkcs8_clear(self):
key_file = load_file("ecc_x448_private.der")
encoded = self.ref_private._export_pkcs8()
self.assertEqual(key_file, encoded)
# ---
encoded = self.ref_private.export_key(format="DER")
self.assertEqual(key_file, encoded)
self.assertRaises(ValueError, self.ref_private.export_key,
format="DER", use_pkcs8=False)
def test_export_private_pkcs8_encrypted(self):
encoded = self.ref_private._export_pkcs8(passphrase="secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
# This should prove that the output is password-protected
self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None)
decoded = ECC._import_pkcs8(encoded, "secret")
self.assertEqual(self.ref_private, decoded)
# ---
encoded = self.ref_private.export_key(format="DER",
passphrase="secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
decoded = ECC.import_key(encoded, "secret")
self.assertEqual(self.ref_private, decoded)
# ---
encoded = self.ref_private.export_key(format="DER",
passphrase="secret",
protection="PBKDF2WithHMAC-SHA256AndAES128-CBC",
prot_params={'iteration_count': 123})
decoded = ECC.import_key(encoded, "secret")
self.assertEqual(self.ref_private, decoded)
def test_export_public_pem(self):
key_file_ref = load_file("ecc_x448_public.pem", "rt").strip()
key_file = self.ref_public.export_key(format="PEM").strip()
self.assertEqual(key_file_ref, key_file)
def test_export_private_pem_clear(self):
key_file = load_file("ecc_x448_private.pem", "rt").strip()
encoded = self.ref_private.export_key(format="PEM").strip()
self.assertEqual(key_file, encoded)
def test_export_private_pem_encrypted(self):
encoded = self.ref_private.export_key(format="PEM",
passphrase=b"secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
# This should prove that the output is password-protected
self.assertRaises(ValueError, ECC.import_key, encoded)
assert "ENCRYPTED PRIVATE KEY" in encoded
decoded = ECC.import_key(encoded, "secret")
self.assertEqual(self.ref_private, decoded)
def test_export_raw(self):
encoded = self.ref_public.export_key(format='raw')
self.assertEqual(len(encoded), 56)
self.assertEqual(encoded, unhexlify(b'e2abae24ab8f65b01969e61f84fee615b525f413a90e3d727f71d0ffe60fb1d0a1a0285f2a7fd88789206e0aa4f3e9fcb9e4ba5d644e691e'))
def test_prng(self):
# Test that password-protected containers use the provided PRNG
encoded1 = self.ref_private.export_key(format="PEM",
passphrase="secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
randfunc=get_fixed_prng())
encoded2 = self.ref_private.export_key(format="PEM",
passphrase="secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
randfunc=get_fixed_prng())
self.assertEqual(encoded1, encoded2)
def test_byte_or_string_passphrase(self):
encoded1 = self.ref_private.export_key(format="PEM",
passphrase="secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
randfunc=get_fixed_prng())
encoded2 = self.ref_private.export_key(format="PEM",
passphrase=b"secret",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
randfunc=get_fixed_prng())
self.assertEqual(encoded1, encoded2)
def test_error_params1(self):
# Unknown format
self.assertRaises(ValueError, self.ref_private.export_key, format="XXX")
# Missing 'protection' parameter when PKCS#8 is used
self.assertRaises(ValueError,
self.ref_private.export_key,
format="PEM",
passphrase="secret")
# Empty password
self.assertRaises(ValueError,
self.ref_private.export_key,
format="PEM",
passphrase="",
use_pkcs8=False)
self.assertRaises(ValueError,
self.ref_private.export_key,
format="PEM",
passphrase="",
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
# No private keys with OpenSSH
self.assertRaises(ValueError,
self.ref_private.export_key,
format="OpenSSH",
passphrase="secret")
class TestImport_Curve448_Weak(unittest.TestCase):
def test_weak_pem(self):
p = 2**448 - 2**224 - 1
weak_x = (0,
1,
p - 1,
p,
p + 1)
for x in weak_x:
low_order_point = ECC.EccXPoint(x, "curve448")
weak_key = ECC.EccKey(point=low_order_point, curve="curve448")
encoded = weak_key.export_key(format="PEM")
self.assertRaises(ValueError,
ECC.import_key,
encoded)
def get_tests(config={}):
tests = []
try:
tests += list_test_cases(TestImport)
tests += list_test_cases(TestImport_Curve448)
tests += list_test_cases(TestExport_Curve448)
tests += list_test_cases(TestImport_Curve448_Weak)
except SkipTest:
pass
return tests
if __name__ == '__main__':
def suit():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,554 @@
# -*- coding: utf-8 -*-
#
# SelfTest/PublicKey/test_import_DSA.py: Self-test for importing DSA keys
#
# ===================================================================
# 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
import re
from Crypto.PublicKey import DSA
from Crypto.SelfTest.st_common import *
from Crypto.Util.py3compat import *
from binascii import unhexlify
class ImportKeyTests(unittest.TestCase):
y = 92137165128186062214622779787483327510946462589285775188003362705875131352591574106484271700740858696583623951844732128165434284507709057439633739849986759064015013893156866539696757799934634945787496920169462601722830899660681779448742875054459716726855443681559131362852474817534616736104831095601710736729
p = 162452170958135306109773853318304545923250830605675936228618290525164105310663722368377131295055868997377338797580997938253236213714988311430600065853662861806894003694743806769284131194035848116051021923956699231855223389086646903420682639786976554552864568460372266462812137447840653688476258666833303658691
q = 988791743931120302950649732173330531512663554851
g = 85583152299197514738065570254868711517748965097380456700369348466136657764813442044039878840094809620913085570225318356734366886985903212775602770761953571967834823306046501307810937486758039063386311593890777319935391363872375452381836756832784184928202587843258855704771836753434368484556809100537243908232
x = 540873410045082450874416847965843801027716145253
def setUp(self):
# It is easier to write test vectors in text form,
# and convert them to byte strigs dynamically here
for mname, mvalue in ImportKeyTests.__dict__.items():
if mname[:4] in ('der_', 'pem_', 'ssh_'):
if mname[:4] == 'der_':
mvalue = unhexlify(tobytes(mvalue))
mvalue = tobytes(mvalue)
setattr(self, mname, mvalue)
# 1. SubjectPublicKeyInfo
der_public=\
'308201b73082012b06072a8648ce3804013082011e02818100e756ee1717f4b6'+\
'794c7c214724a19763742c45572b4b3f8ff3b44f3be9f44ce039a2757695ec91'+\
'5697da74ef914fcd1b05660e2419c761d639f45d2d79b802dbd23e7ab8b81b47'+\
'9a380e1f30932584ba2a0b955032342ebc83cb5ca906e7b0d7cd6fe656cecb4c'+\
'8b5a77123a8c6750a481e3b06057aff6aa6eba620b832d60c3021500ad32f48c'+\
'd3ae0c45a198a61fa4b5e20320763b2302818079dfdc3d614fe635fceb7eaeae'+\
'3718dc2efefb45282993ac6749dc83c223d8c1887296316b3b0b54466cf444f3'+\
'4b82e3554d0b90a778faaf1306f025dae6a3e36c7f93dd5bac4052b92370040a'+\
'ca70b8d5820599711900efbc961812c355dd9beffe0981da85c5548074b41c56'+\
'ae43fd300d89262e4efd89943f99a651b03888038185000281810083352a69a1'+\
'32f34843d2a0eb995bff4e2f083a73f0049d2c91ea2f0ce43d144abda48199e4'+\
'b003c570a8af83303d45105f606c5c48d925a40ed9c2630c2fa4cdbf838539de'+\
'b9a29f919085f2046369f627ca84b2cb1e2c7940564b670f963ab1164d4e2ca2'+\
'bf6ffd39f12f548928bf4d2d1b5e6980b4f1be4c92a91986fba559'
def testImportKey1(self):
key_obj = DSA.importKey(self.der_public)
self.assertFalse(key_obj.has_private())
self.assertEqual(self.y, key_obj.y)
self.assertEqual(self.p, key_obj.p)
self.assertEqual(self.q, key_obj.q)
self.assertEqual(self.g, key_obj.g)
def testExportKey1(self):
tup = (self.y, self.g, self.p, self.q)
key = DSA.construct(tup)
encoded = key.export_key('DER')
self.assertEqual(self.der_public, encoded)
# 2.
pem_public="""\
-----BEGIN PUBLIC KEY-----
MIIBtzCCASsGByqGSM44BAEwggEeAoGBAOdW7hcX9LZ5THwhRyShl2N0LEVXK0s/
j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4uBtH
mjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47BgV6/2
qm66YguDLWDDAhUArTL0jNOuDEWhmKYfpLXiAyB2OyMCgYB539w9YU/mNfzrfq6u
NxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG8CXa
5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0tBxW
rkP9MA2JJi5O/YmUP5mmUbA4iAOBhQACgYEAgzUqaaEy80hD0qDrmVv/Ti8IOnPw
BJ0skeovDOQ9FEq9pIGZ5LADxXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTne
uaKfkZCF8gRjafYnyoSyyx4seUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmA
tPG+TJKpGYb7pVk=
-----END PUBLIC KEY-----"""
def testImportKey2(self):
for pem in (self.pem_public, tostr(self.pem_public)):
key_obj = DSA.importKey(pem)
self.assertFalse(key_obj.has_private())
self.assertEqual(self.y, key_obj.y)
self.assertEqual(self.p, key_obj.p)
self.assertEqual(self.q, key_obj.q)
self.assertEqual(self.g, key_obj.g)
def testExportKey2(self):
tup = (self.y, self.g, self.p, self.q)
key = DSA.construct(tup)
encoded = key.export_key('PEM')
self.assertEqual(self.pem_public, encoded)
# 3. OpenSSL/OpenSSH format
der_private=\
'308201bb02010002818100e756ee1717f4b6794c7c214724a19763742c45572b'+\
'4b3f8ff3b44f3be9f44ce039a2757695ec915697da74ef914fcd1b05660e2419'+\
'c761d639f45d2d79b802dbd23e7ab8b81b479a380e1f30932584ba2a0b955032'+\
'342ebc83cb5ca906e7b0d7cd6fe656cecb4c8b5a77123a8c6750a481e3b06057'+\
'aff6aa6eba620b832d60c3021500ad32f48cd3ae0c45a198a61fa4b5e2032076'+\
'3b2302818079dfdc3d614fe635fceb7eaeae3718dc2efefb45282993ac6749dc'+\
'83c223d8c1887296316b3b0b54466cf444f34b82e3554d0b90a778faaf1306f0'+\
'25dae6a3e36c7f93dd5bac4052b92370040aca70b8d5820599711900efbc9618'+\
'12c355dd9beffe0981da85c5548074b41c56ae43fd300d89262e4efd89943f99'+\
'a651b038880281810083352a69a132f34843d2a0eb995bff4e2f083a73f0049d'+\
'2c91ea2f0ce43d144abda48199e4b003c570a8af83303d45105f606c5c48d925'+\
'a40ed9c2630c2fa4cdbf838539deb9a29f919085f2046369f627ca84b2cb1e2c'+\
'7940564b670f963ab1164d4e2ca2bf6ffd39f12f548928bf4d2d1b5e6980b4f1'+\
'be4c92a91986fba55902145ebd9a3f0b82069d98420986b314215025756065'
def testImportKey3(self):
key_obj = DSA.importKey(self.der_private)
self.assertTrue(key_obj.has_private())
self.assertEqual(self.y, key_obj.y)
self.assertEqual(self.p, key_obj.p)
self.assertEqual(self.q, key_obj.q)
self.assertEqual(self.g, key_obj.g)
self.assertEqual(self.x, key_obj.x)
def testExportKey3(self):
tup = (self.y, self.g, self.p, self.q, self.x)
key = DSA.construct(tup)
encoded = key.export_key('DER', pkcs8=False)
self.assertEqual(self.der_private, encoded)
# 4.
pem_private="""\
-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQDnVu4XF/S2eUx8IUckoZdjdCxFVytLP4/ztE876fRM4DmidXaV
7JFWl9p075FPzRsFZg4kGcdh1jn0XS15uALb0j56uLgbR5o4Dh8wkyWEuioLlVAy
NC68g8tcqQbnsNfNb+ZWzstMi1p3EjqMZ1CkgeOwYFev9qpuumILgy1gwwIVAK0y
9IzTrgxFoZimH6S14gMgdjsjAoGAed/cPWFP5jX8636urjcY3C7++0UoKZOsZ0nc
g8Ij2MGIcpYxazsLVEZs9ETzS4LjVU0LkKd4+q8TBvAl2uaj42x/k91brEBSuSNw
BArKcLjVggWZcRkA77yWGBLDVd2b7/4JgdqFxVSAdLQcVq5D/TANiSYuTv2JlD+Z
plGwOIgCgYEAgzUqaaEy80hD0qDrmVv/Ti8IOnPwBJ0skeovDOQ9FEq9pIGZ5LAD
xXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTneuaKfkZCF8gRjafYnyoSyyx4s
eUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmAtPG+TJKpGYb7pVkCFF69mj8L
ggadmEIJhrMUIVAldWBl
-----END DSA PRIVATE KEY-----"""
def testImportKey4(self):
for pem in (self.pem_private, tostr(self.pem_private)):
key_obj = DSA.importKey(pem)
self.assertTrue(key_obj.has_private())
self.assertEqual(self.y, key_obj.y)
self.assertEqual(self.p, key_obj.p)
self.assertEqual(self.q, key_obj.q)
self.assertEqual(self.g, key_obj.g)
self.assertEqual(self.x, key_obj.x)
def testExportKey4(self):
tup = (self.y, self.g, self.p, self.q, self.x)
key = DSA.construct(tup)
encoded = key.export_key('PEM', pkcs8=False)
self.assertEqual(self.pem_private, encoded)
# 5. PKCS8 (unencrypted)
der_pkcs8=\
'3082014a0201003082012b06072a8648ce3804013082011e02818100e756ee17'+\
'17f4b6794c7c214724a19763742c45572b4b3f8ff3b44f3be9f44ce039a27576'+\
'95ec915697da74ef914fcd1b05660e2419c761d639f45d2d79b802dbd23e7ab8'+\
'b81b479a380e1f30932584ba2a0b955032342ebc83cb5ca906e7b0d7cd6fe656'+\
'cecb4c8b5a77123a8c6750a481e3b06057aff6aa6eba620b832d60c3021500ad'+\
'32f48cd3ae0c45a198a61fa4b5e20320763b2302818079dfdc3d614fe635fceb'+\
'7eaeae3718dc2efefb45282993ac6749dc83c223d8c1887296316b3b0b54466c'+\
'f444f34b82e3554d0b90a778faaf1306f025dae6a3e36c7f93dd5bac4052b923'+\
'70040aca70b8d5820599711900efbc961812c355dd9beffe0981da85c5548074'+\
'b41c56ae43fd300d89262e4efd89943f99a651b03888041602145ebd9a3f0b82'+\
'069d98420986b314215025756065'
def testImportKey5(self):
key_obj = DSA.importKey(self.der_pkcs8)
self.assertTrue(key_obj.has_private())
self.assertEqual(self.y, key_obj.y)
self.assertEqual(self.p, key_obj.p)
self.assertEqual(self.q, key_obj.q)
self.assertEqual(self.g, key_obj.g)
self.assertEqual(self.x, key_obj.x)
def testExportKey5(self):
tup = (self.y, self.g, self.p, self.q, self.x)
key = DSA.construct(tup)
encoded = key.export_key('DER')
self.assertEqual(self.der_pkcs8, encoded)
encoded = key.export_key('DER', pkcs8=True)
self.assertEqual(self.der_pkcs8, encoded)
# 6.
pem_pkcs8="""\
-----BEGIN PRIVATE KEY-----
MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBAOdW7hcX9LZ5THwhRyShl2N0LEVX
K0s/j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4
uBtHmjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47Bg
V6/2qm66YguDLWDDAhUArTL0jNOuDEWhmKYfpLXiAyB2OyMCgYB539w9YU/mNfzr
fq6uNxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG
8CXa5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0
tBxWrkP9MA2JJi5O/YmUP5mmUbA4iAQWAhRevZo/C4IGnZhCCYazFCFQJXVgZQ==
-----END PRIVATE KEY-----"""
def testImportKey6(self):
for pem in (self.pem_pkcs8, tostr(self.pem_pkcs8)):
key_obj = DSA.importKey(pem)
self.assertTrue(key_obj.has_private())
self.assertEqual(self.y, key_obj.y)
self.assertEqual(self.p, key_obj.p)
self.assertEqual(self.q, key_obj.q)
self.assertEqual(self.g, key_obj.g)
self.assertEqual(self.x, key_obj.x)
def testExportKey6(self):
tup = (self.y, self.g, self.p, self.q, self.x)
key = DSA.construct(tup)
encoded = key.export_key('PEM')
self.assertEqual(self.pem_pkcs8, encoded)
encoded = key.export_key('PEM', pkcs8=True)
self.assertEqual(self.pem_pkcs8, encoded)
# 7. OpenSSH/RFC4253
ssh_pub="""ssh-dss AAAAB3NzaC1kc3MAAACBAOdW7hcX9LZ5THwhRyShl2N0LEVXK0s/j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4uBtHmjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47BgV6/2qm66YguDLWDDAAAAFQCtMvSM064MRaGYph+kteIDIHY7IwAAAIB539w9YU/mNfzrfq6uNxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG8CXa5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0tBxWrkP9MA2JJi5O/YmUP5mmUbA4iAAAAIEAgzUqaaEy80hD0qDrmVv/Ti8IOnPwBJ0skeovDOQ9FEq9pIGZ5LADxXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTneuaKfkZCF8gRjafYnyoSyyx4seUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmAtPG+TJKpGYb7pVk="""
def testImportKey7(self):
for ssh in (self.ssh_pub, tostr(self.ssh_pub)):
key_obj = DSA.importKey(ssh)
self.assertFalse(key_obj.has_private())
self.assertEqual(self.y, key_obj.y)
self.assertEqual(self.p, key_obj.p)
self.assertEqual(self.q, key_obj.q)
self.assertEqual(self.g, key_obj.g)
def testExportKey7(self):
tup = (self.y, self.g, self.p, self.q)
key = DSA.construct(tup)
encoded = key.export_key('OpenSSH')
self.assertEqual(self.ssh_pub, encoded)
# 8. Encrypted OpenSSL/OpenSSH
pem_private_encrypted="""\
-----BEGIN DSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,70B6908939D65E9F2EB999E8729788CE
4V6GHRDpCrdZ8MBjbyp5AlGUrjvr2Pn2e2zVxy5RBt4FBj9/pa0ae0nnyUPMLSUU
kKyOR0topRYTVRLElm4qVrb5uNZ3hRwfbklr+pSrB7O9eHz9V5sfOQxyODS07JxK
k1OdOs70/ouMXLF9EWfAZOmWUccZKHNblUwg1p1UrZIz5jXw4dUE/zqhvXh6d+iC
ADsICaBCjCrRQJKDp50h3+ndQjkYBKVH+pj8TiQ79U7lAvdp3+iMghQN6YXs9mdI
gFpWw/f97oWM4GHZFqHJ+VSMNFjBiFhAvYV587d7Lk4dhD8sCfbxj42PnfRgUItc
nnPqHxmhMQozBWzYM4mQuo3XbF2WlsNFbOzFVyGhw1Bx1s91qvXBVWJh2ozrW0s6
HYDV7ZkcTml/4kjA/d+mve6LZ8kuuR1qCiZx6rkffhh1gDN/1Xz3HVvIy/dQ+h9s
5zp7PwUoWbhqp3WCOr156P6gR8qo7OlT6wMh33FSXK/mxikHK136fV2shwTKQVII
rJBvXpj8nACUmi7scKuTWGeUoXa+dwTZVVe+b+L2U1ZM7+h/neTJiXn7u99PFUwu
xVJtxaV37m3aXxtCsPnbBg==
-----END DSA PRIVATE KEY-----"""
def testImportKey8(self):
for pem in (self.pem_private_encrypted, tostr(self.pem_private_encrypted)):
key_obj = DSA.importKey(pem, "PWDTEST")
self.assertTrue(key_obj.has_private())
self.assertEqual(self.y, key_obj.y)
self.assertEqual(self.p, key_obj.p)
self.assertEqual(self.q, key_obj.q)
self.assertEqual(self.g, key_obj.g)
self.assertEqual(self.x, key_obj.x)
def testExportKey8(self):
tup = (self.y, self.g, self.p, self.q, self.x)
key = DSA.construct(tup)
encoded = key.export_key('PEM', pkcs8=False, passphrase="PWDTEST")
key = DSA.importKey(encoded, "PWDTEST")
self.assertEqual(self.y, key.y)
self.assertEqual(self.p, key.p)
self.assertEqual(self.q, key.q)
self.assertEqual(self.g, key.g)
self.assertEqual(self.x, key.x)
# 9. Encrypted PKCS8
# pbeWithMD5AndDES-CBC
pem_pkcs8_encrypted="""\
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBcTAbBgkqhkiG9w0BBQMwDgQI0GC3BJ/jSw8CAggABIIBUHc1cXZpExIE9tC7
7ryiW+5ihtF2Ekurq3e408GYSAu5smJjN2bvQXmzRFBz8W38K8eMf1sbWroZ4+zn
kZSbb9nSm5kAa8lR2+oF2k+WRswMR/PTC3f/D9STO2X0QxdrzKgIHEcSGSHp5jTx
aVvbkCDHo9vhBTl6S3ogZ48As/MEro76+9igUwJ1jNhIQZPJ7e20QH5qDpQFFJN4
CKl2ENSEuwGiqBszItFy4dqH0g63ZGZV/xt9wSO9Rd7SK/EbA/dklOxBa5Y/VItM
gnIhs9XDMoGYyn6F023EicNJm6g/bVQk81BTTma4tm+12TKGdYm+QkeZvCOMZylr
Wv67cKwO3cAXt5C3QXMDgYR64XvuaT5h7C0igMp2afSXJlnbHEbFxQVJlv83T4FM
eZ4k+NQDbEL8GiHmFxzDWQAuPPZKJWEEEV2p/To+WOh+kSDHQw==
-----END ENCRYPTED PRIVATE KEY-----"""
def testImportKey9(self):
for pem in (self.pem_pkcs8_encrypted, tostr(self.pem_pkcs8_encrypted)):
key_obj = DSA.importKey(pem, "PWDTEST")
self.assertTrue(key_obj.has_private())
self.assertEqual(self.y, key_obj.y)
self.assertEqual(self.p, key_obj.p)
self.assertEqual(self.q, key_obj.q)
self.assertEqual(self.g, key_obj.g)
self.assertEqual(self.x, key_obj.x)
# 10. Encrypted PKCS8
# pkcs5PBES2 /
# pkcs5PBKDF2 (rounds=1000, salt=D725BF1B6B8239F4) /
# des-EDE3-CBC (iv=27A1C66C42AFEECE)
#
der_pkcs8_encrypted=\
'30820196304006092a864886f70d01050d3033301b06092a864886f70d01050c'+\
'300e0408d725bf1b6b8239f4020203e8301406082a864886f70d0307040827a1'+\
'c66c42afeece048201505cacfde7bf8edabb3e0d387950dc872662ea7e9b1ed4'+\
'400d2e7e6186284b64668d8d0328c33a9d9397e6f03df7cb68268b0a06b4e22f'+\
'7d132821449ecf998a8b696dbc6dd2b19e66d7eb2edfeb4153c1771d49702395'+\
'4f36072868b5fcccf93413a5ac4b2eb47d4b3f681c6bd67ae363ed776f45ae47'+\
'174a00098a7c930a50f820b227ddf50f9742d8e950d02586ff2dac0e3c372248'+\
'e5f9b6a7a02f4004f20c87913e0f7b52bccc209b95d478256a890b31d4c9adec'+\
'21a4d157a179a93a3dad06f94f3ce486b46dfa7fc15fd852dd7680bbb2f17478'+\
'7e71bd8dbaf81eca7518d76c1d26256e95424864ba45ca5d47d7c5a421be02fa'+\
'b94ab01e18593f66cf9094eb5c94b9ecf3aa08b854a195cf87612fbe5e96c426'+\
'2b0d573e52dc71ba3f5e468c601e816c49b7d32c698b22175e89aaef0c443770'+\
'5ef2f88a116d99d8e2869a4fd09a771b84b49e4ccb79aadcb1c9'
def testImportKey10(self):
key_obj = DSA.importKey(self.der_pkcs8_encrypted, "PWDTEST")
self.assertTrue(key_obj.has_private())
self.assertEqual(self.y, key_obj.y)
self.assertEqual(self.p, key_obj.p)
self.assertEqual(self.q, key_obj.q)
self.assertEqual(self.g, key_obj.g)
self.assertEqual(self.x, key_obj.x)
def testExportKey10(self):
tup = (self.y, self.g, self.p, self.q, self.x)
key = DSA.construct(tup)
randfunc = BytesIO(unhexlify(b("27A1C66C42AFEECE") + b("D725BF1B6B8239F4"))).read
encoded = key.export_key('DER', pkcs8=True, passphrase="PWDTEST", randfunc=randfunc)
self.assertEqual(self.der_pkcs8_encrypted, encoded)
# ----
def testImportError1(self):
self.assertRaises(ValueError, DSA.importKey, self.der_pkcs8_encrypted, "wrongpwd")
def testExportError2(self):
tup = (self.y, self.g, self.p, self.q, self.x)
key = DSA.construct(tup)
self.assertRaises(ValueError, key.export_key, 'DER', pkcs8=False, passphrase="PWDTEST")
def test_import_key(self):
"""Verify importKey is an alias to import_key"""
key_obj = DSA.import_key(self.der_public)
self.assertFalse(key_obj.has_private())
self.assertEqual(self.y, key_obj.y)
self.assertEqual(self.p, key_obj.p)
self.assertEqual(self.q, key_obj.q)
self.assertEqual(self.g, key_obj.g)
def test_exportKey(self):
tup = (self.y, self.g, self.p, self.q, self.x)
key = DSA.construct(tup)
self.assertEqual(key.exportKey(), key.export_key())
def test_import_empty(self):
self.assertRaises(ValueError, DSA.import_key, b'')
class ImportKeyFromX509Cert(unittest.TestCase):
def test_x509v1(self):
# Sample V1 certificate with a 1024 bit DSA key
x509_v1_cert = """
-----BEGIN CERTIFICATE-----
MIIDUjCCArsCAQIwDQYJKoZIhvcNAQEFBQAwfjENMAsGA1UEChMEQWNtZTELMAkG
A1UECxMCUkQxHDAaBgkqhkiG9w0BCQEWDXNwYW1AYWNtZS5vcmcxEzARBgNVBAcT
Ck1ldHJvcG9saXMxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYDVQQGEwJVUzENMAsG
A1UEAxMEdGVzdDAeFw0xNDA3MTEyMDM4NDNaFw0xNzA0MDYyMDM4NDNaME0xCzAJ
BgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazENMAsGA1UEChMEQWNtZTELMAkG
A1UECxMCUkQxDzANBgNVBAMTBnBvbGFuZDCCAbYwggErBgcqhkjOOAQBMIIBHgKB
gQDOrN4Ox4+t3T6wKeHfhzArhcrNEFMQ4Ss+4PIKyimDy9Bn64WPkL1B/9dvYIga
23GLu6tVJmXo6EdJnVOHEMhr99EeOwuDWWeP7Awq7RSlKEejokr4BEzMTW/tExSD
cO6/GI7xzh0eTH+VTTPDfyrJMYCkh0rJAfCP+5xrmPNetwIVALtXYOV1yoRrzJ2Q
M5uEjidH6GiZAoGAfUqA1SAm5g5U68SILMVX9l5rq0OpB0waBMpJQ31/R/yXNDqo
c3gGWZTOJFU4IzwNpGhrGNADUByz/lc1SAOAdEJIr0JVrhbGewQjB4pWqoLGbBKz
RoavTNDc/zD7SYa12evWDHADwvlXoeQg+lWop1zS8OqaDC7aLGKpWN3/m8kDgYQA
AoGAKoirPAfcp1rbbl4y2FFAIktfW8f4+T7d2iKSg73aiVfujhNOt1Zz1lfC0NI2
eonLWO3tAM4XGKf1TLjb5UXngGn40okPsaA81YE6ZIKm20ywjlOY3QkAEdMaLVY3
9PJvM8RGB9m7pLKxyHfGMfF40MVN4222zKeGp7xhM0CNiCUwDQYJKoZIhvcNAQEF
BQADgYEAfbNZfpYa2KlALEM1FZnwvQDvJHntHz8LdeJ4WM7CXDlKi67wY2HKM30w
s2xej75imkVOFd1kF2d0A8sjfriXLVIt1Hwq9ANZomhu4Edx0xpH8tqdh/bDtnM2
TmduZNY9OWkb07h0CtWD6Zt8fhRllVsSSrlWd/2or7FXNC5weFQ=
-----END CERTIFICATE-----
""".strip()
# DSA public key as dumped by openssl
y_str = """
2a:88:ab:3c:07:dc:a7:5a:db:6e:5e:32:d8:51:40:
22:4b:5f:5b:c7:f8:f9:3e:dd:da:22:92:83:bd:da:
89:57:ee:8e:13:4e:b7:56:73:d6:57:c2:d0:d2:36:
7a:89:cb:58:ed:ed:00:ce:17:18:a7:f5:4c:b8:db:
e5:45:e7:80:69:f8:d2:89:0f:b1:a0:3c:d5:81:3a:
64:82:a6:db:4c:b0:8e:53:98:dd:09:00:11:d3:1a:
2d:56:37:f4:f2:6f:33:c4:46:07:d9:bb:a4:b2:b1:
c8:77:c6:31:f1:78:d0:c5:4d:e3:6d:b6:cc:a7:86:
a7:bc:61:33:40:8d:88:25
"""
p_str = """
00:ce:ac:de:0e:c7:8f:ad:dd:3e:b0:29:e1:df:87:
30:2b:85:ca:cd:10:53:10:e1:2b:3e:e0:f2:0a:ca:
29:83:cb:d0:67:eb:85:8f:90:bd:41:ff:d7:6f:60:
88:1a:db:71:8b:bb:ab:55:26:65:e8:e8:47:49:9d:
53:87:10:c8:6b:f7:d1:1e:3b:0b:83:59:67:8f:ec:
0c:2a:ed:14:a5:28:47:a3:a2:4a:f8:04:4c:cc:4d:
6f:ed:13:14:83:70:ee:bf:18:8e:f1:ce:1d:1e:4c:
7f:95:4d:33:c3:7f:2a:c9:31:80:a4:87:4a:c9:01:
f0:8f:fb:9c:6b:98:f3:5e:b7
"""
q_str = """
00:bb:57:60:e5:75:ca:84:6b:cc:9d:90:33:9b:84:
8e:27:47:e8:68:99
"""
g_str = """
7d:4a:80:d5:20:26:e6:0e:54:eb:c4:88:2c:c5:57:
f6:5e:6b:ab:43:a9:07:4c:1a:04:ca:49:43:7d:7f:
47:fc:97:34:3a:a8:73:78:06:59:94:ce:24:55:38:
23:3c:0d:a4:68:6b:18:d0:03:50:1c:b3:fe:57:35:
48:03:80:74:42:48:af:42:55:ae:16:c6:7b:04:23:
07:8a:56:aa:82:c6:6c:12:b3:46:86:af:4c:d0:dc:
ff:30:fb:49:86:b5:d9:eb:d6:0c:70:03:c2:f9:57:
a1:e4:20:fa:55:a8:a7:5c:d2:f0:ea:9a:0c:2e:da:
2c:62:a9:58:dd:ff:9b:c9
"""
key = DSA.importKey(x509_v1_cert)
for comp_name in ('y', 'p', 'q', 'g'):
comp_str = locals()[comp_name + "_str"]
comp = int(re.sub("[^0-9a-f]", "", comp_str), 16)
self.assertEqual(getattr(key, comp_name), comp)
self.assertFalse(key.has_private())
def test_x509v3(self):
# Sample V3 certificate with a 1024 bit DSA key
x509_v3_cert = """
-----BEGIN CERTIFICATE-----
MIIFhjCCA26gAwIBAgIBAzANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEL
MAkGA1UECAwCTUQxEjAQBgNVBAcMCUJhbHRpbW9yZTEQMA4GA1UEAwwHVGVzdCBD
QTEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0xNDA3MTMyMDUz
MjBaFw0xNzA0MDgyMDUzMjBaMEAxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNRDES
MBAGA1UEBwwJQmFsdGltb3JlMRAwDgYDVQQDDAdhdXN0cmlhMIIBtjCCASsGByqG
SM44BAEwggEeAoGBALfd8gyEpVPA0ZI69Kp3nyJcu5N0ZZ3K1K9hleQLNqKEcZOh
7a/C2J1TPdmHTLJ0rAwBZ1nWxnARSgRphziGDFspKCYQwYcSMz8KoFgvXbXpuchy
oFACiQ2LqZnc5MakuLQtLcQciSYGYj3zmZdYMoa904F1aDWr+DxQI6DVC3/bAhUA
hqXMCJ6fQK3G2O9S3/CC/yVZXCsCgYBRXROl3R2khX7l10LQjDEgo3B1IzjXU/jP
McMBl6XO+nBJXxr/scbq8Ajiv7LTnGpSjgryHtvfj887kfvo8QbSS3kp3vq5uSqI
ui7E7r3jguWaLj616AG1HWOctXJUjqsiabZwsp2h09gHTzmHEXBOmiARu8xFxKAH
xsuo7onAbwOBhAACgYBylWjWSnKHE8mHx1A5m/0GQx6xnhWIe3+MJAnEhRGxA2J4
SCsfWU0OwglIQToh1z5uUU9oDi9cYgNPBevOFRnDhc2yaJY6VAYnI+D+6J5IU6Yd
0iaG/iSc4sV4bFr0axcPpse3SN0XaQxiKeSFBfFnoMqL+dd9Gb3QPZSllBcVD6OB
1TCB0jAdBgNVHQ4EFgQUx5wN0Puotv388M9Tp/fsPbZpzAUwHwYDVR0jBBgwFoAU
a0hkif3RMaraiWtsOOZZlLu9wJwwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwSgYD
VR0RBEMwQYILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNvbYIQbWFpbC5leGFt
cGxlLmNvbYIPZnRwLmV4YW1wbGUuY29tMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM
IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAgEAyWf1TiJI
aNEIA9o/PG8/JiGASTS2/HBVTJbkq03k6NkJVk/GxC1DPziTUJ+CdWlHWcAi1EOW
Ach3QxNDRrVfCOfCMDgElIO1094/reJgdFYG00LRi8QkRJuxANV7YS4tLudhyHJC
kR2lhdMNmEuzWK+s2y+5cLrdm7qdvdENQCcV67uvGPx4sc+EaE7x13SczKjWBtbo
QCs6JTOW+EkPRl4Zo27K4OIZ43/J+GxvwU9QUVH3wPVdbbLNw+QeTFBYMTEcxyc4
kv50HPBFaithziXBFyvdIs19FjkFzu0Uz/e0zb1+vMzQlJMD94HVOrMnIj5Sb2cL
KKdYXS4uhxFJmdV091Xur5JkYYwEzuaGav7J3zOzYutrIGTgDluLCvA+VQkRcTsy
jZ065SkY/v+38QHp+cmm8WRluupJTs8wYzVp6Fu0iFaaK7ztFmaZmHpiPIfDFjva
aCIgzzT5NweJd/b71A2SyzHXJ14zBXsr1PMylMp2TpHIidhuuNuQL6I0HaollB4M
Z3FsVBMhVDw4Z76qnFPr8mZE2tar33hSlJI/3pS/bBiukuBk8U7VB0X8OqaUnP3C
7b2Z4G8GtqDVcKGMzkvMjT4n9rKd/Le+qHSsQOGO9W/0LB7UDAZSwUsfAPnoBgdS
5t9tIomLCOstByXi+gGZue1TcdCa3Ph4kO0=
-----END CERTIFICATE-----
""".strip()
# DSA public key as dumped by openssl
y_str = """
72:95:68:d6:4a:72:87:13:c9:87:c7:50:39:9b:fd:
06:43:1e:b1:9e:15:88:7b:7f:8c:24:09:c4:85:11:
b1:03:62:78:48:2b:1f:59:4d:0e:c2:09:48:41:3a:
21:d7:3e:6e:51:4f:68:0e:2f:5c:62:03:4f:05:eb:
ce:15:19:c3:85:cd:b2:68:96:3a:54:06:27:23:e0:
fe:e8:9e:48:53:a6:1d:d2:26:86:fe:24:9c:e2:c5:
78:6c:5a:f4:6b:17:0f:a6:c7:b7:48:dd:17:69:0c:
62:29:e4:85:05:f1:67:a0:ca:8b:f9:d7:7d:19:bd:
d0:3d:94:a5:94:17:15:0f
"""
p_str = """
00:b7:dd:f2:0c:84:a5:53:c0:d1:92:3a:f4:aa:77:
9f:22:5c:bb:93:74:65:9d:ca:d4:af:61:95:e4:0b:
36:a2:84:71:93:a1:ed:af:c2:d8:9d:53:3d:d9:87:
4c:b2:74:ac:0c:01:67:59:d6:c6:70:11:4a:04:69:
87:38:86:0c:5b:29:28:26:10:c1:87:12:33:3f:0a:
a0:58:2f:5d:b5:e9:b9:c8:72:a0:50:02:89:0d:8b:
a9:99:dc:e4:c6:a4:b8:b4:2d:2d:c4:1c:89:26:06:
62:3d:f3:99:97:58:32:86:bd:d3:81:75:68:35:ab:
f8:3c:50:23:a0:d5:0b:7f:db
"""
q_str = """
00:86:a5:cc:08:9e:9f:40:ad:c6:d8:ef:52:df:f0:
82:ff:25:59:5c:2b
"""
g_str = """
51:5d:13:a5:dd:1d:a4:85:7e:e5:d7:42:d0:8c:31:
20:a3:70:75:23:38:d7:53:f8:cf:31:c3:01:97:a5:
ce:fa:70:49:5f:1a:ff:b1:c6:ea:f0:08:e2:bf:b2:
d3:9c:6a:52:8e:0a:f2:1e:db:df:8f:cf:3b:91:fb:
e8:f1:06:d2:4b:79:29:de:fa:b9:b9:2a:88:ba:2e:
c4:ee:bd:e3:82:e5:9a:2e:3e:b5:e8:01:b5:1d:63:
9c:b5:72:54:8e:ab:22:69:b6:70:b2:9d:a1:d3:d8:
07:4f:39:87:11:70:4e:9a:20:11:bb:cc:45:c4:a0:
07:c6:cb:a8:ee:89:c0:6f
"""
key = DSA.importKey(x509_v3_cert)
for comp_name in ('y', 'p', 'q', 'g'):
comp_str = locals()[comp_name + "_str"]
comp = int(re.sub("[^0-9a-f]", "", comp_str), 16)
self.assertEqual(getattr(key, comp_name), comp)
self.assertFalse(key.has_private())
if __name__ == '__main__':
unittest.main()
def get_tests(config={}):
tests = []
tests += list_test_cases(ImportKeyTests)
tests += list_test_cases(ImportKeyFromX509Cert)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,636 @@
# -*- coding: utf-8 -*-
#
# SelfTest/PublicKey/test_importKey.py: Self-test for importing RSA keys
#
# ===================================================================
# 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 os
import re
import errno
import warnings
import unittest
from unittest import SkipTest
from Crypto.PublicKey import RSA
from Crypto.SelfTest.st_common import a2b_hex, list_test_cases
from Crypto.IO import PEM
from Crypto.Util.py3compat import b, tostr, FileNotFoundError
from Crypto.Util.number import inverse
from Crypto.Util import asn1
try:
import pycryptodome_test_vectors # type: ignore
test_vectors_available = True
except ImportError:
test_vectors_available = False
def load_file(file_name, mode="rb"):
results = None
try:
if not test_vectors_available:
raise FileNotFoundError(errno.ENOENT,
os.strerror(errno.ENOENT),
file_name)
dir_comps = ("PublicKey", "RSA")
init_dir = os.path.dirname(pycryptodome_test_vectors.__file__)
full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name)
with open(full_file_name, mode) as file_in:
results = file_in.read()
except FileNotFoundError:
warnings.warn("Skipping tests for RSA based on %s" % file_name,
UserWarning,
stacklevel=2)
if results is None:
raise SkipTest("Missing %s" % file_name)
return results
def der2pem(der, text='PUBLIC'):
import binascii
chunks = [binascii.b2a_base64(der[i:i+48]) for i in range(0, len(der), 48)]
pem = b('-----BEGIN %s KEY-----\n' % text)
pem += b('').join(chunks)
pem += b('-----END %s KEY-----' % text)
return pem
class ImportKeyTests(unittest.TestCase):
# 512-bit RSA key generated with openssl
rsaKeyPEM = u'''-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII
q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8
Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI
OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr
+rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK
JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9
n0CnZCJ6IZYqSt0H5N7+Q+2Ro64nuwV/OSQfM6sBwQ==
-----END RSA PRIVATE KEY-----'''
# As above, but this is actually an unencrypted PKCS#8 key
rsaKeyPEM8 = u'''-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvx4nkAqgiyNRGlwS
ga5tkzEsPv6RP5MuvtSS8S0WtGEMMoy24girX0WsvilQgzKY8xIsGfeEkt7fQPDj
wZAzhQIDAQABAkAJRIMSnxFN7fZ+2rwjAbxaiOXmYB3XAWIg6tn9S/xv3rdYk4mK
5BxU3b2/FTn4zL0Y9ntEDeGsMEQCgdQM+sg5AiEA8g8vPh2mGIP2KYCSK9jfVFzk
B8cmJBEDteLFNyMSSiMCIQDKH+kkeSz8yWv6t080Smi0GN9XgzgGSAYAD+KlyZoC
NwIhAIe+HDApUEvPNOxxPYd5R0R4EyiJdcokAICvewlAkbEhAiBqtGn6bVZIpXUx
yLAxpM6dtTvDEWz0M/Wm9rvqVgHOBQIhAL2fQKdkInohlipK3Qfk3v5D7ZGjrie7
BX85JB8zqwHB
-----END PRIVATE KEY-----'''
# The same RSA private key as in rsaKeyPEM, but now encrypted
rsaKeyEncryptedPEM = (
# PEM encryption
# With DES and passphrase 'test'
('test', u'''-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-CBC,AF8F9A40BD2FA2FC
Ckl9ex1kaVEWhYC2QBmfaF+YPiR4NFkRXA7nj3dcnuFEzBnY5XULupqQpQI3qbfA
u8GYS7+b3toWWiHZivHbAAUBPDIZG9hKDyB9Sq2VMARGsX1yW1zhNvZLIiVJzUHs
C6NxQ1IJWOXzTew/xM2I26kPwHIvadq+/VaT8gLQdjdH0jOiVNaevjWnLgrn1mLP
BCNRMdcexozWtAFNNqSzfW58MJL2OdMi21ED184EFytIc1BlB+FZiGZduwKGuaKy
9bMbdb/1PSvsSzPsqW7KSSrTw6MgJAFJg6lzIYvR5F4poTVBxwBX3+EyEmShiaNY
IRX3TgQI0IjrVuLmvlZKbGWP18FXj7I7k9tSsNOOzllTTdq3ny5vgM3A+ynfAaxp
dysKznQ6P+IoqML1WxAID4aGRMWka+uArOJ148Rbj9s=
-----END RSA PRIVATE KEY-----'''),
# PKCS8 encryption
('winter', u'''-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeZIsbW3O+JcCAggA
MBQGCCqGSIb3DQMHBAgSM2p0D8FilgSCAWBhFyP2tiGKVpGj3mO8qIBzinU60ApR
3unvP+N6j7LVgnV2lFGaXbJ6a1PbQXe+2D6DUyBLo8EMXrKKVLqOMGkFMHc0UaV6
R6MmrsRDrbOqdpTuVRW+NVd5J9kQQh4xnfU/QrcPPt7vpJvSf4GzG0n666Ki50OV
M/feuVlIiyGXY6UWdVDpcOV72cq02eNUs/1JWdh2uEBvA9fCL0c07RnMrdT+CbJQ
NjJ7f8ULtp7xvR9O3Al/yJ4Wv3i4VxF1f3MCXzhlUD4I0ONlr0kJWgeQ80q/cWhw
ntvgJwnCn2XR1h6LA8Wp+0ghDTsL2NhJpWd78zClGhyU4r3hqu1XDjoXa7YCXCix
jCV15+ViDJzlNCwg+W6lRg18sSLkCT7alviIE0U5tHc6UPbbHwT5QqAxAABaP+nZ
CGqJGyiwBzrKebjgSm/KRd4C91XqcsysyH2kKPfT51MLAoD4xelOURBP
-----END ENCRYPTED PRIVATE KEY-----'''
),
)
rsaPublicKeyPEM = u'''-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+T
Lr7UkvEtFrRhDDKMtuIIq19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQ==
-----END PUBLIC KEY-----'''
# Obtained using 'ssh-keygen -i -m PKCS8 -f rsaPublicKeyPEM'
rsaPublicKeyOpenSSH = b('''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQC/HieQCqCLI1EaXBKBrm2TMSw+/pE/ky6+1JLxLRa0YQwyjLbiCKtfRay+KVCDMpjzEiwZ94SS3t9A8OPBkDOF comment\n''')
# The private key, in PKCS#1 format encoded with DER
rsaKeyDER = a2b_hex(
'''3082013b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe
913f932ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f312
2c19f78492dedf40f0e3c190338502030100010240094483129f114dedf6
7edabc2301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c
54ddbdbf1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f
2f3e1da61883f62980922bd8df545ce407c726241103b5e2c53723124a23
022100ca1fe924792cfcc96bfab74f344a68b418df578338064806000fe2
a5c99a023702210087be1c3029504bcf34ec713d877947447813288975ca
240080af7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53b
c3116cf433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07
e4defe43ed91a3ae27bb057f39241f33ab01c1
'''.replace(" ",""))
# The private key, in unencrypted PKCS#8 format encoded with DER
rsaKeyDER8 = a2b_hex(
'''30820155020100300d06092a864886f70d01010105000482013f3082013
b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe913f932
ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f3122c19f78
492dedf40f0e3c190338502030100010240094483129f114dedf67edabc2
301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c54ddbdb
f1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f2f3e1da
61883f62980922bd8df545ce407c726241103b5e2c53723124a23022100c
a1fe924792cfcc96bfab74f344a68b418df578338064806000fe2a5c99a0
23702210087be1c3029504bcf34ec713d877947447813288975ca240080a
f7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53bc3116cf
433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07e4defe4
3ed91a3ae27bb057f39241f33ab01c1
'''.replace(" ",""))
rsaPublicKeyDER = a2b_hex(
'''305c300d06092a864886f70d0101010500034b003048024100bf1e27900a
a08b23511a5c1281ae6d93312c3efe913f932ebed492f12d16b4610c328c
b6e208ab5f45acbe2950833298f3122c19f78492dedf40f0e3c190338502
03010001
'''.replace(" ",""))
n = int('BF 1E 27 90 0A A0 8B 23 51 1A 5C 12 81 AE 6D 93 31 2C 3E FE 91 3F 93 2E BE D4 92 F1 2D 16 B4 61 0C 32 8C B6 E2 08 AB 5F 45 AC BE 29 50 83 32 98 F3 12 2C 19 F7 84 92 DE DF 40 F0 E3 C1 90 33 85'.replace(" ",""),16)
e = 65537
d = int('09 44 83 12 9F 11 4D ED F6 7E DA BC 23 01 BC 5A 88 E5 E6 60 1D D7 01 62 20 EA D9 FD 4B FC 6F DE B7 58 93 89 8A E4 1C 54 DD BD BF 15 39 F8 CC BD 18 F6 7B 44 0D E1 AC 30 44 02 81 D4 0C FA C8 39'.replace(" ",""),16)
p = int('00 F2 0F 2F 3E 1D A6 18 83 F6 29 80 92 2B D8 DF 54 5C E4 07 C7 26 24 11 03 B5 E2 C5 37 23 12 4A 23'.replace(" ",""),16)
q = int('00 CA 1F E9 24 79 2C FC C9 6B FA B7 4F 34 4A 68 B4 18 DF 57 83 38 06 48 06 00 0F E2 A5 C9 9A 02 37'.replace(" ",""),16)
# This is q^{-1} mod p). fastmath and slowmath use pInv (p^{-1}
# mod q) instead!
qInv = int('00 BD 9F 40 A7 64 22 7A 21 96 2A 4A DD 07 E4 DE FE 43 ED 91 A3 AE 27 BB 05 7F 39 24 1F 33 AB 01 C1'.replace(" ",""),16)
pInv = inverse(p,q)
def testImportKey1(self):
"""Verify import of RSAPrivateKey DER SEQUENCE"""
key = RSA.importKey(self.rsaKeyDER)
self.assertTrue(key.has_private())
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
self.assertEqual(key.d, self.d)
self.assertEqual(key.p, self.p)
self.assertEqual(key.q, self.q)
def testImportKey2(self):
"""Verify import of SubjectPublicKeyInfo DER SEQUENCE"""
key = RSA.importKey(self.rsaPublicKeyDER)
self.assertFalse(key.has_private())
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
def testImportKey3unicode(self):
"""Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unicode"""
key = RSA.importKey(self.rsaKeyPEM)
self.assertEqual(key.has_private(),True) # assert_
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
self.assertEqual(key.d, self.d)
self.assertEqual(key.p, self.p)
self.assertEqual(key.q, self.q)
def testImportKey3bytes(self):
"""Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as byte string"""
key = RSA.importKey(b(self.rsaKeyPEM))
self.assertEqual(key.has_private(),True) # assert_
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
self.assertEqual(key.d, self.d)
self.assertEqual(key.p, self.p)
self.assertEqual(key.q, self.q)
def testImportKey4unicode(self):
"""Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unicode"""
key = RSA.importKey(self.rsaPublicKeyPEM)
self.assertEqual(key.has_private(),False) # assertFalse
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
def testImportKey4bytes(self):
"""Verify import of SubjectPublicKeyInfo DER SEQUENCE, encoded with PEM as byte string"""
key = RSA.importKey(b(self.rsaPublicKeyPEM))
self.assertEqual(key.has_private(),False) # assertFalse
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
def testImportKey5(self):
"""Verifies that the imported key is still a valid RSA pair"""
key = RSA.importKey(self.rsaKeyPEM)
idem = key._encrypt(key._decrypt(89))
self.assertEqual(idem, 89)
def testImportKey6(self):
"""Verifies that the imported key is still a valid RSA pair"""
key = RSA.importKey(self.rsaKeyDER)
idem = key._encrypt(key._decrypt(65))
self.assertEqual(idem, 65)
def testImportKey7(self):
"""Verify import of OpenSSH public key"""
key = RSA.importKey(self.rsaPublicKeyOpenSSH)
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
def testImportKey8(self):
"""Verify import of encrypted PrivateKeyInfo DER SEQUENCE"""
for t in self.rsaKeyEncryptedPEM:
key = RSA.importKey(t[1], t[0])
self.assertTrue(key.has_private())
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
self.assertEqual(key.d, self.d)
self.assertEqual(key.p, self.p)
self.assertEqual(key.q, self.q)
def testImportKey9(self):
"""Verify import of unencrypted PrivateKeyInfo DER SEQUENCE"""
key = RSA.importKey(self.rsaKeyDER8)
self.assertTrue(key.has_private())
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
self.assertEqual(key.d, self.d)
self.assertEqual(key.p, self.p)
self.assertEqual(key.q, self.q)
def testImportKey10(self):
"""Verify import of unencrypted PrivateKeyInfo DER SEQUENCE, encoded with PEM"""
key = RSA.importKey(self.rsaKeyPEM8)
self.assertTrue(key.has_private())
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
self.assertEqual(key.d, self.d)
self.assertEqual(key.p, self.p)
self.assertEqual(key.q, self.q)
def testImportKey11(self):
"""Verify import of RSAPublicKey DER SEQUENCE"""
der = asn1.DerSequence([17, 3]).encode()
key = RSA.importKey(der)
self.assertEqual(key.n, 17)
self.assertEqual(key.e, 3)
def testImportKey12(self):
"""Verify import of RSAPublicKey DER SEQUENCE, encoded with PEM"""
der = asn1.DerSequence([17, 3]).encode()
pem = der2pem(der)
key = RSA.importKey(pem)
self.assertEqual(key.n, 17)
self.assertEqual(key.e, 3)
def test_import_key_windows_cr_lf(self):
pem_cr_lf = "\r\n".join(self.rsaKeyPEM.splitlines())
key = RSA.importKey(pem_cr_lf)
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
self.assertEqual(key.d, self.d)
self.assertEqual(key.p, self.p)
self.assertEqual(key.q, self.q)
def test_import_empty(self):
self.assertRaises(ValueError, RSA.import_key, b"")
###
def testExportKey1(self):
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
derKey = key.export_key("DER")
self.assertEqual(derKey, self.rsaKeyDER)
def testExportKey2(self):
key = RSA.construct([self.n, self.e])
derKey = key.export_key("DER")
self.assertEqual(derKey, self.rsaPublicKeyDER)
def testExportKey3(self):
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
pemKey = key.export_key("PEM")
self.assertEqual(pemKey, b(self.rsaKeyPEM))
def testExportKey4(self):
key = RSA.construct([self.n, self.e])
pemKey = key.export_key("PEM")
self.assertEqual(pemKey, b(self.rsaPublicKeyPEM))
def testExportKey5(self):
key = RSA.construct([self.n, self.e])
openssh_1 = key.export_key("OpenSSH").split()
openssh_2 = self.rsaPublicKeyOpenSSH.split()
self.assertEqual(openssh_1[0], openssh_2[0])
self.assertEqual(openssh_1[1], openssh_2[1])
def testExportKey7(self):
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
derKey = key.export_key("DER", pkcs=8)
self.assertEqual(derKey, self.rsaKeyDER8)
def testExportKey8(self):
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
pemKey = key.export_key("PEM", pkcs=8)
self.assertEqual(pemKey, b(self.rsaKeyPEM8))
def testExportKey9(self):
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
self.assertRaises(ValueError, key.export_key, "invalid-format")
def testExportKey10(self):
# Export and re-import the encrypted key. It must match.
# PEM envelope, PKCS#1, old PEM encryption
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
outkey = key.export_key('PEM', 'test')
self.assertTrue(tostr(outkey).find('4,ENCRYPTED')!=-1)
self.assertTrue(tostr(outkey).find('BEGIN RSA PRIVATE KEY')!=-1)
inkey = RSA.importKey(outkey, 'test')
self.assertEqual(key.n, inkey.n)
self.assertEqual(key.e, inkey.e)
self.assertEqual(key.d, inkey.d)
def testExportKey11(self):
# Export and re-import the encrypted key. It must match.
# PEM envelope, PKCS#1, old PEM encryption
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
outkey = key.export_key('PEM', 'test', pkcs=1)
self.assertTrue(tostr(outkey).find('4,ENCRYPTED')!=-1)
self.assertTrue(tostr(outkey).find('BEGIN RSA PRIVATE KEY')!=-1)
inkey = RSA.importKey(outkey, 'test')
self.assertEqual(key.n, inkey.n)
self.assertEqual(key.e, inkey.e)
self.assertEqual(key.d, inkey.d)
def testExportKey12(self):
# Export and re-import the encrypted key. It must match.
# PEM envelope, PKCS#8, old PEM encryption
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
outkey = key.export_key('PEM', 'test', pkcs=8)
self.assertTrue(tostr(outkey).find('4,ENCRYPTED')!=-1)
self.assertTrue(tostr(outkey).find('BEGIN PRIVATE KEY')!=-1)
inkey = RSA.importKey(outkey, 'test')
self.assertEqual(key.n, inkey.n)
self.assertEqual(key.e, inkey.e)
self.assertEqual(key.d, inkey.d)
def testExportKey13(self):
# Export and re-import the encrypted key. It must match.
# PEM envelope, PKCS#8, PKCS#8 encryption
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
outkey = key.export_key('PEM', 'test', pkcs=8,
protection='PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC')
self.assertTrue(tostr(outkey).find('4,ENCRYPTED')==-1)
self.assertTrue(tostr(outkey).find('BEGIN ENCRYPTED PRIVATE KEY')!=-1)
inkey = RSA.importKey(outkey, 'test')
self.assertEqual(key.n, inkey.n)
self.assertEqual(key.e, inkey.e)
self.assertEqual(key.d, inkey.d)
def testExportKey14(self):
# Export and re-import the encrypted key. It must match.
# DER envelope, PKCS#8, PKCS#8 encryption
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
outkey = key.export_key('DER', 'test', pkcs=8)
inkey = RSA.importKey(outkey, 'test')
self.assertEqual(key.n, inkey.n)
self.assertEqual(key.e, inkey.e)
self.assertEqual(key.d, inkey.d)
def testExportKey15(self):
# Verify that that error an condition is detected when trying to
# use a password with DER encoding and PKCS#1.
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
self.assertRaises(ValueError, key.export_key, 'DER', 'test', 1)
def testExportKey16(self):
# Export and re-import the encrypted key. It must match.
# PEM envelope, PKCS#8, PKCS#8 encryption with parameters
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
outkey = key.export_key('PEM', 'test', pkcs=8,
protection='PBKDF2WithHMAC-SHA512AndAES256-CBC',
prot_params={'iteration_count':123}
)
self.assertTrue(tostr(outkey).find('4,ENCRYPTED')==-1)
self.assertTrue(tostr(outkey).find('BEGIN ENCRYPTED PRIVATE KEY')!=-1)
# Verify the iteration count
der = PEM.decode(tostr(outkey))[0]
seq1 = asn1.DerSequence().decode(der)
seq2 = asn1.DerSequence().decode(seq1[0])
seq3 = asn1.DerSequence().decode(seq2[1])
seq4 = asn1.DerSequence().decode(seq3[0])
seq5 = asn1.DerSequence().decode(seq4[1])
self.assertEqual(seq5[1], 123)
inkey = RSA.importKey(outkey, 'test')
self.assertEqual(key.n, inkey.n)
self.assertEqual(key.e, inkey.e)
self.assertEqual(key.d, inkey.d)
def test_import_key(self):
"""Verify that import_key is an alias to importKey"""
key = RSA.import_key(self.rsaPublicKeyDER)
self.assertFalse(key.has_private())
self.assertEqual(key.n, self.n)
self.assertEqual(key.e, self.e)
def test_import_key_ba_mv(self):
"""Verify that import_key can be used on bytearrays and memoryviews"""
key = RSA.import_key(bytearray(self.rsaPublicKeyDER))
key = RSA.import_key(memoryview(self.rsaPublicKeyDER))
def test_exportKey(self):
key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
self.assertEqual(key.export_key(), key.exportKey())
class ImportKeyFromX509Cert(unittest.TestCase):
def test_x509v1(self):
# Sample V1 certificate with a 1024 bit RSA key
x509_v1_cert = """
-----BEGIN CERTIFICATE-----
MIICOjCCAaMCAQEwDQYJKoZIhvcNAQEEBQAwfjENMAsGA1UEChMEQWNtZTELMAkG
A1UECxMCUkQxHDAaBgkqhkiG9w0BCQEWDXNwYW1AYWNtZS5vcmcxEzARBgNVBAcT
Ck1ldHJvcG9saXMxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYDVQQGEwJVUzENMAsG
A1UEAxMEdGVzdDAeFw0xNDA3MTExOTU3MjRaFw0xNzA0MDYxOTU3MjRaME0xCzAJ
BgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazENMAsGA1UEChMEQWNtZTELMAkG
A1UECxMCUkQxDzANBgNVBAMTBmxhdHZpYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEAyG+kytdRj3TFbRmHDYp3TXugVQ81chew0qeOxZWOz80IjtWpgdOaCvKW
NCuc8wUR9BWrEQW+39SaRMLiQfQtyFSQZijc3nsEBu/Lo4uWZ0W/FHDRVSvkJA/V
Ex5NL5ikI+wbUeCV5KajGNDalZ8F1pk32+CBs8h1xNx5DyxuEHUCAwEAATANBgkq
hkiG9w0BAQQFAAOBgQCVQF9Y//Q4Psy+umEM38pIlbZ2hxC5xNz/MbVPwuCkNcGn
KYNpQJP+JyVTsPpO8RLZsAQDzRueMI3S7fbbwTzAflN0z19wvblvu93xkaBytVok
9VBAH28olVhy9b1MMeg2WOt5sUEQaFNPnwwsyiY9+HsRpvpRnPSQF+kyYVsshQ==
-----END CERTIFICATE-----
""".strip()
# RSA public key as dumped by openssl
exponent = 65537
modulus_str = """
00:c8:6f:a4:ca:d7:51:8f:74:c5:6d:19:87:0d:8a:
77:4d:7b:a0:55:0f:35:72:17:b0:d2:a7:8e:c5:95:
8e:cf:cd:08:8e:d5:a9:81:d3:9a:0a:f2:96:34:2b:
9c:f3:05:11:f4:15:ab:11:05:be:df:d4:9a:44:c2:
e2:41:f4:2d:c8:54:90:66:28:dc:de:7b:04:06:ef:
cb:a3:8b:96:67:45:bf:14:70:d1:55:2b:e4:24:0f:
d5:13:1e:4d:2f:98:a4:23:ec:1b:51:e0:95:e4:a6:
a3:18:d0:da:95:9f:05:d6:99:37:db:e0:81:b3:c8:
75:c4:dc:79:0f:2c:6e:10:75
"""
modulus = int(re.sub("[^0-9a-f]","", modulus_str), 16)
key = RSA.importKey(x509_v1_cert)
self.assertEqual(key.e, exponent)
self.assertEqual(key.n, modulus)
self.assertFalse(key.has_private())
def test_x509v3(self):
# Sample V3 certificate with a 1024 bit RSA key
x509_v3_cert = """
-----BEGIN CERTIFICATE-----
MIIEcjCCAlqgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEL
MAkGA1UECAwCTUQxEjAQBgNVBAcMCUJhbHRpbW9yZTEQMA4GA1UEAwwHVGVzdCBD
QTEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0xNDA3MTIwOTM1
MTJaFw0xNzA0MDcwOTM1MTJaMEQxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNRDES
MBAGA1UEBwwJQmFsdGltb3JlMRQwEgYDVQQDDAtUZXN0IFNlcnZlcjCBnzANBgkq
hkiG9w0BAQEFAAOBjQAwgYkCgYEA/S7GJV2OcFdyNMQ4K75KrYFtMEn3VnEFdPHa
jyS37XlMxSh0oS4GeTGVUCJInl5Cpsv8WQdh03FfeOdvzp5IZ46OcjeOPiWnmjgl
2G5j7e2bDH7RSchGV+OD6Fb1Agvuu2/9iy8fdf3rPQ/7eAddzKUrzwacVbnW+tg2
QtSXKRcCAwEAAaOB1TCB0jAdBgNVHQ4EFgQU/WwCX7FfWMIPDFfJ+I8a2COG+l8w
HwYDVR0jBBgwFoAUa0hkif3RMaraiWtsOOZZlLu9wJwwCQYDVR0TBAIwADALBgNV
HQ8EBAMCBeAwSgYDVR0RBEMwQYILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNv
bYIQbWFpbC5leGFtcGxlLmNvbYIPZnRwLmV4YW1wbGUuY29tMCwGCWCGSAGG+EIB
DQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsF
AAOCAgEAvO6xfdsGbnoK4My3eJthodTAjMjPwFVY133LH04QLcCv54TxKhtUg1fi
PgdjVe1HpTytPBfXy2bSZbXAN0abZCtw1rYrnn7o1g2pN8iypVq3zVn0iMTzQzxs
zEPO3bpR/UhNSf90PmCsS5rqZpAAnXSaAy1ClwHWk/0eG2pYkhE1m1ABVMN2lsAW
e9WxGk6IFqaI9O37NYQwmEypMs4DC+ECJEvbPFiqi3n0gbXCZJJ6omDA5xJldaYK
Oa7KR3s/qjBsu9UAiWpLBuFoSTHIF2aeRKRFmUdmzwo43eVPep65pY6eQ4AdL2RF
rqEuINbGlzI5oQyYhu71IwB+iPZXaZZPlwjLgOsuad/p2hOgDb5WxUi8FnDPursQ
ujfpIpmrOP/zpvvQWnwePI3lI+5n41kTBSbefXEdv6rXpHk3QRzB90uPxnXPdxSC
16ASA8bQT5an/1AgoE3k9CrcD2K0EmgaX0YI0HUhkyzbkg34EhpWJ6vvRUbRiNRo
9cIbt/ya9Y9u0Ja8GLXv6dwX0l0IdJMkL8KifXUFAVCujp1FBrr/gdmwQn8itANy
+qbnWSxmOvtaY0zcaFAcONuHva0h51/WqXOMO1eb8PhR4HIIYU8p1oBwQp7dSni8
THDi1F+GG5PsymMDj5cWK42f+QzjVw5PrVmFqqrrEoMlx8DWh5Y=
-----END CERTIFICATE-----
""".strip()
# RSA public key as dumped by openssl
exponent = 65537
modulus_str = """
00:fd:2e:c6:25:5d:8e:70:57:72:34:c4:38:2b:be:
4a:ad:81:6d:30:49:f7:56:71:05:74:f1:da:8f:24:
b7:ed:79:4c:c5:28:74:a1:2e:06:79:31:95:50:22:
48:9e:5e:42:a6:cb:fc:59:07:61:d3:71:5f:78:e7:
6f:ce:9e:48:67:8e:8e:72:37:8e:3e:25:a7:9a:38:
25:d8:6e:63:ed:ed:9b:0c:7e:d1:49:c8:46:57:e3:
83:e8:56:f5:02:0b:ee:bb:6f:fd:8b:2f:1f:75:fd:
eb:3d:0f:fb:78:07:5d:cc:a5:2b:cf:06:9c:55:b9:
d6:fa:d8:36:42:d4:97:29:17
"""
modulus = int(re.sub("[^0-9a-f]","", modulus_str), 16)
key = RSA.importKey(x509_v3_cert)
self.assertEqual(key.e, exponent)
self.assertEqual(key.n, modulus)
self.assertFalse(key.has_private())
class TestImport_2048(unittest.TestCase):
def test_import_pss(self):
pub_key_file = load_file("rsa2048_pss_public.pem")
pub_key = RSA.import_key(pub_key_file)
priv_key_file = load_file("rsa2048_pss_private.pem")
priv_key = RSA.import_key(priv_key_file)
self.assertEqual(pub_key.n, priv_key.n)
def test_import_openssh_public(self):
key_file_ref = load_file("rsa2048_private.pem")
key_file = load_file("rsa2048_public_openssh.txt")
# Skip test if test vectors are not installed
if None in (key_file_ref, key_file):
return
key_ref = RSA.import_key(key_file_ref).public_key()
key = RSA.import_key(key_file)
self.assertEqual(key_ref, key)
def test_import_openssh_private_clear(self):
key_file = load_file("rsa2048_private_openssh.pem")
key_file_old = load_file("rsa2048_private_openssh_old.pem")
# Skip test if test vectors are not installed
if None in (key_file_old, key_file):
return
key = RSA.import_key(key_file)
key_old = RSA.import_key(key_file_old)
self.assertEqual(key, key_old)
def test_import_openssh_private_password(self):
key_file = load_file("rsa2048_private_openssh_pwd.pem")
key_file_old = load_file("rsa2048_private_openssh_pwd_old.pem")
# Skip test if test vectors are not installed
if None in (key_file_old, key_file):
return
key = RSA.import_key(key_file, b"password")
key_old = RSA.import_key(key_file_old)
self.assertEqual(key, key_old)
def test_import_pkcs8_private(self):
key_file_ref = load_file("rsa2048_private.pem")
key_file = load_file("rsa2048_private_p8.der")
# Skip test if test vectors are not installed
if None in (key_file_ref, key_file):
return
key_ref = RSA.import_key(key_file_ref)
key = RSA.import_key(key_file, b'secret')
self.assertEqual(key_ref, key)
def get_tests(config={}):
tests = []
tests += list_test_cases(ImportKeyTests)
tests += list_test_cases(ImportKeyFromX509Cert)
tests += list_test_cases(TestImport_2048)
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
#
# SelfTest/Random/__init__.py: Self-test for random number generation 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 random number generators"""
__revision__ = "$Id$"
def get_tests(config={}):
tests = []
from Crypto.SelfTest.Random import test_random; tests += test_random.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:
@@ -0,0 +1,167 @@
# -*- coding: utf-8 -*-
#
# SelfTest/Util/test_generic.py: Self-test for the Crypto.Random.new() 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.Random.new()"""
import sys
import unittest
from Crypto.Util.py3compat import b
class SimpleTest(unittest.TestCase):
def runTest(self):
"""Crypto.Random.new()"""
# Import the Random module and try to use it
from Crypto import Random
randobj = Random.new()
x = randobj.read(16)
y = randobj.read(16)
self.assertNotEqual(x, y)
z = Random.get_random_bytes(16)
self.assertNotEqual(x, z)
self.assertNotEqual(y, z)
# Test the Random.random module, which
# implements a subset of Python's random API
# Not implemented:
# seed(), getstate(), setstate(), jumpahead()
# random(), uniform(), triangular(), betavariate()
# expovariate(), gammavariate(), gauss(),
# longnormvariate(), normalvariate(),
# vonmisesvariate(), paretovariate()
# weibullvariate()
# WichmannHill(), whseed(), SystemRandom()
from Crypto.Random import random
x = random.getrandbits(16*8)
y = random.getrandbits(16*8)
self.assertNotEqual(x, y)
# Test randrange
if x>y:
start = y
stop = x
else:
start = x
stop = y
for step in range(1,10):
x = random.randrange(start,stop,step)
y = random.randrange(start,stop,step)
self.assertNotEqual(x, y)
self.assertEqual(start <= x < stop, True)
self.assertEqual(start <= y < stop, True)
self.assertEqual((x - start) % step, 0)
self.assertEqual((y - start) % step, 0)
for i in range(10):
self.assertEqual(random.randrange(1,2), 1)
self.assertRaises(ValueError, random.randrange, start, start)
self.assertRaises(ValueError, random.randrange, stop, start, step)
self.assertRaises(TypeError, random.randrange, start, stop, step, step)
self.assertRaises(TypeError, random.randrange, start, stop, "1")
self.assertRaises(TypeError, random.randrange, "1", stop, step)
self.assertRaises(TypeError, random.randrange, 1, "2", step)
self.assertRaises(ValueError, random.randrange, start, stop, 0)
# Test randint
x = random.randint(start,stop)
y = random.randint(start,stop)
self.assertNotEqual(x, y)
self.assertEqual(start <= x <= stop, True)
self.assertEqual(start <= y <= stop, True)
for i in range(10):
self.assertEqual(random.randint(1,1), 1)
self.assertRaises(ValueError, random.randint, stop, start)
self.assertRaises(TypeError, random.randint, start, stop, step)
self.assertRaises(TypeError, random.randint, "1", stop)
self.assertRaises(TypeError, random.randint, 1, "2")
# Test choice
seq = range(10000)
x = random.choice(seq)
y = random.choice(seq)
self.assertNotEqual(x, y)
self.assertEqual(x in seq, True)
self.assertEqual(y in seq, True)
for i in range(10):
self.assertEqual(random.choice((1,2,3)) in (1,2,3), True)
self.assertEqual(random.choice([1,2,3]) in [1,2,3], True)
if sys.version_info[0] == 3:
self.assertEqual(random.choice(bytearray(b('123'))) in bytearray(b('123')), True)
self.assertEqual(1, random.choice([1]))
self.assertRaises(IndexError, random.choice, [])
self.assertRaises(TypeError, random.choice, 1)
# Test shuffle. Lacks random parameter to specify function.
# Make copies of seq
seq = range(500)
x = list(seq)
y = list(seq)
random.shuffle(x)
random.shuffle(y)
self.assertNotEqual(x, y)
self.assertEqual(len(seq), len(x))
self.assertEqual(len(seq), len(y))
for i in range(len(seq)):
self.assertEqual(x[i] in seq, True)
self.assertEqual(y[i] in seq, True)
self.assertEqual(seq[i] in x, True)
self.assertEqual(seq[i] in y, True)
z = [1]
random.shuffle(z)
self.assertEqual(z, [1])
if sys.version_info[0] == 3:
z = bytearray(b('12'))
random.shuffle(z)
self.assertEqual(b('1') in z, True)
self.assertRaises(TypeError, random.shuffle, b('12'))
self.assertRaises(TypeError, random.shuffle, 1)
self.assertRaises(TypeError, random.shuffle, "11")
self.assertRaises(TypeError, random.shuffle, (1,2))
# 2to3 wraps a list() around it, alas - but I want to shoot
# myself in the foot here! :D
# if sys.version_info[0] == 3:
# self.assertRaises(TypeError, random.shuffle, range(3))
# Test sample
x = random.sample(seq, 20)
y = random.sample(seq, 20)
self.assertNotEqual(x, y)
for i in range(20):
self.assertEqual(x[i] in seq, True)
self.assertEqual(y[i] in seq, True)
z = random.sample([1], 1)
self.assertEqual(z, [1])
z = random.sample((1,2,3), 1)
self.assertEqual(z[0] in (1,2,3), True)
z = random.sample("123", 1)
self.assertEqual(z[0] in "123", True)
z = random.sample(range(3), 1)
self.assertEqual(z[0] in range(3), True)
if sys.version_info[0] == 3:
z = random.sample(b("123"), 1)
self.assertEqual(z[0] in b("123"), True)
z = random.sample(bytearray(b("123")), 1)
self.assertEqual(z[0] in bytearray(b("123")), True)
self.assertRaises(TypeError, random.sample, 1)
def get_tests(config={}):
return [SimpleTest()]
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
# vim:set ts=4 sw=4 sts=4 expandtab:
@@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
#
# SelfTest/Signature/__init__.py: Self-test for signature modules
#
# ===================================================================
# 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 signature modules"""
import unittest
from . import test_pkcs1_15, test_pss, test_dss, test_eddsa
def get_tests(config={}):
tests = []
tests += test_pkcs1_15.get_tests(config=config)
tests += test_pss.get_tests(config=config)
tests += test_dss.get_tests(config=config)
tests += test_eddsa.get_tests(config=config)
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,604 @@
#
# Copyright (c) 2022, 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.PublicKey import ECC
from Crypto.Signature import eddsa
from Crypto.Hash import SHA512, SHAKE256
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.SelfTest.loader import load_test_vectors_wycheproof
from Crypto.Util.number import bytes_to_long
rfc8032_tv_str = (
# 7.1 Ed25519
(
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
"",
None,
"",
"e5564300c360ac729086e2cc806e828a"
"84877f1eb8e5d974d873e06522490155"
"5fb8821590a33bacc61e39701cf9b46b"
"d25bf5f0595bbe24655141438e7a100b"
),
(
"4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb",
"3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c",
"72",
None,
"",
"92a009a9f0d4cab8720e820b5f642540"
"a2b27b5416503f8fb3762223ebdb69da"
"085ac1e43e15996e458f3613d0f11d8c"
"387b2eaeb4302aeeb00d291612bb0c00"
),
(
"c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7",
"fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025",
"af82",
None,
"",
"6291d657deec24024827e69c3abe01a3"
"0ce548a284743a445e3680d7db5ac3ac"
"18ff9b538d16f290ae67f760984dc659"
"4a7c15e9716ed28dc027beceea1ec40a"
),
(
"f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5",
"278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e",
"08b8b2b733424243760fe426a4b54908"
"632110a66c2f6591eabd3345e3e4eb98"
"fa6e264bf09efe12ee50f8f54e9f77b1"
"e355f6c50544e23fb1433ddf73be84d8"
"79de7c0046dc4996d9e773f4bc9efe57"
"38829adb26c81b37c93a1b270b20329d"
"658675fc6ea534e0810a4432826bf58c"
"941efb65d57a338bbd2e26640f89ffbc"
"1a858efcb8550ee3a5e1998bd177e93a"
"7363c344fe6b199ee5d02e82d522c4fe"
"ba15452f80288a821a579116ec6dad2b"
"3b310da903401aa62100ab5d1a36553e"
"06203b33890cc9b832f79ef80560ccb9"
"a39ce767967ed628c6ad573cb116dbef"
"efd75499da96bd68a8a97b928a8bbc10"
"3b6621fcde2beca1231d206be6cd9ec7"
"aff6f6c94fcd7204ed3455c68c83f4a4"
"1da4af2b74ef5c53f1d8ac70bdcb7ed1"
"85ce81bd84359d44254d95629e9855a9"
"4a7c1958d1f8ada5d0532ed8a5aa3fb2"
"d17ba70eb6248e594e1a2297acbbb39d"
"502f1a8c6eb6f1ce22b3de1a1f40cc24"
"554119a831a9aad6079cad88425de6bd"
"e1a9187ebb6092cf67bf2b13fd65f270"
"88d78b7e883c8759d2c4f5c65adb7553"
"878ad575f9fad878e80a0c9ba63bcbcc"
"2732e69485bbc9c90bfbd62481d9089b"
"eccf80cfe2df16a2cf65bd92dd597b07"
"07e0917af48bbb75fed413d238f5555a"
"7a569d80c3414a8d0859dc65a46128ba"
"b27af87a71314f318c782b23ebfe808b"
"82b0ce26401d2e22f04d83d1255dc51a"
"ddd3b75a2b1ae0784504df543af8969b"
"e3ea7082ff7fc9888c144da2af58429e"
"c96031dbcad3dad9af0dcbaaaf268cb8"
"fcffead94f3c7ca495e056a9b47acdb7"
"51fb73e666c6c655ade8297297d07ad1"
"ba5e43f1bca32301651339e22904cc8c"
"42f58c30c04aafdb038dda0847dd988d"
"cda6f3bfd15c4b4c4525004aa06eeff8"
"ca61783aacec57fb3d1f92b0fe2fd1a8"
"5f6724517b65e614ad6808d6f6ee34df"
"f7310fdc82aebfd904b01e1dc54b2927"
"094b2db68d6f903b68401adebf5a7e08"
"d78ff4ef5d63653a65040cf9bfd4aca7"
"984a74d37145986780fc0b16ac451649"
"de6188a7dbdf191f64b5fc5e2ab47b57"
"f7f7276cd419c17a3ca8e1b939ae49e4"
"88acba6b965610b5480109c8b17b80e1"
"b7b750dfc7598d5d5011fd2dcc5600a3"
"2ef5b52a1ecc820e308aa342721aac09"
"43bf6686b64b2579376504ccc493d97e"
"6aed3fb0f9cd71a43dd497f01f17c0e2"
"cb3797aa2a2f256656168e6c496afc5f"
"b93246f6b1116398a346f1a641f3b041"
"e989f7914f90cc2c7fff357876e506b5"
"0d334ba77c225bc307ba537152f3f161"
"0e4eafe595f6d9d90d11faa933a15ef1"
"369546868a7f3a45a96768d40fd9d034"
"12c091c6315cf4fde7cb68606937380d"
"b2eaaa707b4c4185c32eddcdd306705e"
"4dc1ffc872eeee475a64dfac86aba41c"
"0618983f8741c5ef68d3a101e8a3b8ca"
"c60c905c15fc910840b94c00a0b9d0",
None,
"",
"0aab4c900501b3e24d7cdf4663326a3a"
"87df5e4843b2cbdb67cbf6e460fec350"
"aa5371b1508f9f4528ecea23c436d94b"
"5e8fcd4f681e30a6ac00a9704a188a03"
),
# 7.2 Ed25519ctx
(
"0305334e381af78f141cb666f6199f57"
"bc3495335a256a95bd2a55bf546663f6",
"dfc9425e4f968f7f0c29f0259cf5f9ae"
"d6851c2bb4ad8bfb860cfee0ab248292",
"f726936d19c800494e3fdaff20b276a8",
None,
"666f6f",
"55a4cc2f70a54e04288c5f4cd1e45a7b"
"b520b36292911876cada7323198dd87a"
"8b36950b95130022907a7fb7c4e9b2d5"
"f6cca685a587b4b21f4b888e4e7edb0d"
),
(
"0305334e381af78f141cb666f6199f57"
"bc3495335a256a95bd2a55bf546663f6",
"dfc9425e4f968f7f0c29f0259cf5f9ae"
"d6851c2bb4ad8bfb860cfee0ab248292",
"f726936d19c800494e3fdaff20b276a8",
None,
"626172",
"fc60d5872fc46b3aa69f8b5b4351d580"
"8f92bcc044606db097abab6dbcb1aee3"
"216c48e8b3b66431b5b186d1d28f8ee1"
"5a5ca2df6668346291c2043d4eb3e90d"
),
(
"0305334e381af78f141cb666f6199f57"
"bc3495335a256a95bd2a55bf546663f6",
"dfc9425e4f968f7f0c29f0259cf5f9ae"
"d6851c2bb4ad8bfb860cfee0ab248292",
"508e9e6882b979fea900f62adceaca35",
None,
"666f6f",
"8b70c1cc8310e1de20ac53ce28ae6e72"
"07f33c3295e03bb5c0732a1d20dc6490"
"8922a8b052cf99b7c4fe107a5abb5b2c"
"4085ae75890d02df26269d8945f84b0b"
),
(
"ab9c2853ce297ddab85c993b3ae14bca"
"d39b2c682beabc27d6d4eb20711d6560",
"0f1d1274943b91415889152e893d80e9"
"3275a1fc0b65fd71b4b0dda10ad7d772",
"f726936d19c800494e3fdaff20b276a8",
None,
"666f6f",
"21655b5f1aa965996b3f97b3c849eafb"
"a922a0a62992f73b3d1b73106a84ad85"
"e9b86a7b6005ea868337ff2d20a7f5fb"
"d4cd10b0be49a68da2b2e0dc0ad8960f"
),
# 7.3 Ed25519ph
(
"833fe62409237b9d62ec77587520911e"
"9a759cec1d19755b7da901b96dca3d42",
"ec172b93ad5e563bf4932c70e1245034"
"c35467ef2efd4d64ebf819683467e2bf",
"616263",
SHA512,
"",
"98a70222f0b8121aa9d30f813d683f80"
"9e462b469c7ff87639499bb94e6dae41"
"31f85042463c2a355a2003d062adf5aa"
"a10b8c61e636062aaad11c2a26083406"
),
# 7.4 Ed448
(
"6c82a562cb808d10d632be89c8513ebf6c929f34ddfa8c9f63c9960ef6e348a3"
"528c8a3fcc2f044e39a3fc5b94492f8f032e7549a20098f95b",
"5fd7449b59b461fd2ce787ec616ad46a1da1342485a70e1f8a0ea75d80e96778"
"edf124769b46c7061bd6783df1e50f6cd1fa1abeafe8256180",
"",
None,
"",
"533a37f6bbe457251f023c0d88f976ae2dfb504a843e34d2074fd823d41a591f"
"2b233f034f628281f2fd7a22ddd47d7828c59bd0a21bfd3980ff0d2028d4b18a"
"9df63e006c5d1c2d345b925d8dc00b4104852db99ac5c7cdda8530a113a0f4db"
"b61149f05a7363268c71d95808ff2e652600"
),
(
"c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463a"
"fbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e",
"43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c086"
"6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
"03",
None,
"",
"26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f435"
"2541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd779805e0dbcc0aae1cb"
"cee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0f"
"f3348ab21aa4adafd1d234441cf807c03a00",
),
(
"c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463a"
"fbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e",
"43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c086"
"6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
"03",
None,
"666f6f",
"d4f8f6131770dd46f40867d6fd5d5055de43541f8c5e35abbcd001b32a89f7d2"
"151f7647f11d8ca2ae279fb842d607217fce6e042f6815ea000c85741de5c8da"
"1144a6a1aba7f96de42505d7a7298524fda538fccbbb754f578c1cad10d54d0d"
"5428407e85dcbc98a49155c13764e66c3c00",
),
(
"cd23d24f714274e744343237b93290f511f6425f98e64459ff203e8985083ffd"
"f60500553abc0e05cd02184bdb89c4ccd67e187951267eb328",
"dcea9e78f35a1bf3499a831b10b86c90aac01cd84b67a0109b55a36e9328b1e3"
"65fce161d71ce7131a543ea4cb5f7e9f1d8b00696447001400",
"0c3e544074ec63b0265e0c",
None,
"",
"1f0a8888ce25e8d458a21130879b840a9089d999aaba039eaf3e3afa090a09d3"
"89dba82c4ff2ae8ac5cdfb7c55e94d5d961a29fe0109941e00b8dbdeea6d3b05"
"1068df7254c0cdc129cbe62db2dc957dbb47b51fd3f213fb8698f064774250a5"
"028961c9bf8ffd973fe5d5c206492b140e00",
),
(
"258cdd4ada32ed9c9ff54e63756ae582fb8fab2ac721f2c8e676a72768513d93"
"9f63dddb55609133f29adf86ec9929dccb52c1c5fd2ff7e21b",
"3ba16da0c6f2cc1f30187740756f5e798d6bc5fc015d7c63cc9510ee3fd44adc"
"24d8e968b6e46e6f94d19b945361726bd75e149ef09817f580",
"64a65f3cdedcdd66811e2915",
None,
"",
"7eeeab7c4e50fb799b418ee5e3197ff6bf15d43a14c34389b59dd1a7b1b85b4a"
"e90438aca634bea45e3a2695f1270f07fdcdf7c62b8efeaf00b45c2c96ba457e"
"b1a8bf075a3db28e5c24f6b923ed4ad747c3c9e03c7079efb87cb110d3a99861"
"e72003cbae6d6b8b827e4e6c143064ff3c00",
),
(
"7ef4e84544236752fbb56b8f31a23a10e42814f5f55ca037cdcc11c64c9a3b29"
"49c1bb60700314611732a6c2fea98eebc0266a11a93970100e",
"b3da079b0aa493a5772029f0467baebee5a8112d9d3a22532361da294f7bb381"
"5c5dc59e176b4d9f381ca0938e13c6c07b174be65dfa578e80",
"64a65f3cdedcdd66811e2915e7",
None,
"",
"6a12066f55331b6c22acd5d5bfc5d71228fbda80ae8dec26bdd306743c5027cb"
"4890810c162c027468675ecf645a83176c0d7323a2ccde2d80efe5a1268e8aca"
"1d6fbc194d3f77c44986eb4ab4177919ad8bec33eb47bbb5fc6e28196fd1caf5"
"6b4e7e0ba5519234d047155ac727a1053100",
),
(
"d65df341ad13e008567688baedda8e9dcdc17dc024974ea5b4227b6530e339bf"
"f21f99e68ca6968f3cca6dfe0fb9f4fab4fa135d5542ea3f01",
"df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a"
"39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00",
"bd0f6a3747cd561bdddf4640a332461a4a30a12a434cd0bf40d766d9c6d458e5"
"512204a30c17d1f50b5079631f64eb3112182da3005835461113718d1a5ef944",
None,
"",
"554bc2480860b49eab8532d2a533b7d578ef473eeb58c98bb2d0e1ce488a98b1"
"8dfde9b9b90775e67f47d4a1c3482058efc9f40d2ca033a0801b63d45b3b722e"
"f552bad3b4ccb667da350192b61c508cf7b6b5adadc2c8d9a446ef003fb05cba"
"5f30e88e36ec2703b349ca229c2670833900",
),
(
"2ec5fe3c17045abdb136a5e6a913e32ab75ae68b53d2fc149b77e504132d3756"
"9b7e766ba74a19bd6162343a21c8590aa9cebca9014c636df5",
"79756f014dcfe2079f5dd9e718be4171e2ef2486a08f25186f6bff43a9936b9b"
"fe12402b08ae65798a3d81e22e9ec80e7690862ef3d4ed3a00",
"15777532b0bdd0d1389f636c5f6b9ba734c90af572877e2d272dd078aa1e567c"
"fa80e12928bb542330e8409f3174504107ecd5efac61ae7504dabe2a602ede89"
"e5cca6257a7c77e27a702b3ae39fc769fc54f2395ae6a1178cab4738e543072f"
"c1c177fe71e92e25bf03e4ecb72f47b64d0465aaea4c7fad372536c8ba516a60"
"39c3c2a39f0e4d832be432dfa9a706a6e5c7e19f397964ca4258002f7c0541b5"
"90316dbc5622b6b2a6fe7a4abffd96105eca76ea7b98816af0748c10df048ce0"
"12d901015a51f189f3888145c03650aa23ce894c3bd889e030d565071c59f409"
"a9981b51878fd6fc110624dcbcde0bf7a69ccce38fabdf86f3bef6044819de11",
None,
"",
"c650ddbb0601c19ca11439e1640dd931f43c518ea5bea70d3dcde5f4191fe53f"
"00cf966546b72bcc7d58be2b9badef28743954e3a44a23f880e8d4f1cfce2d7a"
"61452d26da05896f0a50da66a239a8a188b6d825b3305ad77b73fbac0836ecc6"
"0987fd08527c1a8e80d5823e65cafe2a3d00",
),
(
"872d093780f5d3730df7c212664b37b8a0f24f56810daa8382cd4fa3f77634ec"
"44dc54f1c2ed9bea86fafb7632d8be199ea165f5ad55dd9ce8",
"a81b2e8a70a5ac94ffdbcc9badfc3feb0801f258578bb114ad44ece1ec0e799d"
"a08effb81c5d685c0c56f64eecaef8cdf11cc38737838cf400",
"6ddf802e1aae4986935f7f981ba3f0351d6273c0a0c22c9c0e8339168e675412"
"a3debfaf435ed651558007db4384b650fcc07e3b586a27a4f7a00ac8a6fec2cd"
"86ae4bf1570c41e6a40c931db27b2faa15a8cedd52cff7362c4e6e23daec0fbc"
"3a79b6806e316efcc7b68119bf46bc76a26067a53f296dafdbdc11c77f7777e9"
"72660cf4b6a9b369a6665f02e0cc9b6edfad136b4fabe723d2813db3136cfde9"
"b6d044322fee2947952e031b73ab5c603349b307bdc27bc6cb8b8bbd7bd32321"
"9b8033a581b59eadebb09b3c4f3d2277d4f0343624acc817804728b25ab79717"
"2b4c5c21a22f9c7839d64300232eb66e53f31c723fa37fe387c7d3e50bdf9813"
"a30e5bb12cf4cd930c40cfb4e1fc622592a49588794494d56d24ea4b40c89fc0"
"596cc9ebb961c8cb10adde976a5d602b1c3f85b9b9a001ed3c6a4d3b1437f520"
"96cd1956d042a597d561a596ecd3d1735a8d570ea0ec27225a2c4aaff26306d1"
"526c1af3ca6d9cf5a2c98f47e1c46db9a33234cfd4d81f2c98538a09ebe76998"
"d0d8fd25997c7d255c6d66ece6fa56f11144950f027795e653008f4bd7ca2dee"
"85d8e90f3dc315130ce2a00375a318c7c3d97be2c8ce5b6db41a6254ff264fa6"
"155baee3b0773c0f497c573f19bb4f4240281f0b1f4f7be857a4e59d416c06b4"
"c50fa09e1810ddc6b1467baeac5a3668d11b6ecaa901440016f389f80acc4db9"
"77025e7f5924388c7e340a732e554440e76570f8dd71b7d640b3450d1fd5f041"
"0a18f9a3494f707c717b79b4bf75c98400b096b21653b5d217cf3565c9597456"
"f70703497a078763829bc01bb1cbc8fa04eadc9a6e3f6699587a9e75c94e5bab"
"0036e0b2e711392cff0047d0d6b05bd2a588bc109718954259f1d86678a579a3"
"120f19cfb2963f177aeb70f2d4844826262e51b80271272068ef5b3856fa8535"
"aa2a88b2d41f2a0e2fda7624c2850272ac4a2f561f8f2f7a318bfd5caf969614"
"9e4ac824ad3460538fdc25421beec2cc6818162d06bbed0c40a387192349db67"
"a118bada6cd5ab0140ee273204f628aad1c135f770279a651e24d8c14d75a605"
"9d76b96a6fd857def5e0b354b27ab937a5815d16b5fae407ff18222c6d1ed263"
"be68c95f32d908bd895cd76207ae726487567f9a67dad79abec316f683b17f2d"
"02bf07e0ac8b5bc6162cf94697b3c27cd1fea49b27f23ba2901871962506520c"
"392da8b6ad0d99f7013fbc06c2c17a569500c8a7696481c1cd33e9b14e40b82e"
"79a5f5db82571ba97bae3ad3e0479515bb0e2b0f3bfcd1fd33034efc6245eddd"
"7ee2086ddae2600d8ca73e214e8c2b0bdb2b047c6a464a562ed77b73d2d841c4"
"b34973551257713b753632efba348169abc90a68f42611a40126d7cb21b58695"
"568186f7e569d2ff0f9e745d0487dd2eb997cafc5abf9dd102e62ff66cba87",
None,
"",
"e301345a41a39a4d72fff8df69c98075a0cc082b802fc9b2b6bc503f926b65bd"
"df7f4c8f1cb49f6396afc8a70abe6d8aef0db478d4c6b2970076c6a0484fe76d"
"76b3a97625d79f1ce240e7c576750d295528286f719b413de9ada3e8eb78ed57"
"3603ce30d8bb761785dc30dbc320869e1a00"
),
# 7.5 Ed448ph
(
"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"
"ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49",
"259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743"
"c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880",
"616263",
SHAKE256,
"",
"822f6901f7480f3d5f562c592994d9693602875614483256505600bbc281ae38"
"1f54d6bce2ea911574932f52a4e6cadd78769375ec3ffd1b801a0d9b3f4030cd"
"433964b6457ea39476511214f97469b57dd32dbc560a9a94d00bff07620464a3"
"ad203df7dc7ce360c3cd3696d9d9fab90f00"
),
(
"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"
"ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49",
"259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743"
"c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880",
"616263",
SHAKE256,
"666f6f",
"c32299d46ec8ff02b54540982814dce9a05812f81962b649d528095916a2aa48"
"1065b1580423ef927ecf0af5888f90da0f6a9a85ad5dc3f280d91224ba9911a3"
"653d00e484e2ce232521481c8658df304bb7745a73514cdb9bf3e15784ab7128"
"4f8d0704a608c54a6b62d97beb511d132100",
),
)
rfc8032_tv_bytes = []
for tv_str in rfc8032_tv_str:
rfc8032_tv_bytes.append([unhexlify(i) if isinstance(i, str) else i for i in tv_str])
class TestEdDSA(unittest.TestCase):
def test_sign(self):
for sk, _, msg, hashmod, ctx, exp_signature in rfc8032_tv_bytes:
key = eddsa.import_private_key(sk)
signer = eddsa.new(key, 'rfc8032', context=ctx)
if hashmod is None:
# PureEdDSA
signature = signer.sign(msg)
else:
# HashEdDSA
hashobj = hashmod.new(msg)
signature = signer.sign(hashobj)
self.assertEqual(exp_signature, signature)
def test_verify(self):
for _, pk, msg, hashmod, ctx, exp_signature in rfc8032_tv_bytes:
key = eddsa.import_public_key(pk)
verifier = eddsa.new(key, 'rfc8032', context=ctx)
if hashmod is None:
# PureEdDSA
verifier.verify(msg, exp_signature)
else:
# HashEdDSA
hashobj = hashmod.new(msg)
verifier.verify(hashobj, exp_signature)
def test_double_sign_verify_ed25519(self):
msg_hash = SHA512.new(b'abc')
key = ECC.generate(curve='ed25519')
signer = eddsa.new(key, 'rfc8032')
verifier = eddsa.new(key, 'rfc8032')
signature = signer.sign(msg_hash)
signature2 = signer.sign(msg_hash)
self.assertEqual(signature, signature2)
verifier.verify(msg_hash, signature)
verifier.verify(msg_hash, signature)
def test_double_sign_verify_ed448(self):
msg_hash = SHAKE256.new(b'abc')
key = ECC.generate(curve='ed448')
signer = eddsa.new(key, 'rfc8032')
verifier = eddsa.new(key, 'rfc8032')
signature = signer.sign(msg_hash)
signature2 = signer.sign(msg_hash)
self.assertEqual(signature, signature2)
verifier.verify(msg_hash, signature)
verifier.verify(msg_hash, signature)
def test_negative(self):
key = ECC.generate(curve="ed25519")
self.assertRaises(ValueError, eddsa.new, key, 'rfc9999')
nist_key = ECC.generate(curve="p256")
self.assertRaises(ValueError, eddsa.new, nist_key, 'rfc8032')
class TestExport_Ed25519(unittest.TestCase):
def test_raw(self):
key = ECC.generate(curve="Ed25519")
x, y = key.pointQ.xy
raw = bytearray(key._export_eddsa_public())
sign_x = raw[31] >> 7
raw[31] &= 0x7F
yt = bytes_to_long(raw[::-1])
self.assertEqual(y, yt)
self.assertEqual(x & 1, sign_x)
key = ECC.construct(point_x=0, point_y=1, curve="Ed25519")
out = key._export_eddsa_public()
self.assertEqual(b'\x01' + b'\x00' * 31, out)
class TestExport_Ed448(unittest.TestCase):
def test_raw(self):
key = ECC.generate(curve="Ed448")
x, y = key.pointQ.xy
raw = bytearray(key._export_eddsa_public())
sign_x = raw[56] >> 7
raw[56] &= 0x7F
yt = bytes_to_long(raw[::-1])
self.assertEqual(y, yt)
self.assertEqual(x & 1, sign_x)
key = ECC.construct(point_x=0, point_y=1, curve="Ed448")
out = key._export_eddsa_public()
self.assertEqual(b'\x01' + b'\x00' * 56, out)
class TestImport_Ed25519(unittest.TestCase):
def test_raw(self):
Px = 24407857220263921307776619664228778204996144802740950419837658238229122415920
Py = 56480760040633817885061096979765646085062883740629155052073094891081309750690
encoded = b'\xa2\x05\xd6\x00\xe1 \xe1\xc0\xff\x96\xee?V\x8e\xba/\xd3\x89\x06\xd7\xc4c\xe8$\xc2d\xd7a1\xfa\xde|'
key = eddsa.import_public_key(encoded)
self.assertEqual(Py, key.pointQ.y)
self.assertEqual(Px, key.pointQ.x)
encoded = b'\x01' + b'\x00' * 31
key = eddsa.import_public_key(encoded)
self.assertEqual(1, key.pointQ.y)
self.assertEqual(0, key.pointQ.x)
class TestImport_Ed448(unittest.TestCase):
def test_raw(self):
Px = 0x153f42025aba3b0daecaa5cd79458b3146c7c9378c16c17b4a59bc3561113d90c169045bc12966c3f93e140c2ca0a3acc33d9205b9daf9b1
Py = 0x38f5c0015d3dedd576c232810dd90373b5b1d631a12894c043b7be529cbae03ede177d8fa490b56131dbcb2465d2aba777ef839fc1719b25
encoded = unhexlify("259b71c19f83ef77a7abd26524cbdb31"
"61b590a48f7d17de3ee0ba9c52beb743"
"c09428a131d6b1b57303d90d8132c276"
"d5ed3d5d01c0f53880")
key = eddsa.import_public_key(encoded)
self.assertEqual(Py, key.pointQ.y)
self.assertEqual(Px, key.pointQ.x)
encoded = b'\x01' + b'\x00' * 56
key = eddsa.import_public_key(encoded)
self.assertEqual(1, key.pointQ.y)
self.assertEqual(0, key.pointQ.x)
class TestVectorsEdDSAWycheproof(unittest.TestCase):
def add_tests(self, filename):
def pk(group):
elem = group['key']['pk']
return unhexlify(elem)
def sk(group):
elem = group['key']['sk']
return unhexlify(elem)
result = load_test_vectors_wycheproof(("Signature", "wycheproof"),
filename,
"Wycheproof ECDSA signature (%s)"
% filename,
group_tag={'pk': pk, 'sk': sk})
self.tv += result
def setUp(self):
self.tv = []
self.add_tests("eddsa_test.json")
self.add_tests("ed448_test.json")
def test_sign(self, tv):
if not tv.valid:
return
self._id = "Wycheproof EdDSA Sign Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
key = eddsa.import_private_key(tv.sk)
signer = eddsa.new(key, 'rfc8032')
signature = signer.sign(tv.msg)
self.assertEqual(signature, tv.sig)
def test_verify(self, tv):
self._id = "Wycheproof EdDSA Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
key = eddsa.import_public_key(tv.pk)
verifier = eddsa.new(key, 'rfc8032')
try:
verifier.verify(tv.msg, tv.sig)
except ValueError:
assert not tv.valid
else:
assert tv.valid
def runTest(self):
for tv in self.tv:
self.test_sign(tv)
self.test_verify(tv)
def get_tests(config={}):
tests = []
tests += list_test_cases(TestExport_Ed25519)
tests += list_test_cases(TestExport_Ed448)
tests += list_test_cases(TestImport_Ed25519)
tests += list_test_cases(TestImport_Ed448)
tests += list_test_cases(TestEdDSA)
tests += [TestVectorsEdDSAWycheproof()]
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,348 @@
# ===================================================================
#
# 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 json
import unittest
from binascii import unhexlify
from Crypto.Util.py3compat import bchr
from Crypto.Util.number import bytes_to_long
from Crypto.Util.strxor import strxor
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof
from Crypto.Hash import (SHA1, SHA224, SHA256, SHA384, SHA512, SHA3_384,
SHA3_224, SHA3_256, SHA3_512)
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from Crypto.Signature import PKCS1_v1_5
from Crypto.Util._file_system import pycryptodome_filename
from Crypto.Util.strxor import strxor
def load_hash_by_name(hash_name):
return __import__("Crypto.Hash." + hash_name, globals(), locals(), ["new"])
class FIPS_PKCS1_Verify_Tests(unittest.TestCase):
def shortDescription(self):
return "FIPS PKCS1 Tests (Verify)"
def test_can_sign(self):
test_public_key = RSA.generate(1024).public_key()
verifier = pkcs1_15.new(test_public_key)
self.assertEqual(verifier.can_sign(), False)
class FIPS_PKCS1_Verify_Tests_KAT(unittest.TestCase):
pass
test_vectors_verify = load_test_vectors(("Signature", "PKCS1-v1.5"),
"SigVer15_186-3.rsp",
"Signature Verification 186-3",
{'shaalg': lambda x: x,
'd': lambda x: int(x),
'result': lambda x: x}) or []
for count, tv in enumerate(test_vectors_verify):
if isinstance(tv, str):
continue
if hasattr(tv, "n"):
modulus = tv.n
continue
hash_module = load_hash_by_name(tv.shaalg.upper())
hash_obj = hash_module.new(tv.msg)
public_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e)]) # type: ignore
verifier = pkcs1_15.new(public_key)
def positive_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s):
verifier.verify(hash_obj, signature)
def negative_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s):
self.assertRaises(ValueError, verifier.verify, hash_obj, signature)
if tv.result == 'f':
setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_negative_%d" % count, negative_test)
else:
setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_positive_%d" % count, positive_test)
class FIPS_PKCS1_Sign_Tests(unittest.TestCase):
def shortDescription(self):
return "FIPS PKCS1 Tests (Sign)"
def test_can_sign(self):
test_private_key = RSA.generate(1024)
signer = pkcs1_15.new(test_private_key)
self.assertEqual(signer.can_sign(), True)
class FIPS_PKCS1_Sign_Tests_KAT(unittest.TestCase):
pass
test_vectors_sign = load_test_vectors(("Signature", "PKCS1-v1.5"),
"SigGen15_186-2.txt",
"Signature Generation 186-2",
{'shaalg': lambda x: x}) or []
test_vectors_sign += load_test_vectors(("Signature", "PKCS1-v1.5"),
"SigGen15_186-3.txt",
"Signature Generation 186-3",
{'shaalg': lambda x: x}) or []
for count, tv in enumerate(test_vectors_sign):
if isinstance(tv, str):
continue
if hasattr(tv, "n"):
modulus = tv.n
continue
if hasattr(tv, "e"):
private_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e, tv.d)]) # type: ignore
signer = pkcs1_15.new(private_key)
continue
hash_module = load_hash_by_name(tv.shaalg.upper())
hash_obj = hash_module.new(tv.msg)
def new_test(self, hash_obj=hash_obj, signer=signer, result=tv.s):
signature = signer.sign(hash_obj)
self.assertEqual(signature, result)
setattr(FIPS_PKCS1_Sign_Tests_KAT, "test_%d" % count, new_test)
class PKCS1_15_NoParams(unittest.TestCase):
"""Verify that PKCS#1 v1.5 signatures pass even without NULL parameters in
the algorithm identifier (PyCrypto/LP bug #1119552)."""
rsakey = """-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII
q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8
Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI
OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr
+rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK
JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9
n0CnZCJ6IZYqSt0H5N7+Q+2Ro64nuwV/OSQfM6sBwQ==
-----END RSA PRIVATE KEY-----"""
msg = b"This is a test\x0a"
# PKCS1 v1.5 signature of the message computed using SHA-1.
# The digestAlgorithm SEQUENCE does NOT contain the NULL parameter.
sig_str = "a287a13517f716e72fb14eea8e33a8db4a4643314607e7ca3e3e28"\
"1893db74013dda8b855fd99f6fecedcb25fcb7a434f35cd0a101f8"\
"b19348e0bd7b6f152dfc"
signature = unhexlify(sig_str)
def runTest(self):
verifier = pkcs1_15.new(RSA.importKey(self.rsakey))
hashed = SHA1.new(self.msg)
verifier.verify(hashed, self.signature)
class PKCS1_Legacy_Module_Tests(unittest.TestCase):
"""Verify that the legacy module Crypto.Signature.PKCS1_v1_5
behaves as expected. The only difference is that the verify()
method returns True/False and does not raise exceptions."""
def shortDescription(self):
return "Test legacy Crypto.Signature.PKCS1_v1_5"
def runTest(self):
key = RSA.importKey(PKCS1_15_NoParams.rsakey)
hashed = SHA1.new(b"Test")
good_signature = PKCS1_v1_5.new(key).sign(hashed)
verifier = PKCS1_v1_5.new(key.public_key())
self.assertEqual(verifier.verify(hashed, good_signature), True)
# Flip a few bits in the signature
bad_signature = strxor(good_signature, bchr(1) * len(good_signature))
self.assertEqual(verifier.verify(hashed, bad_signature), False)
class PKCS1_All_Hashes_Tests(unittest.TestCase):
def shortDescription(self):
return "Test PKCS#1v1.5 signature in combination with all hashes"
def runTest(self):
key = RSA.generate(1024)
signer = pkcs1_15.new(key)
hash_names = ("MD2", "MD4", "MD5", "RIPEMD160", "SHA1",
"SHA224", "SHA256", "SHA384", "SHA512",
"SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512")
for name in hash_names:
hashed = load_hash_by_name(name).new(b"Test")
signer.sign(hashed)
from Crypto.Hash import BLAKE2b, BLAKE2s
for hash_size in (20, 32, 48, 64):
hashed_b = BLAKE2b.new(digest_bytes=hash_size, data=b"Test")
signer.sign(hashed_b)
for hash_size in (16, 20, 28, 32):
hashed_s = BLAKE2s.new(digest_bytes=hash_size, data=b"Test")
signer.sign(hashed_s)
class TestVectorsWycheproof(unittest.TestCase):
def __init__(self, wycheproof_warnings):
unittest.TestCase.__init__(self)
self._wycheproof_warnings = wycheproof_warnings
self._id = "None"
def setUp(self):
self.tv = []
self.add_tests("rsa_sig_gen_misc_test.json")
self.add_tests("rsa_signature_2048_sha224_test.json")
self.add_tests("rsa_signature_2048_sha256_test.json")
self.add_tests("rsa_signature_2048_sha384_test.json")
self.add_tests("rsa_signature_2048_sha3_224_test.json")
self.add_tests("rsa_signature_2048_sha3_256_test.json")
self.add_tests("rsa_signature_2048_sha3_384_test.json")
self.add_tests("rsa_signature_2048_sha3_512_test.json")
self.add_tests("rsa_signature_2048_sha512_test.json")
self.add_tests("rsa_signature_2048_sha512_224_test.json")
self.add_tests("rsa_signature_2048_sha512_256_test.json")
self.add_tests("rsa_signature_3072_sha256_test.json")
self.add_tests("rsa_signature_3072_sha384_test.json")
self.add_tests("rsa_signature_3072_sha3_256_test.json")
self.add_tests("rsa_signature_3072_sha3_384_test.json")
self.add_tests("rsa_signature_3072_sha3_512_test.json")
self.add_tests("rsa_signature_3072_sha512_test.json")
self.add_tests("rsa_signature_3072_sha512_256_test.json")
self.add_tests("rsa_signature_4096_sha384_test.json")
self.add_tests("rsa_signature_4096_sha512_test.json")
self.add_tests("rsa_signature_4096_sha512_256_test.json")
self.add_tests("rsa_signature_test.json")
def add_tests(self, filename):
def filter_rsa(group):
return RSA.import_key(group['keyPem'])
def filter_sha(group):
hash_name = group['sha']
if hash_name == "SHA-512":
return SHA512
elif hash_name == "SHA-512/224":
return SHA512.new(truncate="224")
elif hash_name == "SHA-512/256":
return SHA512.new(truncate="256")
elif hash_name == "SHA3-512":
return SHA3_512
elif hash_name == "SHA-384":
return SHA384
elif hash_name == "SHA3-384":
return SHA3_384
elif hash_name == "SHA-256":
return SHA256
elif hash_name == "SHA3-256":
return SHA3_256
elif hash_name == "SHA-224":
return SHA224
elif hash_name == "SHA3-224":
return SHA3_224
elif hash_name == "SHA-1":
return SHA1
else:
raise ValueError("Unknown hash algorithm: " + hash_name)
def filter_type(group):
type_name = group['type']
if type_name not in ("RsassaPkcs1Verify", "RsassaPkcs1Generate"):
raise ValueError("Unknown type name " + type_name)
result = load_test_vectors_wycheproof(("Signature", "wycheproof"),
filename,
"Wycheproof PKCS#1v1.5 signature (%s)" % filename,
group_tag={'rsa_key': filter_rsa,
'hash_mod': filter_sha,
'type': filter_type})
return result
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_verify(self, tv):
self._id = "Wycheproof RSA PKCS$#1 Test #" + str(tv.id)
hashed_msg = tv.hash_module.new(tv.msg)
signer = pkcs1_15.new(tv.key)
try:
signature = signer.verify(hashed_msg, tv.sig)
except ValueError as e:
if tv.warning:
return
assert not tv.valid
else:
assert tv.valid
self.warn(tv)
def runTest(self):
for tv in self.tv:
self.test_verify(tv)
def get_tests(config={}):
wycheproof_warnings = config.get('wycheproof_warnings')
tests = []
tests += list_test_cases(FIPS_PKCS1_Verify_Tests)
tests += list_test_cases(FIPS_PKCS1_Sign_Tests)
tests += list_test_cases(PKCS1_15_NoParams)
tests += list_test_cases(PKCS1_Legacy_Module_Tests)
tests += list_test_cases(PKCS1_All_Hashes_Tests)
tests += [ TestVectorsWycheproof(wycheproof_warnings) ]
if config.get('slow_tests'):
tests += list_test_cases(FIPS_PKCS1_Verify_Tests_KAT)
tests += list_test_cases(FIPS_PKCS1_Sign_Tests_KAT)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,377 @@
# ===================================================================
#
# 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 Crypto.Util.py3compat import b, bchr
from Crypto.Util.number import bytes_to_long
from Crypto.Util.strxor import strxor
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof
from Crypto.Hash import SHA1, SHA224, SHA256, SHA384, SHA512
from Crypto.PublicKey import RSA
from Crypto.Signature import pss
from Crypto.Signature import PKCS1_PSS
from Crypto.Signature.pss import MGF1
def load_hash_by_name(hash_name):
return __import__("Crypto.Hash." + hash_name, globals(), locals(), ["new"])
class PRNG(object):
def __init__(self, stream):
self.stream = stream
self.idx = 0
def __call__(self, rnd_size):
result = self.stream[self.idx:self.idx + rnd_size]
self.idx += rnd_size
return result
class PSS_Tests(unittest.TestCase):
rsa_key = b'-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAsvI34FgiTK8+txBvmooNGpNwk23YTU51dwNZi5yha3W4lA/Q\nvcZrDalkmD7ekWQwnduxVKa6pRSI13KBgeUOIqJoGXSWhntEtY3FEwvWOHW5AE7Q\njUzTzCiYT6TVaCcpa/7YLai+p6ai2g5f5Zfh4jSawa9uYeuggFygQq4IVW796MgV\nyqxYMM/arEj+/sKz3Viua9Rp9fFosertCYCX4DUTgW0mX9bwEnEOgjSI3pLOPXz1\n8vx+DRZS5wMCmwCUa0sKonLn3cAUPq+sGix7+eo7T0Z12MU8ud7IYVX/75r3cXiF\nPaYE2q8Le0kgOApIXbb+x74x0rNgyIh1yGygkwIDAQABAoIBABz4t1A0pLT6qHI2\nEIOaNz3mwhK0dZEqkz0GB1Dhtoax5ATgvKCFB98J3lYB08IBURe1snOsnMpOVUtg\naBRSM+QqnCUG6bnzKjAkuFP5liDE+oNQv1YpKp9CsUovuzdmI8Au3ewihl+ZTIN2\nUVNYMEOR1b5m+z2SSwWNOYsiJwpBrT7zkpdlDyjat7FiiPhMMIMXjhQFVxURMIcB\njUBtPzGvV/PG90cVDWi1wRGeeP1dDqti/jsnvykQ15KW1MqGrpeNKRmDdTy/Ucl1\nWIoYklKw3U456lgZ/rDTDB818+Tlnk35z4yF7d5ANPM8CKfqOPcnO1BCKVFzf4eq\n54wvUtkCgYEA1Zv2lp06l7rXMsvNtyYQjbFChezRDRnPwZmN4NCdRtTgGG1G0Ryd\nYz6WWoPGqZp0b4LAaaHd3W2GTcpXF8WXMKfMX1W+tMAxMozfsXRKMcHoypwuS5wT\nfJRXJCG4pvd57AB0iVUEJW2we+uGKU5Zxcx//id2nXGCpoRyViIplQsCgYEA1nVC\neHupHChht0Fh4N09cGqZHZzuwXjOUMzR3Vsfz+4WzVS3NvIgN4g5YgmQFOeKwo5y\niRq5yvubcNdFvf85eHWClg0zPAyxJCVUWigCrrOanGEhJo6re4idJvNVzu4Ucg0v\n6B3SJ1HsCda+ZSNz24bSyqRep8A+RoAaoVSFx5kCgYEAn3RvXPs9s+obnqWYiPF3\nRe5etE6Vt2vfNKwFxx6zaR6bsmBQjuUHcABWiHb6I71S0bMPI0tbrWGG8ibrYKl1\nNTLtUvVVCOS3VP7oNTWT9RTFTAnOXU7DFSo+6o/poWn3r36ff6zhDXeWWMr2OXtt\ndEQ1/2lCGEGVv+v61eVmmQUCgYABFHITPTwqwiFL1O5zPWnzyPWgaovhOYSAb6eW\n38CXQXGn8wdBJZL39J2lWrr4//l45VK6UgIhfYbY2JynSkO10ZGow8RARygVMILu\nOUlaK9lZdDvAf/NpGdUAvzTtZ9F+iYZ2OsA2JnlzyzsGM1l//3vMPWukmJk3ral0\nqoJJ8QKBgGRG3eVHnIegBbFVuMDp2NTcfuSuDVUQ1fGAwtPiFa8u81IodJnMk2pq\niXu2+0ytNA/M+SVrAnE2AgIzcaJbtr0p2srkuVM7KMWnG1vWFNjtXN8fAhf/joOv\nD+NmPL/N4uE57e40tbiU/H7KdyZaDt+5QiTmdhuyAe6CBjKsF2jy\n-----END RSA PRIVATE KEY-----'
msg = b'AAA'
tag = b'\x00[c5\xd8\xb0\x8b!D\x81\x83\x07\xc0\xdd\xb9\xb4\xb2`\x92\xe7\x02\xf1\xe1P\xea\xc3\xf0\xe3>\xddX5\xdd\x8e\xc5\x89\xef\xf3\xc2\xdc\xfeP\x02\x7f\x12+\xc9\xaf\xbb\xec\xfe\xb0\xa5\xb9\x08\x11P\x8fL\xee5\x9b\xb0k{=_\xd2\x14\xfb\x01R\xb7\xfe\x14}b\x03\x8d5Y\x89~}\xfc\xf2l\xd01-\xbd\xeb\x11\xcdV\x11\xe9l\x19k/o5\xa2\x0f\x15\xe7Q$\t=\xec\x1dAB\x19\xa5P\x9a\xaf\xa3G\x86"\xd6~\xf0<p5\x00\x86\xe0\xf3\x99\xc7+\xcfc,\\\x13)v\xcd\xff\x08o\x90\xc5\xd1\xca\x869\xf45\x1e\xfd\xa2\xf1n\xa3\xa6e\xc5\x11Q\xe4@\xbd\x17\x83x\xc9\x9b\xb5\xc7\xea\x03U\x9b\xa0\xccC\x17\xc9T\x86/\x05\x1c\xc7\x95hC\xf9b1\xbb\x05\xc3\xf0\x9a>j\xfcqkbs\x13\x84b\xe4\xbdm(\xed`\xa4F\xfb\x8f.\xe1\x8c)/_\x9eS\x98\xa4v\xb8\xdc\xfe\xf7/D\x18\x19\xb3T\x97:\xe2\x96s\xe8<\xa2\xb4\xb9\xf8/'
def test_positive_1(self):
key = RSA.import_key(self.rsa_key)
h = SHA256.new(self.msg)
verifier = pss.new(key)
verifier.verify(h, self.tag)
def test_negative_1(self):
key = RSA.import_key(self.rsa_key)
h = SHA256.new(self.msg + b'A')
verifier = pss.new(key)
tag = bytearray(self.tag)
self.assertRaises(ValueError, verifier.verify, h, tag)
def test_negative_2(self):
key = RSA.import_key(self.rsa_key)
h = SHA256.new(self.msg)
verifier = pss.new(key, salt_bytes=1000)
tag = bytearray(self.tag)
self.assertRaises(ValueError, verifier.verify, h, tag)
class FIPS_PKCS1_Verify_Tests(unittest.TestCase):
def shortDescription(self):
return "FIPS PKCS1 Tests (Verify)"
def verify_positive(self, hashmod, message, public_key, salt, signature):
prng = PRNG(salt)
hashed = hashmod.new(message)
verifier = pss.new(public_key, salt_bytes=len(salt), rand_func=prng)
verifier.verify(hashed, signature)
def verify_negative(self, hashmod, message, public_key, salt, signature):
prng = PRNG(salt)
hashed = hashmod.new(message)
verifier = pss.new(public_key, salt_bytes=len(salt), rand_func=prng)
self.assertRaises(ValueError, verifier.verify, hashed, signature)
def test_can_sign(self):
test_public_key = RSA.generate(1024).public_key()
verifier = pss.new(test_public_key)
self.assertEqual(verifier.can_sign(), False)
class FIPS_PKCS1_Verify_Tests_KAT(unittest.TestCase):
pass
test_vectors_verify = load_test_vectors(("Signature", "PKCS1-PSS"),
"SigVerPSS_186-3.rsp",
"Signature Verification 186-3",
{'shaalg': lambda x: x,
'result': lambda x: x}) or []
for count, tv in enumerate(test_vectors_verify):
if isinstance(tv, str):
continue
if hasattr(tv, "n"):
modulus = tv.n
continue
if hasattr(tv, "p"):
continue
hash_module = load_hash_by_name(tv.shaalg.upper())
hash_obj = hash_module.new(tv.msg)
public_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e)]) # type: ignore
if tv.saltval != b("\x00"):
prng = PRNG(tv.saltval)
verifier = pss.new(public_key, salt_bytes=len(tv.saltval), rand_func=prng)
else:
verifier = pss.new(public_key, salt_bytes=0)
def positive_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s):
verifier.verify(hash_obj, signature)
def negative_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s):
self.assertRaises(ValueError, verifier.verify, hash_obj, signature)
if tv.result == 'p':
setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_positive_%d" % count, positive_test)
else:
setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_negative_%d" % count, negative_test)
class FIPS_PKCS1_Sign_Tests(unittest.TestCase):
def shortDescription(self):
return "FIPS PKCS1 Tests (Sign)"
def test_can_sign(self):
test_private_key = RSA.generate(1024)
signer = pss.new(test_private_key)
self.assertEqual(signer.can_sign(), True)
class FIPS_PKCS1_Sign_Tests_KAT(unittest.TestCase):
pass
test_vectors_sign = load_test_vectors(("Signature", "PKCS1-PSS"),
"SigGenPSS_186-2.txt",
"Signature Generation 186-2",
{'shaalg': lambda x: x}) or []
test_vectors_sign += load_test_vectors(("Signature", "PKCS1-PSS"),
"SigGenPSS_186-3.txt",
"Signature Generation 186-3",
{'shaalg': lambda x: x}) or []
for count, tv in enumerate(test_vectors_sign):
if isinstance(tv, str):
continue
if hasattr(tv, "n"):
modulus = tv.n
continue
if hasattr(tv, "e"):
private_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e, tv.d)]) # type: ignore
continue
hash_module = load_hash_by_name(tv.shaalg.upper())
hash_obj = hash_module.new(tv.msg)
if tv.saltval != b("\x00"):
prng = PRNG(tv.saltval)
signer = pss.new(private_key, salt_bytes=len(tv.saltval), rand_func=prng)
else:
signer = pss.new(private_key, salt_bytes=0)
def new_test(self, hash_obj=hash_obj, signer=signer, result=tv.s):
signature = signer.sign(hash_obj)
self.assertEqual(signature, result)
setattr(FIPS_PKCS1_Sign_Tests_KAT, "test_%d" % count, new_test)
class PKCS1_Legacy_Module_Tests(unittest.TestCase):
"""Verify that the legacy module Crypto.Signature.PKCS1_PSS
behaves as expected. The only difference is that the verify()
method returns True/False and does not raise exceptions."""
def shortDescription(self):
return "Test legacy Crypto.Signature.PKCS1_PSS"
def runTest(self):
key = RSA.generate(1024)
hashed = SHA1.new(b("Test"))
good_signature = PKCS1_PSS.new(key).sign(hashed)
verifier = PKCS1_PSS.new(key.public_key())
self.assertEqual(verifier.verify(hashed, good_signature), True)
# Flip a few bits in the signature
bad_signature = strxor(good_signature, bchr(1) * len(good_signature))
self.assertEqual(verifier.verify(hashed, bad_signature), False)
class PKCS1_All_Hashes_Tests(unittest.TestCase):
def shortDescription(self):
return "Test PKCS#1 PSS signature in combination with all hashes"
def runTest(self):
key = RSA.generate(1280)
signer = pss.new(key)
hash_names = ("MD2", "MD4", "MD5", "RIPEMD160", "SHA1",
"SHA224", "SHA256", "SHA384", "SHA512",
"SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512")
for name in hash_names:
hashed = load_hash_by_name(name).new(b("Test"))
signer.sign(hashed)
from Crypto.Hash import BLAKE2b, BLAKE2s
for hash_size in (20, 32, 48, 64):
hashed_b = BLAKE2b.new(digest_bytes=hash_size, data=b("Test"))
signer.sign(hashed_b)
for hash_size in (16, 20, 28, 32):
hashed_s = BLAKE2s.new(digest_bytes=hash_size, data=b("Test"))
signer.sign(hashed_s)
def get_hash_module(hash_name):
if hash_name == "SHA-512":
hash_module = SHA512
elif hash_name == "SHA-512/224":
hash_module = SHA512.new(truncate="224")
elif hash_name == "SHA-512/256":
hash_module = SHA512.new(truncate="256")
elif hash_name == "SHA-384":
hash_module = SHA384
elif hash_name == "SHA-256":
hash_module = SHA256
elif hash_name == "SHA-224":
hash_module = SHA224
elif hash_name == "SHA-1":
hash_module = SHA1
else:
raise ValueError("Unknown hash algorithm: " + hash_name)
return hash_module
class TestVectorsPSSWycheproof(unittest.TestCase):
def __init__(self, wycheproof_warnings):
unittest.TestCase.__init__(self)
self._wycheproof_warnings = wycheproof_warnings
self._id = "None"
def add_tests(self, filename):
def filter_rsa(group):
return RSA.import_key(group['keyPem'])
def filter_sha(group):
return get_hash_module(group['sha'])
def filter_type(group):
type_name = group['type']
if type_name not in ("RsassaPssVerify", ):
raise ValueError("Unknown type name " + type_name)
def filter_slen(group):
return group['sLen']
def filter_mgf(group):
mgf = group['mgf']
if mgf not in ("MGF1", ):
raise ValueError("Unknown MGF " + mgf)
mgf1_hash = get_hash_module(group['mgfSha'])
def mgf(x, y, mh=mgf1_hash):
return MGF1(x, y, mh)
return mgf
result = load_test_vectors_wycheproof(("Signature", "wycheproof"),
filename,
"Wycheproof PSS signature (%s)" % filename,
group_tag={'key': filter_rsa,
'hash_module': filter_sha,
'sLen': filter_slen,
'mgf': filter_mgf,
'type': filter_type})
return result
def setUp(self):
self.tv = []
self.add_tests("rsa_pss_2048_sha1_mgf1_20_test.json")
self.add_tests("rsa_pss_2048_sha256_mgf1_0_test.json")
self.add_tests("rsa_pss_2048_sha256_mgf1_32_test.json")
self.add_tests("rsa_pss_2048_sha512_256_mgf1_28_test.json")
self.add_tests("rsa_pss_2048_sha512_256_mgf1_32_test.json")
self.add_tests("rsa_pss_3072_sha256_mgf1_32_test.json")
self.add_tests("rsa_pss_4096_sha256_mgf1_32_test.json")
self.add_tests("rsa_pss_4096_sha512_mgf1_32_test.json")
self.add_tests("rsa_pss_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_verify(self, tv):
self._id = "Wycheproof RSA PSS Test #%d (%s)" % (tv.id, tv.comment)
hashed_msg = tv.hash_module.new(tv.msg)
signer = pss.new(tv.key, mask_func=tv.mgf, salt_bytes=tv.sLen)
try:
signature = signer.verify(hashed_msg, tv.sig)
except ValueError as e:
if tv.warning:
return
assert not tv.valid
else:
assert tv.valid
self.warn(tv)
def runTest(self):
for tv in self.tv:
self.test_verify(tv)
def get_tests(config={}):
wycheproof_warnings = config.get('wycheproof_warnings')
tests = []
tests += list_test_cases(PSS_Tests)
tests += list_test_cases(FIPS_PKCS1_Verify_Tests)
tests += list_test_cases(FIPS_PKCS1_Sign_Tests)
tests += list_test_cases(PKCS1_Legacy_Module_Tests)
tests += list_test_cases(PKCS1_All_Hashes_Tests)
if config.get('slow_tests'):
tests += list_test_cases(FIPS_PKCS1_Verify_Tests_KAT)
tests += list_test_cases(FIPS_PKCS1_Sign_Tests_KAT)
tests += [TestVectorsPSSWycheproof(wycheproof_warnings)]
return tests
if __name__ == '__main__':
def suite():
return unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
#
# SelfTest/Util/__init__.py: Self-test for utility 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 utility modules"""
__revision__ = "$Id$"
import os
def get_tests(config={}):
tests = []
from Crypto.SelfTest.Util import test_number; tests += test_number.get_tests(config=config)
from Crypto.SelfTest.Util import test_Counter; tests += test_Counter.get_tests(config=config)
from Crypto.SelfTest.Util import test_Padding; tests += test_Padding.get_tests(config=config)
from Crypto.SelfTest.Util import test_strxor; tests += test_strxor.get_tests(config=config)
from Crypto.SelfTest.Util import test_asn1; tests += test_asn1.get_tests(config=config)
from Crypto.SelfTest.Util import test_rfc1751; tests += test_rfc1751.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:
@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
#
# SelfTest/Util/test_Counter: Self-test for the Crypto.Util.Counter module
#
# Written in 2009 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-tests for Crypto.Util.Counter"""
from Crypto.Util.py3compat import *
import unittest
class CounterTests(unittest.TestCase):
def setUp(self):
global Counter
from Crypto.Util import Counter
def test_BE(self):
"""Big endian"""
c = Counter.new(128)
c = Counter.new(128, little_endian=False)
def test_LE(self):
"""Little endian"""
c = Counter.new(128, little_endian=True)
def test_nbits(self):
c = Counter.new(nbits=128)
self.assertRaises(ValueError, Counter.new, 129)
def test_prefix(self):
c = Counter.new(128, prefix=b("xx"))
def test_suffix(self):
c = Counter.new(128, suffix=b("xx"))
def test_iv(self):
c = Counter.new(128, initial_value=2)
self.assertRaises(ValueError, Counter.new, 16, initial_value=0x1FFFF)
def get_tests(config={}):
from Crypto.SelfTest.st_common import list_test_cases
return list_test_cases(CounterTests)
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
# vim:set ts=4 sw=4 sts=4 expandtab:
@@ -0,0 +1,153 @@
#
# SelfTest/Util/test_Padding.py: Self-test for padding functions
#
# ===================================================================
#
# 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 as uh
from Crypto.Util.py3compat import *
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Util.Padding import pad, unpad
class PKCS7_Tests(unittest.TestCase):
def test1(self):
padded = pad(b(""), 4)
self.assertTrue(padded == uh(b("04040404")))
padded = pad(b(""), 4, 'pkcs7')
self.assertTrue(padded == uh(b("04040404")))
back = unpad(padded, 4)
self.assertTrue(back == b(""))
def test2(self):
padded = pad(uh(b("12345678")), 4)
self.assertTrue(padded == uh(b("1234567804040404")))
back = unpad(padded, 4)
self.assertTrue(back == uh(b("12345678")))
def test3(self):
padded = pad(uh(b("123456")), 4)
self.assertTrue(padded == uh(b("12345601")))
back = unpad(padded, 4)
self.assertTrue(back == uh(b("123456")))
def test4(self):
padded = pad(uh(b("1234567890")), 4)
self.assertTrue(padded == uh(b("1234567890030303")))
back = unpad(padded, 4)
self.assertTrue(back == uh(b("1234567890")))
def testn1(self):
self.assertRaises(ValueError, pad, uh(b("12")), 4, 'pkcs8')
def testn2(self):
self.assertRaises(ValueError, unpad, b("\0\0\0"), 4)
self.assertRaises(ValueError, unpad, b(""), 4)
def testn3(self):
self.assertRaises(ValueError, unpad, b("123456\x02"), 4)
self.assertRaises(ValueError, unpad, b("123456\x00"), 4)
self.assertRaises(ValueError, unpad, b("123456\x05\x05\x05\x05\x05"), 4)
class X923_Tests(unittest.TestCase):
def test1(self):
padded = pad(b(""), 4, 'x923')
self.assertTrue(padded == uh(b("00000004")))
back = unpad(padded, 4, 'x923')
self.assertTrue(back == b(""))
def test2(self):
padded = pad(uh(b("12345678")), 4, 'x923')
self.assertTrue(padded == uh(b("1234567800000004")))
back = unpad(padded, 4, 'x923')
self.assertTrue(back == uh(b("12345678")))
def test3(self):
padded = pad(uh(b("123456")), 4, 'x923')
self.assertTrue(padded == uh(b("12345601")))
back = unpad(padded, 4, 'x923')
self.assertTrue(back == uh(b("123456")))
def test4(self):
padded = pad(uh(b("1234567890")), 4, 'x923')
self.assertTrue(padded == uh(b("1234567890000003")))
back = unpad(padded, 4, 'x923')
self.assertTrue(back == uh(b("1234567890")))
def testn1(self):
self.assertRaises(ValueError, unpad, b("123456\x02"), 4, 'x923')
self.assertRaises(ValueError, unpad, b("123456\x00"), 4, 'x923')
self.assertRaises(ValueError, unpad, b("123456\x00\x00\x00\x00\x05"), 4, 'x923')
self.assertRaises(ValueError, unpad, b(""), 4, 'x923')
class ISO7816_Tests(unittest.TestCase):
def test1(self):
padded = pad(b(""), 4, 'iso7816')
self.assertTrue(padded == uh(b("80000000")))
back = unpad(padded, 4, 'iso7816')
self.assertTrue(back == b(""))
def test2(self):
padded = pad(uh(b("12345678")), 4, 'iso7816')
self.assertTrue(padded == uh(b("1234567880000000")))
back = unpad(padded, 4, 'iso7816')
self.assertTrue(back == uh(b("12345678")))
def test3(self):
padded = pad(uh(b("123456")), 4, 'iso7816')
self.assertTrue(padded == uh(b("12345680")))
back = unpad(padded, 4, 'iso7816')
self.assertTrue(back == uh(b("123456")))
def test4(self):
padded = pad(uh(b("1234567890")), 4, 'iso7816')
self.assertTrue(padded == uh(b("1234567890800000")))
back = unpad(padded, 4, 'iso7816')
self.assertTrue(back == uh(b("1234567890")))
def testn1(self):
self.assertRaises(ValueError, unpad, b("123456\x81"), 4, 'iso7816')
self.assertRaises(ValueError, unpad, b(""), 4, 'iso7816')
def get_tests(config={}):
tests = []
tests += list_test_cases(PKCS7_Tests)
tests += list_test_cases(X923_Tests)
tests += list_test_cases(ISO7816_Tests)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,851 @@
#
# SelfTest/Util/test_asn.py: Self-test for the Crypto.Util.asn1 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-tests for Crypto.Util.asn1"""
import unittest
from Crypto.Util.py3compat import *
from Crypto.Util.asn1 import (DerObject, DerSetOf, DerInteger,
DerBitString,
DerObjectId, DerNull, DerOctetString,
DerSequence, DerBoolean)
class DerObjectTests(unittest.TestCase):
def testObjInit1(self):
# Fail with invalid tag format (must be 1 byte)
self.assertRaises(ValueError, DerObject, b('\x00\x99'))
# Fail with invalid implicit tag (must be <0x1F)
self.assertRaises(ValueError, DerObject, 0x1F)
# ------
def testObjEncode1(self):
# No payload
der = DerObject(b('\x02'))
self.assertEqual(der.encode(), b('\x02\x00'))
# Small payload (primitive)
der.payload = b('\x45')
self.assertEqual(der.encode(), b('\x02\x01\x45'))
# Invariant
self.assertEqual(der.encode(), b('\x02\x01\x45'))
# Initialize with numerical tag
der = DerObject(0x04)
der.payload = b('\x45')
self.assertEqual(der.encode(), b('\x04\x01\x45'))
# Initialize with constructed type
der = DerObject(b('\x10'), constructed=True)
self.assertEqual(der.encode(), b('\x30\x00'))
def testObjEncode2(self):
# Initialize with payload
der = DerObject(0x03, b('\x12\x12'))
self.assertEqual(der.encode(), b('\x03\x02\x12\x12'))
def testObjEncode3(self):
# Long payload
der = DerObject(b('\x10'))
der.payload = b("0")*128
self.assertEqual(der.encode(), b('\x10\x81\x80' + "0"*128))
def testObjEncode4(self):
# Implicit tags (constructed)
der = DerObject(0x10, implicit=1, constructed=True)
der.payload = b('ppll')
self.assertEqual(der.encode(), b('\xa1\x04ppll'))
# Implicit tags (primitive)
der = DerObject(0x02, implicit=0x1E, constructed=False)
der.payload = b('ppll')
self.assertEqual(der.encode(), b('\x9E\x04ppll'))
def testObjEncode5(self):
# Encode type with explicit tag
der = DerObject(0x10, explicit=5)
der.payload = b("xxll")
self.assertEqual(der.encode(), b("\xa5\x06\x10\x04xxll"))
# -----
def testObjDecode1(self):
# Decode short payload
der = DerObject(0x02)
der.decode(b('\x02\x02\x01\x02'))
self.assertEqual(der.payload, b("\x01\x02"))
self.assertEqual(der._tag_octet, 0x02)
def testObjDecode2(self):
# Decode long payload
der = DerObject(0x02)
der.decode(b('\x02\x81\x80' + "1"*128))
self.assertEqual(der.payload, b("1")*128)
self.assertEqual(der._tag_octet, 0x02)
def testObjDecode3(self):
# Decode payload with too much data gives error
der = DerObject(0x02)
self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02\xFF'))
# Decode payload with too little data gives error
der = DerObject(0x02)
self.assertRaises(ValueError, der.decode, b('\x02\x02\x01'))
def testObjDecode4(self):
# Decode implicit tag (primitive)
der = DerObject(0x02, constructed=False, implicit=0xF)
self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02'))
der.decode(b('\x8F\x01\x00'))
self.assertEqual(der.payload, b('\x00'))
# Decode implicit tag (constructed)
der = DerObject(0x02, constructed=True, implicit=0xF)
self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02'))
der.decode(b('\xAF\x01\x00'))
self.assertEqual(der.payload, b('\x00'))
def testObjDecode5(self):
# Decode payload with unexpected tag gives error
der = DerObject(0x02)
self.assertRaises(ValueError, der.decode, b('\x03\x02\x01\x02'))
def testObjDecode6(self):
# Arbitrary DER object
der = DerObject()
der.decode(b('\x65\x01\x88'))
self.assertEqual(der._tag_octet, 0x65)
self.assertEqual(der.payload, b('\x88'))
def testObjDecode7(self):
# Decode explicit tag
der = DerObject(0x10, explicit=5)
der.decode(b("\xa5\x06\x10\x04xxll"))
self.assertEqual(der._inner_tag_octet, 0x10)
self.assertEqual(der.payload, b('xxll'))
# Explicit tag may be 0
der = DerObject(0x10, explicit=0)
der.decode(b("\xa0\x06\x10\x04xxll"))
self.assertEqual(der._inner_tag_octet, 0x10)
self.assertEqual(der.payload, b('xxll'))
def testObjDecode8(self):
# Verify that decode returns the object
der = DerObject(0x02)
self.assertEqual(der, der.decode(b('\x02\x02\x01\x02')))
class DerIntegerTests(unittest.TestCase):
def testInit1(self):
der = DerInteger(1)
self.assertEqual(der.encode(), b('\x02\x01\x01'))
def testEncode1(self):
# Single-byte integers
# Value 0
der = DerInteger(0)
self.assertEqual(der.encode(), b('\x02\x01\x00'))
# Value 1
der = DerInteger(1)
self.assertEqual(der.encode(), b('\x02\x01\x01'))
# Value 127
der = DerInteger(127)
self.assertEqual(der.encode(), b('\x02\x01\x7F'))
def testEncode2(self):
# Multi-byte integers
# Value 128
der = DerInteger(128)
self.assertEqual(der.encode(), b('\x02\x02\x00\x80'))
# Value 0x180
der = DerInteger(0x180)
self.assertEqual(der.encode(), b('\x02\x02\x01\x80'))
# One very long integer
der = DerInteger(2**2048)
self.assertEqual(der.encode(),
b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
def testEncode3(self):
# Negative integers
# Value -1
der = DerInteger(-1)
self.assertEqual(der.encode(), b('\x02\x01\xFF'))
# Value -128
der = DerInteger(-128)
self.assertEqual(der.encode(), b('\x02\x01\x80'))
# Value
der = DerInteger(-87873)
self.assertEqual(der.encode(), b('\x02\x03\xFE\xA8\xBF'))
def testEncode4(self):
# Explicit encoding
number = DerInteger(0x34, explicit=3)
self.assertEqual(number.encode(), b('\xa3\x03\x02\x01\x34'))
# -----
def testDecode1(self):
# Single-byte integer
der = DerInteger()
# Value 0
der.decode(b('\x02\x01\x00'))
self.assertEqual(der.value, 0)
# Value 1
der.decode(b('\x02\x01\x01'))
self.assertEqual(der.value, 1)
# Value 127
der.decode(b('\x02\x01\x7F'))
self.assertEqual(der.value, 127)
def testDecode2(self):
# Multi-byte integer
der = DerInteger()
# Value 0x180L
der.decode(b('\x02\x02\x01\x80'))
self.assertEqual(der.value,0x180)
# One very long integer
der.decode(
b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
self.assertEqual(der.value,2**2048)
def testDecode3(self):
# Negative integer
der = DerInteger()
# Value -1
der.decode(b('\x02\x01\xFF'))
self.assertEqual(der.value, -1)
# Value -32768
der.decode(b('\x02\x02\x80\x00'))
self.assertEqual(der.value, -32768)
def testDecode5(self):
# We still accept BER integer format
der = DerInteger()
# Redundant leading zeroes
der.decode(b('\x02\x02\x00\x01'))
self.assertEqual(der.value, 1)
# Redundant leading 0xFF
der.decode(b('\x02\x02\xFF\xFF'))
self.assertEqual(der.value, -1)
# Empty payload
der.decode(b('\x02\x00'))
self.assertEqual(der.value, 0)
def testDecode6(self):
# Explicit encoding
number = DerInteger(explicit=3)
number.decode(b('\xa3\x03\x02\x01\x34'))
self.assertEqual(number.value, 0x34)
def testDecode7(self):
# Verify decode returns the DerInteger
der = DerInteger()
self.assertEqual(der, der.decode(b('\x02\x01\x7F')))
###
def testStrict1(self):
number = DerInteger()
number.decode(b'\x02\x02\x00\x01')
number.decode(b'\x02\x02\x00\x7F')
self.assertRaises(ValueError, number.decode, b'\x02\x02\x00\x01', strict=True)
self.assertRaises(ValueError, number.decode, b'\x02\x02\x00\x7F', strict=True)
###
def testErrDecode1(self):
# Wide length field
der = DerInteger()
self.assertRaises(ValueError, der.decode, b('\x02\x81\x01\x01'))
class DerSequenceTests(unittest.TestCase):
def testInit1(self):
der = DerSequence([1, DerInteger(2), b('0\x00')])
self.assertEqual(der.encode(), b('0\x08\x02\x01\x01\x02\x01\x020\x00'))
def testEncode1(self):
# Empty sequence
der = DerSequence()
self.assertEqual(der.encode(), b('0\x00'))
self.assertFalse(der.hasOnlyInts())
# One single-byte integer (zero)
der.append(0)
self.assertEqual(der.encode(), b('0\x03\x02\x01\x00'))
self.assertEqual(der.hasInts(),1)
self.assertEqual(der.hasInts(False),1)
self.assertTrue(der.hasOnlyInts())
self.assertTrue(der.hasOnlyInts(False))
# Invariant
self.assertEqual(der.encode(), b('0\x03\x02\x01\x00'))
def testEncode2(self):
# Indexing
der = DerSequence()
der.append(0)
der[0] = 1
self.assertEqual(len(der),1)
self.assertEqual(der[0],1)
self.assertEqual(der[-1],1)
self.assertEqual(der.encode(), b('0\x03\x02\x01\x01'))
#
der[:] = [1]
self.assertEqual(len(der),1)
self.assertEqual(der[0],1)
self.assertEqual(der.encode(), b('0\x03\x02\x01\x01'))
def testEncode3(self):
# One multi-byte integer (non-zero)
der = DerSequence()
der.append(0x180)
self.assertEqual(der.encode(), b('0\x04\x02\x02\x01\x80'))
def testEncode4(self):
# One very long integer
der = DerSequence()
der.append(2**2048)
self.assertEqual(der.encode(), b('0\x82\x01\x05')+
b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
def testEncode5(self):
der = DerSequence()
der += 1
der += b('\x30\x00')
self.assertEqual(der.encode(), b('\x30\x05\x02\x01\x01\x30\x00'))
def testEncode6(self):
# Two positive integers
der = DerSequence()
der.append(0x180)
der.append(0xFF)
self.assertEqual(der.encode(), b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff'))
self.assertTrue(der.hasOnlyInts())
self.assertTrue(der.hasOnlyInts(False))
# Two mixed integers
der = DerSequence()
der.append(2)
der.append(-2)
self.assertEqual(der.encode(), b('0\x06\x02\x01\x02\x02\x01\xFE'))
self.assertEqual(der.hasInts(), 1)
self.assertEqual(der.hasInts(False), 2)
self.assertFalse(der.hasOnlyInts())
self.assertTrue(der.hasOnlyInts(False))
#
der.append(0x01)
der[1:] = [9,8]
self.assertEqual(len(der),3)
self.assertEqual(der[1:],[9,8])
self.assertEqual(der[1:-1],[9])
self.assertEqual(der.encode(), b('0\x09\x02\x01\x02\x02\x01\x09\x02\x01\x08'))
def testEncode7(self):
# One integer and another type (already encoded)
der = DerSequence()
der.append(0x180)
der.append(b('0\x03\x02\x01\x05'))
self.assertEqual(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05'))
self.assertFalse(der.hasOnlyInts())
def testEncode8(self):
# One integer and another type (yet to encode)
der = DerSequence()
der.append(0x180)
der.append(DerSequence([5]))
self.assertEqual(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05'))
self.assertFalse(der.hasOnlyInts())
####
def testDecode1(self):
# Empty sequence
der = DerSequence()
der.decode(b('0\x00'))
self.assertEqual(len(der),0)
# One single-byte integer (zero)
der.decode(b('0\x03\x02\x01\x00'))
self.assertEqual(len(der),1)
self.assertEqual(der[0],0)
# Invariant
der.decode(b('0\x03\x02\x01\x00'))
self.assertEqual(len(der),1)
self.assertEqual(der[0],0)
def testDecode2(self):
# One single-byte integer (non-zero)
der = DerSequence()
der.decode(b('0\x03\x02\x01\x7f'))
self.assertEqual(len(der),1)
self.assertEqual(der[0],127)
def testDecode4(self):
# One very long integer
der = DerSequence()
der.decode(b('0\x82\x01\x05')+
b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
self.assertEqual(len(der),1)
self.assertEqual(der[0],2**2048)
def testDecode6(self):
# Two integers
der = DerSequence()
der.decode(b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff'))
self.assertEqual(len(der),2)
self.assertEqual(der[0],0x180)
self.assertEqual(der[1],0xFF)
def testDecode7(self):
# One integer and 2 other types
der = DerSequence()
der.decode(b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00'))
self.assertEqual(len(der),3)
self.assertEqual(der[0],0x180)
self.assertEqual(der[1],b('\x24\x02\xb6\x63'))
self.assertEqual(der[2],b('\x12\x00'))
def testDecode8(self):
# Only 2 other types
der = DerSequence()
der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00'))
self.assertEqual(len(der),2)
self.assertEqual(der[0],b('\x24\x02\xb6\x63'))
self.assertEqual(der[1],b('\x12\x00'))
self.assertEqual(der.hasInts(), 0)
self.assertEqual(der.hasInts(False), 0)
self.assertFalse(der.hasOnlyInts())
self.assertFalse(der.hasOnlyInts(False))
def testDecode9(self):
# Verify that decode returns itself
der = DerSequence()
self.assertEqual(der, der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00')))
###
def testErrDecode1(self):
# Not a sequence
der = DerSequence()
self.assertRaises(ValueError, der.decode, b(''))
self.assertRaises(ValueError, der.decode, b('\x00'))
self.assertRaises(ValueError, der.decode, b('\x30'))
def testErrDecode2(self):
der = DerSequence()
# Too much data
self.assertRaises(ValueError, der.decode, b('\x30\x00\x00'))
def testErrDecode3(self):
# Wrong length format
der = DerSequence()
# Missing length in sub-item
self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x01\x01\x00'))
# Valid BER, but invalid DER length
self.assertRaises(ValueError, der.decode, b('\x30\x81\x03\x02\x01\x01'))
self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x81\x01\x01'))
def test_expected_nr_elements(self):
der_bin = DerSequence([1, 2, 3]).encode()
DerSequence().decode(der_bin, nr_elements=3)
DerSequence().decode(der_bin, nr_elements=(2,3))
self.assertRaises(ValueError, DerSequence().decode, der_bin, nr_elements=1)
self.assertRaises(ValueError, DerSequence().decode, der_bin, nr_elements=(4,5))
def test_expected_only_integers(self):
der_bin1 = DerSequence([1, 2, 3]).encode()
der_bin2 = DerSequence([1, 2, DerSequence([3, 4])]).encode()
DerSequence().decode(der_bin1, only_ints_expected=True)
DerSequence().decode(der_bin1, only_ints_expected=False)
DerSequence().decode(der_bin2, only_ints_expected=False)
self.assertRaises(ValueError, DerSequence().decode, der_bin2, only_ints_expected=True)
class DerOctetStringTests(unittest.TestCase):
def testInit1(self):
der = DerOctetString(b('\xFF'))
self.assertEqual(der.encode(), b('\x04\x01\xFF'))
def testEncode1(self):
# Empty sequence
der = DerOctetString()
self.assertEqual(der.encode(), b('\x04\x00'))
# Small payload
der.payload = b('\x01\x02')
self.assertEqual(der.encode(), b('\x04\x02\x01\x02'))
####
def testDecode1(self):
# Empty sequence
der = DerOctetString()
der.decode(b('\x04\x00'))
self.assertEqual(der.payload, b(''))
# Small payload
der.decode(b('\x04\x02\x01\x02'))
self.assertEqual(der.payload, b('\x01\x02'))
def testDecode2(self):
# Verify that decode returns the object
der = DerOctetString()
self.assertEqual(der, der.decode(b('\x04\x00')))
def testErrDecode1(self):
# No leftovers allowed
der = DerOctetString()
self.assertRaises(ValueError, der.decode, b('\x04\x01\x01\xff'))
class DerNullTests(unittest.TestCase):
def testEncode1(self):
der = DerNull()
self.assertEqual(der.encode(), b('\x05\x00'))
####
def testDecode1(self):
# Empty sequence
der = DerNull()
self.assertEqual(der, der.decode(b('\x05\x00')))
class DerObjectIdTests(unittest.TestCase):
def testInit1(self):
der = DerObjectId("1.1")
self.assertEqual(der.encode(), b'\x06\x01)')
def testEncode1(self):
der = DerObjectId('1.2.840.113549.1.1.1')
self.assertEqual(der.encode(), b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01')
der = DerObjectId()
der.value = '1.2.840.113549.1.1.1'
self.assertEqual(der.encode(), b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01')
der = DerObjectId('2.999.1234')
self.assertEqual(der.encode(), b'\x06\x04\x88\x37\x89\x52')
def testEncode2(self):
der = DerObjectId('3.4')
self.assertRaises(ValueError, der.encode)
der = DerObjectId('1.40')
self.assertRaises(ValueError, der.encode)
####
def testDecode1(self):
# Empty sequence
der = DerObjectId()
der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01')
self.assertEqual(der.value, '1.2.840.113549.1.1.1')
def testDecode2(self):
# Verify that decode returns the object
der = DerObjectId()
self.assertEqual(der,
der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'))
def testDecode3(self):
der = DerObjectId()
der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x00\x01')
self.assertEqual(der.value, '1.2.840.113549.1.0.1')
def testDecode4(self):
der = DerObjectId()
der.decode(b'\x06\x04\x88\x37\x89\x52')
self.assertEqual(der.value, '2.999.1234')
class DerBitStringTests(unittest.TestCase):
def testInit1(self):
der = DerBitString(b("\xFF"))
self.assertEqual(der.encode(), b('\x03\x02\x00\xFF'))
def testInit2(self):
der = DerBitString(DerInteger(1))
self.assertEqual(der.encode(), b('\x03\x04\x00\x02\x01\x01'))
def testEncode1(self):
# Empty sequence
der = DerBitString()
self.assertEqual(der.encode(), b('\x03\x01\x00'))
# Small payload
der = DerBitString(b('\x01\x02'))
self.assertEqual(der.encode(), b('\x03\x03\x00\x01\x02'))
# Small payload
der = DerBitString()
der.value = b('\x01\x02')
self.assertEqual(der.encode(), b('\x03\x03\x00\x01\x02'))
####
def testDecode1(self):
# Empty sequence
der = DerBitString()
der.decode(b('\x03\x00'))
self.assertEqual(der.value, b(''))
# Small payload
der.decode(b('\x03\x03\x00\x01\x02'))
self.assertEqual(der.value, b('\x01\x02'))
def testDecode2(self):
# Verify that decode returns the object
der = DerBitString()
self.assertEqual(der, der.decode(b('\x03\x00')))
class DerSetOfTests(unittest.TestCase):
def testInit1(self):
der = DerSetOf([DerInteger(1), DerInteger(2)])
self.assertEqual(der.encode(), b('1\x06\x02\x01\x01\x02\x01\x02'))
def testEncode1(self):
# Empty set
der = DerSetOf()
self.assertEqual(der.encode(), b('1\x00'))
# One single-byte integer (zero)
der.add(0)
self.assertEqual(der.encode(), b('1\x03\x02\x01\x00'))
# Invariant
self.assertEqual(der.encode(), b('1\x03\x02\x01\x00'))
def testEncode2(self):
# Two integers
der = DerSetOf()
der.add(0x180)
der.add(0xFF)
self.assertEqual(der.encode(), b('1\x08\x02\x02\x00\xff\x02\x02\x01\x80'))
# Initialize with integers
der = DerSetOf([0x180, 0xFF])
self.assertEqual(der.encode(), b('1\x08\x02\x02\x00\xff\x02\x02\x01\x80'))
def testEncode3(self):
# One integer and another type (no matter what it is)
der = DerSetOf()
der.add(0x180)
self.assertRaises(ValueError, der.add, b('\x00\x02\x00\x00'))
def testEncode4(self):
# Only non integers
der = DerSetOf()
der.add(b('\x01\x00'))
der.add(b('\x01\x01\x01'))
self.assertEqual(der.encode(), b('1\x05\x01\x00\x01\x01\x01'))
####
def testDecode1(self):
# Empty sequence
der = DerSetOf()
der.decode(b('1\x00'))
self.assertEqual(len(der),0)
# One single-byte integer (zero)
der.decode(b('1\x03\x02\x01\x00'))
self.assertEqual(len(der),1)
self.assertEqual(list(der),[0])
def testDecode2(self):
# Two integers
der = DerSetOf()
der.decode(b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff'))
self.assertEqual(len(der),2)
l = list(der)
self.assertTrue(0x180 in l)
self.assertTrue(0xFF in l)
def testDecode3(self):
# One integer and 2 other types
der = DerSetOf()
#import pdb; pdb.set_trace()
self.assertRaises(ValueError, der.decode,
b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00'))
def testDecode4(self):
# Verify that decode returns the object
der = DerSetOf()
self.assertEqual(der,
der.decode(b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff')))
###
def testErrDecode1(self):
# No leftovers allowed
der = DerSetOf()
self.assertRaises(ValueError, der.decode,
b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff\xAA'))
class DerBooleanTests(unittest.TestCase):
def testEncode1(self):
der = DerBoolean(False)
self.assertEqual(der.encode(), b'\x01\x01\x00')
def testEncode2(self):
der = DerBoolean(True)
self.assertEqual(der.encode(), b'\x01\x01\xFF')
def testEncode3(self):
der = DerBoolean(False, implicit=0x12)
self.assertEqual(der.encode(), b'\x92\x01\x00')
def testEncode4(self):
der = DerBoolean(False, explicit=0x05)
self.assertEqual(der.encode(), b'\xA5\x03\x01\x01\x00')
####
def testDecode1(self):
der = DerBoolean()
der.decode(b'\x01\x01\x00')
self.assertEqual(der.value, False)
def testDecode2(self):
der = DerBoolean()
der.decode(b'\x01\x01\xFF')
self.assertEqual(der.value, True)
def testDecode3(self):
der = DerBoolean(implicit=0x12)
der.decode(b'\x92\x01\x00')
self.assertEqual(der.value, False)
def testDecode4(self):
der = DerBoolean(explicit=0x05)
der.decode(b'\xA5\x03\x01\x01\x00')
self.assertEqual(der.value, False)
def testErrorDecode1(self):
der = DerBoolean()
# Wrong tag
self.assertRaises(ValueError, der.decode, b'\x02\x01\x00')
def testErrorDecode2(self):
der = DerBoolean()
# Payload too long
self.assertRaises(ValueError, der.decode, b'\x01\x01\x00\xFF')
def get_tests(config={}):
from Crypto.SelfTest.st_common import list_test_cases
listTests = []
listTests += list_test_cases(DerObjectTests)
listTests += list_test_cases(DerIntegerTests)
listTests += list_test_cases(DerSequenceTests)
listTests += list_test_cases(DerOctetStringTests)
listTests += list_test_cases(DerNullTests)
listTests += list_test_cases(DerObjectIdTests)
listTests += list_test_cases(DerBitStringTests)
listTests += list_test_cases(DerSetOfTests)
listTests += list_test_cases(DerBooleanTests)
return listTests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
# vim:set ts=4 sw=4 sts=4 expandtab:
@@ -0,0 +1,192 @@
# -*- coding: utf-8 -*-
#
# SelfTest/Util/test_number.py: Self-test for parts of the Crypto.Util.number 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-tests for (some of) Crypto.Util.number"""
import math
import unittest
from Crypto.Util.py3compat import *
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Util import number
from Crypto.Util.number import long_to_bytes
class MyError(Exception):
"""Dummy exception used for tests"""
# NB: In some places, we compare tuples instead of just output values so that
# if any inputs cause a test failure, we'll be able to tell which ones.
class MiscTests(unittest.TestCase):
def test_ceil_div(self):
"""Util.number.ceil_div"""
self.assertRaises(TypeError, number.ceil_div, "1", 1)
self.assertRaises(ZeroDivisionError, number.ceil_div, 1, 0)
self.assertRaises(ZeroDivisionError, number.ceil_div, -1, 0)
# b = 1
self.assertEqual(0, number.ceil_div(0, 1))
self.assertEqual(1, number.ceil_div(1, 1))
self.assertEqual(2, number.ceil_div(2, 1))
self.assertEqual(3, number.ceil_div(3, 1))
# b = 2
self.assertEqual(0, number.ceil_div(0, 2))
self.assertEqual(1, number.ceil_div(1, 2))
self.assertEqual(1, number.ceil_div(2, 2))
self.assertEqual(2, number.ceil_div(3, 2))
self.assertEqual(2, number.ceil_div(4, 2))
self.assertEqual(3, number.ceil_div(5, 2))
# b = 3
self.assertEqual(0, number.ceil_div(0, 3))
self.assertEqual(1, number.ceil_div(1, 3))
self.assertEqual(1, number.ceil_div(2, 3))
self.assertEqual(1, number.ceil_div(3, 3))
self.assertEqual(2, number.ceil_div(4, 3))
self.assertEqual(2, number.ceil_div(5, 3))
self.assertEqual(2, number.ceil_div(6, 3))
self.assertEqual(3, number.ceil_div(7, 3))
# b = 4
self.assertEqual(0, number.ceil_div(0, 4))
self.assertEqual(1, number.ceil_div(1, 4))
self.assertEqual(1, number.ceil_div(2, 4))
self.assertEqual(1, number.ceil_div(3, 4))
self.assertEqual(1, number.ceil_div(4, 4))
self.assertEqual(2, number.ceil_div(5, 4))
self.assertEqual(2, number.ceil_div(6, 4))
self.assertEqual(2, number.ceil_div(7, 4))
self.assertEqual(2, number.ceil_div(8, 4))
self.assertEqual(3, number.ceil_div(9, 4))
def test_getPrime(self):
"""Util.number.getPrime"""
self.assertRaises(ValueError, number.getPrime, -100)
self.assertRaises(ValueError, number.getPrime, 0)
self.assertRaises(ValueError, number.getPrime, 1)
bits = 4
for i in range(100):
x = number.getPrime(bits)
self.assertEqual(x >= (1 << bits - 1), 1)
self.assertEqual(x < (1 << bits), 1)
bits = 512
x = number.getPrime(bits)
self.assertNotEqual(x % 2, 0)
self.assertEqual(x >= (1 << bits - 1), 1)
self.assertEqual(x < (1 << bits), 1)
def test_getStrongPrime(self):
"""Util.number.getStrongPrime"""
self.assertRaises(ValueError, number.getStrongPrime, 256)
self.assertRaises(ValueError, number.getStrongPrime, 513)
bits = 512
x = number.getStrongPrime(bits)
self.assertNotEqual(x % 2, 0)
self.assertEqual(x > (1 << bits-1)-1, 1)
self.assertEqual(x < (1 << bits), 1)
e = 2**16+1
x = number.getStrongPrime(bits, e)
self.assertEqual(number.GCD(x-1, e), 1)
self.assertNotEqual(x % 2, 0)
self.assertEqual(x > (1 << bits-1)-1, 1)
self.assertEqual(x < (1 << bits), 1)
e = 2**16+2
x = number.getStrongPrime(bits, e)
self.assertEqual(number.GCD((x-1)>>1, e), 1)
self.assertNotEqual(x % 2, 0)
self.assertEqual(x > (1 << bits-1)-1, 1)
self.assertEqual(x < (1 << bits), 1)
def test_isPrime(self):
"""Util.number.isPrime"""
self.assertEqual(number.isPrime(-3), False) # Regression test: negative numbers should not be prime
self.assertEqual(number.isPrime(-2), False) # Regression test: negative numbers should not be prime
self.assertEqual(number.isPrime(1), False) # Regression test: isPrime(1) caused some versions of PyCrypto to crash.
self.assertEqual(number.isPrime(2), True)
self.assertEqual(number.isPrime(3), True)
self.assertEqual(number.isPrime(4), False)
self.assertEqual(number.isPrime(2**1279-1), True)
self.assertEqual(number.isPrime(-(2**1279-1)), False) # Regression test: negative numbers should not be prime
# test some known gmp pseudo-primes taken from
# http://www.trnicely.net/misc/mpzspsp.html
for composite in (43 * 127 * 211, 61 * 151 * 211, 15259 * 30517,
346141 * 692281, 1007119 * 2014237, 3589477 * 7178953,
4859419 * 9718837, 2730439 * 5460877,
245127919 * 490255837, 963939391 * 1927878781,
4186358431 * 8372716861, 1576820467 * 3153640933):
self.assertEqual(number.isPrime(int(composite)), False)
def test_size(self):
self.assertEqual(number.size(2),2)
self.assertEqual(number.size(3),2)
self.assertEqual(number.size(0xa2),8)
self.assertEqual(number.size(0xa2ba40),8*3)
self.assertEqual(number.size(0xa2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5), 1024)
self.assertRaises(ValueError, number.size, -1)
class LongTests(unittest.TestCase):
def test1(self):
self.assertEqual(long_to_bytes(0), b'\x00')
self.assertEqual(long_to_bytes(1), b'\x01')
self.assertEqual(long_to_bytes(0x100), b'\x01\x00')
self.assertEqual(long_to_bytes(0xFF00000000), b'\xFF\x00\x00\x00\x00')
self.assertEqual(long_to_bytes(0xFF00000000), b'\xFF\x00\x00\x00\x00')
self.assertEqual(long_to_bytes(0x1122334455667788), b'\x11\x22\x33\x44\x55\x66\x77\x88')
self.assertEqual(long_to_bytes(0x112233445566778899), b'\x11\x22\x33\x44\x55\x66\x77\x88\x99')
def test2(self):
self.assertEqual(long_to_bytes(0, 1), b'\x00')
self.assertEqual(long_to_bytes(0, 2), b'\x00\x00')
self.assertEqual(long_to_bytes(1, 3), b'\x00\x00\x01')
self.assertEqual(long_to_bytes(65535, 2), b'\xFF\xFF')
self.assertEqual(long_to_bytes(65536, 2), b'\x00\x01\x00\x00')
self.assertEqual(long_to_bytes(0x100, 1), b'\x01\x00')
self.assertEqual(long_to_bytes(0xFF00000001, 6), b'\x00\xFF\x00\x00\x00\x01')
self.assertEqual(long_to_bytes(0xFF00000001, 8), b'\x00\x00\x00\xFF\x00\x00\x00\x01')
self.assertEqual(long_to_bytes(0xFF00000001, 10), b'\x00\x00\x00\x00\x00\xFF\x00\x00\x00\x01')
self.assertEqual(long_to_bytes(0xFF00000001, 11), b'\x00\x00\x00\x00\x00\x00\xFF\x00\x00\x00\x01')
def test_err1(self):
self.assertRaises(ValueError, long_to_bytes, -1)
def get_tests(config={}):
tests = []
tests += list_test_cases(MiscTests)
tests += list_test_cases(LongTests)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
# vim:set ts=4 sw=4 sts=4 expandtab:
@@ -0,0 +1,38 @@
import unittest
import binascii
from Crypto.Util.RFC1751 import key_to_english, english_to_key
class RFC1751_Tests(unittest.TestCase):
def test1(self):
data = [
('EB33F77EE73D4053', 'TIDE ITCH SLOW REIN RULE MOT'),
('CCAC2AED591056BE4F90FD441C534766', 'RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE'),
('EFF81F9BFBC65350920CDD7416DE8009', 'TROD MUTE TAIL WARM CHAR KONG HAAG CITY BORE O TEAL AWL')
]
for key_hex, words in data:
key_bin = binascii.a2b_hex(key_hex)
w2 = key_to_english(key_bin)
self.assertEqual(w2, words)
k2 = english_to_key(words)
self.assertEqual(k2, key_bin)
def test_error_key_to_english(self):
self.assertRaises(ValueError, key_to_english, b'0' * 7)
def get_tests(config={}):
from Crypto.SelfTest.st_common import list_test_cases
tests = list_test_cases(RFC1751_Tests)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,280 @@
#
# SelfTest/Util/test_strxor.py: Self-test for XORing
#
# ===================================================================
#
# 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, hexlify
from Crypto.SelfTest.st_common import list_test_cases
from Crypto.Util.strxor import strxor, strxor_c
class StrxorTests(unittest.TestCase):
def test1(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
term2 = unhexlify(b"383d4ba020573314395b")
result = unhexlify(b"c70ed123c59a7fcb6f12")
self.assertEqual(strxor(term1, term2), result)
self.assertEqual(strxor(term2, term1), result)
def test2(self):
es = b""
self.assertEqual(strxor(es, es), es)
def test3(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
all_zeros = b"\x00" * len(term1)
self.assertEqual(strxor(term1, term1), all_zeros)
def test_wrong_length(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
term2 = unhexlify(b"ff339a83e5cd4cdf564990")
self.assertRaises(ValueError, strxor, term1, term2)
def test_bytearray(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
term1_ba = bytearray(term1)
term2 = unhexlify(b"383d4ba020573314395b")
result = unhexlify(b"c70ed123c59a7fcb6f12")
self.assertEqual(strxor(term1_ba, term2), result)
def test_memoryview(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
term1_mv = memoryview(term1)
term2 = unhexlify(b"383d4ba020573314395b")
result = unhexlify(b"c70ed123c59a7fcb6f12")
self.assertEqual(strxor(term1_mv, term2), result)
def test_output_bytearray(self):
"""Verify result can be stored in pre-allocated memory"""
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
term2 = unhexlify(b"383d4ba020573314395b")
original_term1 = term1[:]
original_term2 = term2[:]
expected_xor = unhexlify(b"c70ed123c59a7fcb6f12")
output = bytearray(len(term1))
result = strxor(term1, term2, output=output)
self.assertEqual(result, None)
self.assertEqual(output, expected_xor)
self.assertEqual(term1, original_term1)
self.assertEqual(term2, original_term2)
def test_output_memoryview(self):
"""Verify result can be stored in pre-allocated memory"""
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
term2 = unhexlify(b"383d4ba020573314395b")
original_term1 = term1[:]
original_term2 = term2[:]
expected_xor = unhexlify(b"c70ed123c59a7fcb6f12")
output = memoryview(bytearray(len(term1)))
result = strxor(term1, term2, output=output)
self.assertEqual(result, None)
self.assertEqual(output, expected_xor)
self.assertEqual(term1, original_term1)
self.assertEqual(term2, original_term2)
def test_output_overlapping_bytearray(self):
"""Verify result can be stored in overlapping memory"""
term1 = bytearray(unhexlify(b"ff339a83e5cd4cdf5649"))
term2 = unhexlify(b"383d4ba020573314395b")
original_term2 = term2[:]
expected_xor = unhexlify(b"c70ed123c59a7fcb6f12")
result = strxor(term1, term2, output=term1)
self.assertEqual(result, None)
self.assertEqual(term1, expected_xor)
self.assertEqual(term2, original_term2)
def test_output_overlapping_memoryview(self):
"""Verify result can be stored in overlapping memory"""
term1 = memoryview(bytearray(unhexlify(b"ff339a83e5cd4cdf5649")))
term2 = unhexlify(b"383d4ba020573314395b")
original_term2 = term2[:]
expected_xor = unhexlify(b"c70ed123c59a7fcb6f12")
result = strxor(term1, term2, output=term1)
self.assertEqual(result, None)
self.assertEqual(term1, expected_xor)
self.assertEqual(term2, original_term2)
def test_output_ro_bytes(self):
"""Verify result cannot be stored in read-only memory"""
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
term2 = unhexlify(b"383d4ba020573314395b")
self.assertRaises(TypeError, strxor, term1, term2, output=term1)
def test_output_ro_memoryview(self):
"""Verify result cannot be stored in read-only memory"""
term1 = memoryview(unhexlify(b"ff339a83e5cd4cdf5649"))
term2 = unhexlify(b"383d4ba020573314395b")
self.assertRaises(TypeError, strxor, term1, term2, output=term1)
def test_output_incorrect_length(self):
"""Verify result cannot be stored in memory of incorrect length"""
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
term2 = unhexlify(b"383d4ba020573314395b")
output = bytearray(len(term1) - 1)
self.assertRaises(ValueError, strxor, term1, term2, output=output)
class Strxor_cTests(unittest.TestCase):
def test1(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
result = unhexlify(b"be72dbc2a48c0d9e1708")
self.assertEqual(strxor_c(term1, 65), result)
def test2(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
self.assertEqual(strxor_c(term1, 0), term1)
def test3(self):
self.assertEqual(strxor_c(b"", 90), b"")
def test_wrong_range(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
self.assertRaises(ValueError, strxor_c, term1, -1)
self.assertRaises(ValueError, strxor_c, term1, 256)
def test_bytearray(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
term1_ba = bytearray(term1)
result = unhexlify(b"be72dbc2a48c0d9e1708")
self.assertEqual(strxor_c(term1_ba, 65), result)
def test_memoryview(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
term1_mv = memoryview(term1)
result = unhexlify(b"be72dbc2a48c0d9e1708")
self.assertEqual(strxor_c(term1_mv, 65), result)
def test_output_bytearray(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
original_term1 = term1[:]
expected_result = unhexlify(b"be72dbc2a48c0d9e1708")
output = bytearray(len(term1))
result = strxor_c(term1, 65, output=output)
self.assertEqual(result, None)
self.assertEqual(output, expected_result)
self.assertEqual(term1, original_term1)
def test_output_memoryview(self):
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
original_term1 = term1[:]
expected_result = unhexlify(b"be72dbc2a48c0d9e1708")
output = memoryview(bytearray(len(term1)))
result = strxor_c(term1, 65, output=output)
self.assertEqual(result, None)
self.assertEqual(output, expected_result)
self.assertEqual(term1, original_term1)
def test_output_overlapping_bytearray(self):
"""Verify result can be stored in overlapping memory"""
term1 = bytearray(unhexlify(b"ff339a83e5cd4cdf5649"))
expected_xor = unhexlify(b"be72dbc2a48c0d9e1708")
result = strxor_c(term1, 65, output=term1)
self.assertEqual(result, None)
self.assertEqual(term1, expected_xor)
def test_output_overlapping_memoryview(self):
"""Verify result can be stored in overlapping memory"""
term1 = memoryview(bytearray(unhexlify(b"ff339a83e5cd4cdf5649")))
expected_xor = unhexlify(b"be72dbc2a48c0d9e1708")
result = strxor_c(term1, 65, output=term1)
self.assertEqual(result, None)
self.assertEqual(term1, expected_xor)
def test_output_ro_bytes(self):
"""Verify result cannot be stored in read-only memory"""
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
self.assertRaises(TypeError, strxor_c, term1, 65, output=term1)
def test_output_ro_memoryview(self):
"""Verify result cannot be stored in read-only memory"""
term1 = memoryview(unhexlify(b"ff339a83e5cd4cdf5649"))
term2 = unhexlify(b"383d4ba020573314395b")
self.assertRaises(TypeError, strxor_c, term1, 65, output=term1)
def test_output_incorrect_length(self):
"""Verify result cannot be stored in memory of incorrect length"""
term1 = unhexlify(b"ff339a83e5cd4cdf5649")
output = bytearray(len(term1) - 1)
self.assertRaises(ValueError, strxor_c, term1, 65, output=output)
def get_tests(config={}):
tests = []
tests += list_test_cases(StrxorTests)
tests += list_test_cases(Strxor_cTests)
return tests
if __name__ == '__main__':
suite = lambda: unittest.TestSuite(get_tests())
unittest.main(defaultTest='suite')
@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
#
# SelfTest/__init__.py: Self-test for PyCrypto
#
# 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 tests
These tests should perform quickly and can ideally be used every time an
application runs.
"""
import sys
import unittest
from importlib import import_module
from Crypto.Util.py3compat import StringIO
class SelfTestError(Exception):
def __init__(self, message, result):
Exception.__init__(self, message, result)
self.message = message
self.result = result
def run(module=None, verbosity=0, stream=None, tests=None, config=None, **kwargs):
"""Execute self-tests.
This raises SelfTestError if any test is unsuccessful.
You may optionally pass in a sub-module of SelfTest if you only want to
perform some of the tests. For example, the following would test only the
hash modules:
Crypto.SelfTest.run(Crypto.SelfTest.Hash)
"""
if config is None:
config = {}
suite = unittest.TestSuite()
if module is None:
if tests is None:
tests = get_tests(config=config)
suite.addTests(tests)
else:
if tests is None:
suite.addTests(module.get_tests(config=config))
else:
raise ValueError("'module' and 'tests' arguments are mutually exclusive")
if stream is None:
kwargs['stream'] = StringIO()
else:
kwargs['stream'] = stream
runner = unittest.TextTestRunner(verbosity=verbosity, **kwargs)
result = runner.run(suite)
if not result.wasSuccessful():
if stream is None:
sys.stderr.write(kwargs['stream'].getvalue())
raise SelfTestError("Self-test failed", result)
return result
def get_tests(config={}):
tests = []
module_names = [
"Cipher", "Hash", "Protocol", "PublicKey", "Random",
"Util", "Signature", "IO", "Math",
]
for name in module_names:
module = import_module("Crypto.SelfTest." + name)
tests += module.get_tests(config=config)
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,43 @@
#! /usr/bin/env python
#
# __main__.py : Stand-along loader for PyCryptodome test suite
#
# ===================================================================
# 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 sys
from Crypto import SelfTest
slow_tests = not ("--skip-slow-tests" in sys.argv)
if not slow_tests:
print("Skipping slow tests")
wycheproof_warnings = "--wycheproof-warnings" in sys.argv
if wycheproof_warnings:
print("Printing Wycheproof warnings")
if "-v" in sys.argv:
verbosity=2
else:
verbosity=1
config = {'slow_tests': slow_tests, 'wycheproof_warnings': wycheproof_warnings}
SelfTest.run(stream=sys.stdout, verbosity=verbosity, config=config)
@@ -0,0 +1,250 @@
# ===================================================================
#
# Copyright (c) 2016, 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 json
import errno
import binascii
import warnings
from binascii import unhexlify
from Crypto.Util.py3compat import FileNotFoundError
try:
import pycryptodome_test_vectors # type: ignore
test_vectors_available = True
except ImportError:
test_vectors_available = False
def _load_tests(dir_comps, file_in, description, conversions):
"""Load and parse a test vector file
Return a list of objects, one per group of adjacent
KV lines or for a single line in the form "[.*]".
For a group of lines, the object has one attribute per line.
"""
line_number = 0
results = []
class TestVector(object):
def __init__(self, description, count):
self.desc = description
self.count = count
self.others = []
test_vector = None
count = 0
new_group = True
while True:
line_number += 1
line = file_in.readline()
if not line:
if test_vector is not None:
results.append(test_vector)
break
line = line.strip()
# Skip comments and empty lines
if line.startswith('#') or not line:
new_group = True
continue
if line.startswith("["):
if test_vector is not None:
results.append(test_vector)
test_vector = None
results.append(line)
continue
if new_group:
count += 1
new_group = False
if test_vector is not None:
results.append(test_vector)
test_vector = TestVector("%s (#%d)" % (description, count), count)
res = re.match("([A-Za-z0-9]+) = ?(.*)", line)
if not res:
test_vector.others += [line]
else:
token = res.group(1).lower()
data = res.group(2).lower()
conversion = conversions.get(token, None)
if conversion is None:
if len(data) % 2 != 0:
data = "0" + data
setattr(test_vector, token, binascii.unhexlify(data))
else:
setattr(test_vector, token, conversion(data))
# This line is ignored
return results
def load_test_vectors(dir_comps, file_name, description, conversions):
"""Load and parse a test vector file, formatted using the NIST style.
Args:
dir_comps (list of strings):
The path components under the ``pycryptodome_test_vectors`` package.
For instance ``("Cipher", "AES")``.
file_name (string):
The name of the file with the test vectors.
description (string):
A description applicable to the test vectors in the file.
conversions (dictionary):
The dictionary contains functions.
Values in the file that have an entry in this dictionary
will be converted usign the matching function.
Otherwise, values will be considered as hexadecimal and
converted to binary.
Returns:
A list of test vector objects.
The file is formatted in the following way:
- Lines starting with "#" are comments and will be ignored.
- Each test vector is a sequence of 1 or more adjacent lines, where
each lines is an assignement.
- Test vectors are separated by an empty line, a comment, or
a line starting with "[".
A test vector object has the following attributes:
- desc (string): description
- counter (int): the order of the test vector in the file (from 1)
- others (list): zero or more lines of the test vector that were not assignments
- left-hand side of each assignment (lowercase): the value of the
assignement, either converted or bytes.
"""
results = None
try:
if not test_vectors_available:
raise FileNotFoundError(errno.ENOENT,
os.strerror(errno.ENOENT),
file_name)
description = "%s test (%s)" % (description, file_name)
init_dir = os.path.dirname(pycryptodome_test_vectors.__file__)
full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name)
with open(full_file_name) as file_in:
results = _load_tests(dir_comps, file_in, description, conversions)
except FileNotFoundError:
warnings.warn("Warning: skipping extended tests for " + description,
UserWarning,
stacklevel=2)
return results
def load_test_vectors_wycheproof(dir_comps, file_name, description,
root_tag={}, group_tag={}, unit_tag={}):
result = []
try:
if not test_vectors_available:
raise FileNotFoundError(errno.ENOENT,
os.strerror(errno.ENOENT),
file_name)
init_dir = os.path.dirname(pycryptodome_test_vectors.__file__)
full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name)
with open(full_file_name) as file_in:
tv_tree = json.load(file_in)
except FileNotFoundError:
warnings.warn("Warning: skipping extended tests for " + description,
UserWarning,
stacklevel=2)
return result
class TestVector(object):
pass
# Unique attributes that will be converted from
# hexadecimal to binary, unless the attribute is
# listed in the unit_tag dict
unit_attr_hex = {'key', 'iv', 'aad', 'msg', 'ct', 'tag', 'label',
'ikm', 'salt', 'info', 'okm', 'sig', 'public',
'shared'}
unit_attr_hex -= set(unit_tag.keys())
common_root = {}
for k, v in root_tag.items():
common_root[k] = v(tv_tree)
for group in tv_tree['testGroups']:
common_group = {}
for k, v in group_tag.items():
common_group[k] = v(group)
for test in group['tests']:
tv = TestVector()
for k, v in common_root.items():
setattr(tv, k, v)
for k, v in common_group.items():
setattr(tv, k, v)
tv.id = test['tcId']
tv.comment = test['comment']
for attr in unit_attr_hex:
if attr in test:
try:
setattr(tv, attr, unhexlify(test[attr]))
except binascii.Error:
raise ValueError("Error decoding attribute '%s' (tcId=%s, file %s)" % (attr, tv.id, file_name))
tv.filename = file_name
for k, v in unit_tag.items():
setattr(tv, k, v(test))
tv.valid = test['result'] != "invalid"
tv.warning = test['result'] == "acceptable"
tv.flags = test.get('flags')
tv.filename = file_name
result.append(tv)
return result
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
#
# SelfTest/st_common.py: Common functions for SelfTest 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.
# ===================================================================
"""Common functions for SelfTest modules"""
import unittest
import binascii
from Crypto.Util.py3compat import b
def list_test_cases(class_):
"""Return a list of TestCase instances given a TestCase class
This is useful when you have defined test* methods on your TestCase class.
"""
return unittest.TestLoader().loadTestsFromTestCase(class_)
def strip_whitespace(s):
"""Remove whitespace from a text or byte string"""
if isinstance(s,str):
return b("".join(s.split()))
else:
return b("").join(s.split())
def a2b_hex(s):
"""Convert hexadecimal to binary, ignoring whitespace"""
return binascii.a2b_hex(strip_whitespace(s))
def b2a_hex(s):
"""Convert binary to hexadecimal"""
# For completeness
return binascii.b2a_hex(s)
# vim:set ts=4 sw=4 sts=4 expandtab: