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 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 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_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_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_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_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_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_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_invalid_mac(self): from Cryptodome.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_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_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_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_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_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_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_invalid_mac(self): from Cryptodome.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_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_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_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_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_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_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 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)
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)
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 chacha20_poly1305_decrypt(*, key: bytes, nonce: bytes, associated_data: bytes = None, data: bytes) -> bytes: assert isinstance(key, (bytes, bytearray)) assert isinstance(nonce, (bytes, bytearray)) assert isinstance(associated_data, (bytes, bytearray, type(None))) assert isinstance(data, (bytes, bytearray)) assert len(key) == 32, f"unexpected key size: {len(key)} (expected: 32)" assert len( nonce) == 12, f"unexpected nonce size: {len(nonce)} (expected: 12)" if HAS_CRYPTODOME: cipher = CD_ChaCha20_Poly1305.new(key=key, nonce=nonce) if associated_data is not None: cipher.update(associated_data) # raises ValueError if not valid (e.g. incorrect MAC) return cipher.decrypt_and_verify(ciphertext=data[:-16], received_mac_tag=data[-16:]) if HAS_CRYPTOGRAPHY: a = CG_aead.ChaCha20Poly1305(key) try: return a.decrypt(nonce, data, associated_data) except cryptography.exceptions.InvalidTag as e: raise ValueError("invalid tag") from e raise Exception("no chacha20 backend found")
def aead_encrypt(key: bytes, nonce: int, associated_data: bytes, data: bytes) -> bytes: nonce_bytes = get_nonce_bytes(nonce) cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce_bytes) cipher.update(associated_data) ciphertext, mac = cipher.encrypt_and_digest(plaintext=data) return ciphertext + mac
def receiveM2(self, data): logger.info("Receive M2") pvDict = OPACK.decode(data) tlv = TLV8Box.decodeFromData(pvDict["pd"]).toDict() searching_device_pub_key = x25519.X25519PublicKey.from_public_bytes( bytes(tlv[0x03])) self.shared_secret = self.session_keys.private.exchange( searching_device_pub_key) hkdf_inst = hkdf.Hkdf("Pair-Verify-Encrypt-Salt".encode(), self.shared_secret, hash=hashlib.sha512) key = hkdf_inst.expand("Pair-Verify-Encrypt-Info".encode(), 32) encryptedData = bytes(tlv[0x05])[:-16] authKey = bytes(tlv[0x05])[-16:] nonce = "PV-Msg02".encode() cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) plainData = cipher.decrypt_and_verify(encryptedData, authKey) plainTLV = TLV8Box.decodeFromData(plainData).toDict() # plainTLV contains authentication data: # { # 9: Signature over public keys of grantor and requestor # 10: Apple ID certificate (NSDataCompressed) # 20: Apple ID validation record (NSDataCompressed) # } logger.debug(f"Identity TLV: {plainTLV}") self.sendM3()
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)
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): # 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) import sys if sys.version[:3] != '2.6': 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 aead_decrypt(key: bytes, nonce: int, associated_data: bytes, data: bytes) -> bytes: nonce_bytes = get_nonce_bytes(nonce) cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce_bytes) cipher.update(associated_data) # raises ValueError if not valid (e.g. incorrect MAC) return cipher.decrypt_and_verify(ciphertext=data[:-16], received_mac_tag=data[-16:])
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.assertEquals(cipher.digest(), ref_mac)
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.assertEquals(cipher.digest(), ref_mac)
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 can_decrypt(key, package): try: jv = decode_package(package) cipher = ChaCha20_Poly1305.new(key=key, nonce=jv['nonce']) cipher.update(jv['header']) plaintext = cipher.decrypt_and_verify(jv['ciphertext'], jv['tag']) #print("The message was: " + str(plaintext)) return True, plaintext except ValueError: #print("Incorrect decryption") return False, None
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 pyCrypto(): import Cryptodome from Cryptodome.Cipher import AES, ChaCha20, DES, DES3, ARC2, ARC4, Blowfish, CAST, PKCS1_v1_5, PKCS1_OAEP, ChaCha20_Poly1305, Salsa20 from Cryptodome.PublicKey import ElGamal Cryptodome.Cipher.AES.new() # Noncompliant Cryptodome.Other.AES.new() # OK AES.new(key=key) # Noncompliant ChaCha20.new(key=key) # Noncompliant DES.new(key=key) # Noncompliant DES3.new(key=key) # Noncompliant ARC2.new(key=key) # Noncompliant ARC4.new(key=key) # Noncompliant Blowfish.new(key=key) # Noncompliant CAST.new(key=key) # Noncompliant PKCS1_v1_5.new(key=key) # Noncompliant PKCS1_OAEP.new(key=key) # Noncompliant ChaCha20_Poly1305.new(key=key) # Noncompliant Salsa20.new(key=key) # Noncompliant ElGamal.generate(key_size) # Noncompliant
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) import sys if sys.version[:3] != '2.6': 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 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_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 encrypt(self, msg, aad, iv, key): """Content Encryption with AEAD_XCHACHA20_POLY1305 :param msg: text to be encrypt in bytes :param aad: additional authenticated data in bytes :param iv: initialization vector in bytes :param key: encrypted key in bytes :return: (ciphertext, tag) """ self.check_iv(iv) chacha = Cryptodome_ChaCha20_Poly1305.new(key=key, nonce=iv) chacha.update(aad) ciphertext, tag = chacha.encrypt_and_digest(msg) return ciphertext, tag
def decrypt(self, ciphertext, aad, iv, tag, key): """Content Decryption with AEAD_XCHACHA20_POLY1305 :param ciphertext: ciphertext in bytes :param aad: additional authenticated data in bytes :param iv: initialization vector in bytes :param tag: authentication tag in bytes :param key: encrypted key in bytes :return: message """ self.check_iv(iv) chacha = Cryptodome_ChaCha20_Poly1305.new(key=key, nonce=iv) chacha.update(aad) return chacha.decrypt_and_verify(ciphertext, tag)
def chacha20_poly1305_encrypt(*, key: bytes, nonce: bytes, associated_data: bytes, data: bytes) -> bytes: assert isinstance(key, (bytes, bytearray)) assert isinstance(nonce, (bytes, bytearray)) assert isinstance(associated_data, (bytes, bytearray)) assert isinstance(data, (bytes, bytearray)) if HAS_CRYPTODOME: cipher = CD_ChaCha20_Poly1305.new(key=key, nonce=nonce) cipher.update(associated_data) ciphertext, mac = cipher.encrypt_and_digest(plaintext=data) return ciphertext + mac if HAS_CRYPTOGRAPHY: a = CG_aead.ChaCha20Poly1305(key) return a.encrypt(nonce, data, associated_data) raise Exception("no chacha20 backend found")
def test_encrypt(self, tv): self._id = "Wycheproof Encrypt ChaCha20-Poly1305 Test #" + str(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 ChaCha20-Poly1305 Test #" + str(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_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.assertEquals(ct, cipher.encrypt(self.data_128))
def test_block_size(self): # Not based on block ciphers cipher = ChaCha20_Poly1305.new(key=self.key_256, nonce=self.nonce_96) self.failIf(hasattr(cipher, 'block_size'))
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_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_valid_init_digest(self): # Verify path INIT->DIGEST cipher = ChaCha20_Poly1305.new(key=self.key_256, nonce=self.nonce_96) cipher.digest()