1# Copyright 2022 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"""Helper functions to access the information in this module. 15""" 16 17from typing import Any, Iterable, List 18 19from tink.proto import tink_pb2 20from tink_config import _key_types 21 22_TYPE_URL_PREFIX = 'type.googleapis.com/google.crypto.tink.' 23 24 25def all_key_types() -> List[str]: 26 """Returns all key types which Tink currently knows in short format. 27 28 The related TypeUrl equals the short format returned here, but prefixed with 29 type.googleapis.com/google.crypto.tink. 30 """ 31 result = [] 32 for key_types_for_single_primitive in _key_types.KEY_TYPES.values(): 33 result += key_types_for_single_primitive 34 return result 35 36 37def key_types_for_primitive(p: Any) -> List[str]: 38 """Returns all key types for the given primitive which Tink currently has. 39 40 The related TypeUrl equals the short format returned here, but prefixed with 41 type.googleapis.com/google.crypto.tink. 42 Args: 43 p: The class of the primitive (e.g. tink.Aead) 44 Returns: 45 The list of key types (e.g. ['AesGcmKey', 'AesEaxKey']) 46 """ 47 return list(_key_types.KEY_TYPES[p]) 48 49 50def key_type_from_type_url(type_url: str) -> str: 51 """Returns the key type from a given TypeUrl. 52 53 If the TypeUrl is invalid throws an exception. 54 Args: 55 type_url: For example 'type.googleapis.com/google.crypto.tink.AesGcmKey' 56 Returns: 57 The stripped version (e.g. AesGcmKey) 58 Raises: 59 ValueError if the type url is unknown or in a bad format. 60 """ 61 if not type_url.startswith(_TYPE_URL_PREFIX): 62 raise ValueError('Invalid type_url: ' + type_url) 63 # removeprefix does not yet exist in all our supported python versions. 64 key_type = type_url[len(_TYPE_URL_PREFIX):] 65 if key_type not in all_key_types(): 66 raise ValueError('key type unknown: ' + key_type) 67 return key_type 68 69 70def supported_languages_for_key_type(key_type: str) -> List[str]: 71 """Returns the list of supported languages for a given KeyType. 72 73 Throws an except if the key type is unkonwn. 74 Args: 75 key_type: The shortened type URL (e.g. 'AesGcmKey') 76 Returns: 77 The list of languages which this key type supportes. 78 Raises: 79 ValueError if the key type is unknown. 80 """ 81 if key_type not in all_key_types(): 82 raise ValueError('key_type unknown: ' + key_type) 83 return _key_types.SUPPORTED_LANGUAGES[key_type] 84 85 86def supported_languages_for_primitive(p: Any) -> List[str]: 87 """Returns the list of languages which support a primitive. 88 89 Throws an except if the key type is unkonwn. 90 Args: 91 p: The Primitive 92 Returns: 93 The list of languages which this primitive supportes. 94 Raises: 95 ValueError if the key type is unknown. 96 """ 97 result = set() 98 for key_type in key_types_for_primitive(p): 99 result.update(set(supported_languages_for_key_type(key_type))) 100 return list(result) 101 102 103def all_primitives() -> Iterable[Any]: 104 """Returns all the primitive types (such as tink.aead.Aead).""" 105 return [p for p, _ in _key_types.KEY_TYPES.items()] 106 107 108def primitive_for_keytype(key_type: str) -> Any: 109 """Returns the primitive for the given key type.""" 110 111 for p, key_types in _key_types.KEY_TYPES.items(): 112 if key_type in key_types: 113 return p 114 raise ValueError('Unknown key type: ' + key_type) 115 116 117def is_asymmetric_public_key_primitive(p: Any) -> bool: 118 """Returns true iff this p is the public part of an asymmetric scheme.""" 119 return p in _key_types.PRIVATE_TO_PUBLIC_PRIMITIVE.values() 120 121 122def get_private_key_primitive(p: Any) -> Any: 123 """Returns the private primitive corresponding to this public part.""" 124 inverted = {v: k for (k, v) in _key_types.PRIVATE_TO_PUBLIC_PRIMITIVE.items()} 125 return inverted[p] 126 127 128def _key_types_in_keyset(keyset: bytes) -> List[str]: 129 parsed_keyset = tink_pb2.Keyset.FromString(keyset) 130 type_urls = [k.key_data.type_url for k in parsed_keyset.key] 131 return [key_type_from_type_url(t) for t in type_urls] 132 133 134def keyset_supported(keyset: bytes, p: Any, lang: str) -> bool: 135 """Checks if the given keyset can be instantiated as 'p' in the 'lang'. 136 137 Returns true if it is expected that the keyset can be instantiated in language 138 'lang', according to the current configuration stored in tink_config. This 139 only looks at the key types in the keyset, and does not check if the keys 140 themselves are valid. It also does not check that the keyset is valid. 141 142 Args: 143 keyset: The serialized keyset 144 p: The primitive class, e.g. aead.Aead 145 lang: The language, e.g. 'python' or 'java'. 146 147 Returns: 148 True iff all key types are for this primitive and supported in the given 149 language. 150 """ 151 152 key_types = _key_types_in_keyset(keyset) 153 for key_type in key_types: 154 if primitive_for_keytype(key_type) != p: 155 return False 156 if lang not in supported_languages_for_key_type(key_type): 157 return False 158 return True 159