1# Copyright 2019 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Tests for tink.python.tink.hybrid_key_manager.""" 16 17from typing import cast 18from absl.testing import absltest 19from absl.testing import parameterized 20from tink.proto import common_pb2 21from tink.proto import ecies_aead_hkdf_pb2 22from tink.proto import hpke_pb2 23from tink.proto import tink_pb2 24import tink 25from tink import aead 26from tink import core 27from tink import hybrid 28 29 30def setUpModule(): 31 hybrid.register() 32 33 34class HybridKeyManagerTest(parameterized.TestCase): 35 36 def test_new_key_data(self): 37 tmpl = hybrid.hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM 38 key_manager = core.Registry.key_manager(tmpl.type_url) 39 key_data = key_manager.new_key_data(tmpl) 40 self.assertEqual(key_data.type_url, key_manager.key_type()) 41 self.assertEqual(key_data.key_material_type, 42 tink_pb2.KeyData.ASYMMETRIC_PRIVATE) 43 key = ecies_aead_hkdf_pb2.EciesAeadHkdfPrivateKey.FromString(key_data.value) 44 self.assertLen(key.key_value, 32) 45 self.assertEqual(key.public_key.params.kem_params.curve_type, 46 common_pb2.NIST_P256) 47 48 def test_new_keyset_handle_invalid_params_throw_exception(self): 49 templates = hybrid.hybrid_key_templates 50 key_template = templates.create_ecies_aead_hkdf_key_template( 51 curve_type=cast(common_pb2.EllipticCurveType, 100), 52 ec_point_format=common_pb2.UNCOMPRESSED, 53 hash_type=common_pb2.SHA256, 54 dem_key_template=aead.aead_key_templates.AES128_GCM) 55 with self.assertRaises(core.TinkError): 56 tink.new_keyset_handle(key_template) 57 58 def test_new_keyset_handle_on_public_key_fails(self): 59 key_format = ecies_aead_hkdf_pb2.EciesAeadHkdfKeyFormat() 60 key_template = tink_pb2.KeyTemplate() 61 key_template.type_url = ( 62 'type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey') 63 key_template.value = key_format.SerializeToString() 64 key_template.output_prefix_type = tink_pb2.TINK 65 with self.assertRaises(core.TinkError): 66 tink.new_keyset_handle(key_template) 67 68 @parameterized.parameters([ 69 hybrid.hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM, hybrid 70 .hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256 71 ]) 72 def test_encrypt_decrypt(self, template): 73 private_handle = tink.new_keyset_handle(template) 74 public_handle = private_handle.public_keyset_handle() 75 hybrid_enc = public_handle.primitive(hybrid.HybridEncrypt) 76 ciphertext = hybrid_enc.encrypt(b'some plaintext', b'some context info') 77 hybrid_dec = private_handle.primitive(hybrid.HybridDecrypt) 78 self.assertEqual(hybrid_dec.decrypt(ciphertext, b'some context info'), 79 b'some plaintext') 80 81 @parameterized.parameters([ 82 hybrid.hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM, hybrid 83 .hybrid_key_templates.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256 84 ]) 85 def test_decrypt_fails(self, template): 86 private_handle = tink.new_keyset_handle(template) 87 hybrid_dec = private_handle.primitive(hybrid.HybridDecrypt) 88 with self.assertRaises(core.TinkError): 89 hybrid_dec.decrypt(b'bad ciphertext', b'some context info') 90 91 92class HpkeKeyManagerTest(parameterized.TestCase): 93 94 def test_new_key_data(self): 95 tmpl = hybrid.hybrid_key_templates.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM 96 key_manager = core.Registry.key_manager(tmpl.type_url) 97 key_data = key_manager.new_key_data(tmpl) 98 self.assertEqual(key_data.type_url, key_manager.key_type()) 99 self.assertEqual(key_data.key_material_type, 100 tink_pb2.KeyData.ASYMMETRIC_PRIVATE) 101 key = hpke_pb2.HpkePrivateKey.FromString(key_data.value) 102 self.assertLen(key.private_key, 32) # HPKE 'Nsk' parameter length = 32 103 self.assertEqual(key.public_key.params.kem, 104 hpke_pb2.DHKEM_X25519_HKDF_SHA256) 105 self.assertEqual(key.public_key.params.kdf, hpke_pb2.HKDF_SHA256) 106 self.assertEqual(key.public_key.params.aead, hpke_pb2.AES_128_GCM) 107 108 def test_new_keyset_handle_invalid_kem_raises_exception(self): 109 templates = hybrid.hybrid_key_templates 110 key_template = templates._create_hpke_key_template( 111 hpke_kem=hpke_pb2.KEM_UNKNOWN, 112 hpke_kdf=hpke_pb2.HKDF_SHA256, 113 hpke_aead=hpke_pb2.AES_128_GCM, 114 output_prefix_type=tink_pb2.TINK) 115 with self.assertRaises(core.TinkError): 116 tink.new_keyset_handle(key_template) 117 118 def test_new_keyset_handle_invalid_kdf_raises_exception(self): 119 templates = hybrid.hybrid_key_templates 120 key_template = templates._create_hpke_key_template( 121 hpke_kem=hpke_pb2.DHKEM_X25519_HKDF_SHA256, 122 hpke_kdf=hpke_pb2.KDF_UNKNOWN, 123 hpke_aead=hpke_pb2.AES_128_GCM, 124 output_prefix_type=tink_pb2.TINK) 125 with self.assertRaises(core.TinkError): 126 tink.new_keyset_handle(key_template) 127 128 def test_new_keyset_handle_invalid_aead_raises_exception(self): 129 templates = hybrid.hybrid_key_templates 130 key_template = templates._create_hpke_key_template( 131 hpke_kem=hpke_pb2.DHKEM_X25519_HKDF_SHA256, 132 hpke_kdf=hpke_pb2.HKDF_SHA256, 133 hpke_aead=hpke_pb2.AEAD_UNKNOWN, 134 output_prefix_type=tink_pb2.TINK) 135 with self.assertRaises(core.TinkError): 136 tink.new_keyset_handle(key_template) 137 138 def test_new_keyset_handle_on_public_key_fails(self): 139 key_format = hpke_pb2.HpkeKeyFormat() 140 key_template = tink_pb2.KeyTemplate() 141 key_template.type_url = ( 142 'type.googleapis.com/google.crypto.tink.HpkePublicKey') 143 key_template.value = key_format.SerializeToString() 144 key_template.output_prefix_type = tink_pb2.TINK 145 with self.assertRaises(core.TinkError): 146 tink.new_keyset_handle(key_template) 147 148 @parameterized.parameters([ 149 hybrid.hybrid_key_templates 150 .DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM, 151 hybrid.hybrid_key_templates 152 .DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM_RAW, hybrid 153 .hybrid_key_templates.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM, 154 hybrid.hybrid_key_templates 155 .DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM_RAW, 156 hybrid.hybrid_key_templates 157 .DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305, 158 hybrid.hybrid_key_templates 159 .DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305_RAW 160 ]) 161 def test_encrypt_decrypt(self, template): 162 private_handle = tink.new_keyset_handle(template) 163 public_handle = private_handle.public_keyset_handle() 164 hybrid_encrypt = public_handle.primitive(hybrid.HybridEncrypt) 165 ciphertext = hybrid_encrypt.encrypt(b'some plaintext', b'some context info') 166 hybrid_decrypt = private_handle.primitive(hybrid.HybridDecrypt) 167 self.assertEqual( 168 hybrid_decrypt.decrypt(ciphertext, b'some context info'), 169 b'some plaintext') 170 171 @parameterized.parameters([ 172 hybrid.hybrid_key_templates 173 .DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM, 174 hybrid.hybrid_key_templates 175 .DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM_RAW, hybrid 176 .hybrid_key_templates.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM, 177 hybrid.hybrid_key_templates 178 .DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM_RAW, 179 hybrid.hybrid_key_templates 180 .DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305, 181 hybrid.hybrid_key_templates 182 .DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305_RAW 183 ]) 184 def test_decrypt_fails(self, template): 185 private_handle = tink.new_keyset_handle(template) 186 hybrid_decrypt = private_handle.primitive(hybrid.HybridDecrypt) 187 with self.assertRaises(core.TinkError): 188 hybrid_decrypt.decrypt(b'bad ciphertext', b'some context info') 189 190if __name__ == '__main__': 191 absltest.main() 192