def test_wrapped_encrypt_decrypt_two_keys(self, input_stream_factory): template = (streaming_aead.streaming_aead_key_templates. AES128_CTR_HMAC_SHA256_4KB) old_keyset = tink_pb2.Keyset() key1 = old_keyset.key.add() key1.key_data.CopyFrom(tink.core.Registry.new_key_data(template)) key1.status = tink_pb2.ENABLED key1.key_id = 1234 key1.output_prefix_type = template.output_prefix_type old_keyset.primary_key_id = key1.key_id old_keyset_handle = cleartext_keyset_handle.from_keyset(old_keyset) old_primitive = old_keyset_handle.primitive( streaming_aead.StreamingAead) new_keyset = tink_pb2.Keyset() new_keyset.CopyFrom(old_keyset) key2 = new_keyset.key.add() key2.key_data.CopyFrom(tink.core.Registry.new_key_data(template)) key2.status = tink_pb2.ENABLED key2.key_id = 5678 key2.output_prefix_type = template.output_prefix_type new_keyset.primary_key_id = key2.key_id new_keyset_handle = cleartext_keyset_handle.from_keyset(new_keyset) new_primitive = new_keyset_handle.primitive( streaming_aead.StreamingAead) plaintext1 = b' '.join(b'%d' % i for i in range(100 * 1000)) ciphertext1_dest = bytes_io.BytesIOWithValueAfterClose() with old_primitive.new_encrypting_stream(ciphertext1_dest, b'aad1') as es: es.write(plaintext1) ciphertext1 = ciphertext1_dest.value_after_close() plaintext2 = b' '.join(b'%d' % i for i in range(100 * 1001)) ciphertext2_dest = bytes_io.BytesIOWithValueAfterClose() with new_primitive.new_encrypting_stream(ciphertext2_dest, b'aad2') as es: es.write(plaintext2) ciphertext2 = ciphertext2_dest.value_after_close() # old_primitive can read 1st ciphertext, but not the 2nd with old_primitive.new_decrypting_stream( cast(BinaryIO, input_stream_factory(ciphertext1)), b'aad1') as ds: self.assertEqual(ds.read(), plaintext1) with old_primitive.new_decrypting_stream( cast(BinaryIO, input_stream_factory(ciphertext2)), b'aad2') as ds: with self.assertRaises(tink.TinkError): ds.read() # new_primitive can read both ciphertexts with new_primitive.new_decrypting_stream( cast(BinaryIO, input_stream_factory(ciphertext1)), b'aad1') as ds: self.assertEqual(ds.read(), plaintext1) with new_primitive.new_decrypting_stream( cast(BinaryIO, input_stream_factory(ciphertext2)), b'aad2') as ds: self.assertEqual(ds.read(), plaintext2)
def test_get_two_encrypting_streams(self): """Test that multiple EncryptingStreams can be obtained from a primitive.""" primitive = self.get_primitive() f1 = bytes_io.BytesIOWithValueAfterClose() f2 = bytes_io.BytesIOWithValueAfterClose() with primitive.new_encrypting_stream(f1, B_AAD_) as es: es.write(b'some data' + B_X80) with primitive.new_encrypting_stream(f2, b'another aad' + B_X80) as es: es.write(b'some other data' + B_X80) self.assertNotEmpty(f1.value_after_close()) self.assertNotEmpty(f2.value_after_close())
def test_raw_encrypt_decrypt(self): raw_primitive = self.key_manager_ctr.primitive( self.key_manager_ctr.new_key_data( streaming_aead.streaming_aead_key_templates. AES128_CTR_HMAC_SHA256_4KB)) plaintext = b'plaintext' + B_X80 aad = b'associated_data' + B_X80 # Encrypt ct_destination = bytes_io.BytesIOWithValueAfterClose() with raw_primitive.new_raw_encrypting_stream(ct_destination, aad) as es: self.assertLen(plaintext, es.write(plaintext)) # context manager closes es, which also closes ciphertext_dest self.assertTrue(ct_destination.closed) # Decrypt, with and without close_ciphertext_source for close_ciphertext_source in [True, False]: ct_source = io.BytesIO(ct_destination.value_after_close()) with raw_primitive.new_raw_decrypting_stream( ct_source, aad, close_ciphertext_source=close_ciphertext_source) as ds: output = ds.readall() self.assertEqual(ct_source.closed, close_ciphertext_source) self.assertEqual(output, plaintext)
def test_raw_encrypt_decrypt_close(self): raw_primitive = self.get_raw_primitive() plaintext = b'plaintext' + B_X80 aad = b'associated_data' + B_X80 # Encrypt ct_destination = bytes_io.BytesIOWithValueAfterClose() es = raw_primitive.new_raw_encrypting_stream(ct_destination, aad) es.write(plaintext) self.assertFalse(ct_destination.closed) self.assertFalse(es.closed) es.close() self.assertTrue(ct_destination.closed) self.assertTrue(es.closed) # Decrypt, with and without close_ciphertext_source for close_ciphertext_source in [True, False]: ct_source = io.BytesIO(ct_destination.value_after_close()) ds = raw_primitive.new_raw_decrypting_stream( ct_source, aad, close_ciphertext_source=close_ciphertext_source) self.assertFalse(ct_source.closed) self.assertFalse(ds.closed) ds.close() self.assertEqual(ct_source.closed, close_ciphertext_source) self.assertTrue(ds.closed)
def _encrypt(primitive: streaming_aead.StreamingAead, plaintext: bytes, associated_data: bytes) -> bytes: ciphertext_dest = bytes_io.BytesIOWithValueAfterClose() with primitive.new_encrypting_stream(ciphertext_dest, associated_data) as es: es.write(plaintext) return ciphertext_dest.value_after_close()
def test_with_text_wrapper_success(self): f = bytes_io.BytesIOWithValueAfterClose() with io.TextIOWrapper(f, encoding='utf8') as t: t.write(u'foobar') self.assertTrue(f.closed) value = f.value_after_close() self.assertEqual(value, u'foobar'.encode('utf8'))
def test_slow_encrypt_decrypt_with_two_keys(self, input_stream_factory): primitive1, key1 = _primitive_key_pair(1234) pset1 = core.new_primitive_set(_raw_streaming_aead.RawStreamingAead) entry1 = pset1.add_primitive(primitive1, key1) pset1.set_primary(entry1) old_primitive = core.Registry.wrap(pset1, streaming_aead.StreamingAead) plaintext1 = b' '.join(b'%d' % i for i in range(100 * 1000)) aad1 = b'aad1' ciphertext_dest1 = bytes_io.BytesIOWithValueAfterClose() with old_primitive.new_encrypting_stream(ciphertext_dest1, aad1) as es: es.write(plaintext1) ciphertext1 = ciphertext_dest1.value_after_close() pset2 = core.new_primitive_set(_raw_streaming_aead.RawStreamingAead) pset2.add_primitive(primitive1, key1) primitive2, key2 = _primitive_key_pair(5678) entry2 = pset2.add_primitive(primitive2, key2) pset2.set_primary(entry2) new_primitive = core.Registry.wrap(pset2, streaming_aead.StreamingAead) plaintext2 = b' '.join(b'%d' % i for i in range(100 * 1001)) aad2 = b'aad2' ciphertext_dest2 = bytes_io.BytesIOWithValueAfterClose() with new_primitive.new_encrypting_stream(ciphertext_dest2, aad2) as es: es.write(plaintext2) ciphertext2 = ciphertext_dest2.value_after_close() # old_primitive can read 1st ciphertext, but not the 2nd with old_primitive.new_decrypting_stream( cast(BinaryIO, input_stream_factory(ciphertext1)), aad1) as ds: self.assertEqual(_readall(ds), plaintext1) with old_primitive.new_decrypting_stream( cast(BinaryIO, input_stream_factory(ciphertext2)), aad2) as ds: with self.assertRaises(core.TinkError): _readall(ds) # new_primitive can read both ciphertexts with new_primitive.new_decrypting_stream( cast(BinaryIO, input_stream_factory(ciphertext1)), aad1) as ds: self.assertEqual(_readall(ds), plaintext1) with new_primitive.new_decrypting_stream( cast(BinaryIO, input_stream_factory(ciphertext2)), aad2) as ds: self.assertEqual(_readall(ds), plaintext2)
def test_textiowrapper_compatibility(self): """A test that checks the TextIOWrapper works as expected. It encrypts the same plaintext twice - once directly from bytes, and once through TextIOWrapper's encoding. The two ciphertexts should have the same length. """ file_1 = bytes_io.BytesIOWithValueAfterClose() file_2 = bytes_io.BytesIOWithValueAfterClose() with get_encrypting_stream(file_1, B_AAD_) as es: with io.TextIOWrapper(es) as wrapper: wrapper.write(b'some data'.decode('utf-8')) with get_encrypting_stream(file_2, B_AAD_) as es: es.write(b'some data') self.assertEqual(len(file_1.value_after_close()), len(file_2.value_after_close()))
def test_get_encrypting_stream(self): primitive = self.get_primitive() # Use the primitive to get an encrypting stream. f = bytes_io.BytesIOWithValueAfterClose() with primitive.new_encrypting_stream(f, B_AAD_) as es: es.write(b'some data' + B_X80) ciphertext = f.value_after_close() self.assertNotEmpty(ciphertext)
def test_raw_encrypt_decrypt_empty(self): raw_primitive = self.get_raw_primitive() plaintext = b'' aad = b'' ct_destination = bytes_io.BytesIOWithValueAfterClose() with raw_primitive.new_raw_encrypting_stream(ct_destination, aad) as es: es.write(plaintext) ct_source = io.BytesIO(ct_destination.value_after_close()) with raw_primitive.new_raw_decrypting_stream( ct_source, aad, close_ciphertext_source=True) as ds: self.assertEqual(ds.read(5), b'')
def test_encrypt_decrypt_success(self, plaintext): aad = b'associated_data' wrapped_saead = _wrapped_saead(1234) ciphertext_dest = bytes_io.BytesIOWithValueAfterClose() with wrapped_saead.new_encrypting_stream(ciphertext_dest, aad) as es: self.assertLen(plaintext, es.write(plaintext)) self.assertTrue(ciphertext_dest.closed) ciphertext_src = io.BytesIO(ciphertext_dest.value_after_close()) with wrapped_saead.new_decrypting_stream(ciphertext_src, aad) as ds: output = ds.read() self.assertTrue(ciphertext_src.closed) self.assertEqual(output, plaintext)
def test_fake_streaming_aead_fails_wrong_aad(self): saead = fake_streaming_aead.FakeRawStreamingAead('Name') ciphertext_dest = bytes_io.BytesIOWithValueAfterClose() with saead.new_raw_encrypting_stream(ciphertext_dest, b'aad') as es: self.assertLen(b'plaintext', es.write(b'plaintext')) self.assertTrue(ciphertext_dest.closed) ciphertext_src = io.BytesIO(ciphertext_dest.value_after_close()) with saead.new_raw_decrypting_stream( ciphertext_src, b'bad aad', close_ciphertext_source=True) as ds: with self.assertRaises(core.TinkError): _ = ds.read()
def test_raw_read_after_eof_returns_empty_bytes(self): raw_primitive = self.get_raw_primitive() plaintext = b'plaintext' + B_X80 aad = b'associated_data' + B_X80 ct_destination = bytes_io.BytesIOWithValueAfterClose() with raw_primitive.new_raw_encrypting_stream(ct_destination, aad) as es: self.assertLen(plaintext, es.write(plaintext)) ct_source = io.BytesIO(ct_destination.value_after_close()) with raw_primitive.new_raw_decrypting_stream( ct_source, aad, close_ciphertext_source=True) as ds: _ = ds.readall() self.assertEqual(ds.read(100), b'')
def test_raw_fake_streaming_aead_readall_success(self): saead = fake_streaming_aead.FakeRawStreamingAead('Name') ciphertext_dest = bytes_io.BytesIOWithValueAfterClose() with saead.new_raw_encrypting_stream(ciphertext_dest, b'aad') as es: self.assertLen(b'plaintext', es.write(b'plaintext')) self.assertTrue(ciphertext_dest.closed) ciphertext_src = io.BytesIO(ciphertext_dest.value_after_close()) with saead.new_raw_decrypting_stream( ciphertext_src, b'aad', close_ciphertext_source=True) as ds: output = ds.readall() self.assertTrue(ciphertext_src.closed) self.assertEqual(output, b'plaintext')
def test_long_plaintext_encrypt_decrypt_success(self): long_plaintext = b' '.join(b'%d' % i for i in range(10 * 1000 * 1000)) aad = b'associated_data' wrapped_saead = _wrapped_saead(1234) ciphertext_dest = bytes_io.BytesIOWithValueAfterClose() with wrapped_saead.new_encrypting_stream(ciphertext_dest, aad) as es: self.assertLen(long_plaintext, es.write(long_plaintext)) self.assertTrue(ciphertext_dest.closed) ciphertext_src = io.BytesIO(ciphertext_dest.value_after_close()) with wrapped_saead.new_decrypting_stream(ciphertext_src, aad) as ds: output = ds.read() self.assertTrue(ciphertext_src.closed) self.assertEqual(output, long_plaintext)
def test_round_trip(self): primitive = self.get_primitive() f = bytes_io.BytesIOWithValueAfterClose() original_plaintext = b'some data' + B_X80 with primitive.new_encrypting_stream(f, B_TEST_AAD_) as es: es.write(original_plaintext) with io.BytesIO(f.value_after_close()) as f2: with primitive.new_decrypting_stream(f2, B_TEST_AAD_) as ds: read_plaintext = ds.read() self.assertEqual(read_plaintext, original_plaintext)
def test_encrypt_decrypt_success(self, plaintext): keyset_handle = tink.new_keyset_handle(TEMPLATE) primitive = keyset_handle.primitive(streaming_aead.StreamingAead) aad = b'associated_data' ciphertext_dest = bytes_io.BytesIOWithValueAfterClose() with primitive.new_encrypting_stream(ciphertext_dest, aad) as es: self.assertLen(plaintext, es.write(plaintext)) self.assertTrue(ciphertext_dest.closed) ciphertext_src = io.BytesIO(ciphertext_dest.value_after_close()) with primitive.new_decrypting_stream(ciphertext_src, aad) as ds: output = ds.read() self.assertTrue(ciphertext_src.closed) self.assertEqual(output, plaintext)
def test_encrypt_decrypt_bad_aad(self): wrapped_saead = _wrapped_saead(1234) plaintext = b'plaintext' aad = b'associated_data' ciphertext_dest = bytes_io.BytesIOWithValueAfterClose() with wrapped_saead.new_encrypting_stream(ciphertext_dest, aad) as es: self.assertLen(plaintext, es.write(plaintext)) self.assertTrue(ciphertext_dest.closed) ciphertext_src = io.BytesIO(ciphertext_dest.value_after_close()) with wrapped_saead.new_decrypting_stream(ciphertext_src, b'bad aad') as ds: with self.assertRaises(core.TinkError): _ = ds.read()
def test_decrypt_unknown_key_fails(self): plaintext = b'plaintext' aad = b'associated_data' unknown_saead = _wrapped_saead(1234) unknown_ciphertext_dest = bytes_io.BytesIOWithValueAfterClose() with unknown_saead.new_encrypting_stream(unknown_ciphertext_dest, aad) as es: es.write(plaintext) wrapped_saead = _wrapped_saead(2345) ciphertext_src = io.BytesIO( unknown_ciphertext_dest.value_after_close()) with wrapped_saead.new_decrypting_stream(ciphertext_src, aad) as ds: with self.assertRaises(core.TinkError): _ = ds.read()
def test_encrypt_decrypt_bad_aad(self): keyset_handle = tink.new_keyset_handle(TEMPLATE) primitive = keyset_handle.primitive(streaming_aead.StreamingAead) plaintext = b'plaintext' aad = b'associated_data' ciphertext_dest = bytes_io.BytesIOWithValueAfterClose() with primitive.new_encrypting_stream(ciphertext_dest, aad) as es: self.assertLen(plaintext, es.write(plaintext)) self.assertTrue(ciphertext_dest.closed) ciphertext_src = io.BytesIO(ciphertext_dest.value_after_close()) with primitive.new_decrypting_stream(ciphertext_src, b'bad aad') as ds: with self.assertRaises(tink.TinkError): _ = ds.read()
def test_round_trip_textiowrapper_single_line(self): """Read and write a single line through a TextIOWrapper.""" primitive = self.get_primitive() f = bytes_io.BytesIOWithValueAfterClose() original_plaintext = b'One-line string.'.decode('utf-8') with primitive.new_encrypting_stream(f, B_TEST_AAD_) as es: with io.TextIOWrapper(es) as wrapper: wrapper.write(original_plaintext) with io.BytesIO(f.value_after_close()) as f2: with primitive.new_decrypting_stream(f2, B_TEST_AAD_) as ds: with io.TextIOWrapper(ds) as wrapper: read_plaintext = wrapper.read() self.assertEqual(original_plaintext, read_plaintext)
def test_read_after_eof_returns_empty_bytes(self): saead_primitive = self.key_manager_ctr.primitive( self.key_manager_ctr.new_key_data( streaming_aead.streaming_aead_key_templates. AES128_CTR_HMAC_SHA256_4KB)) plaintext = b'plaintext' + B_X80 aad = b'associated_data' + B_X80 ct_destination = bytes_io.BytesIOWithValueAfterClose() with saead_primitive.new_encrypting_stream(ct_destination, aad) as es: self.assertLen(plaintext, es.write(plaintext)) ct_source = io.BytesIO(ct_destination.value_after_close()) with saead_primitive.new_decrypting_stream(ct_source, aad) as ds: _ = ds.read() self.assertEqual(ds.read(100), b'')
def test_round_trip_encrypt_textiowrapper(self): """Encrypt with TextIOWrapper, then decrypt direct bytes.""" primitive = self.get_primitive() f = bytes_io.BytesIOWithValueAfterClose() original_plaintext = b'''some data on multiple lines.'''.decode('utf-8') with primitive.new_encrypting_stream(f, B_TEST_AAD_) as es: with io.TextIOWrapper(es) as wrapper: wrapper.write(original_plaintext) with io.BytesIO(f.value_after_close()) as f2: with primitive.new_decrypting_stream(f2, B_TEST_AAD_) as ds: data = ds.read().decode('utf-8') self.assertEqual(data, original_plaintext)
def test_round_trip_decrypt_textiowrapper(self): """Write bytes to EncryptingStream, then decrypt through TextIOWrapper.""" primitive = self.get_primitive() f = bytes_io.BytesIOWithValueAfterClose() original_plaintext = '''some data on multiple lines.''' with primitive.new_encrypting_stream(f, B_TEST_AAD_) as es: es.write(original_plaintext.encode('utf-8')) with io.BytesIO(f.value_after_close()) as f2: with primitive.new_decrypting_stream(f2, B_TEST_AAD_) as ds: with io.TextIOWrapper(ds) as wrapper: data = wrapper.read() self.assertEqual(data, original_plaintext)
def Encrypt( self, request: testing_api_pb2.StreamingAeadEncryptRequest, context: grpc.ServicerContext ) -> testing_api_pb2.StreamingAeadEncryptResponse: """Encrypts a message.""" try: keyset_handle = cleartext_keyset_handle.read( tink.BinaryKeysetReader(request.keyset)) p = keyset_handle.primitive(streaming_aead.StreamingAead) ciphertext_destination = bytes_io.BytesIOWithValueAfterClose() with p.new_encrypting_stream(ciphertext_destination, request.associated_data) as plaintext_stream: plaintext_stream.write(request.plaintext) return testing_api_pb2.StreamingAeadEncryptResponse( ciphertext=ciphertext_destination.value_after_close()) except tink.TinkError as e: return testing_api_pb2.StreamingAeadEncryptResponse(err=str(e))
def test_raw_encrypt_decrypt_wrong_aad(self): raw_primitive = self.get_raw_primitive() plaintext = b'plaintext' + B_X80 aad = b'associated_data' + B_X80 # Encrypt ct_destination = bytes_io.BytesIOWithValueAfterClose() with raw_primitive.new_raw_encrypting_stream(ct_destination, aad) as es: self.assertLen(plaintext, es.write(plaintext)) self.assertNotEqual(ct_destination.value_after_close(), plaintext) # Decrypt ct_source = io.BytesIO(ct_destination.value_after_close()) with raw_primitive.new_raw_decrypting_stream( ct_source, b'bad' + aad, close_ciphertext_source=True) as ds: with self.assertRaises(core.TinkError): ds.read()
def test_fake_streaming_aead_slow_read_success(self): saead = fake_streaming_aead.FakeRawStreamingAead('Name') ciphertext_dest = bytes_io.BytesIOWithValueAfterClose() with saead.new_raw_encrypting_stream(ciphertext_dest, b'aad') as es: self.assertLen(b'plaintext', es.write(b'plaintext')) self.assertTrue(ciphertext_dest.closed) ciphertext_src = bytes_io.SlowReadableRawBytes( ciphertext_dest.value_after_close()) with saead.new_raw_decrypting_stream( cast(BinaryIO, ciphertext_src), b'aad', close_ciphertext_source=True) as ds: # explicitly test that read returns None on the first call, because # that is needed to test one execution path in the wrapper. self.assertIsNone(ds.read()) self.assertEqual(ds.read(), b'plaintext')
def test_decrypt_unknown_key_fails(self): plaintext = b'plaintext' aad = b'associated_data' unknown_keyset_handle = tink.new_keyset_handle(TEMPLATE) unknown_primitive = unknown_keyset_handle.primitive( streaming_aead.StreamingAead) unknown_ciphertext_dest = bytes_io.BytesIOWithValueAfterClose() with unknown_primitive.new_encrypting_stream(unknown_ciphertext_dest, aad) as es: es.write(plaintext) keyset_handle = tink.new_keyset_handle(TEMPLATE) primitive = keyset_handle.primitive(streaming_aead.StreamingAead) ciphertext_src = io.BytesIO( unknown_ciphertext_dest.value_after_close()) with primitive.new_decrypting_stream(ciphertext_src, aad) as ds: with self.assertRaises(tink.TinkError): _ = ds.read()
def test_raw_encrypt_decrypt_readinto(self): raw_primitive = self.get_raw_primitive() plaintext = b'plaintext' aad = b'aad' ct_destination = bytes_io.BytesIOWithValueAfterClose() with raw_primitive.new_raw_encrypting_stream(ct_destination, aad) as es: es.write(plaintext) ct_source = io.BytesIO(ct_destination.value_after_close()) with raw_primitive.new_raw_decrypting_stream( ct_source, aad, close_ciphertext_source=True) as ds: data = bytearray(b'xxxxx') n = ds.readinto(data) # writes 5 bytes into data. self.assertEqual(n, 5) self.assertEqual(data, b'plain') n = ds.readinto(data) # writes remaining 4 bytes, leave the rest self.assertEqual(n, 4) self.assertEqual(data, b'textn')
def test_encrypt_decrypt_wrong_aad(self): saead_primitive = self.key_manager_ctr.primitive( self.key_manager_ctr.new_key_data( streaming_aead.streaming_aead_key_templates. AES128_CTR_HMAC_SHA256_4KB)) plaintext = b'plaintext' + B_X80 aad = b'associated_data' + B_X80 # Encrypt ct_destination = bytes_io.BytesIOWithValueAfterClose() with saead_primitive.new_encrypting_stream(ct_destination, aad) as es: self.assertLen(plaintext, es.write(plaintext)) self.assertNotEqual(ct_destination.value_after_close(), plaintext) # Decrypt ct_source = io.BytesIO(ct_destination.value_after_close()) with saead_primitive.new_decrypting_stream(ct_source, b'bad ' + aad) as ds: with self.assertRaises(core.TinkError): ds.read()