Gilles Peskine | 0156a15 | 2021-01-26 21:23:56 +0100 | [diff] [blame] | 1 | """Knowledge about cryptographic mechanisms implemented in Mbed TLS. |
| 2 | |
| 3 | This module is entirely based on the PSA API. |
| 4 | """ |
| 5 | |
| 6 | # Copyright The Mbed TLS Contributors |
| 7 | # SPDX-License-Identifier: Apache-2.0 |
| 8 | # |
| 9 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 10 | # not use this file except in compliance with the License. |
| 11 | # You may obtain a copy of the License at |
| 12 | # |
| 13 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 14 | # |
| 15 | # Unless required by applicable law or agreed to in writing, software |
| 16 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 17 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 18 | # See the License for the specific language governing permissions and |
| 19 | # limitations under the License. |
| 20 | |
| 21 | import re |
Gilles Peskine | df63968 | 2021-01-26 21:25:34 +0100 | [diff] [blame] | 22 | from typing import List, Optional, Tuple |
Gilles Peskine | 0156a15 | 2021-01-26 21:23:56 +0100 | [diff] [blame] | 23 | |
| 24 | class KeyType: |
| 25 | """Knowledge about a PSA key type.""" |
| 26 | |
| 27 | def __init__(self, name: str, params: Optional[List[str]] = None): |
| 28 | """Analyze a key type. |
| 29 | |
| 30 | The key type must be specified in PSA syntax. In its simplest form, |
| 31 | this is a string 'PSA_KEY_TYPE_xxx' which is the name of a PSA key |
| 32 | type macro. For key types that take arguments, the arguments can |
| 33 | be passed either through the optional argument `params` or by |
| 34 | passing an expression of the form 'PSA_KEY_TYPE_xxx(param1, param2)' |
| 35 | as the a string. |
| 36 | """ |
| 37 | self.name = name.strip() |
| 38 | if params is None: |
| 39 | if '(' in self.name: |
| 40 | m = re.match(r'(\w+)\s*\((.*)\)\Z', self.name) |
| 41 | assert m is not None |
| 42 | self.name = m.group(1) |
| 43 | params = ','.split(m.group(2)) |
| 44 | if params is None: |
| 45 | self.params = params |
| 46 | else: |
| 47 | self.params = [param.strip() for param in params] |
| 48 | self.expression = self.name |
| 49 | if self.params is not None: |
| 50 | self.expression += '(' + ', '.join(self.params) + ')' |
| 51 | self.private_type = re.sub(r'_PUBLIC_KEY\Z', r'_KEY_PAIR', self.name) |
Gilles Peskine | df63968 | 2021-01-26 21:25:34 +0100 | [diff] [blame] | 52 | |
| 53 | ECC_KEY_SIZES = { |
| 54 | 'PSA_ECC_FAMILY_SECP_K1': (192, 224, 256), |
| 55 | 'PSA_ECC_FAMILY_SECP_R1': (192, 225, 256, 384, 521), |
| 56 | 'PSA_ECC_FAMILY_SECP_R2': (160,), |
| 57 | 'PSA_ECC_FAMILY_SECT_K1': (163, 233, 239, 283, 409, 571), |
| 58 | 'PSA_ECC_FAMILY_SECT_R1': (163, 233, 283, 409, 571), |
| 59 | 'PSA_ECC_FAMILY_SECT_R2': (163,), |
| 60 | 'PSA_ECC_FAMILY_BRAINPOOL_P_R1': (160, 192, 224, 256, 320, 384, 512), |
| 61 | 'PSA_ECC_FAMILY_MONTGOMERY': (255, 448), |
| 62 | } |
| 63 | KEY_TYPE_SIZES = { |
| 64 | 'PSA_KEY_TYPE_AES': (128, 192, 256), # exhaustive |
| 65 | 'PSA_KEY_TYPE_ARC4': (8, 128, 2048), # extremes + sensible |
| 66 | 'PSA_KEY_TYPE_ARIA': (128, 192, 256), # exhaustive |
| 67 | 'PSA_KEY_TYPE_CAMELLIA': (128, 192, 256), # exhaustive |
| 68 | 'PSA_KEY_TYPE_CHACHA20': (256,), # exhaustive |
| 69 | 'PSA_KEY_TYPE_DERIVE': (120, 128), # sample |
| 70 | 'PSA_KEY_TYPE_DES': (64, 128, 192), # exhaustive |
| 71 | 'PSA_KEY_TYPE_HMAC': (128, 160, 224, 256, 384, 512), # standard size for each supported hash |
| 72 | 'PSA_KEY_TYPE_RAW_DATA': (8, 40, 128), # sample |
| 73 | 'PSA_KEY_TYPE_RSA_KEY_PAIR': (1024, 1536), # small sample |
| 74 | } |
| 75 | def sizes_to_test(self) -> Tuple[int, ...]: |
| 76 | """Return a tuple of key sizes to test. |
| 77 | |
| 78 | For key types that only allow a single size, or only a small set of |
| 79 | sizes, these are all the possible sizes. For key types that allow a |
| 80 | wide range of sizes, these are a representative sample of sizes, |
| 81 | excluding large sizes for which a typical resource-constrained platform |
| 82 | may run out of memory. |
| 83 | """ |
| 84 | if self.private_type == 'PSA_KEY_TYPE_ECC_KEY_PAIR': |
| 85 | assert self.params is not None |
| 86 | return self.ECC_KEY_SIZES[self.params[0]] |
| 87 | return self.KEY_TYPE_SIZES[self.private_type] |
Gilles Peskine | 397b028 | 2021-01-26 21:26:26 +0100 | [diff] [blame^] | 88 | |
| 89 | # "48657265006973206b6579a064617461" |
| 90 | DATA_BLOCK = b'Here\000is key\240data' |
| 91 | def key_material(self, bits: int) -> bytes: |
| 92 | """Return a byte string containing suitable key material with the given bit length. |
| 93 | |
| 94 | Use the PSA export representation. The resulting byte string is one that |
| 95 | can be obtained with the following code: |
| 96 | ``` |
| 97 | psa_set_key_type(&attributes, `self.expression`); |
| 98 | psa_set_key_bits(&attributes, `bits`); |
| 99 | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_EXPORT); |
| 100 | psa_generate_key(&attributes, &id); |
| 101 | psa_export_key(id, `material`, ...); |
| 102 | ``` |
| 103 | """ |
| 104 | if bits % 8 != 0: |
| 105 | raise ValueError('Non-integer number of bytes: {} bits'.format(bits)) |
| 106 | length = bits // 8 |
| 107 | if self.name == 'PSA_KEY_TYPE_DES': |
| 108 | # "644573206b457901644573206b457902644573206b457904" |
| 109 | des3 = b'dEs kEy\001dEs kEy\002dEs kEy\004' |
| 110 | return des3[:length] |
| 111 | # TODO: ECC, RSA |
| 112 | return b''.join([self.DATA_BLOCK] * (length // len(self.DATA_BLOCK)) + |
| 113 | [self.DATA_BLOCK[:length % len(self.DATA_BLOCK)]]) |