class MacTest(parameterized.TestCase): @parameterized.parameters( supported_key_types.test_cases(supported_key_types.MAC_KEY_TYPES)) def test_encrypt_decrypt(self, key_template_name, supported_langs): key_template = supported_key_types.KEY_TEMPLATE[key_template_name] keyset_handle = testing_servers.new_keyset_handle('java', key_template) supported_macs = [ testing_servers.mac(lang, keyset_handle) for lang in supported_langs ] unsupported_macs = [ testing_servers.mac(lang, keyset_handle) for lang in testing_servers.LANGUAGES if lang not in supported_langs ] for p in supported_macs: data = ( b'This is some data to be authenticated using key_template ' b'%s in %s.' % (key_template_name.encode('utf8'), p.lang.encode('utf8'))) mac_value = p.compute_mac(data) for p2 in supported_macs: self.assertIsNone(p2.verify_mac(mac_value, data)) for p2 in unsupported_macs: with self.assertRaises(tink.TinkError): p2.verify_mac(mac_value, data) for p in unsupported_macs: with self.assertRaises(tink.TinkError): p.compute_mac(data)
class AeadPythonTest(parameterized.TestCase): @parameterized.parameters( supported_key_types.test_cases(supported_key_types.AEAD_KEY_TYPES)) def test_encrypt_decrypt(self, key_template_name, supported_langs): key_template = supported_key_types.KEY_TEMPLATE[key_template_name] # use java to generate keys, as it supports all key types. keyset_handle = testing_servers.new_keyset_handle('java', key_template) supported_aeads = [ testing_servers.aead(lang, keyset_handle) for lang in supported_langs ] unsupported_aeads = [ testing_servers.aead(lang, keyset_handle) for lang in testing_servers.LANGUAGES if lang not in supported_langs ] for p in supported_aeads: plaintext = ( b'This is some plaintext message to be encrypted using key_template ' b'%s using %s for encryption.' % (key_template_name.encode('utf8'), p.lang.encode('utf8'))) associated_data = ( b'Some associated data for %s using %s for encryption.' % (key_template_name.encode('utf8'), p.lang.encode('utf8'))) ciphertext = p.encrypt(plaintext, associated_data) for p2 in supported_aeads: output = p2.decrypt(ciphertext, associated_data) self.assertEqual(output, plaintext) for p2 in unsupported_aeads: with self.assertRaises(tink.TinkError): p2.decrypt(ciphertext, associated_data) for p in unsupported_aeads: with self.assertRaises(tink.TinkError): p.encrypt(b'plaintext', b'associated_data')
def test_test_cases(self): self.assertEqual( list( supported_key_types.test_cases( ['AesEaxKey', 'ChaCha20Poly1305Key'])), [('AES128_EAX', ['cc', 'java', 'python']), ('AES256_EAX', ['cc', 'java', 'python']), ('CHACHA20_POLY1305', ['java', 'go'])])
class JsonTest(parameterized.TestCase): def test_is_equal_keyset(self): keyset1 = tink_pb2.Keyset() key11 = keyset1.key.add() key11.key_id = 21 key12 = keyset1.key.add() key12.key_id = 42 keyset2 = tink_pb2.Keyset() key21 = keyset2.key.add() key21.key_id = 42 key22 = keyset2.key.add() key22.key_id = 21 self.assertTrue( _is_equal_keyset(keyset1.SerializeToString(), keyset2.SerializeToString())) def test_is_not_equal_keyset(self): keyset1 = tink_pb2.Keyset() key11 = keyset1.key.add() key11.key_id = 21 key12 = keyset1.key.add() key12.key_id = 42 keyset2 = tink_pb2.Keyset() key3 = keyset2.key.add() key3.key_id = 21 self.assertFalse( _is_equal_keyset(keyset1.SerializeToString(), keyset2.SerializeToString())) def assertEqualKeyset(self, keyset1: bytes, keyset2: bytes): if not _is_equal_keyset(keyset1, keyset2): self.fail('these keysets are not equal: \n%s\n \n%s\n' % (_keyset_proto(keyset1), _keyset_proto(keyset2))) @parameterized.parameters( supported_key_types.test_cases(supported_key_types.ALL_KEY_TYPES)) def test_to_from_json(self, key_template_name, supported_langs): self.assertNotEmpty(supported_langs) key_template = supported_key_types.KEY_TEMPLATE[key_template_name] # Take the first supported language to generate the keyset. keyset = testing_servers.new_keyset(supported_langs[0], key_template) for to_lang in supported_langs: json_keyset = testing_servers.keyset_to_json(to_lang, keyset) for from_lang in supported_langs: keyset2 = testing_servers.keyset_from_json( from_lang, json_keyset) self.assertEqualKeyset(keyset, keyset2)
class HybridEncryptionTest(parameterized.TestCase): @parameterized.parameters( supported_key_types.test_cases( supported_key_types.HYBRID_PRIVATE_KEY_TYPES)) def test_encrypt_decrypt(self, key_template_name, supported_langs): self.assertNotEmpty(supported_langs) key_template = supported_key_types.KEY_TEMPLATE[key_template_name] # Take the first supported language to generate the private keyset. private_keyset = testing_servers.new_keyset(supported_langs[0], key_template) supported_decs = [ testing_servers.hybrid_decrypt(lang, private_keyset) for lang in supported_langs ] unsupported_decs = [ testing_servers.hybrid_decrypt(lang, private_keyset) for lang in SUPPORTED_LANGUAGES if lang not in supported_langs ] public_keyset = testing_servers.public_keyset('java', private_keyset) supported_encs = [ testing_servers.hybrid_encrypt(lang, public_keyset) for lang in supported_langs ] unsupported_encs = [ testing_servers.hybrid_encrypt(lang, public_keyset) for lang in testing_servers.LANGUAGES if lang not in supported_langs ] for enc in supported_encs: plaintext = ( b'This is some plaintext message to be encrypted using key_template ' b'%s in %s.' % (key_template_name.encode('utf8'), enc.lang.encode('utf8'))) context_info = ( b'Some context info for %s using %s for encryption.' % (key_template_name.encode('utf8'), enc.lang.encode('utf8'))) ciphertext = enc.encrypt(plaintext, context_info) for dec in supported_decs: output = dec.decrypt(ciphertext, context_info) self.assertEqual(output, plaintext) for dec in unsupported_decs: with self.assertRaises(tink.TinkError): dec.decrypt(ciphertext, context_info) for enc in unsupported_encs: with self.assertRaises(tink.TinkError): enc.encrypt(b'plaintext', b'context_info')
class StreamingAeadPythonTest(parameterized.TestCase): @parameterized.parameters( supported_key_types.test_cases( supported_key_types.STREAMING_AEAD_KEY_TYPES)) def test_encrypt_decrypt(self, key_template_name, supported_langs): self.assertNotEmpty(supported_langs) key_template = supported_key_types.KEY_TEMPLATE[key_template_name] # Take the first supported language to generate the keyset. keyset = testing_servers.new_keyset(supported_langs[0], key_template) supported_streaming_aeads = [ testing_servers.streaming_aead(lang, keyset) for lang in supported_langs ] unsupported_streaming_aeads = [ testing_servers.streaming_aead(lang, keyset) for lang in SUPPORTED_LANGUAGES if lang not in supported_langs ] for p in supported_streaming_aeads: plaintext = ( b'This is some plaintext message to be encrypted using key_template ' b'%s using %s for encryption.' % (key_template_name.encode('utf8'), p.lang.encode('utf8'))) associated_data = ( b'Some associated data for %s using %s for encryption.' % (key_template_name.encode('utf8'), p.lang.encode('utf8'))) plaintext_stream = io.BytesIO(plaintext) ciphertext_result_stream = p.new_encrypting_stream( plaintext_stream, associated_data) ciphertext = ciphertext_result_stream.read() for p2 in supported_streaming_aeads: ciphertext_stream = io.BytesIO(ciphertext) decrypted_stream = p2.new_decrypting_stream( ciphertext_stream, associated_data) self.assertEqual(decrypted_stream.read(), plaintext) for p2 in unsupported_streaming_aeads: with self.assertRaises(tink.TinkError): ciphertext_stream = io.BytesIO(ciphertext) decrypted_stream = p2.new_decrypting_stream( ciphertext_stream, associated_data) for p in unsupported_streaming_aeads: with self.assertRaises(tink.TinkError): plaintext_stream = io.BytesIO(b'plaintext') ciphertext_result_stream = p.new_encrypting_stream( plaintext_stream, b'associated_data')
class SignaturePythonTest(parameterized.TestCase): @parameterized.parameters( supported_key_types.test_cases(supported_key_types.SIGNATURE_KEY_TYPES) ) def test_encrypt_decrypt(self, key_template_name, supported_langs): self.assertNotEmpty(supported_langs) key_template = supported_key_types.KEY_TEMPLATE[key_template_name] # Take the first supported language to generate the private keyset. private_keyset = testing_servers.new_keyset(supported_langs[0], key_template) supported_signers = [ testing_servers.public_key_sign(lang, private_keyset) for lang in supported_langs ] unsupported_signers = [ testing_servers.public_key_sign(lang, private_keyset) for lang in SUPPORTED_LANGUAGES if lang not in supported_langs ] public_keyset = testing_servers.public_keyset('java', private_keyset) supported_verifiers = [ testing_servers.public_key_verify(lang, public_keyset) for lang in supported_langs ] unsupported_verifiers = [ testing_servers.public_key_verify(lang, public_keyset) for lang in testing_servers.LANGUAGES if lang not in supported_langs ] for signer in supported_signers: message = ( b'A message to be signed using key_template %s in %s.' % (key_template_name.encode('utf8'), signer.lang.encode('utf8'))) sign = signer.sign(message) for verifier in supported_verifiers: self.assertIsNone(verifier.verify(sign, message)) for verifier in unsupported_verifiers: with self.assertRaises(tink.TinkError): verifier.verify(sign, message) for signer in unsupported_signers: with self.assertRaises(tink.TinkError): _ = signer.sign(message)
class DeterministicAeadTest(parameterized.TestCase): @parameterized.parameters( supported_key_types.test_cases(supported_key_types.DAEAD_KEY_TYPES)) def test_encrypt_decrypt(self, key_template_name, supported_langs): key_template = supported_key_types.KEY_TEMPLATE[key_template_name] keyset_handle = testing_servers.new_keyset_handle('java', key_template) supported_daeads = [ testing_servers.deterministic_aead(lang, keyset_handle) for lang in supported_langs ] self.assertNotEmpty(supported_daeads) unsupported_daeads = [ testing_servers.deterministic_aead(lang, keyset_handle) for lang in testing_servers.LANGUAGES if lang not in supported_langs ] plaintext = ( b'This is some plaintext message to be encrypted using ' b'key_template %s.' % key_template_name.encode('utf8')) associated_data = ( b'Some associated data for %s.' % key_template_name.encode('utf8')) ciphertext = None for p in supported_daeads: if ciphertext: self.assertEqual( ciphertext, p.encrypt_deterministically(plaintext, associated_data)) else: ciphertext = p.encrypt_deterministically(plaintext, associated_data) for p2 in supported_daeads: output = p2.decrypt_deterministically(ciphertext, associated_data) self.assertEqual(output, plaintext) for p2 in unsupported_daeads: with self.assertRaises(tink.TinkError): p2.decrypt_deterministically(ciphertext, associated_data) for p in unsupported_daeads: with self.assertRaises(tink.TinkError): p.encrypt_deterministically(b'plaintext', b'associated_data')
class PrfSetPythonTest(parameterized.TestCase): @parameterized.parameters( supported_key_types.test_cases(supported_key_types.PRF_KEY_TYPES)) def test_unsupported(self, key_template_name, supported_langs): self.assertNotEmpty(supported_langs) keyset = gen_keyset(key_template_name) unsupported_languages = [ lang for lang in SUPPORTED_LANGUAGES if lang not in supported_langs ] for lang in unsupported_languages: p = testing_servers.prf_set(lang, keyset) with self.assertRaises(tink.TinkError): p.primary().compute(b'input_data', output_length=16) @parameterized.parameters( supported_key_types.test_cases(supported_key_types.PRF_KEY_TYPES)) def test_supported(self, key_template_name, supported_langs): self.assertNotEmpty(supported_langs) keyset = gen_keyset(key_template_name) input_data = b'This is some input data.' outputs = [] for lang in supported_langs: p = testing_servers.prf_set(lang, keyset) outputs.append(p.primary().compute(input_data, 16)) self.assertLen(outputs, len(supported_langs)) self.assertLen(outputs[0], 16) self.assertLen(set(outputs), 1) @parameterized.parameters(test_cases_with_output_length()) def test_compute_consistent_for_output_length(self, key_template_name, output_length, supported_langs): # This test checks that for a given output_length, either all # implementations fail or all produce the same value. self.assertNotEmpty(supported_langs) keyset = gen_keyset(key_template_name) input_data = b'This is some input data.' errors = {} outputs = {} for lang in supported_langs: try: p = testing_servers.prf_set(lang, keyset) outputs[lang] = p.primary().compute(input_data, output_length) except tink.TinkError as e: errors[lang] = e inconsistent_errors = bool(errors) and bool(outputs) inconsistent_output_values = len(set(outputs.values())) > 1 if inconsistent_errors or inconsistent_output_values: self.fail( 'The PRF for template %s and output_length=%d is inconsistent: ' 'outputs = %s, errors = %s.' % (key_template_name, output_length, outputs, errors)) @parameterized.parameters(SUPPORTED_LANGUAGES) def test_multiple_prfs(self, lang): keyset = gen_keyset_with_2_prfs() input_data = b'This is some input data.' output_length = 15 p = testing_servers.prf_set(lang, keyset) primary_output = p.primary().compute(input_data, output_length) primary_id = p.primary_id() all_outputs = { key_id: f.compute(input_data, output_length) for key_id, f in p.all().items() } self.assertLen(all_outputs, 2) self.assertEqual(all_outputs[primary_id], primary_output)
def test_cases_with_output_length(): for key_template_name, supported_langs in supported_key_types.test_cases( supported_key_types.PRF_KEY_TYPES): for output_length in OUTPUT_LENGTHS: yield (key_template_name, output_length, supported_langs)
class AeadPythonTest(parameterized.TestCase): @parameterized.parameters( supported_key_types.test_cases(supported_key_types.AEAD_KEY_TYPES)) def test_encrypt_decrypt(self, key_template_name, supported_langs): self.assertNotEmpty(supported_langs) key_template = supported_key_types.KEY_TEMPLATE[key_template_name] # Take the first supported language to generate the keyset. keyset = testing_servers.new_keyset(supported_langs[0], key_template) supported_aeads = [ testing_servers.aead(lang, keyset) for lang in supported_langs ] unsupported_aeads = [ testing_servers.aead(lang, keyset) for lang in SUPPORTED_LANGUAGES if lang not in supported_langs ] for p in supported_aeads: plaintext = ( b'This is some plaintext message to be encrypted using key_template ' b'%s using %s for encryption.' % (key_template_name.encode('utf8'), p.lang.encode('utf8'))) associated_data = ( b'Some associated data for %s using %s for encryption.' % (key_template_name.encode('utf8'), p.lang.encode('utf8'))) ciphertext = p.encrypt(plaintext, associated_data) for p2 in supported_aeads: output = p2.decrypt(ciphertext, associated_data) self.assertEqual(output, plaintext) for p2 in unsupported_aeads: with self.assertRaises(tink.TinkError): p2.decrypt(ciphertext, associated_data) for p in unsupported_aeads: with self.assertRaises(tink.TinkError): p.encrypt(b'plaintext', b'associated_data') @parameterized.parameters(key_rotation_test_cases()) def test_key_rotation(self, enc_lang, dec_lang, old_key_tmpl, new_key_tmpl): # Do a key rotation from an old key generated from old_key_tmpl to a new # key generated from new_key_tmpl. Encryption and decryption are done # in languages enc_lang and dec_lang. builder = keyset_builder.new_keyset_builder() older_key_id = builder.add_new_key(old_key_tmpl) builder.set_primary_key(older_key_id) enc_aead1 = testing_servers.aead(enc_lang, builder.keyset()) dec_aead1 = testing_servers.aead(dec_lang, builder.keyset()) newer_key_id = builder.add_new_key(new_key_tmpl) enc_aead2 = testing_servers.aead(enc_lang, builder.keyset()) dec_aead2 = testing_servers.aead(dec_lang, builder.keyset()) builder.set_primary_key(newer_key_id) enc_aead3 = testing_servers.aead(enc_lang, builder.keyset()) dec_aead3 = testing_servers.aead(dec_lang, builder.keyset()) builder.disable_key(older_key_id) enc_aead4 = testing_servers.aead(enc_lang, builder.keyset()) dec_aead4 = testing_servers.aead(dec_lang, builder.keyset()) self.assertNotEqual(older_key_id, newer_key_id) # 1 encrypts with the older key. So 1, 2 and 3 can decrypt it, but not 4. ciphertext1 = enc_aead1.encrypt(b'plaintext', b'ad') self.assertEqual(dec_aead1.decrypt(ciphertext1, b'ad'), b'plaintext') self.assertEqual(dec_aead2.decrypt(ciphertext1, b'ad'), b'plaintext') self.assertEqual(dec_aead3.decrypt(ciphertext1, b'ad'), b'plaintext') with self.assertRaises(tink.TinkError): _ = dec_aead4.decrypt(ciphertext1, b'ad') # 2 encrypts with the older key. So 1, 2 and 3 can decrypt it, but not 4. ciphertext2 = enc_aead2.encrypt(b'plaintext', b'ad') self.assertEqual(dec_aead1.decrypt(ciphertext2, b'ad'), b'plaintext') self.assertEqual(dec_aead2.decrypt(ciphertext2, b'ad'), b'plaintext') self.assertEqual(dec_aead3.decrypt(ciphertext2, b'ad'), b'plaintext') with self.assertRaises(tink.TinkError): _ = dec_aead4.decrypt(ciphertext2, b'ad') # 3 encrypts with the newer key. So 2, 3 and 4 can decrypt it, but not 1. ciphertext3 = enc_aead3.encrypt(b'plaintext', b'ad') with self.assertRaises(tink.TinkError): _ = dec_aead1.decrypt(ciphertext3, b'ad') self.assertEqual(dec_aead2.decrypt(ciphertext3, b'ad'), b'plaintext') self.assertEqual(dec_aead3.decrypt(ciphertext3, b'ad'), b'plaintext') self.assertEqual(dec_aead4.decrypt(ciphertext3, b'ad'), b'plaintext') # 4 encrypts with the newer key. So 2, 3 and 4 can decrypt it, but not 1. ciphertext4 = enc_aead4.encrypt(b'plaintext', b'ad') with self.assertRaises(tink.TinkError): _ = dec_aead1.decrypt(ciphertext4, b'ad') self.assertEqual(dec_aead2.decrypt(ciphertext4, b'ad'), b'plaintext') self.assertEqual(dec_aead3.decrypt(ciphertext4, b'ad'), b'plaintext') self.assertEqual(dec_aead4.decrypt(ciphertext4, b'ad'), b'plaintext')
class MacTest(parameterized.TestCase): @parameterized.parameters( supported_key_types.test_cases(supported_key_types.MAC_KEY_TYPES)) def test_encrypt_decrypt(self, key_template_name, supported_langs): self.assertNotEmpty(supported_langs) key_template = supported_key_types.KEY_TEMPLATE[key_template_name] # Take the first supported language to generate the keyset. keyset = testing_servers.new_keyset(supported_langs[0], key_template) supported_macs = [ testing_servers.mac(lang, keyset) for lang in supported_langs ] unsupported_macs = [ testing_servers.mac(lang, keyset) for lang in SUPPORTED_LANGUAGES if lang not in supported_langs ] for p in supported_macs: data = ( b'This is some data to be authenticated using key_template ' b'%s in %s.' % (key_template_name.encode('utf8'), p.lang.encode('utf8'))) mac_value = p.compute_mac(data) for p2 in supported_macs: self.assertIsNone(p2.verify_mac(mac_value, data)) for p2 in unsupported_macs: with self.assertRaises(tink.TinkError): p2.verify_mac(mac_value, data) for p in unsupported_macs: with self.assertRaises(tink.TinkError): p.compute_mac(data) @parameterized.parameters(key_rotation_test_cases()) def test_key_rotation(self, compute_lang, verify_lang, old_key_tmpl, new_key_tmpl): # Do a key rotation from an old key generated from old_key_tmpl to a new # key generated from new_key_tmpl. MAC computation and verification are done # in languages compute_lang and verify_lang. builder = keyset_builder.new_keyset_builder() older_key_id = builder.add_new_key(old_key_tmpl) builder.set_primary_key(older_key_id) compute_mac1 = testing_servers.mac(compute_lang, builder.keyset()) verify_mac1 = testing_servers.mac(verify_lang, builder.keyset()) newer_key_id = builder.add_new_key(new_key_tmpl) compute_mac2 = testing_servers.mac(compute_lang, builder.keyset()) verify_mac2 = testing_servers.mac(verify_lang, builder.keyset()) builder.set_primary_key(newer_key_id) compute_mac3 = testing_servers.mac(compute_lang, builder.keyset()) verify_mac3 = testing_servers.mac(verify_lang, builder.keyset()) builder.disable_key(older_key_id) compute_mac4 = testing_servers.mac(compute_lang, builder.keyset()) verify_mac4 = testing_servers.mac(verify_lang, builder.keyset()) self.assertNotEqual(older_key_id, newer_key_id) # 1 uses the older key. So 1, 2 and 3 can verify the mac, but not 4. mac_value1 = compute_mac1.compute_mac(b'plaintext') verify_mac1.verify_mac(mac_value1, b'plaintext') verify_mac2.verify_mac(mac_value1, b'plaintext') verify_mac3.verify_mac(mac_value1, b'plaintext') with self.assertRaises(tink.TinkError): verify_mac4.verify_mac(mac_value1, b'plaintext') # 2 uses the older key. So 1, 2 and 3 can verify the mac, but not 4. mac_value2 = compute_mac2.compute_mac(b'plaintext') verify_mac1.verify_mac(mac_value2, b'plaintext') verify_mac2.verify_mac(mac_value2, b'plaintext') verify_mac3.verify_mac(mac_value2, b'plaintext') with self.assertRaises(tink.TinkError): verify_mac4.verify_mac(mac_value2, b'plaintext') # 3 uses the newer key. So 2, 3 and 4 can verify the mac, but not 1. mac_value3 = compute_mac3.compute_mac(b'plaintext') with self.assertRaises(tink.TinkError): verify_mac1.verify_mac(mac_value3, b'plaintext') verify_mac2.verify_mac(mac_value3, b'plaintext') verify_mac3.verify_mac(mac_value3, b'plaintext') verify_mac4.verify_mac(mac_value3, b'plaintext') # 4 uses the newer key. So 2, 3 and 4 can verify the mac, but not 1. mac_value4 = compute_mac4.compute_mac(b'plaintext') with self.assertRaises(tink.TinkError): verify_mac1.verify_mac(mac_value4, b'plaintext') verify_mac2.verify_mac(mac_value4, b'plaintext') verify_mac3.verify_mac(mac_value4, b'plaintext') verify_mac4.verify_mac(mac_value4, b'plaintext')
class StreamingAeadPythonTest(parameterized.TestCase): @parameterized.parameters( supported_key_types.test_cases( supported_key_types.STREAMING_AEAD_KEY_TYPES)) def test_encrypt_decrypt(self, key_template_name, supported_langs): self.assertNotEmpty(supported_langs) key_template = supported_key_types.KEY_TEMPLATE[key_template_name] # Take the first supported language to generate the keyset. keyset = testing_servers.new_keyset(supported_langs[0], key_template) supported_streaming_aeads = [ testing_servers.streaming_aead(lang, keyset) for lang in supported_langs ] unsupported_streaming_aeads = [ testing_servers.streaming_aead(lang, keyset) for lang in SUPPORTED_LANGUAGES if lang not in supported_langs ] for p in supported_streaming_aeads: desc = ( b'This is some plaintext message to be encrypted using key_template ' b'%s using %s for encryption.' % (key_template_name.encode('utf8'), p.lang.encode('utf8'))) plaintext = desc + LONG_PLAINTEXT associated_data = ( b'Some associated data for %s using %s for encryption.' % (key_template_name.encode('utf8'), p.lang.encode('utf8'))) plaintext_stream = io.BytesIO(plaintext) ciphertext_result_stream = p.new_encrypting_stream( plaintext_stream, associated_data) ciphertext = ciphertext_result_stream.read() for p2 in supported_streaming_aeads: ciphertext_stream = io.BytesIO(ciphertext) decrypted_stream = p2.new_decrypting_stream( ciphertext_stream, associated_data) self.assertEqual(decrypted_stream.read(), plaintext) for p2 in unsupported_streaming_aeads: with self.assertRaises(tink.TinkError): ciphertext_stream = io.BytesIO(ciphertext) decrypted_stream = p2.new_decrypting_stream( ciphertext_stream, associated_data) for p in unsupported_streaming_aeads: with self.assertRaises(tink.TinkError): plaintext_stream = io.BytesIO(b'plaintext') ciphertext_result_stream = p.new_encrypting_stream( plaintext_stream, b'associated_data') @parameterized.parameters(key_rotation_test_cases()) def test_key_rotation(self, enc_lang, dec_lang): # Do a key rotation from an old key to a new key. # Encryption and decryption are done in languages enc_lang and dec_lang. builder = keyset_builder.new_keyset_builder() older_key_id = builder.add_new_key( streaming_aead.streaming_aead_key_templates.AES128_GCM_HKDF_4KB) builder.set_primary_key(older_key_id) enc1 = testing_servers.streaming_aead(enc_lang, builder.keyset()) dec1 = testing_servers.streaming_aead(dec_lang, builder.keyset()) newer_key_id = builder.add_new_key( streaming_aead.streaming_aead_key_templates.AES256_GCM_HKDF_4KB) enc2 = testing_servers.streaming_aead(enc_lang, builder.keyset()) dec2 = testing_servers.streaming_aead(dec_lang, builder.keyset()) builder.set_primary_key(newer_key_id) enc3 = testing_servers.streaming_aead(enc_lang, builder.keyset()) dec3 = testing_servers.streaming_aead(dec_lang, builder.keyset()) builder.disable_key(older_key_id) enc4 = testing_servers.streaming_aead(enc_lang, builder.keyset()) dec4 = testing_servers.streaming_aead(dec_lang, builder.keyset()) self.assertNotEqual(older_key_id, newer_key_id) # 1 encrypts with the older key. So 1, 2 and 3 can decrypt it, but not 4. plaintext = LONG_PLAINTEXT ad = b'associated_data' ciphertext1 = enc1.new_encrypting_stream(io.BytesIO(plaintext), ad).read() self.assertEqual( dec1.new_decrypting_stream(io.BytesIO(ciphertext1), ad).read(), plaintext) self.assertEqual( dec2.new_decrypting_stream(io.BytesIO(ciphertext1), ad).read(), plaintext) self.assertEqual( dec3.new_decrypting_stream(io.BytesIO(ciphertext1), ad).read(), plaintext) with self.assertRaises(tink.TinkError): _ = dec4.new_decrypting_stream(io.BytesIO(ciphertext1), ad).read() # 2 encrypts with the older key. So 1, 2 and 3 can decrypt it, but not 4. ciphertext2 = enc2.new_encrypting_stream(io.BytesIO(plaintext), ad).read() self.assertEqual( dec1.new_decrypting_stream(io.BytesIO(ciphertext2), ad).read(), plaintext) self.assertEqual( dec2.new_decrypting_stream(io.BytesIO(ciphertext2), ad).read(), plaintext) self.assertEqual( dec3.new_decrypting_stream(io.BytesIO(ciphertext2), ad).read(), plaintext) with self.assertRaises(tink.TinkError): _ = dec4.new_decrypting_stream(io.BytesIO(ciphertext2), ad).read() # 3 encrypts with the newer key. So 2, 3 and 4 can decrypt it, but not 1. ciphertext3 = enc3.new_encrypting_stream(io.BytesIO(plaintext), ad).read() with self.assertRaises(tink.TinkError): _ = dec1.new_decrypting_stream(io.BytesIO(ciphertext3), ad).read() self.assertEqual( dec2.new_decrypting_stream(io.BytesIO(ciphertext3), ad).read(), plaintext) self.assertEqual( dec3.new_decrypting_stream(io.BytesIO(ciphertext3), ad).read(), plaintext) self.assertEqual( dec4.new_decrypting_stream(io.BytesIO(ciphertext3), ad).read(), plaintext) # 4 encrypts with the newer key. So 2, 3 and 4 can decrypt it, but not 1. ciphertext4 = enc4.new_encrypting_stream(io.BytesIO(plaintext), ad).read() with self.assertRaises(tink.TinkError): _ = dec1.new_decrypting_stream(io.BytesIO(ciphertext4), ad).read() self.assertEqual( dec2.new_decrypting_stream(io.BytesIO(ciphertext4), ad).read(), plaintext) self.assertEqual( dec3.new_decrypting_stream(io.BytesIO(ciphertext4), ad).read(), plaintext) self.assertEqual( dec4.new_decrypting_stream(io.BytesIO(ciphertext4), ad).read(), plaintext)