Skip to content
Snippets Groups Projects
Commit 37afa568 authored by epuig's avatar epuig Committed by Copybara-Service
Browse files

Add CleartextKeysetHandle

PiperOrigin-RevId: 270278753
parent b8094318
No related branches found
No related tags found
No related merge requests found
......@@ -36,6 +36,7 @@ from absl import app
from absl import flags
from absl import logging
import tink
from tink.core import cleartext_keyset_handle
FLAGS = flags.FLAGS
......@@ -74,7 +75,8 @@ def main(argv):
with open(keyset_filename, 'rb') as keyset_file:
try:
text = keyset_file.read()
keyset = tink.KeysetHandle(tink.JsonKeysetReader(text).read())
keyset = cleartext_keyset_handle.CleartextKeysetHandle(
tink.JsonKeysetReader(text).read())
except tink.TinkError as e:
logging.error('Error reading key: %s', e)
return 1
......
......@@ -31,9 +31,9 @@ from tink.python.core import tink_error
KeyManager = key_manager.KeyManager
PrivateKeyManager = key_manager.PrivateKeyManager
new_keyset_handle = keyset_handle.generate_new
read_keyset_handle = keyset_handle.read
KeysetHandle = keyset_handle.KeysetHandle
new_keyset_handle = KeysetHandle.generate_new
read_keyset_handle = KeysetHandle.read
KeysetReader = keyset_reader.KeysetReader
JsonKeysetReader = keyset_reader.JsonKeysetReader
......
# Copyright 2019 Google LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""CleartextKeysetHandle module.
WARNING
Reading or writing cleartext keysets is a bad practice, usage of this API
should be restricted. Users can read encrypted keysets using KeysetHandle.read.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import google_type_annotations
from __future__ import print_function
from tink.proto import tink_pb2
from tink.python.core import keyset_handle
from tink.python.core import keyset_reader as reader
from tink.python.core import keyset_writer as writer
class CleartextKeysetHandle(keyset_handle.KeysetHandle):
"""CleartextKeysetHandle creates KeysetHandle from a Tink Keyset."""
def __new__(cls, keyset: tink_pb2.Keyset):
return cls._create(keyset)
@classmethod
def read(cls,
keyset_reader: reader.KeysetReader) -> keyset_handle.KeysetHandle:
"""Create a KeysetHandle from a keyset read with keyset_reader."""
keyset = keyset_reader.read()
return cls._create(keyset)
def write(self, keyset_writer: writer.KeysetWriter) -> None:
"""Serializes and writes the keyset."""
keyset_writer.write(self._keyset)
# Copyright 2019 Google LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for tink.python.core.cleartext_keyset_handle."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import io
from absl.testing import absltest
from tink.python import core
from tink.python import mac
from tink.python import tink_config
from tink.python.core import cleartext_keyset_handle
def setUpModule():
tink_config.register()
class CleartextKeysetHandleTest(absltest.TestCase):
def test_write(self):
handle = cleartext_keyset_handle.CleartextKeysetHandle.generate_new(
mac.mac_key_templates.HMAC_SHA256_128BITTAG)
output_stream = io.BytesIO()
writer = core.BinaryKeysetWriter(output_stream)
handle.write(writer)
reader = core.BinaryKeysetReader(output_stream.getvalue())
handle2 = cleartext_keyset_handle.CleartextKeysetHandle.read(reader)
# Check that handle2 has the same primitive as handle.
handle2.primitive(mac.Mac).verify_mac(
handle.primitive(mac.Mac).compute_mac(b'data'), b'data')
def test_read_empty_keyset_fails(self):
with self.assertRaisesRegex(core.TinkError, 'No keyset found'):
cleartext_keyset_handle.CleartextKeysetHandle.read(
core.BinaryKeysetReader(b''))
if __name__ == '__main__':
absltest.main()
......@@ -11,7 +11,6 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This module defines KeysetHandle."""
from __future__ import absolute_import
......@@ -45,9 +44,50 @@ class KeysetHandle(object):
keysets.
"""
def __new__(cls):
raise tink_error.TinkError(
('KeysetHandle cannot be instantiated directly.'))
def __init__(self, keyset: tink_pb2.Keyset):
self._keyset = keyset
@classmethod
def generate_new(cls, key_template: tink_pb2.KeyTemplate) -> 'KeysetHandle':
"""Return a new KeysetHandle.
It contains a single fresh key generated according to key_template.
Args:
key_template: A tink_pb2.KeyTemplate object.
Returns:
A new KeysetHandle.
"""
keyset = tink_pb2.Keyset()
key_data = registry.Registry.new_key_data(key_template)
key_id = _generate_unused_key_id(keyset)
key = keyset.key.add()
key.key_data.CopyFrom(key_data)
key.status = tink_pb2.ENABLED
key.key_id = key_id
key.output_prefix_type = key_template.output_prefix_type
keyset.primary_key_id = key_id
return cls._create(keyset)
@classmethod
def read(cls, keyset_reader: reader.KeysetReader,
master_key_aead: aead.Aead) -> 'KeysetHandle':
"""Tries to create a KeysetHandle from an encrypted keyset."""
encrypted_keyset = keyset_reader.read_encrypted()
_assert_enough_encrypted_key_material(encrypted_keyset)
return cls._create(_decrypt(encrypted_keyset, master_key_aead))
@classmethod
def _create(cls, keyset: tink_pb2.Keyset):
o = object.__new__(cls)
o.__init__(keyset)
return o
def keyset_info(self) -> tink_pb2.KeysetInfo:
"""Returns the KeysetInfo that doesn't contain actual key material."""
return _keyset_info(self._keyset)
......@@ -68,7 +108,7 @@ class KeysetHandle(object):
registry.Registry.public_key_data(key.key_data))
_validate_key(public_key)
public_keyset.primary_key_id = self._keyset.primary_key_id
return KeysetHandle(public_keyset)
return self._create(public_keyset)
def primitive(self, primitive_class: Type[P]) -> P:
"""Returns a wrapped primitive from this KeysetHandle.
......@@ -98,37 +138,6 @@ class KeysetHandle(object):
return registry.Registry.wrap(pset)
def generate_new(key_template: tink_pb2.KeyTemplate) -> KeysetHandle:
"""Return a new KeysetHandle.
It contains a single fresh key generated according to key_template.
Args:
key_template: A tink_pb2.KeyTemplate object.
Returns:
A new KeysetHandle.
"""
keyset = tink_pb2.Keyset()
key_data = registry.Registry.new_key_data(key_template)
key_id = _generate_unused_key_id(keyset)
key = keyset.key.add()
key.key_data.CopyFrom(key_data)
key.status = tink_pb2.ENABLED
key.key_id = key_id
key.output_prefix_type = key_template.output_prefix_type
keyset.primary_key_id = key_id
return KeysetHandle(keyset)
def read(keyset_reader: reader.KeysetReader,
master_key_aead: aead.Aead) -> KeysetHandle:
"""Tries to create a KeysetHandle from an encrypted keyset."""
encrypted_keyset = keyset_reader.read_encrypted()
_assert_enough_encrypted_key_material(encrypted_keyset)
return KeysetHandle(_decrypt(encrypted_keyset, master_key_aead))
def _keyset_info(keyset: tink_pb2.Keyset) -> tink_pb2.KeysetInfo:
keyset_info = tink_pb2.KeysetInfo(primary_key_id=keyset.primary_key_id)
for key in keyset.key:
......
......@@ -11,7 +11,6 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for tink.python.keyset_handle."""
from __future__ import absolute_import
......@@ -64,12 +63,21 @@ class BadAead2(aead.Aead):
def _master_key_aead():
return core.Registry.primitive(
core.Registry.new_key_data(aead.aead_key_templates.AES128_EAX),
aead.Aead)
core.Registry.new_key_data(aead.aead_key_templates.AES128_EAX), aead.Aead)
def _keyset_handle(keyset):
# CleartextKeysetHandle is encouraged but we want to avoid that dependency
# in the test
return core.KeysetHandle._create(keyset)
class KeysetHandleTest(absltest.TestCase):
def test_instantiation(self):
with self.assertRaisesRegex(core.TinkError, 'cannot be instantiated'):
core.KeysetHandle()
def test_generate_new(self):
keyset_info = core.new_keyset_handle(
mac.mac_key_templates.HMAC_SHA256_128BITTAG).keyset_info()
......@@ -90,8 +98,7 @@ class KeysetHandleTest(absltest.TestCase):
handle2.keyset_info().key_info[0].key_id)
def test_write_encrypted(self):
handle = core.new_keyset_handle(
mac.mac_key_templates.HMAC_SHA256_128BITTAG)
handle = core.new_keyset_handle(mac.mac_key_templates.HMAC_SHA256_128BITTAG)
# Encrypt the keyset with Aead.
master_key_aead = _master_key_aead()
output_stream = io.BytesIO()
......@@ -104,31 +111,27 @@ class KeysetHandleTest(absltest.TestCase):
handle.primitive(mac.Mac).compute_mac(b'data'), b'data')
def test_write_raises_error_when_encrypt_failed(self):
handle = core.new_keyset_handle(
mac.mac_key_templates.HMAC_SHA256_128BITTAG)
handle = core.new_keyset_handle(mac.mac_key_templates.HMAC_SHA256_128BITTAG)
writer = core.BinaryKeysetWriter(io.BytesIO())
with self.assertRaisesRegex(core.TinkError, 'encrypt failed'):
handle.write(writer, FaultyAead())
def test_write_raises_error_when_decrypt_not_possible(self):
handle = core.new_keyset_handle(
mac.mac_key_templates.HMAC_SHA256_128BITTAG)
handle = core.new_keyset_handle(mac.mac_key_templates.HMAC_SHA256_128BITTAG)
writer = core.BinaryKeysetWriter(io.BytesIO())
with self.assertRaisesRegex(core.TinkError,
'invalid keyset, corrupted key material'):
handle.write(writer, BadAead1())
def test_write_raises_error_when_decrypt_to_wrong_keyset(self):
handle = core.new_keyset_handle(
mac.mac_key_templates.HMAC_SHA256_128BITTAG)
handle = core.new_keyset_handle(mac.mac_key_templates.HMAC_SHA256_128BITTAG)
writer = core.BinaryKeysetWriter(io.BytesIO())
with self.assertRaisesRegex(core.TinkError, 'cannot encrypt keyset:'):
handle.write(writer, BadAead2())
def test_read_empty_keyset_fails(self):
with self.assertRaisesRegex(core.TinkError, 'No keyset found'):
core.read_keyset_handle(
core.BinaryKeysetReader(b''), _master_key_aead())
core.read_keyset_handle(core.BinaryKeysetReader(b''), _master_key_aead())
def test_public_keyset_handle(self):
private_handle = core.new_keyset_handle(
......@@ -157,7 +160,7 @@ class KeysetHandleTest(absltest.TestCase):
key.key_id = 1
key.status = tink_pb2.ENABLED
keyset.primary_key_id = 1
handle = core.KeysetHandle(keyset)
handle = _keyset_handle(keyset)
aead_primitive = handle.primitive(aead.Aead)
self.assertEqual(
aead_primitive.decrypt(
......@@ -167,7 +170,7 @@ class KeysetHandleTest(absltest.TestCase):
keyset = tink_pb2.Keyset()
keyset.key.extend([helper.fake_key(key_id=1, status=tink_pb2.DESTROYED)])
keyset.primary_key_id = 1
handle = core.KeysetHandle(keyset)
handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError, 'empty keyset'):
handle.primitive(aead.Aead)
......@@ -177,9 +180,8 @@ class KeysetHandleTest(absltest.TestCase):
key.ClearField('key_data')
keyset.key.extend([key])
keyset.primary_key_id = 123
handle = core.KeysetHandle(keyset)
with self.assertRaisesRegex(core.TinkError,
'key 123 has no key data'):
handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError, 'key 123 has no key data'):
handle.primitive(aead.Aead)
def test_primitive_fails_on_key_with_unknown_prefix(self):
......@@ -188,9 +190,8 @@ class KeysetHandleTest(absltest.TestCase):
helper.fake_key(key_id=12, output_prefix_type=tink_pb2.UNKNOWN_PREFIX)
])
keyset.primary_key_id = 12
handle = core.KeysetHandle(keyset)
with self.assertRaisesRegex(core.TinkError,
'key 12 has unknown prefix'):
handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError, 'key 12 has unknown prefix'):
handle.primitive(aead.Aead)
def test_primitive_fails_on_key_with_unknown_status(self):
......@@ -198,9 +199,8 @@ class KeysetHandleTest(absltest.TestCase):
keyset.key.extend(
[helper.fake_key(key_id=1234, status=tink_pb2.UNKNOWN_STATUS)])
keyset.primary_key_id = 1234
handle = core.KeysetHandle(keyset)
with self.assertRaisesRegex(core.TinkError,
'key 1234 has unknown status'):
handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError, 'key 1234 has unknown status'):
handle.primitive(aead.Aead)
def test_primitive_fails_on_multiple_primary_keys(self):
......@@ -209,7 +209,7 @@ class KeysetHandleTest(absltest.TestCase):
[helper.fake_key(key_id=12345),
helper.fake_key(key_id=12345)])
keyset.primary_key_id = 12345
handle = core.KeysetHandle(keyset)
handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError,
'keyset contains multiple primary keys'):
handle.primitive(aead.Aead)
......@@ -223,7 +223,7 @@ class KeysetHandleTest(absltest.TestCase):
key.key_id = 2
key.status = tink_pb2.ENABLED
keyset.primary_key_id = 1
handle = core.KeysetHandle(keyset)
handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError,
'keyset does not contain a valid primary key'):
handle.primitive(aead.Aead)
......@@ -237,13 +237,12 @@ class KeysetHandleTest(absltest.TestCase):
key.key_id = 1
key.status = tink_pb2.ENABLED
keyset.primary_key_id = 1
handle = core.KeysetHandle(keyset)
handle = _keyset_handle(keyset)
with self.assertRaisesRegex(core.TinkError, 'Wrong primitive class'):
handle.primitive(mac.Mac)
def test_primitive_wrapped_correctly(self):
keydata2 = core.Registry.new_key_data(
aead.aead_key_templates.AES128_EAX)
keydata2 = core.Registry.new_key_data(aead.aead_key_templates.AES128_EAX)
keyset = tink_pb2.Keyset()
key = keyset.key.add()
key.key_data.CopyFrom(
......@@ -257,7 +256,7 @@ class KeysetHandleTest(absltest.TestCase):
key.key_id = 2
key.status = tink_pb2.ENABLED
keyset.primary_key_id = 1
handle = core.KeysetHandle(keyset)
handle = _keyset_handle(keyset)
aead_primitive = handle.primitive(aead.Aead)
aead_primitive2 = core.Registry.primitive(keydata2, aead.Aead)
self.assertEqual(
......@@ -280,7 +279,7 @@ class KeysetHandleTest(absltest.TestCase):
status=tink_pb2.DESTROYED,
output_prefix_type=tink_pb2.RAW)
])
handle = core.KeysetHandle(keyset)
handle = _keyset_handle(keyset)
expected_keyset_info = tink_pb2.KeysetInfo(primary_key_id=2)
info1 = expected_keyset_info.key_info.add()
info1.type_url = 't1'
......
......@@ -11,7 +11,6 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""A command-line utility for testing AEAD-primitives.
It requires 5 arguments:
......@@ -34,6 +33,7 @@ from absl import flags
from absl import logging
import tink
from tink.core import cleartext_keyset_handle
FLAGS = flags.FLAGS
......@@ -43,6 +43,7 @@ def read_keyset(keyset_filename):
Args:
keyset_filename: A path to a keyset file
Returns:
A KeysetHandle of the file's keyset
Raises:
......@@ -51,7 +52,8 @@ def read_keyset(keyset_filename):
"""
with open(keyset_filename, 'rb') as keyset_file:
text = keyset_file.read()
keyset = tink.KeysetHandle(tink.BinaryKeysetReader(text).read())
keyset = cleartext_keyset_handle.CleartextKeysetHandle(
tink.BinaryKeysetReader(text).read())
return keyset
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment