# -*- coding: utf-8 -*- # # SelfTest/Hash/common.py: Common code for Crypto.SelfTest.Hash # # Written in 2008 by Dwayne C. Litzenberger # # =================================================================== # 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""" from __future__ import nested_scopes __revision__ = "$Id$" import sys if sys.version_info[0] == 2 and sys.version_info[1] == 1: from Crypto.Util.py21compat import * import unittest from binascii import a2b_hex, b2a_hex, hexlify from Crypto.Util.py3compat import * from Crypto.Util.strxor import strxor_c # For compatibility with Python 2.1 and Python 2.2 if sys.hexversion < 0x02030000: # Python 2.1 doesn't have a dict() function # Python 2.2 dict() function raises TypeError if you do dict(MD5='blah') def dict(**kwargs): return kwargs.copy() else: dict = dict 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) # Only relevant for OPENPGP mode self.encrypted_iv = _extract(params, 'encrypted_iv', None) if self.encrypted_iv is not None: self.encrypted_iv = b(self.encrypted_iv) else: # Stream cipher self.mode = None self.iv = None self.extra_params = params def shortDescription(self): return self.description def _new(self, do_decryption=0): params = self.extra_params.copy() # Handle CTR mode parameters. By default, we use Counter.new(self.module.block_size) if hasattr(self.module, "MODE_CTR") and self.mode == self.module.MODE_CTR: from Crypto.Util import Counter ctr_class = _extract(params, 'ctr_class', Counter.new) ctr_params = _extract(params, 'ctr_params', {}).copy() if ctr_params.has_key('prefix'): ctr_params['prefix'] = a2b_hex(b(ctr_params['prefix'])) if ctr_params.has_key('suffix'): ctr_params['suffix'] = a2b_hex(b(ctr_params['suffix'])) if not ctr_params.has_key('nbits'): ctr_params['nbits'] = 8*(self.module.block_size - len(ctr_params.get('prefix', '')) - len(ctr_params.get('suffix', ''))) params['counter'] = ctr_class(**ctr_params) if self.mode is None: # Stream cipher return self.module.new(a2b_hex(self.key), **params) elif self.iv is None: # Block cipher without iv return self.module.new(a2b_hex(self.key), self.mode, **params) else: # Block cipher with iv if do_decryption and self.mode == self.module.MODE_OPENPGP: # In PGP mode, the IV to feed for decryption is the *encrypted* one return self.module.new(a2b_hex(self.key), self.mode, a2b_hex(self.encrypted_iv), **params) else: return self.module.new(a2b_hex(self.key), self.mode, a2b_hex(self.iv), **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 xrange(2): cipher = self._new() decipher = self._new(1) # Only AEAD modes for comp in assoc_data: cipher.update(comp) decipher.update(comp) ctX = b2a_hex(cipher.encrypt(plaintext)) if self.isMode("SIV"): ptX = b2a_hex(decipher.decrypt_and_verify(ciphertext, a2b_hex(self.mac))) else: ptX = b2a_hex(decipher.decrypt(ciphertext)) if ct: self.assertEqual(ct, ctX) self.assertEqual(pt, ptX) ct, pt = ctX, ptX if self.isMode("OPENPGP"): # In PGP mode, data returned by the first encrypt() # is prefixed with the encrypted IV. # Here we check it and then remove it from the ciphertexts. eilen = len(self.encrypted_iv) self.assertEqual(self.encrypted_iv, ct[:eilen]) ct = ct[eilen:] 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 CTRSegfaultTest(unittest.TestCase): def __init__(self, module, params): unittest.TestCase.__init__(self) self.module = module self.key = b(params['key']) self.module_name = params.get('module_name', None) def shortDescription(self): return """Regression test: %s.new(key, %s.MODE_CTR) should raise TypeError, not segfault""" % (self.module_name, self.module_name) def runTest(self): self.assertRaises(TypeError, self.module.new, a2b_hex(self.key), self.module.MODE_CTR) class CTRWraparoundTest(unittest.TestCase): def __init__(self, module, params): unittest.TestCase.__init__(self) self.module = module self.key = b(params['key']) self.module_name = params.get('module_name', None) def shortDescription(self): return """Regression test: %s with MODE_CTR raising OverflowError on wraparound""" % (self.module_name,) def runTest(self): from Crypto.Util import Counter def pythonCounter(): state = [0] def ctr(): # First block succeeds; Second and subsequent blocks raise OverflowError if state[0] == 0: state[0] = 1 return b("\xff") * self.module.block_size else: raise OverflowError return ctr for little_endian in (0, 1): # (False, True) Test both endiannesses block = b("\x00") * self.module.block_size # Test PyObject_CallObject code path: if the counter raises OverflowError cipher = self.module.new(a2b_hex(self.key), self.module.MODE_CTR, counter=pythonCounter()) cipher.encrypt(block) self.assertRaises(OverflowError, cipher.encrypt, block) self.assertRaises(OverflowError, cipher.encrypt, block) # Test PyObject_CallObject code path: counter object should raise OverflowError ctr = Counter.new(8*self.module.block_size, initial_value=2L**(8*self.module.block_size)-1, little_endian=little_endian) ctr() self.assertRaises(OverflowError, ctr) self.assertRaises(OverflowError, ctr) # Test the CTR-mode shortcut ctr = Counter.new(8*self.module.block_size, initial_value=2L**(8*self.module.block_size)-1, little_endian=little_endian) cipher = self.module.new(a2b_hex(self.key), self.module.MODE_CTR, counter=ctr) cipher.encrypt(block) self.assertRaises(OverflowError, cipher.encrypt, block) self.assertRaises(OverflowError, cipher.encrypt, block) class CFBSegmentSizeTest(unittest.TestCase): def __init__(self, module, params): unittest.TestCase.__init__(self) self.module = module self.key = b(params['key']) self.description = params['description'] def shortDescription(self): return self.description def runTest(self): """Regression test: m.new(key, m.MODE_CFB, segment_size=N) should require segment_size to be a multiple of 8 bits""" for i in range(1, 8): self.assertRaises(ValueError, self.module.new, a2b_hex(self.key), self.module.MODE_CFB, segment_size=i) self.module.new(a2b_hex(self.key), self.module.MODE_CFB, "\0"*self.module.block_size, segment_size=8) # should succeed class CCMMACLengthTest(unittest.TestCase): """CCM specific tests about MAC""" def __init__(self, module): unittest.TestCase.__init__(self) self.module = module self.key = b('\xFF')*16 self.iv = b('\x00')*10 def shortDescription(self): return self.description def runTest(self): """Verify that MAC can only be 4,6,8,..,16 bytes long.""" for i in range(3,16,2): self.description = "CCM MAC length check (%d bytes)" % i self.assertRaises(ValueError, self.module.new, self.key, self.module.MODE_CCM, self.iv, msg_len=10, mac_len=i) """Verify that default MAC length is 16.""" self.description = "CCM default MAC length check" cipher = self.module.new(self.key, self.module.MODE_CCM, self.iv, msg_len=4) cipher.encrypt(b('z')*4) self.assertEqual(len(cipher.digest()), 16) class CCMSplitEncryptionTest(unittest.TestCase): """CCM specific tests to validate how encrypt() decrypt() can be called multiple times on the same object.""" def __init__(self, module): unittest.TestCase.__init__(self) self.module = module self.key = b('\xFF')*16 self.iv = b('\x00')*10 self.description = "CCM Split Encryption Test" def shortDescription(self): return self.description def runTest(self): """Verify that CCM update()/encrypt() can be called multiple times, provided that lengths are declared beforehand""" data = b("AUTH DATA") pt1 = b("PLAINTEXT1") # Short pt2 = b("PLAINTEXT2") # Long pt_ref = pt1+pt2 # REFERENCE: Run with 1 update() and 1 encrypt() cipher = self.module.new(self.key, self.module.MODE_CCM, self.iv) cipher.update(data) ct_ref = cipher.encrypt(pt_ref) mac_ref = cipher.digest() # Verify that calling CCM encrypt()/decrypt() twice is not # possible without the 'msg_len' parameter and regardless # of the 'assoc_len' parameter for ad_len in None, len(data): cipher = self.module.new(self.key, self.module.MODE_CCM, self.iv, assoc_len=ad_len) cipher.update(data) cipher.encrypt(pt1) self.assertRaises(TypeError, cipher.encrypt, pt2) cipher = self.module.new(self.key, self.module.MODE_CCM, self.iv, assoc_len=ad_len) cipher.update(data) cipher.decrypt(ct_ref[:len(pt1)]) self.assertRaises(TypeError, cipher.decrypt, ct_ref[len(pt1):]) # Run with 2 encrypt()/decrypt(). Results must be the same # regardless of the 'assoc_len' parameter for ad_len in None, len(data): cipher = self.module.new(self.key, self.module.MODE_CCM, self.iv, assoc_len=ad_len, msg_len=len(pt_ref)) cipher.update(data) ct = cipher.encrypt(pt1) ct += cipher.encrypt(pt2) mac = cipher.digest() self.assertEqual(ct_ref, ct) self.assertEqual(mac_ref, mac) cipher = self.module.new(self.key, self.module.MODE_CCM, self.iv, msg_len=len(pt1+pt2)) cipher.update(data) pt = cipher.decrypt(ct[:len(pt1)]) pt += cipher.decrypt(ct[len(pt1):]) mac = cipher.verify(mac_ref) self.assertEqual(pt_ref, pt) class AEADTests(unittest.TestCase): """Tests generic to all AEAD modes""" def __init__(self, module, mode_name, key_size): unittest.TestCase.__init__(self) self.module = module self.mode_name = mode_name self.mode = getattr(module, mode_name) if not self.isMode("SIV"): self.key = b('\xFF')*key_size else: self.key = b('\xFF')*key_size*2 self.iv = b('\x00')*10 self.description = "AEAD Test" def isMode(self, name): if not hasattr(self.module, "MODE_"+name): return False return self.mode == getattr(self.module, "MODE_"+name) def right_mac_test(self): """Positive tests for MAC""" self.description = "Test for right MAC in %s of %s" % \ (self.mode_name, self.module.__name__) ad_ref = b("Reference AD") pt_ref = b("Reference plaintext") # Encrypt and create the reference MAC cipher = self.module.new(self.key, self.mode, self.iv) cipher.update(ad_ref) ct_ref = cipher.encrypt(pt_ref) mac_ref = cipher.digest() # Decrypt and verify that MAC is accepted decipher = self.module.new(self.key, self.mode, self.iv) decipher.update(ad_ref) pt = decipher.decrypt_and_verify(ct_ref, mac_ref) self.assertEqual(pt, pt_ref) # Verify that hexverify work decipher.hexverify(hexlify(mac_ref)) def wrong_mac_test(self): """Negative tests for MAC""" self.description = "Test for wrong MAC in %s of %s" % \ (self.mode_name, self.module.__name__) ad_ref = b("Reference AD") pt_ref = b("Reference plaintext") # Encrypt and create the reference MAC cipher = self.module.new(self.key, self.mode, self.iv) cipher.update(ad_ref) ct_ref = cipher.encrypt(pt_ref) mac_ref = cipher.digest() # Modify the MAC and verify it is NOT ACCEPTED wrong_mac = strxor_c(mac_ref, 255) decipher = self.module.new(self.key, self.mode, self.iv) decipher.update(ad_ref) self.assertRaises(ValueError, decipher.decrypt_and_verify, ct_ref, wrong_mac) def zero_data(self): """Verify transition from INITIALIZED to FINISHED""" self.description = "Test for zero data in %s of %s" % \ (self.mode_name, self.module.__name__) cipher = self.module.new(self.key, self.mode, self.iv) cipher.digest() def multiple_updates(self): """Verify that update() can be called multiple times""" self.description = "Test for multiple updates in %s of %s" % \ (self.mode_name, self.module.__name__) # In all modes other than SIV, the associated data is a single # component that can be arbitrarilly split and submitted to update(). # # In SIV, associated data is instead organized in a vector or multiple # components. Each component is passed to update() as a whole. # This test is therefore not meaningful to SIV. if self.isMode("SIV"): return ad = b("").join([bchr(x) for x in xrange(0,128)]) mac1, mac2, mac3 = (None,)*3 for chunk_length in 1,10,40,80,128: chunks = [ad[i:i+chunk_length] for i in range(0, len(ad), chunk_length)] # No encryption/decryption cipher = self.module.new(self.key, self.mode, self.iv) for c in chunks: cipher.update(c) if mac1: cipher.verify(mac1) else: mac1 = cipher.digest() # Encryption cipher = self.module.new(self.key, self.mode, self.iv) for c in chunks: cipher.update(c) ct = cipher.encrypt(b("PT")) mac2 = cipher.digest() # Decryption cipher = self.module.new(self.key, self.mode, self.iv) for c in chunks: cipher.update(c) cipher.decrypt(ct) cipher.verify(mac2) def no_mix_encrypt_decrypt(self): """Verify that encrypt and decrypt cannot be mixed up""" self.description = "Test for mix of encrypt and decrypt in %s of %s" % \ (self.mode_name, self.module.__name__) # Calling decrypt after encrypt raises an exception cipher = self.module.new(self.key, self.mode, self.iv) cipher.encrypt(b("PT")*40) self.assertRaises(TypeError, cipher.decrypt, b("XYZ")*40) # Calling encrypt() after decrypt() raises an exception # (excluded for SIV, since decrypt() is not valid) if not self.isMode("SIV"): cipher = self.module.new(self.key, self.mode, self.iv) cipher.decrypt(b("CT")*40) self.assertRaises(TypeError, cipher.encrypt, b("XYZ")*40) # Calling verify after encrypt raises an exception cipher = self.module.new(self.key, self.mode, self.iv) cipher.encrypt(b("PT")*40) self.assertRaises(TypeError, cipher.verify, b("XYZ")) self.assertRaises(TypeError, cipher.hexverify, "12") # Calling digest() after decrypt() raises an exception # (excluded for SIV, since decrypt() is not valid) if not self.isMode("SIV"): cipher = self.module.new(self.key, self.mode, self.iv) cipher.decrypt(b("CT")*40) self.assertRaises(TypeError, cipher.digest) self.assertRaises(TypeError, cipher.hexdigest) def no_late_update(self): """Verify that update cannot be called after encrypt or decrypt""" self.description = "Test for late update in %s of %s" % \ (self.mode_name, self.module.__name__) # Calling update after encrypt raises an exception cipher = self.module.new(self.key, self.mode, self.iv) cipher.update(b("XX")) cipher.encrypt(b("PT")*40) self.assertRaises(TypeError, cipher.update, b("XYZ")) # Calling update() after decrypt() raises an exception # (excluded for SIV, since decrypt() is not valid) if not self.isMode("SIV"): cipher = self.module.new(self.key, self.mode, self.iv) cipher.update(b("XX")) cipher.decrypt(b("CT")*40) self.assertRaises(TypeError, cipher.update, b("XYZ")) def loopback(self): """Verify composition of encrypt_and_digest() and decrypt_and_verify() is the identity function.""" self.description = "Lookback test decrypt_and_verify(encrypt_and_digest)"\ "for %s in %s" % (self.mode_name, self.module.__name__) enc_cipher = self.module.new(self.key, self.mode, self.iv) dec_cipher = self.module.new(self.key, self.mode, self.iv) enc_cipher.update(b("XXX")) dec_cipher.update(b("XXX")) plaintext = b("Reference") * 10 ct, mac = enc_cipher.encrypt_and_digest(plaintext) pt = dec_cipher.decrypt_and_verify(ct, mac) self.assertEqual(plaintext, pt) def runTest(self): self.right_mac_test() self.wrong_mac_test() self.zero_data() self.multiple_updates() self.no_mix_encrypt_decrypt() self.no_late_update() self.loopback() def shortDescription(self): return self.description 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): for mode in (self.module.MODE_ECB, self.module.MODE_CBC, self.module.MODE_CFB, self.module.MODE_OFB, self.module.MODE_OPENPGP): encryption_cipher = self.module.new(a2b_hex(self.key), mode, self.iv) ciphertext = encryption_cipher.encrypt(self.plaintext) if mode != self.module.MODE_OPENPGP: decryption_cipher = self.module.new(a2b_hex(self.key), mode, self.iv) else: eiv = ciphertext[:self.module.block_size+2] ciphertext = ciphertext[self.module.block_size+2:] decryption_cipher = self.module.new(a2b_hex(self.key), mode, eiv) decrypted_plaintext = decryption_cipher.decrypt(ciphertext) self.assertEqual(self.plaintext, decrypted_plaintext) class PGPTest(unittest.TestCase): def __init__(self, module, params): unittest.TestCase.__init__(self) self.module = module self.key = b(params['key']) def shortDescription(self): return "MODE_PGP was implemented incorrectly and insecurely. It's completely banished now." def runTest(self): self.assertRaises(ValueError, self.module.new, a2b_hex(self.key), self.module.MODE_PGP) 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(ValueError, self.module.new, a2b_hex(self.key), self.module.MODE_CBC, "") self.assertRaises(ValueError, self.module.new, a2b_hex(self.key), self.module.MODE_CFB, "") self.assertRaises(ValueError, self.module.new, a2b_hex(self.key), self.module.MODE_OFB, "") self.assertRaises(ValueError, self.module.new, a2b_hex(self.key), self.module.MODE_OPENPGP, "") if hasattr(self.module, "MODE_CCM"): for ivlen in (0,6,14): self.assertRaises(ValueError, self.module.new, a2b_hex(self.key), self.module.MODE_CCM, bchr(0)*ivlen, msg_len=10) self.module.new(a2b_hex(self.key), self.module.MODE_ECB, "") self.module.new(a2b_hex(self.key), self.module.MODE_CTR, "", counter=self._dummy_counter) def _dummy_counter(self): return "\0" * self.module.block_size def make_block_tests(module, module_name, test_data, additional_params=dict()): tests = [] extra_tests_added = 0 for i in range(len(test_data)): row = test_data[i] # Build the "params" dictionary params = {'mode': 'ECB'} 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) p_mode = p2.get('mode', 'ECB') if p_mode == 'ECB': _extract(p2, 'mode', 'ECB') 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 += [ CTRSegfaultTest(module, params), CTRWraparoundTest(module, params), CFBSegmentSizeTest(module, params), RoundtripTest(module, params), PGPTest(module, params), IVLengthTest(module, params), ] extra_tests_added = 1 # Extract associated data and MAC for AEAD modes if p_mode in ('CCM', 'EAX', 'SIV', 'GCM'): assoc_data, params['plaintext'] = params['plaintext'].split('|') assoc_data2, params['ciphertext'], params['mac'] = params['ciphertext'].split('|') params['assoc_data'] = assoc_data.split("-") params['mac_len'] = len(params['mac'])>>1 # Add the current test to the test suite tests.append(CipherSelfTest(module, params)) # When using CTR mode, test that the interface behaves like a stream cipher if p_mode in ('OFB', 'CTR'): tests.append(CipherStreamingSelfTest(module, params)) # When using CTR mode, test the non-shortcut code path. if p_mode == 'CTR' and not params.has_key('ctr_class'): params2 = params.copy() params2['description'] += " (shortcut disabled)" ctr_params2 = params.get('ctr_params', {}).copy() params2['ctr_params'] = ctr_params2 if not params2['ctr_params'].has_key('disable_shortcut'): params2['ctr_params']['disable_shortcut'] = 1 tests.append(CipherSelfTest(module, params2)) # Add tests that don't use test vectors if hasattr(module, "MODE_CCM"): tests += [ CCMMACLengthTest(module), CCMSplitEncryptionTest(module), ] for aead_mode in ("MODE_CCM","MODE_EAX", "MODE_SIV", "MODE_GCM"): if hasattr(module, aead_mode): key_sizes = [] try: key_sizes += module.key_size except TypeError: key_sizes = [ module.key_size ] for ks in key_sizes: tests += [ AEADTests(module, aead_mode, ks), ] return tests def make_stream_tests(module, module_name, test_data): tests = [] 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 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: