blob: e9dad1d2d1f42e6188214d34e65148230d2e9d38 [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
Gilles Peskine6f6483f2021-01-27 12:43:24 +010024from mbedtls_dev.asymmetric_key_data import ASYMMETRIC_KEY_DATA
25
Gilles Peskine0156a152021-01-26 21:23:56 +010026class KeyType:
27 """Knowledge about a PSA key type."""
28
29 def __init__(self, name: str, params: Optional[List[str]] = None):
30 """Analyze a key type.
31
32 The key type must be specified in PSA syntax. In its simplest form,
33 this is a string 'PSA_KEY_TYPE_xxx' which is the name of a PSA key
34 type macro. For key types that take arguments, the arguments can
35 be passed either through the optional argument `params` or by
36 passing an expression of the form 'PSA_KEY_TYPE_xxx(param1, param2)'
37 as the a string.
38 """
39 self.name = name.strip()
40 if params is None:
41 if '(' in self.name:
42 m = re.match(r'(\w+)\s*\((.*)\)\Z', self.name)
43 assert m is not None
44 self.name = m.group(1)
45 params = ','.split(m.group(2))
46 if params is None:
47 self.params = params
48 else:
49 self.params = [param.strip() for param in params]
50 self.expression = self.name
51 if self.params is not None:
52 self.expression += '(' + ', '.join(self.params) + ')'
53 self.private_type = re.sub(r'_PUBLIC_KEY\Z', r'_KEY_PAIR', self.name)
Gilles Peskinedf639682021-01-26 21:25:34 +010054
55 ECC_KEY_SIZES = {
56 'PSA_ECC_FAMILY_SECP_K1': (192, 224, 256),
Gilles Peskine0ac258e2021-01-27 13:11:59 +010057 'PSA_ECC_FAMILY_SECP_R1': (225, 256, 384, 521),
Gilles Peskinedf639682021-01-26 21:25:34 +010058 'PSA_ECC_FAMILY_SECP_R2': (160,),
59 'PSA_ECC_FAMILY_SECT_K1': (163, 233, 239, 283, 409, 571),
60 'PSA_ECC_FAMILY_SECT_R1': (163, 233, 283, 409, 571),
61 'PSA_ECC_FAMILY_SECT_R2': (163,),
62 'PSA_ECC_FAMILY_BRAINPOOL_P_R1': (160, 192, 224, 256, 320, 384, 512),
63 'PSA_ECC_FAMILY_MONTGOMERY': (255, 448),
64 }
65 KEY_TYPE_SIZES = {
66 'PSA_KEY_TYPE_AES': (128, 192, 256), # exhaustive
67 'PSA_KEY_TYPE_ARC4': (8, 128, 2048), # extremes + sensible
68 'PSA_KEY_TYPE_ARIA': (128, 192, 256), # exhaustive
69 'PSA_KEY_TYPE_CAMELLIA': (128, 192, 256), # exhaustive
70 'PSA_KEY_TYPE_CHACHA20': (256,), # exhaustive
71 'PSA_KEY_TYPE_DERIVE': (120, 128), # sample
72 'PSA_KEY_TYPE_DES': (64, 128, 192), # exhaustive
73 'PSA_KEY_TYPE_HMAC': (128, 160, 224, 256, 384, 512), # standard size for each supported hash
74 'PSA_KEY_TYPE_RAW_DATA': (8, 40, 128), # sample
75 'PSA_KEY_TYPE_RSA_KEY_PAIR': (1024, 1536), # small sample
76 }
77 def sizes_to_test(self) -> Tuple[int, ...]:
78 """Return a tuple of key sizes to test.
79
80 For key types that only allow a single size, or only a small set of
81 sizes, these are all the possible sizes. For key types that allow a
82 wide range of sizes, these are a representative sample of sizes,
83 excluding large sizes for which a typical resource-constrained platform
84 may run out of memory.
85 """
86 if self.private_type == 'PSA_KEY_TYPE_ECC_KEY_PAIR':
87 assert self.params is not None
88 return self.ECC_KEY_SIZES[self.params[0]]
89 return self.KEY_TYPE_SIZES[self.private_type]
Gilles Peskine397b0282021-01-26 21:26:26 +010090
91 # "48657265006973206b6579a064617461"
92 DATA_BLOCK = b'Here\000is key\240data'
93 def key_material(self, bits: int) -> bytes:
94 """Return a byte string containing suitable key material with the given bit length.
95
96 Use the PSA export representation. The resulting byte string is one that
97 can be obtained with the following code:
98 ```
99 psa_set_key_type(&attributes, `self.expression`);
100 psa_set_key_bits(&attributes, `bits`);
101 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_EXPORT);
102 psa_generate_key(&attributes, &id);
103 psa_export_key(id, `material`, ...);
104 ```
105 """
Gilles Peskine6f6483f2021-01-27 12:43:24 +0100106 if self.expression in ASYMMETRIC_KEY_DATA:
107 if bits not in ASYMMETRIC_KEY_DATA[self.expression]:
108 raise ValueError('No key data for {}-bit {}'
109 .format(bits, self.expression))
110 return ASYMMETRIC_KEY_DATA[self.expression][bits]
Gilles Peskine397b0282021-01-26 21:26:26 +0100111 if bits % 8 != 0:
Gilles Peskine6f6483f2021-01-27 12:43:24 +0100112 raise ValueError('Non-integer number of bytes: {} bits for {}'
113 .format(bits, self.expression))
Gilles Peskine397b0282021-01-26 21:26:26 +0100114 length = bits // 8
115 if self.name == 'PSA_KEY_TYPE_DES':
116 # "644573206b457901644573206b457902644573206b457904"
117 des3 = b'dEs kEy\001dEs kEy\002dEs kEy\004'
118 return des3[:length]
Gilles Peskine397b0282021-01-26 21:26:26 +0100119 return b''.join([self.DATA_BLOCK] * (length // len(self.DATA_BLOCK)) +
120 [self.DATA_BLOCK[:length % len(self.DATA_BLOCK)]])