blob: 2e0fa2fd1540311977fe21eb952e906cf58d87ee [file] [log] [blame]
Gilles Peskine0156a152021-01-26 21:23:56 +01001"""Knowledge about cryptographic mechanisms implemented in Mbed TLS.
2
3This 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
21import re
Gilles Peskinedf639682021-01-26 21:25:34 +010022from typing import List, Optional, Tuple
Gilles Peskine0156a152021-01-26 21:23:56 +010023
24class 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 Peskinedf639682021-01-26 21:25:34 +010052
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 Peskine397b0282021-01-26 21:26:26 +010088
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)]])