diff options
author | Legrandin <helderijs@gmail.com> | 2013-08-18 23:07:32 +0200 |
---|---|---|
committer | Dwayne Litzenberger <dlitz@dlitz.net> | 2013-10-20 13:30:22 -0700 |
commit | 2062e5f843fa54d9da45e5d53652f3fb5dbbd97e (patch) | |
tree | 46251d5d19d1a2c8563f42eed95905416e134043 /lib/Crypto/SelfTest | |
parent | 965871a72773457d73fda6a1a2970a4279dcbe6f (diff) | |
download | pycrypto-2062e5f843fa54d9da45e5d53652f3fb5dbbd97e.tar.gz |
Add encrypt_and_digest() and decrypt_and_verify()
This patch adds encrypt_and_digest() and decrypt_and_verify()
methods to a cipher object.
In most cases they are just shortcuts to the existing functions.
For SIV mode, decrypt_and_verify() replaces decrypt().
[dlitz@dlitz.net: Squashed with bugfix commit:]
Bug in encrypt_and_digest() (all AEAD modes)
decrypt() was being called instead of encrypt().
Added also a unit test to validate that composition
of encrypt_and_digest() and decrypt_and_verify()
is the identity function.
[dlitz@dlitz.net: Included changes from the following commit from the author's pull request:]
- [9c13f9c] Rename 'IV' parameter to 'nonce' for AEAD modes.
[dlitz@dlitz.net: Whitespace fixed with "git rebase --whitespace=fix"]
[dlitz@dlitz.net: Replaced MacMismatchError with ValueError]
[dlitz@dlitz.net: Replaced ApiUsageError with TypeError]
Diffstat (limited to 'lib/Crypto/SelfTest')
-rw-r--r-- | lib/Crypto/SelfTest/Cipher/common.py | 69 |
1 files changed, 46 insertions, 23 deletions
diff --git a/lib/Crypto/SelfTest/Cipher/common.py b/lib/Crypto/SelfTest/Cipher/common.py index 727086d..420b6ff 100644 --- a/lib/Crypto/SelfTest/Cipher/common.py +++ b/lib/Crypto/SelfTest/Cipher/common.py @@ -162,7 +162,7 @@ class CipherSelfTest(unittest.TestCase): ctX = b2a_hex(cipher.encrypt(plaintext)) if self.isMode("SIV"): - ptX = b2a_hex(decipher.decrypt(ciphertext+a2b_hex(self.mac))) + ptX = b2a_hex(decipher.decrypt_and_verify(ciphertext, a2b_hex(self.mac))) else: ptX = b2a_hex(decipher.decrypt(ciphertext)) @@ -427,11 +427,7 @@ class AEADTests(unittest.TestCase): # Decrypt and verify that MAC is accepted decipher = self.module.new(self.key, self.mode, self.iv) decipher.update(ad_ref) - if not self.isMode("SIV"): - pt = decipher.decrypt(ct_ref) - else: - pt = decipher.decrypt(ct_ref+mac_ref) - decipher.verify(mac_ref) + pt = decipher.decrypt_and_verify(ct_ref, mac_ref) self.assertEqual(pt, pt_ref) # Verify that hexverify work @@ -456,8 +452,8 @@ class AEADTests(unittest.TestCase): wrong_mac = strxor_c(mac_ref, 255) decipher = self.module.new(self.key, self.mode, self.iv) decipher.update(ad_ref) - pt = decipher.decrypt(ct_ref) - self.assertRaises(ValueError, decipher.verify, wrong_mac) + self.assertRaises(ValueError, decipher.decrypt_and_verify, + ct_ref, wrong_mac) def zero_data(self): """Verify transition from INITIALIZED to FINISHED""" @@ -522,10 +518,12 @@ class AEADTests(unittest.TestCase): cipher.encrypt(b("PT")*40) self.assertRaises(TypeError, cipher.decrypt, b("XYZ")*40) - # Calling encrypt after decrypt raises an exception - cipher = self.module.new(self.key, self.mode, self.iv) - cipher.decrypt(b("CT")*40) - self.assertRaises(TypeError, cipher.encrypt, 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) @@ -533,11 +531,13 @@ class AEADTests(unittest.TestCase): self.assertRaises(TypeError, cipher.verify, b("XYZ")) self.assertRaises(TypeError, cipher.hexverify, "12") - # Calling digest after decrypt raises an exception - 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) + # 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""" @@ -551,11 +551,33 @@ class AEADTests(unittest.TestCase): cipher.encrypt(b("PT")*40) self.assertRaises(TypeError, cipher.update, b("XYZ")) - # Calling update after decrypt raises an exception - 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")) + # 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() @@ -564,6 +586,7 @@ class AEADTests(unittest.TestCase): self.multiple_updates() self.no_mix_encrypt_decrypt() self.no_late_update() + self.loopback() def shortDescription(self): return self.description @@ -585,7 +608,7 @@ class RoundtripTest(unittest.TestCase): 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: |