1 /*
2 * PSA AEAD entry points
3 */
4 /*
5 * Copyright The Mbed TLS Contributors
6 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
7 */
8
9 #include "common.h"
10
11 #if defined(MBEDTLS_PSA_CRYPTO_C)
12
13 #include "psa_crypto_aead.h"
14 #include "psa_crypto_core.h"
15 #include "psa_crypto_cipher.h"
16
17 #include "mbedtls/ccm.h"
18 #include "mbedtls/chachapoly.h"
19 #include "mbedtls/cipher.h"
20 #include "mbedtls/gcm.h"
21
22 typedef struct {
23 psa_algorithm_t core_alg;
24 uint8_t tag_length;
25 union {
26 unsigned dummy; /* Make the union non-empty even with no supported algorithms. */
27 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
28 mbedtls_ccm_context ccm;
29 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
30 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
31 mbedtls_gcm_context gcm;
32 #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
33 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
34 mbedtls_chachapoly_context chachapoly;
35 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
36 } ctx;
37 } aead_operation_t;
38
39 #define AEAD_OPERATION_INIT { 0, 0, { 0 } }
40
psa_aead_abort_internal(aead_operation_t * operation)41 static void psa_aead_abort_internal(aead_operation_t *operation)
42 {
43 switch (operation->core_alg) {
44 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
45 case PSA_ALG_CCM:
46 mbedtls_ccm_free(&operation->ctx.ccm);
47 break;
48 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
49 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
50 case PSA_ALG_GCM:
51 mbedtls_gcm_free(&operation->ctx.gcm);
52 break;
53 #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
54 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
55 case PSA_ALG_CHACHA20_POLY1305:
56 mbedtls_chachapoly_free(&operation->ctx.chachapoly);
57 break;
58 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
59 }
60 }
61
psa_aead_setup(aead_operation_t * operation,const psa_key_attributes_t * attributes,const uint8_t * key_buffer,psa_algorithm_t alg)62 static psa_status_t psa_aead_setup(
63 aead_operation_t *operation,
64 const psa_key_attributes_t *attributes,
65 const uint8_t *key_buffer,
66 psa_algorithm_t alg)
67 {
68 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
69 size_t key_bits;
70 const mbedtls_cipher_info_t *cipher_info;
71 mbedtls_cipher_id_t cipher_id;
72 size_t full_tag_length = 0;
73
74 key_bits = attributes->core.bits;
75
76 cipher_info = mbedtls_cipher_info_from_psa(alg,
77 attributes->core.type, key_bits,
78 &cipher_id);
79 if (cipher_info == NULL) {
80 return PSA_ERROR_NOT_SUPPORTED;
81 }
82
83 switch (PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, 0)) {
84 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
85 case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, 0):
86 operation->core_alg = PSA_ALG_CCM;
87 full_tag_length = 16;
88 /* CCM allows the following tag lengths: 4, 6, 8, 10, 12, 14, 16.
89 * The call to mbedtls_ccm_encrypt_and_tag or
90 * mbedtls_ccm_auth_decrypt will validate the tag length. */
91 if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->core.type) != 16) {
92 return PSA_ERROR_INVALID_ARGUMENT;
93 }
94
95 mbedtls_ccm_init(&operation->ctx.ccm);
96 status = mbedtls_to_psa_error(
97 mbedtls_ccm_setkey(&operation->ctx.ccm, cipher_id,
98 key_buffer, (unsigned int) key_bits));
99 if (status != PSA_SUCCESS) {
100 return status;
101 }
102 break;
103 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
104
105 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
106 case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 0):
107 operation->core_alg = PSA_ALG_GCM;
108 full_tag_length = 16;
109 /* GCM allows the following tag lengths: 4, 8, 12, 13, 14, 15, 16.
110 * The call to mbedtls_gcm_crypt_and_tag or
111 * mbedtls_gcm_auth_decrypt will validate the tag length. */
112 if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->core.type) != 16) {
113 return PSA_ERROR_INVALID_ARGUMENT;
114 }
115
116 mbedtls_gcm_init(&operation->ctx.gcm);
117 status = mbedtls_to_psa_error(
118 mbedtls_gcm_setkey(&operation->ctx.gcm, cipher_id,
119 key_buffer, (unsigned int) key_bits));
120 if (status != PSA_SUCCESS) {
121 return status;
122 }
123 break;
124 #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
125
126 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
127 case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CHACHA20_POLY1305, 0):
128 operation->core_alg = PSA_ALG_CHACHA20_POLY1305;
129 full_tag_length = 16;
130 /* We only support the default tag length. */
131 if (alg != PSA_ALG_CHACHA20_POLY1305) {
132 return PSA_ERROR_NOT_SUPPORTED;
133 }
134
135 mbedtls_chachapoly_init(&operation->ctx.chachapoly);
136 status = mbedtls_to_psa_error(
137 mbedtls_chachapoly_setkey(&operation->ctx.chachapoly,
138 key_buffer));
139 if (status != PSA_SUCCESS) {
140 return status;
141 }
142 break;
143 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
144
145 default:
146 (void) status;
147 (void) key_buffer;
148 return PSA_ERROR_NOT_SUPPORTED;
149 }
150
151 if (PSA_AEAD_TAG_LENGTH(attributes->core.type,
152 key_bits, alg)
153 > full_tag_length) {
154 return PSA_ERROR_INVALID_ARGUMENT;
155 }
156
157 operation->tag_length = PSA_AEAD_TAG_LENGTH(attributes->core.type,
158 key_bits,
159 alg);
160
161 return PSA_SUCCESS;
162 }
163
mbedtls_psa_aead_encrypt(const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg,const uint8_t * nonce,size_t nonce_length,const uint8_t * additional_data,size_t additional_data_length,const uint8_t * plaintext,size_t plaintext_length,uint8_t * ciphertext,size_t ciphertext_size,size_t * ciphertext_length)164 psa_status_t mbedtls_psa_aead_encrypt(
165 const psa_key_attributes_t *attributes,
166 const uint8_t *key_buffer, size_t key_buffer_size,
167 psa_algorithm_t alg,
168 const uint8_t *nonce, size_t nonce_length,
169 const uint8_t *additional_data, size_t additional_data_length,
170 const uint8_t *plaintext, size_t plaintext_length,
171 uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length)
172 {
173 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
174 aead_operation_t operation = AEAD_OPERATION_INIT;
175 uint8_t *tag;
176 (void) key_buffer_size;
177
178 status = psa_aead_setup(&operation, attributes, key_buffer, alg);
179 if (status != PSA_SUCCESS) {
180 goto exit;
181 }
182
183 /* For all currently supported modes, the tag is at the end of the
184 * ciphertext. */
185 if (ciphertext_size < (plaintext_length + operation.tag_length)) {
186 status = PSA_ERROR_BUFFER_TOO_SMALL;
187 goto exit;
188 }
189 tag = ciphertext + plaintext_length;
190
191 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
192 if (operation.core_alg == PSA_ALG_CCM) {
193 status = mbedtls_to_psa_error(
194 mbedtls_ccm_encrypt_and_tag(&operation.ctx.ccm,
195 plaintext_length,
196 nonce, nonce_length,
197 additional_data,
198 additional_data_length,
199 plaintext, ciphertext,
200 tag, operation.tag_length));
201 } else
202 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
203 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
204 if (operation.core_alg == PSA_ALG_GCM) {
205 status = mbedtls_to_psa_error(
206 mbedtls_gcm_crypt_and_tag(&operation.ctx.gcm,
207 MBEDTLS_GCM_ENCRYPT,
208 plaintext_length,
209 nonce, nonce_length,
210 additional_data, additional_data_length,
211 plaintext, ciphertext,
212 operation.tag_length, tag));
213 } else
214 #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
215 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
216 if (operation.core_alg == PSA_ALG_CHACHA20_POLY1305) {
217 if (nonce_length != 12) {
218 if (nonce_length == 8) {
219 status = PSA_ERROR_NOT_SUPPORTED;
220 } else {
221 status = PSA_ERROR_INVALID_ARGUMENT;
222 }
223 goto exit;
224 }
225
226 if (operation.tag_length != 16) {
227 status = PSA_ERROR_NOT_SUPPORTED;
228 goto exit;
229 }
230 status = mbedtls_to_psa_error(
231 mbedtls_chachapoly_encrypt_and_tag(&operation.ctx.chachapoly,
232 plaintext_length,
233 nonce,
234 additional_data,
235 additional_data_length,
236 plaintext,
237 ciphertext,
238 tag));
239 } else
240 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
241 {
242 (void) tag;
243 (void) nonce;
244 (void) nonce_length;
245 (void) additional_data;
246 (void) additional_data_length;
247 (void) plaintext;
248 return PSA_ERROR_NOT_SUPPORTED;
249 }
250
251 if (status == PSA_SUCCESS) {
252 *ciphertext_length = plaintext_length + operation.tag_length;
253 }
254
255 exit:
256 psa_aead_abort_internal(&operation);
257
258 return status;
259 }
260
261 /* Locate the tag in a ciphertext buffer containing the encrypted data
262 * followed by the tag. Return the length of the part preceding the tag in
263 * *plaintext_length. This is the size of the plaintext in modes where
264 * the encrypted data has the same size as the plaintext, such as
265 * CCM and GCM. */
psa_aead_unpadded_locate_tag(size_t tag_length,const uint8_t * ciphertext,size_t ciphertext_length,size_t plaintext_size,const uint8_t ** p_tag)266 static psa_status_t psa_aead_unpadded_locate_tag(size_t tag_length,
267 const uint8_t *ciphertext,
268 size_t ciphertext_length,
269 size_t plaintext_size,
270 const uint8_t **p_tag)
271 {
272 size_t payload_length;
273 if (tag_length > ciphertext_length) {
274 return PSA_ERROR_INVALID_ARGUMENT;
275 }
276 payload_length = ciphertext_length - tag_length;
277 if (payload_length > plaintext_size) {
278 return PSA_ERROR_BUFFER_TOO_SMALL;
279 }
280 *p_tag = ciphertext + payload_length;
281 return PSA_SUCCESS;
282 }
283
mbedtls_psa_aead_decrypt(const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg,const uint8_t * nonce,size_t nonce_length,const uint8_t * additional_data,size_t additional_data_length,const uint8_t * ciphertext,size_t ciphertext_length,uint8_t * plaintext,size_t plaintext_size,size_t * plaintext_length)284 psa_status_t mbedtls_psa_aead_decrypt(
285 const psa_key_attributes_t *attributes,
286 const uint8_t *key_buffer, size_t key_buffer_size,
287 psa_algorithm_t alg,
288 const uint8_t *nonce, size_t nonce_length,
289 const uint8_t *additional_data, size_t additional_data_length,
290 const uint8_t *ciphertext, size_t ciphertext_length,
291 uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length)
292 {
293 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
294 aead_operation_t operation = AEAD_OPERATION_INIT;
295 const uint8_t *tag = NULL;
296 (void) key_buffer_size;
297
298 status = psa_aead_setup(&operation, attributes, key_buffer, alg);
299 if (status != PSA_SUCCESS) {
300 goto exit;
301 }
302
303 status = psa_aead_unpadded_locate_tag(operation.tag_length,
304 ciphertext, ciphertext_length,
305 plaintext_size, &tag);
306 if (status != PSA_SUCCESS) {
307 goto exit;
308 }
309
310 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
311 if (operation.core_alg == PSA_ALG_CCM) {
312 status = mbedtls_to_psa_error(
313 mbedtls_ccm_auth_decrypt(&operation.ctx.ccm,
314 ciphertext_length - operation.tag_length,
315 nonce, nonce_length,
316 additional_data,
317 additional_data_length,
318 ciphertext, plaintext,
319 tag, operation.tag_length));
320 } else
321 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
322 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
323 if (operation.core_alg == PSA_ALG_GCM) {
324 status = mbedtls_to_psa_error(
325 mbedtls_gcm_auth_decrypt(&operation.ctx.gcm,
326 ciphertext_length - operation.tag_length,
327 nonce, nonce_length,
328 additional_data,
329 additional_data_length,
330 tag, operation.tag_length,
331 ciphertext, plaintext));
332 } else
333 #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
334 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
335 if (operation.core_alg == PSA_ALG_CHACHA20_POLY1305) {
336 if (nonce_length != 12) {
337 if (nonce_length == 8) {
338 status = PSA_ERROR_NOT_SUPPORTED;
339 } else {
340 status = PSA_ERROR_INVALID_ARGUMENT;
341 }
342 goto exit;
343 }
344
345 if (operation.tag_length != 16) {
346 status = PSA_ERROR_NOT_SUPPORTED;
347 goto exit;
348 }
349 status = mbedtls_to_psa_error(
350 mbedtls_chachapoly_auth_decrypt(&operation.ctx.chachapoly,
351 ciphertext_length - operation.tag_length,
352 nonce,
353 additional_data,
354 additional_data_length,
355 tag,
356 ciphertext,
357 plaintext));
358 } else
359 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
360 {
361 (void) nonce;
362 (void) nonce_length;
363 (void) additional_data;
364 (void) additional_data_length;
365 (void) plaintext;
366 return PSA_ERROR_NOT_SUPPORTED;
367 }
368
369 if (status == PSA_SUCCESS) {
370 *plaintext_length = ciphertext_length - operation.tag_length;
371 }
372
373 exit:
374 psa_aead_abort_internal(&operation);
375
376 if (status == PSA_SUCCESS) {
377 *plaintext_length = ciphertext_length - operation.tag_length;
378 }
379 return status;
380 }
381
382 #endif /* MBEDTLS_PSA_CRYPTO_C */
383