blob: b43287b357409b8ea7c79c6d23216571ba167cab [file] [log] [blame]
Ronald Cron7ceee8d2021-03-17 16:55:43 +01001/*
2 * PSA AEAD entry points
3 */
4/*
5 * Copyright The Mbed TLS Contributors
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License"); you may
9 * not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21#include "common.h"
22
23#if defined(MBEDTLS_PSA_CRYPTO_C)
24
25#include "psa_crypto_aead.h"
Ronald Cron46f91782021-03-17 08:16:34 +010026#include "psa_crypto_core.h"
27
28#include "mbedtls/ccm.h"
29#include "mbedtls/chachapoly.h"
30#include "mbedtls/cipher.h"
31#include "mbedtls/gcm.h"
32
33typedef struct
34{
Ronald Cron46f91782021-03-17 08:16:34 +010035 union
36 {
37 unsigned dummy; /* Make the union non-empty even with no supported algorithms. */
38#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
39 mbedtls_ccm_context ccm;
40#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
41#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
42 mbedtls_gcm_context gcm;
43#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
44#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
45 mbedtls_chachapoly_context chachapoly;
46#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
47 } ctx;
48 psa_algorithm_t core_alg;
Ronald Cron46f91782021-03-17 08:16:34 +010049 uint8_t tag_length;
50} aead_operation_t;
51
Ronald Cronecbc0682021-03-26 13:25:17 +010052#define AEAD_OPERATION_INIT {{0}, 0, 0}
Ronald Cron46f91782021-03-17 08:16:34 +010053
54static void psa_aead_abort_internal( aead_operation_t *operation )
55{
56 switch( operation->core_alg )
57 {
58#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
59 case PSA_ALG_CCM:
60 mbedtls_ccm_free( &operation->ctx.ccm );
61 break;
62#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
63#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
64 case PSA_ALG_GCM:
65 mbedtls_gcm_free( &operation->ctx.gcm );
66 break;
67#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cronb9349a62021-03-26 13:32:29 +010068#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
69 case PSA_ALG_CHACHA20_POLY1305:
70 mbedtls_chachapoly_free( &operation->ctx.chachapoly );
71 break;
72#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
Ronald Cron46f91782021-03-17 08:16:34 +010073 }
74}
75
76static psa_status_t psa_aead_setup(
77 aead_operation_t *operation,
78 const psa_key_attributes_t *attributes,
79 const uint8_t *key_buffer,
80 psa_algorithm_t alg )
81{
82 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
83 size_t key_bits;
Ronald Cronecbc0682021-03-26 13:25:17 +010084 const mbedtls_cipher_info_t *cipher_info;
Ronald Cron46f91782021-03-17 08:16:34 +010085 mbedtls_cipher_id_t cipher_id;
Ronald Cronecbc0682021-03-26 13:25:17 +010086 size_t full_tag_length = 0;
Ronald Cron46f91782021-03-17 08:16:34 +010087
88 key_bits = attributes->core.bits;
89
Ronald Cronecbc0682021-03-26 13:25:17 +010090 cipher_info = mbedtls_cipher_info_from_psa( alg,
91 attributes->core.type, key_bits,
92 &cipher_id );
93 if( cipher_info == NULL )
Ronald Cron46f91782021-03-17 08:16:34 +010094 return( PSA_ERROR_NOT_SUPPORTED );
95
96 switch( PSA_ALG_AEAD_WITH_SHORTENED_TAG( alg, 0 ) )
97 {
98#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
99 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, 0 ):
100 operation->core_alg = PSA_ALG_CCM;
Ronald Cronecbc0682021-03-26 13:25:17 +0100101 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +0100102 /* CCM allows the following tag lengths: 4, 6, 8, 10, 12, 14, 16.
103 * The call to mbedtls_ccm_encrypt_and_tag or
104 * mbedtls_ccm_auth_decrypt will validate the tag length. */
105 if( PSA_BLOCK_CIPHER_BLOCK_LENGTH( attributes->core.type ) != 16 )
106 return( PSA_ERROR_INVALID_ARGUMENT );
107
108 mbedtls_ccm_init( &operation->ctx.ccm );
109 status = mbedtls_to_psa_error(
110 mbedtls_ccm_setkey( &operation->ctx.ccm, cipher_id,
111 key_buffer, (unsigned int) key_bits ) );
112 if( status != PSA_SUCCESS )
113 return( status );
114 break;
115#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
116
117#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
118 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_GCM, 0 ):
119 operation->core_alg = PSA_ALG_GCM;
Ronald Cronecbc0682021-03-26 13:25:17 +0100120 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +0100121 /* GCM allows the following tag lengths: 4, 8, 12, 13, 14, 15, 16.
122 * The call to mbedtls_gcm_crypt_and_tag or
123 * mbedtls_gcm_auth_decrypt will validate the tag length. */
124 if( PSA_BLOCK_CIPHER_BLOCK_LENGTH( attributes->core.type ) != 16 )
125 return( PSA_ERROR_INVALID_ARGUMENT );
126
127 mbedtls_gcm_init( &operation->ctx.gcm );
128 status = mbedtls_to_psa_error(
129 mbedtls_gcm_setkey( &operation->ctx.gcm, cipher_id,
130 key_buffer, (unsigned int) key_bits ) );
131 if( status != PSA_SUCCESS )
132 return( status );
133 break;
134#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
135
136#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
137 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CHACHA20_POLY1305, 0 ):
138 operation->core_alg = PSA_ALG_CHACHA20_POLY1305;
Ronald Cronecbc0682021-03-26 13:25:17 +0100139 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +0100140 /* We only support the default tag length. */
141 if( alg != PSA_ALG_CHACHA20_POLY1305 )
142 return( PSA_ERROR_NOT_SUPPORTED );
143
144 mbedtls_chachapoly_init( &operation->ctx.chachapoly );
145 status = mbedtls_to_psa_error(
146 mbedtls_chachapoly_setkey( &operation->ctx.chachapoly,
147 key_buffer ) );
148 if( status != PSA_SUCCESS )
149 return( status );
150 break;
151#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
152
153 default:
Ronald Cron485559e2021-04-28 14:29:00 +0200154 (void) status;
155 (void) key_buffer;
Ronald Cron46f91782021-03-17 08:16:34 +0100156 return( PSA_ERROR_NOT_SUPPORTED );
157 }
158
Bence Szépkútiec174e22021-03-19 18:46:15 +0100159 if( PSA_AEAD_TAG_LENGTH( attributes->core.type,
160 key_bits, alg )
161 > full_tag_length )
Ronald Cron46f91782021-03-17 08:16:34 +0100162 return( PSA_ERROR_INVALID_ARGUMENT );
163
Bence Szépkútiec174e22021-03-19 18:46:15 +0100164 operation->tag_length = PSA_AEAD_TAG_LENGTH( attributes->core.type,
165 key_bits,
166 alg );
Ronald Cron46f91782021-03-17 08:16:34 +0100167
168 return( PSA_SUCCESS );
169}
170
171psa_status_t mbedtls_psa_aead_encrypt(
172 const psa_key_attributes_t *attributes,
173 const uint8_t *key_buffer, size_t key_buffer_size,
174 psa_algorithm_t alg,
175 const uint8_t *nonce, size_t nonce_length,
176 const uint8_t *additional_data, size_t additional_data_length,
177 const uint8_t *plaintext, size_t plaintext_length,
178 uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length )
179{
180 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
181 aead_operation_t operation = AEAD_OPERATION_INIT;
182 uint8_t *tag;
183 (void) key_buffer_size;
184
185 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
186 if( status != PSA_SUCCESS )
187 goto exit;
188
189 /* For all currently supported modes, the tag is at the end of the
190 * ciphertext. */
191 if( ciphertext_size < ( plaintext_length + operation.tag_length ) )
192 {
193 status = PSA_ERROR_BUFFER_TOO_SMALL;
194 goto exit;
195 }
196 tag = ciphertext + plaintext_length;
197
Ronald Cron46f91782021-03-17 08:16:34 +0100198#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
199 if( operation.core_alg == PSA_ALG_CCM )
200 {
201 status = mbedtls_to_psa_error(
202 mbedtls_ccm_encrypt_and_tag( &operation.ctx.ccm,
203 plaintext_length,
204 nonce, nonce_length,
205 additional_data,
206 additional_data_length,
207 plaintext, ciphertext,
208 tag, operation.tag_length ) );
209 }
210 else
211#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
Ronald Cron810eb162021-04-06 09:01:39 +0200212#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
213 if( operation.core_alg == PSA_ALG_GCM )
214 {
215 status = mbedtls_to_psa_error(
216 mbedtls_gcm_crypt_and_tag( &operation.ctx.gcm,
217 MBEDTLS_GCM_ENCRYPT,
218 plaintext_length,
219 nonce, nonce_length,
220 additional_data, additional_data_length,
221 plaintext, ciphertext,
222 operation.tag_length, tag ) );
223 }
224 else
225#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cron46f91782021-03-17 08:16:34 +0100226#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
227 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
228 {
Bence Szépkúti358e0ea2021-11-17 14:03:08 +0100229 if( nonce_length != 12 )
230 {
231 if( nonce_length == 8 )
232 status = PSA_ERROR_NOT_SUPPORTED;
233 else
234 status = PSA_ERROR_INVALID_ARGUMENT;
235 goto exit;
236 }
237
238 if( operation.tag_length != 16 )
Ronald Cron46f91782021-03-17 08:16:34 +0100239 {
240 status = PSA_ERROR_NOT_SUPPORTED;
241 goto exit;
242 }
243 status = mbedtls_to_psa_error(
244 mbedtls_chachapoly_encrypt_and_tag( &operation.ctx.chachapoly,
245 plaintext_length,
246 nonce,
247 additional_data,
248 additional_data_length,
249 plaintext,
250 ciphertext,
251 tag ) );
252 }
253 else
254#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
255 {
256 (void) tag;
Ronald Cron485559e2021-04-28 14:29:00 +0200257 (void) nonce;
258 (void) nonce_length;
259 (void) additional_data;
260 (void) additional_data_length;
261 (void) plaintext;
Ronald Cron46f91782021-03-17 08:16:34 +0100262 return( PSA_ERROR_NOT_SUPPORTED );
263 }
264
265 if( status == PSA_SUCCESS )
266 *ciphertext_length = plaintext_length + operation.tag_length;
267
268exit:
269 psa_aead_abort_internal( &operation );
270
271 return( status );
272}
273
274/* Locate the tag in a ciphertext buffer containing the encrypted data
275 * followed by the tag. Return the length of the part preceding the tag in
276 * *plaintext_length. This is the size of the plaintext in modes where
277 * the encrypted data has the same size as the plaintext, such as
278 * CCM and GCM. */
279static psa_status_t psa_aead_unpadded_locate_tag( size_t tag_length,
280 const uint8_t *ciphertext,
281 size_t ciphertext_length,
282 size_t plaintext_size,
283 const uint8_t **p_tag )
284{
285 size_t payload_length;
286 if( tag_length > ciphertext_length )
287 return( PSA_ERROR_INVALID_ARGUMENT );
288 payload_length = ciphertext_length - tag_length;
289 if( payload_length > plaintext_size )
290 return( PSA_ERROR_BUFFER_TOO_SMALL );
291 *p_tag = ciphertext + payload_length;
292 return( PSA_SUCCESS );
293}
294
295psa_status_t mbedtls_psa_aead_decrypt(
296 const psa_key_attributes_t *attributes,
297 const uint8_t *key_buffer, size_t key_buffer_size,
298 psa_algorithm_t alg,
299 const uint8_t *nonce, size_t nonce_length,
300 const uint8_t *additional_data, size_t additional_data_length,
301 const uint8_t *ciphertext, size_t ciphertext_length,
302 uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length )
303{
304 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
305 aead_operation_t operation = AEAD_OPERATION_INIT;
306 const uint8_t *tag = NULL;
307 (void) key_buffer_size;
308
309 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
310 if( status != PSA_SUCCESS )
311 goto exit;
312
313 status = psa_aead_unpadded_locate_tag( operation.tag_length,
314 ciphertext, ciphertext_length,
315 plaintext_size, &tag );
316 if( status != PSA_SUCCESS )
317 goto exit;
318
Ronald Cron46f91782021-03-17 08:16:34 +0100319#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
320 if( operation.core_alg == PSA_ALG_CCM )
321 {
322 status = mbedtls_to_psa_error(
323 mbedtls_ccm_auth_decrypt( &operation.ctx.ccm,
324 ciphertext_length - operation.tag_length,
325 nonce, nonce_length,
326 additional_data,
327 additional_data_length,
328 ciphertext, plaintext,
329 tag, operation.tag_length ) );
330 }
331 else
332#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
Ronald Cron810eb162021-04-06 09:01:39 +0200333#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
334 if( operation.core_alg == PSA_ALG_GCM )
335 {
336 status = mbedtls_to_psa_error(
337 mbedtls_gcm_auth_decrypt( &operation.ctx.gcm,
338 ciphertext_length - operation.tag_length,
339 nonce, nonce_length,
340 additional_data,
341 additional_data_length,
342 tag, operation.tag_length,
343 ciphertext, plaintext ) );
344 }
345 else
346#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cron46f91782021-03-17 08:16:34 +0100347#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
348 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
349 {
Bence Szépkúti358e0ea2021-11-17 14:03:08 +0100350 if( nonce_length != 12 )
351 {
352 if( nonce_length == 8 )
353 status = PSA_ERROR_NOT_SUPPORTED;
354 else
355 status = PSA_ERROR_INVALID_ARGUMENT;
356 goto exit;
357 }
358
359 if( operation.tag_length != 16 )
Ronald Cron46f91782021-03-17 08:16:34 +0100360 {
361 status = PSA_ERROR_NOT_SUPPORTED;
362 goto exit;
363 }
364 status = mbedtls_to_psa_error(
365 mbedtls_chachapoly_auth_decrypt( &operation.ctx.chachapoly,
366 ciphertext_length - operation.tag_length,
367 nonce,
368 additional_data,
369 additional_data_length,
370 tag,
371 ciphertext,
372 plaintext ) );
373 }
374 else
375#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
376 {
Ronald Cron485559e2021-04-28 14:29:00 +0200377 (void) nonce;
378 (void) nonce_length;
379 (void) additional_data;
380 (void) additional_data_length;
381 (void) plaintext;
Ronald Cron46f91782021-03-17 08:16:34 +0100382 return( PSA_ERROR_NOT_SUPPORTED );
383 }
384
385 if( status == PSA_SUCCESS )
386 *plaintext_length = ciphertext_length - operation.tag_length;
387
388exit:
389 psa_aead_abort_internal( &operation );
390
391 if( status == PSA_SUCCESS )
392 *plaintext_length = ciphertext_length - operation.tag_length;
393 return( status );
394}
Ronald Cron7ceee8d2021-03-17 16:55:43 +0100395
396#endif /* MBEDTLS_PSA_CRYPTO_C */
397