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

Add python Tink signature.

PiperOrigin-RevId: 258183343
parent a2dbd909
No related branches found
No related tags found
No related merge requests found
Showing
with 1098 additions and 0 deletions
# 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.
"""Signature package."""
from __future__ import absolute_import
from __future__ import division
from __future__ import google_type_annotations
from __future__ import print_function
from tink.python.signature import public_key_sign
from tink.python.signature import public_key_sign_key_manager
from tink.python.signature import public_key_sign_wrapper
from tink.python.signature import public_key_verify
from tink.python.signature import public_key_verify_key_manager
from tink.python.signature import public_key_verify_wrapper
from tink.python.signature import signature_key_templates
PublicKeySign = public_key_sign.PublicKeySign
PublicKeyVerify = public_key_verify.PublicKeyVerify
PublicKeySignWrapper = public_key_sign_wrapper.PublicKeySignWrapper
PublicKeyVerifyWrapper = public_key_verify_wrapper.PublicKeyVerifyWrapper
# 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.
"""Interface for PublicKeySign."""
from __future__ import absolute_import
from __future__ import division
from __future__ import google_type_annotations
from __future__ import print_function
import abc
class PublicKeySign(object):
"""Interface for public key signing.
Digital Signatures provide functionality of signing data and verification of
the signatures. They are represented by a pair of primitives (interfaces)
'PublicKeySign' for signing of data, and 'PublicKeyVerify' for verification
of signatures. Implementations of these interfaces are secure against
adaptive chosen-message attacks. Signing data ensures the authenticity and
the integrity of that data, but not its secrecy.
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def sign(self, data: bytes) -> bytes:
"""Computes the signature for data.
Args:
data: bytes, the input data.
Returns:
The signature as bytes.
"""
raise NotImplementedError()
# 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.
"""Python wrapper of the CLIF-wrapped C++ Public Key Signature key manager."""
from __future__ import absolute_import
from __future__ import division
from __future__ import google_type_annotations
from __future__ import print_function
from typing import Text
from tink.cc.python import public_key_sign as cc_public_key_sign
from tink.python.cc.clif import cc_key_manager
from tink.python.core import key_manager
from tink.python.core import tink_error
from tink.python.signature import public_key_sign
class _PublicKeySignCcToPyWrapper(public_key_sign.PublicKeySign):
"""Transforms cliffed C++ PublicKeySign into a Python primitive."""
def __init__(self, cc_primitive: cc_public_key_sign.PublicKeySign):
self._public_key_sign = cc_primitive
@tink_error.use_tink_errors
def sign(self, data: bytes) -> bytes:
return self._public_key_sign.sign(data)
def from_cc_registry(
type_url: Text
) -> key_manager.PrivateKeyManager[public_key_sign.PublicKeySign]:
return key_manager.PrivateKeyManagerCcToPyWrapper(
cc_key_manager.PublicKeySignKeyManager.from_cc_registry(type_url),
public_key_sign.PublicKeySign, _PublicKeySignCcToPyWrapper)
# 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.public_key_sign_key_manager."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import unittest
from tink.proto import common_pb2
from tink.proto import ecdsa_pb2
from tink.proto import tink_pb2
from tink.python.core import tink_config
from tink.python.signature import public_key_sign
from tink.python.signature import public_key_sign_key_manager
from tink.python.signature import public_key_verify_key_manager
def setUpModule():
tink_config.register()
def new_ecdsa_key_template(hash_type, curve_type, encoding):
key_format = ecdsa_pb2.EcdsaKeyFormat()
key_format.params.hash_type = hash_type
key_format.params.curve = curve_type
key_format.params.encoding = encoding
key_template = tink_pb2.KeyTemplate()
key_template.type_url = (
'type.googleapis.com/google.crypto.tink.EcdsaPrivateKey')
key_template.value = key_format.SerializeToString()
return key_template
class PublicKeySignKeyManagerTest(googletest.TestCase):
def setUp(self):
super(PublicKeySignKeyManagerTest, self).setUp()
self.key_manager = public_key_sign_key_manager.from_cc_registry(
'type.googleapis.com/google.crypto.tink.EcdsaPrivateKey')
self.key_manager_verify = public_key_verify_key_manager.from_cc_registry(
'type.googleapis.com/google.crypto.tink.EcdsaPublicKey')
def test_primitive_class(self):
self.assertEqual(self.key_manager.primitive_class(),
public_key_sign.PublicKeySign)
def test_key_type(self):
self.assertEqual(self.key_manager.key_type(),
'type.googleapis.com/google.crypto.tink.EcdsaPrivateKey')
def test_new_key_data(self):
key_template = new_ecdsa_key_template(common_pb2.SHA256,
common_pb2.NIST_P256, ecdsa_pb2.DER)
key_data = self.key_manager.new_key_data(key_template)
self.assertEqual(key_data.type_url, self.key_manager.key_type())
key = ecdsa_pb2.EcdsaPrivateKey()
key.ParseFromString(key_data.value)
public_key = key.public_key
self.assertEqual(key.version, 0)
self.assertEqual(public_key.version, 0)
self.assertEqual(public_key.params.hash_type, common_pb2.SHA256)
self.assertEqual(public_key.params.curve, common_pb2.NIST_P256)
self.assertEqual(public_key.params.encoding, ecdsa_pb2.DER)
self.assertLen(key.key_value, 32)
def test_signature_success(self):
priv_key = self.key_manager.new_key_data(
new_ecdsa_key_template(common_pb2.SHA256, common_pb2.NIST_P256,
ecdsa_pb2.DER))
pub_key = self.key_manager.public_key_data(priv_key)
verifier = self.key_manager_verify.primitive(pub_key)
signer = self.key_manager.primitive(priv_key)
data = b'data'
signature = signer.sign(data)
# Starts with a DER sequence
self.assertEqual(bytearray(signature)[0], 0x30)
verifier.verify(signature, data)
if __name__ == '__main__':
googletest.main()
# 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.
"""Public Key Sign wrapper."""
from __future__ import absolute_import
from __future__ import division
from __future__ import google_type_annotations
from __future__ import print_function
from typing import Type
from tink.proto import tink_pb2
from tink.python.core import crypto_format
from tink.python.core import primitive_set
from tink.python.core import primitive_wrapper
from tink.python.core import tink_error
from tink.python.signature import public_key_sign
class _WrappedPublicKeySign(public_key_sign.PublicKeySign):
"""Implements PublicKeySign for a set of PublicKeySign primitives."""
def __init__(self, primitives_set: primitive_set.PrimitiveSet):
self._primitive_set = primitives_set
def sign(self, data: bytes) -> bytes:
"""Computes the signature for data using the primary primitive.
Args:
data: The input data.
Returns:
The signature.
"""
primary = self._primitive_set.primary()
if not primary:
raise tink_error.TinkError('primary primitive not set')
sign_data = data
if primary.output_prefix_type == tink_pb2.LEGACY:
sign_data = sign_data + crypto_format.LEGACY_START_BYTE
return primary.identifier + primary.primitive.sign(sign_data)
class PublicKeySignWrapper(
primitive_wrapper.PrimitiveWrapper[public_key_sign.PublicKeySign]):
"""A PrimitiveWrapper for the PublicKeySign primitive.
The returned primitive works with a keyset (rather than a single key). To sign
a message, it uses the primary key in the keyset, and prepends to the
signature a certain prefix associated with the primary key.
"""
def wrap(self, primitives_set: primitive_set.PrimitiveSet
) -> _WrappedPublicKeySign:
return _WrappedPublicKeySign(primitives_set)
def primitive_class(self) -> Type[public_key_sign.PublicKeySign]:
return public_key_sign.PublicKeySign
# 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.public_key_sign_wrapper."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import unittest
from google3.testing.pybase import parameterized
from tink.proto import tink_pb2
from tink.python.core import primitive_set
from tink.python.core import tink_error
from tink.python.signature import public_key_sign
from tink.python.signature import public_key_sign_wrapper
from tink.python.signature import public_key_verify
from tink.python.signature import public_key_verify_wrapper
from tink.python.testing import helper
def new_primitive_key_pair(key_id, output_prefix_type):
fake_key = helper.fake_key(
key_id=key_id,
key_material_type=tink_pb2.KeyData.ASYMMETRIC_PRIVATE,
output_prefix_type=output_prefix_type)
fake_sign = helper.FakePublicKeySign('fakePublicKeySign {}'.format(key_id))
return fake_sign, fake_key,
def to_verify_key_pair(key):
fake_verify = helper.FakePublicKeyVerify('fakePublicKeySign {}'.format(
key.key_id))
return fake_verify, key,
class PublicKeySignWrapperTest(parameterized.TestCase):
@parameterized.named_parameters(('tink', tink_pb2.TINK),
('legacy', tink_pb2.LEGACY))
def test_signature(self, output_prefix_type):
pair0 = new_primitive_key_pair(1234, output_prefix_type)
pair1 = new_primitive_key_pair(5678, output_prefix_type)
pset = primitive_set.new_primitive_set(public_key_sign.PublicKeySign)
pset_verify = primitive_set.new_primitive_set(
public_key_verify.PublicKeyVerify)
pset.add_primitive(*pair0)
pset.set_primary(pset.add_primitive(*pair1))
pset_verify.add_primitive(*to_verify_key_pair(pair0[1]))
entry = pset_verify.add_primitive(*to_verify_key_pair(pair1[1]))
pset_verify.set_primary(entry)
wrapped_pk_sign = public_key_sign_wrapper.PublicKeySignWrapper().wrap(pset)
wrapped_pk_verify = public_key_verify_wrapper.PublicKeyVerifyWrapper().wrap(
pset_verify)
signature = wrapped_pk_sign.sign(b'data')
wrapped_pk_verify.verify(signature, b'data')
with self.assertRaisesRegex(tink_error.TinkError, 'invalid signature'):
wrapped_pk_verify.verify(signature, b'invalid')
if __name__ == '__main__':
googletest.main()
# 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.
"""Interface for PublicKeyVerify."""
from __future__ import absolute_import
from __future__ import division
from __future__ import google_type_annotations
from __future__ import print_function
import abc
class PublicKeyVerify(object):
"""Interface for public key verifying.
Digital Signatures provide functionality of signing data and verification of
the signatures. They are represented by a pair of primitives (interfaces)
'PublicKeySign' for signing of data, and 'PublicKeyVerify' for verification
of signatures. Implementations of these interfaces are secure against
adaptive chosen-message attacks. Signing data ensures the authenticity and
the integrity of that data, but not its secrecy.
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def verify(self, signature: bytes, data: bytes) -> bytes:
"""Verifies that signature is a digital signature for data.
Args:
signature: The signature bytes to be checked.
data: The data bytes to be checked.
Raises:
google3.third_party.tink.python.tink_error.TinkError if the verification
fails.
"""
raise NotImplementedError()
# 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.
"""Python wrapper of the CLIF-wrapped C++ Public Key Verify key manager."""
from __future__ import absolute_import
from __future__ import division
from __future__ import google_type_annotations
from __future__ import print_function
from typing import Text
from tink.cc.python import public_key_verify as cc_public_key_verify
from tink.python.cc.clif import cc_key_manager
from tink.python.core import key_manager
from tink.python.core import tink_error
from tink.python.signature import public_key_verify
class _PublicKeyVerifyCcToPyWrapper(public_key_verify.PublicKeyVerify):
"""Transforms cliffed C++ PublicKeyVerify into a Python primitive."""
def __init__(self, cc_primitive: cc_public_key_verify.PublicKeyVerify):
self._public_key_verify = cc_primitive
@tink_error.use_tink_errors
def verify(self, signature: bytes, data: bytes) -> None:
self._public_key_verify.verify(signature, data)
def from_cc_registry(
type_url: Text
) -> key_manager.KeyManager[public_key_verify.PublicKeyVerify]:
return key_manager.KeyManagerCcToPyWrapper(
cc_key_manager.PublicKeyVerifyKeyManager.from_cc_registry(type_url),
public_key_verify.PublicKeyVerify, _PublicKeyVerifyCcToPyWrapper)
# 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.public_key_verify_key_manager."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import unittest
from tink.proto import common_pb2
from tink.proto import ecdsa_pb2
from tink.proto import tink_pb2
from tink.python.core import tink_config
from tink.python.core import tink_error
from tink.python.signature import public_key_sign_key_manager
from tink.python.signature import public_key_verify_key_manager
def setUpModule():
tink_config.register()
def new_ecdsa_key_template(hash_type, curve_type, encoding, public=True):
params = ecdsa_pb2.EcdsaParams(
hash_type=hash_type, curve=curve_type, encoding=encoding)
key_format = ecdsa_pb2.EcdsaKeyFormat(params=params)
key_template = tink_pb2.KeyTemplate()
if public:
append = 'EcdsaPublicKey'
else:
append = 'EcdsaPrivateKey'
key_template.type_url = 'type.googleapis.com/google.crypto.tink.' + append
key_template.value = key_format.SerializeToString()
return key_template
class PublicKeyVerifyKeyManagerTest(googletest.TestCase):
def setUp(self):
super(PublicKeyVerifyKeyManagerTest, self).setUp()
self.key_manager = public_key_verify_key_manager.from_cc_registry(
'type.googleapis.com/google.crypto.tink.EcdsaPublicKey')
self.key_manager_sign = public_key_sign_key_manager.from_cc_registry(
'type.googleapis.com/google.crypto.tink.EcdsaPrivateKey')
def test_key_type(self):
self.assertEqual(self.key_manager.key_type(),
'type.googleapis.com/google.crypto.tink.EcdsaPublicKey')
def test_new_key_data(self):
key_template = new_ecdsa_key_template(
common_pb2.SHA256, common_pb2.NIST_P256, ecdsa_pb2.DER, True)
with self.assertRaisesRegex(tink_error.TinkError,
'Operation not supported'):
self.key_manager.new_key_data(key_template)
def test_verify_success(self):
key_template = new_ecdsa_key_template(
common_pb2.SHA256, common_pb2.NIST_P256, ecdsa_pb2.DER, False)
priv_key = self.key_manager_sign.new_key_data(key_template)
pub_key = self.key_manager_sign.public_key_data(priv_key)
signer = self.key_manager_sign.primitive(priv_key)
verifier = self.key_manager.primitive(pub_key)
data = b'data'
signature = signer.sign(data)
verifier.verify(signature, data)
def test_verify_wrong(self):
key_template = new_ecdsa_key_template(
common_pb2.SHA256, common_pb2.NIST_P256, ecdsa_pb2.DER, False)
priv_key = self.key_manager_sign.new_key_data(key_template)
pub_key = self.key_manager_sign.public_key_data(priv_key)
signer = self.key_manager_sign.primitive(priv_key)
verifier = self.key_manager.primitive(pub_key)
data = b'data'
signature = signer.sign(data)
with self.assertRaisesRegex(tink_error.TinkError, 'Signature is not valid'):
verifier.verify(signature, 'wrongdata')
with self.assertRaisesRegex(tink_error.TinkError, 'Signature is not valid'):
verifier.verify('wrongsignature', data)
if __name__ == '__main__':
googletest.main()
# 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.
"""Public Key Verify wrapper."""
from __future__ import absolute_import
from __future__ import division
from __future__ import google_type_annotations
from __future__ import print_function
import logging
from typing import Type
from tink.proto import tink_pb2
from tink.python.core import crypto_format
from tink.python.core import primitive_set
from tink.python.core import primitive_wrapper
from tink.python.core import tink_error
from tink.python.signature import public_key_verify
class _WrappedPublicKeyVerify(public_key_verify.PublicKeyVerify):
"""Implements PublicKeyVerify for a set of PublicKeyVerify primitives."""
def __init__(self, primitives_set: primitive_set.PrimitiveSet):
self._primitive_set = primitives_set
def verify(self, signature: bytes, data: bytes):
"""Verifies that signature is a digital signature for data.
Args:
signature: The signature bytes to be checked.
data: The data bytes to be checked.
Raises:
tink_error.TinkError if the verification fails.
"""
if len(signature) <= crypto_format.NON_RAW_PREFIX_SIZE:
# This also rejects raw signatures with size of 4 bytes or fewer.
# We're not aware of any schemes that output signatures that small.
raise tink_error.TinkError('signature too short')
key_id = signature[:crypto_format.NON_RAW_PREFIX_SIZE]
raw_sig = signature[crypto_format.NON_RAW_PREFIX_SIZE:]
for entry in self._primitive_set.primitive_from_identifier(key_id):
try:
if entry.output_prefix_type == tink_pb2.LEGACY:
entry.primitive.verify(raw_sig,
data + crypto_format.LEGACY_START_BYTE)
else:
entry.primitive.verify(raw_sig, data)
# Signature is valid, we can return
return
except tink_error.TinkError as err:
logging.info('signature prefix matches a key, but cannot verify: %s',
err)
# No matching key succeeded with verification, try all RAW keys
for entry in self._primitive_set.raw_primitives():
try:
entry.primitive.verify(signature, data)
# Signature is valid, we can return
return
except tink_error.TinkError:
pass
raise tink_error.TinkError('invalid signature')
class PublicKeyVerifyWrapper(
primitive_wrapper.PrimitiveWrapper[public_key_verify.PublicKeyVerify]):
"""WrappedPublicKeyVerify is the PrimitiveWrapper for PublicKeyVerify.
The returned primitive works with a keyset (rather than a single key). To sign
a message, it uses the primary key in the keyset, and prepends to the
signature a certain prefix associated with the primary key.
The returned primitive works with a keyset (rather than a single key). To
verify a signature, the primitive uses the prefix of the signature to
efficiently select the right key in the set. If there is no key associated
with the prefix or if the keys associated with the prefix do not work, the
primitive tries all keys with tink_pb2.OutputPrefixType = tink_pb2.RAW.
"""
def wrap(self, primitives_set: primitive_set.PrimitiveSet
) -> _WrappedPublicKeyVerify:
return _WrappedPublicKeyVerify(primitives_set)
def primitive_class(self) -> Type[public_key_verify.PublicKeyVerify]:
return public_key_verify.PublicKeyVerify
# 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.public_key_verify_wrapper."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import unittest
from tink.proto import tink_pb2
from tink.python.core import primitive_set
from tink.python.signature import public_key_sign
from tink.python.signature import public_key_sign_wrapper
from tink.python.signature import public_key_verify
from tink.python.signature import public_key_verify_wrapper
from tink.python.testing import helper
def new_primitive_key_pair(key_id, output_prefix_type):
fake_key = helper.fake_key(
key_id=key_id,
key_material_type=tink_pb2.KeyData.ASYMMETRIC_PRIVATE,
output_prefix_type=output_prefix_type)
fake_sign = helper.FakePublicKeyVerify('fakePublicKeySign {}'.format(key_id))
return fake_sign, fake_key,
class PublicKeyVerifyWrapperTest(googletest.TestCase):
def test_verify_signature(self):
pair0 = new_primitive_key_pair(1234, tink_pb2.RAW)
pair1 = new_primitive_key_pair(5678, tink_pb2.TINK)
pair2 = new_primitive_key_pair(9012, tink_pb2.LEGACY)
pset = primitive_set.new_primitive_set(public_key_verify.PublicKeyVerify)
pset.add_primitive(*pair0)
pset.add_primitive(*pair1)
pset.set_primary(pset.add_primitive(*pair2))
# Check all keys work
for unused_primitive, key in (pair0, pair1, pair2):
pset_sign = primitive_set.new_primitive_set(public_key_sign.PublicKeySign)
pset_sign.set_primary(
pset_sign.add_primitive(
helper.FakePublicKeySign('fakePublicKeySign {}'.format(
key.key_id)), key))
wrapped_pk_verify = public_key_verify_wrapper.PublicKeyVerifyWrapper(
).wrap(pset)
wrapped_pk_sign = public_key_sign_wrapper.PublicKeySignWrapper().wrap(
pset_sign)
wrapped_pk_verify.verify(wrapped_pk_sign.sign(b'data'), b'data')
if __name__ == '__main__':
googletest.main()
# 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.
"""Pre-generated KeyTemplate for PublicKeySign and PublicKeyVerify.
One can use these templates to generate new tink_pb2.Keyset with
tink_pb2.KeysetHandle. To generate a new keyset that contains a single
EcdsaPrivateKey, one can do:
handle = keyset_handle.KeysetHandle(signature_key_templates.ECDSA_P256);
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import google_type_annotations
from __future__ import print_function
from tink.proto import common_pb2
from tink.proto import ecdsa_pb2
from tink.proto import rsa_ssa_pkcs1_pb2
from tink.proto import rsa_ssa_pss_pb2
from tink.proto import tink_pb2
_prefix = 'type.googleapis.com/google.crypto.tink.'
_ECDSA_KEY_TYPE_URL = _prefix + 'EcdsaPrivateKey'
_ED25519_KEY_TYPE_URL = _prefix + 'Ed25519PrivateKey'
_RSA_PKCS1_KEY_TYPE_URL = _prefix + 'RsaSsaPkcs1PrivateKey'
_RSA_PSS_KEY_TYPE_URL = _prefix + 'RsaSsaPssPrivateKey'
_RSA_F4 = 65537
def _num_to_bytes(n: int) -> bytes:
"""Converts a number to bytes."""
if n < 0:
raise OverflowError("number can't be negative")
if n == 0:
return b'\x00'
octets = bytearray()
while n:
octets.append(n % 256)
n //= 256
return bytes(octets[::-1])
def create_ecdsa_key_template(hash_type: common_pb2.HashType,
curve: common_pb2.EllipticCurveType,
encoding: ecdsa_pb2.EcdsaSignatureEncoding
) -> tink_pb2.KeyTemplate:
"""Creates a KeyTemplate containing an EcdsaKeyFormat."""
params = ecdsa_pb2.EcdsaParams(
hash_type=hash_type, curve=curve, encoding=encoding)
key_format = ecdsa_pb2.EcdsaKeyFormat(params=params)
key_template = tink_pb2.KeyTemplate(
value=key_format.SerializeToString(),
type_url=_ECDSA_KEY_TYPE_URL,
output_prefix_type=tink_pb2.TINK)
return key_template
def create_rsa_ssa_pkcs1_key_template(hash_type: common_pb2.HashType,
modulus_size: int, public_exponent: int
) -> tink_pb2.KeyTemplate:
"""Creates a KeyTemplate containing an RsaSsaPkcs1KeyFormat."""
params = rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(hash_type=hash_type)
key_format = rsa_ssa_pkcs1_pb2.RsaSsaPkcs1KeyFormat(
params=params,
modulus_size_in_bits=modulus_size,
public_exponent=_num_to_bytes(public_exponent))
key_template = tink_pb2.KeyTemplate(
value=key_format.SerializeToString(),
type_url=_RSA_PKCS1_KEY_TYPE_URL,
output_prefix_type=tink_pb2.TINK)
return key_template
def create_rsa_ssa_pss_key_template(sig_hash: common_pb2.HashType,
mgf1_hash: common_pb2.HashType,
salt_length: int, modulus_size: int,
public_exponent: int
) -> tink_pb2.KeyTemplate:
"""Creates a KeyTemplate containing an RsaSsaPssKeyFormat."""
params = rsa_ssa_pss_pb2.RsaSsaPssParams(
sig_hash=sig_hash, mgf1_hash=mgf1_hash, salt_length=salt_length)
key_format = rsa_ssa_pss_pb2.RsaSsaPssKeyFormat(
params=params,
modulus_size_in_bits=modulus_size,
public_exponent=_num_to_bytes(public_exponent))
key_template = tink_pb2.KeyTemplate(
value=key_format.SerializeToString(),
type_url=_RSA_PSS_KEY_TYPE_URL,
output_prefix_type=tink_pb2.TINK)
return key_template
ECDSA_P256 = create_ecdsa_key_template(common_pb2.SHA256, common_pb2.NIST_P256,
ecdsa_pb2.DER)
ECDSA_P384 = create_ecdsa_key_template(common_pb2.SHA512, common_pb2.NIST_P384,
ecdsa_pb2.DER)
ECDSA_P521 = create_ecdsa_key_template(common_pb2.SHA512, common_pb2.NIST_P521,
ecdsa_pb2.DER)
ECDSA_P256_IEEE_P1363 = create_ecdsa_key_template(common_pb2.SHA256,
common_pb2.NIST_P256,
ecdsa_pb2.IEEE_P1363)
ECDSA_P384_IEEE_P1363 = create_ecdsa_key_template(common_pb2.SHA512,
common_pb2.NIST_P384,
ecdsa_pb2.IEEE_P1363)
ECDSA_P521_IEEE_P1363 = create_ecdsa_key_template(common_pb2.SHA512,
common_pb2.NIST_P521,
ecdsa_pb2.IEEE_P1363)
ED25519 = tink_pb2.KeyTemplate(
type_url=_ED25519_KEY_TYPE_URL, output_prefix_type=tink_pb2.TINK)
RSA_SSA_PKCS1_3072_SHA256_F4 = create_rsa_ssa_pkcs1_key_template(
common_pb2.SHA256, 3072, _RSA_F4)
RSA_SSA_PKCS1_4096_SHA512_F4 = create_rsa_ssa_pkcs1_key_template(
common_pb2.SHA512, 4096, _RSA_F4)
RSA_SSA_PSS_3072_SHA256_SHA256_32_F4 = create_rsa_ssa_pss_key_template(
common_pb2.SHA256, common_pb2.SHA256, 32, 3072, _RSA_F4)
RSA_SSA_PSS_4096_SHA512_SHA512_64_F4 = create_rsa_ssa_pss_key_template(
common_pb2.SHA512, common_pb2.SHA512, 64, 4096, _RSA_F4)
# 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.signature_key_templates."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import unittest
from google3.testing.pybase import parameterized
from tink.proto import common_pb2
from tink.proto import ecdsa_pb2
from tink.proto import rsa_ssa_pkcs1_pb2
from tink.proto import rsa_ssa_pss_pb2
from tink.proto import tink_pb2
from tink.python.core import tink_config
from tink.python.signature import public_key_sign_key_manager
from tink.python.signature import signature_key_templates
ECDSA_DER_PARAMS_P256 = [
signature_key_templates.ECDSA_P256, common_pb2.SHA256, common_pb2.NIST_P256
]
ECDSA_DER_PARAMS_P384 = [
signature_key_templates.ECDSA_P384, common_pb2.SHA512, common_pb2.NIST_P384
]
ECDSA_DER_PARAMS_P521 = [
signature_key_templates.ECDSA_P521, common_pb2.SHA512, common_pb2.NIST_P521
]
ECDSA_IEEE_PARAMS_P256 = [
signature_key_templates.ECDSA_P256_IEEE_P1363, common_pb2.SHA256,
common_pb2.NIST_P256
]
ECDSA_IEEE_PARAMS_P384 = [
signature_key_templates.ECDSA_P384_IEEE_P1363, common_pb2.SHA512,
common_pb2.NIST_P384
]
ECDSA_IEEE_PARAMS_P521 = [
signature_key_templates.ECDSA_P521_IEEE_P1363, common_pb2.SHA512,
common_pb2.NIST_P521
]
RSA_PKCS1_PARAMS_3072 = [
signature_key_templates.RSA_SSA_PKCS1_3072_SHA256_F4, common_pb2.SHA256,
3072, 65537
]
RSA_PKCS1_PARAMS_4096 = [
signature_key_templates.RSA_SSA_PKCS1_4096_SHA512_F4, common_pb2.SHA512,
4096, 65537
]
RSA_PSS_PARAMS_3072 = [
signature_key_templates.RSA_SSA_PSS_3072_SHA256_SHA256_32_F4,
common_pb2.SHA256, 3072, 65537
]
RSA_PSS_PARAMS_4096 = [
signature_key_templates.RSA_SSA_PSS_4096_SHA512_SHA512_64_F4,
common_pb2.SHA512, 4096, 65537
]
def bytes_to_num(data):
res = 0
for b in bytearray(data):
res <<= 8
res |= b
return res
def setUpModule():
tink_config.register()
class SignatureKeyTemplatesTest(parameterized.TestCase):
def test_bytes_to_num(self):
for i in range(100000):
res = bytes_to_num(signature_key_templates._num_to_bytes(i))
self.assertEqual(res, i)
@parameterized.named_parameters(('0', 0, b'\x00'), ('256', 256, b'\x01\x00'),
('65537', 65537, b'\x01\x00\x01'))
def test_num_to_bytes(self, number, expected):
self.assertEqual(signature_key_templates._num_to_bytes(number), expected)
with self.assertRaises(OverflowError):
signature_key_templates._num_to_bytes(-1)
@parameterized.named_parameters(
['ecdsa_p256'] + ECDSA_DER_PARAMS_P256,
['ecdsa_p384'] + ECDSA_DER_PARAMS_P384,
['ecdsa_p521'] + ECDSA_DER_PARAMS_P521,
)
def test_ecdsa_der(self, key_template, hash_type, curve):
self.assertEqual(key_template.type_url,
'type.googleapis.com/google.crypto.tink.EcdsaPrivateKey')
self.assertEqual(key_template.output_prefix_type, tink_pb2.TINK)
key_format = ecdsa_pb2.EcdsaKeyFormat()
key_format.ParseFromString(key_template.value)
self.assertEqual(key_format.params.hash_type, hash_type)
self.assertEqual(key_format.params.curve, curve)
self.assertEqual(key_format.params.encoding, ecdsa_pb2.DER)
# Check that the template works with the key manager
key_manager = public_key_sign_key_manager.from_cc_registry(
key_template.type_url)
key_manager.new_key_data(key_template)
@parameterized.named_parameters(
['ecdsa_p256'] + ECDSA_IEEE_PARAMS_P256,
['ecdsa_p384'] + ECDSA_IEEE_PARAMS_P384,
['ecdsa_p521'] + ECDSA_IEEE_PARAMS_P521,
)
def test_ecdsa_ieee(self, key_template, hash_type, curve):
self.assertEqual(key_template.type_url,
'type.googleapis.com/google.crypto.tink.EcdsaPrivateKey')
self.assertEqual(key_template.output_prefix_type, tink_pb2.TINK)
key_format = ecdsa_pb2.EcdsaKeyFormat()
key_format.ParseFromString(key_template.value)
self.assertEqual(key_format.params.hash_type, hash_type)
self.assertEqual(key_format.params.curve, curve)
self.assertEqual(key_format.params.encoding, ecdsa_pb2.IEEE_P1363)
# Check that the template works with the key manager
key_manager = public_key_sign_key_manager.from_cc_registry(
key_template.type_url)
key_manager.new_key_data(key_template)
def test_ed25519(self):
key_template = signature_key_templates.ED25519
self.assertEqual(
key_template.type_url,
'type.googleapis.com/google.crypto.tink.Ed25519PrivateKey')
self.assertEqual(key_template.output_prefix_type, tink_pb2.TINK)
# Check that the template works with the key manager
key_manager = public_key_sign_key_manager.from_cc_registry(
key_template.type_url)
key_manager.new_key_data(key_template)
@parameterized.named_parameters(
['rsa_pkcs1_3072'] + RSA_PKCS1_PARAMS_3072,
['rsa_pkcs1_4096'] + RSA_PKCS1_PARAMS_4096,
)
def test_rsa_pkcs1(self, key_template, hash_algo, modulus_size, exponent):
self.assertEqual(
key_template.type_url,
'type.googleapis.com/google.crypto.tink.RsaSsaPkcs1PrivateKey')
self.assertEqual(key_template.output_prefix_type, tink_pb2.TINK)
key_format = rsa_ssa_pkcs1_pb2.RsaSsaPkcs1KeyFormat()
key_format.ParseFromString(key_template.value)
self.assertEqual(key_format.modulus_size_in_bits, modulus_size)
self.assertEqual(key_format.params.hash_type, hash_algo)
self.assertEqual(bytes_to_num(key_format.public_exponent), exponent)
# Check that the template works with the key manager
key_manager = public_key_sign_key_manager.from_cc_registry(
key_template.type_url)
key_manager.new_key_data(key_template)
@parameterized.named_parameters(
['rsa_pss_3072'] + RSA_PSS_PARAMS_3072,
['rsa_pss_4096'] + RSA_PSS_PARAMS_4096,
)
def test_rsa_pss(self, key_template, hash_algo, modulus_size, exponent):
self.assertEqual(
key_template.type_url,
'type.googleapis.com/google.crypto.tink.RsaSsaPssPrivateKey')
self.assertEqual(key_template.output_prefix_type, tink_pb2.TINK)
key_format = rsa_ssa_pss_pb2.RsaSsaPssKeyFormat()
key_format.ParseFromString(key_template.value)
self.assertEqual(key_format.modulus_size_in_bits, modulus_size)
self.assertEqual(key_format.params.sig_hash, hash_algo)
self.assertEqual(key_format.params.mgf1_hash, hash_algo)
self.assertEqual(bytes_to_num(key_format.public_exponent), exponent)
# Check that the template works with the key manager
key_manager = public_key_sign_key_manager.from_cc_registry(
key_template.type_url)
key_manager.new_key_data(key_template)
if __name__ == '__main__':
googletest.main()
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