blob: 2b07a6871ec1cba72e5bc1a97247a47af91dce95 [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"
Dave Rodgman8e322b12022-11-02 09:25:38 +000027#include "psa_crypto_cipher.h"
Ronald Cron46f91782021-03-17 08:16:34 +010028
29#include "mbedtls/ccm.h"
30#include "mbedtls/chachapoly.h"
31#include "mbedtls/cipher.h"
32#include "mbedtls/gcm.h"
33
34typedef struct
35{
Gilles Peskinef5d7eef2021-11-08 22:12:47 +010036 psa_algorithm_t core_alg;
37 uint8_t tag_length;
Ronald Cron46f91782021-03-17 08:16:34 +010038 union
39 {
40 unsigned dummy; /* Make the union non-empty even with no supported algorithms. */
41#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
42 mbedtls_ccm_context ccm;
43#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
44#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
45 mbedtls_gcm_context gcm;
46#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
47#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
48 mbedtls_chachapoly_context chachapoly;
49#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
50 } ctx;
Ronald Cron46f91782021-03-17 08:16:34 +010051} aead_operation_t;
52
Gilles Peskinef5d7eef2021-11-08 22:12:47 +010053#define AEAD_OPERATION_INIT {0, 0, {0}}
Ronald Cron46f91782021-03-17 08:16:34 +010054
55static void psa_aead_abort_internal( aead_operation_t *operation )
56{
57 switch( operation->core_alg )
58 {
59#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
60 case PSA_ALG_CCM:
61 mbedtls_ccm_free( &operation->ctx.ccm );
62 break;
63#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
64#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
65 case PSA_ALG_GCM:
66 mbedtls_gcm_free( &operation->ctx.gcm );
67 break;
68#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cronb9349a62021-03-26 13:32:29 +010069#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
70 case PSA_ALG_CHACHA20_POLY1305:
71 mbedtls_chachapoly_free( &operation->ctx.chachapoly );
72 break;
73#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
Ronald Cron46f91782021-03-17 08:16:34 +010074 }
75}
76
77static psa_status_t psa_aead_setup(
78 aead_operation_t *operation,
79 const psa_key_attributes_t *attributes,
80 const uint8_t *key_buffer,
81 psa_algorithm_t alg )
82{
83 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
84 size_t key_bits;
Ronald Cronecbc0682021-03-26 13:25:17 +010085 const mbedtls_cipher_info_t *cipher_info;
Ronald Cron46f91782021-03-17 08:16:34 +010086 mbedtls_cipher_id_t cipher_id;
Ronald Cronecbc0682021-03-26 13:25:17 +010087 size_t full_tag_length = 0;
Ronald Cron46f91782021-03-17 08:16:34 +010088
89 key_bits = attributes->core.bits;
90
Ronald Cronecbc0682021-03-26 13:25:17 +010091 cipher_info = mbedtls_cipher_info_from_psa( alg,
92 attributes->core.type, key_bits,
93 &cipher_id );
94 if( cipher_info == NULL )
Ronald Cron46f91782021-03-17 08:16:34 +010095 return( PSA_ERROR_NOT_SUPPORTED );
96
97 switch( PSA_ALG_AEAD_WITH_SHORTENED_TAG( alg, 0 ) )
98 {
99#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
100 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, 0 ):
101 operation->core_alg = PSA_ALG_CCM;
Ronald Cronecbc0682021-03-26 13:25:17 +0100102 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +0100103 /* CCM allows the following tag lengths: 4, 6, 8, 10, 12, 14, 16.
104 * The call to mbedtls_ccm_encrypt_and_tag or
105 * mbedtls_ccm_auth_decrypt will validate the tag length. */
106 if( PSA_BLOCK_CIPHER_BLOCK_LENGTH( attributes->core.type ) != 16 )
107 return( PSA_ERROR_INVALID_ARGUMENT );
108
109 mbedtls_ccm_init( &operation->ctx.ccm );
110 status = mbedtls_to_psa_error(
111 mbedtls_ccm_setkey( &operation->ctx.ccm, cipher_id,
112 key_buffer, (unsigned int) key_bits ) );
113 if( status != PSA_SUCCESS )
114 return( status );
115 break;
116#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
117
118#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
119 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_GCM, 0 ):
120 operation->core_alg = PSA_ALG_GCM;
Ronald Cronecbc0682021-03-26 13:25:17 +0100121 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +0100122 /* GCM allows the following tag lengths: 4, 8, 12, 13, 14, 15, 16.
123 * The call to mbedtls_gcm_crypt_and_tag or
124 * mbedtls_gcm_auth_decrypt will validate the tag length. */
125 if( PSA_BLOCK_CIPHER_BLOCK_LENGTH( attributes->core.type ) != 16 )
126 return( PSA_ERROR_INVALID_ARGUMENT );
127
128 mbedtls_gcm_init( &operation->ctx.gcm );
129 status = mbedtls_to_psa_error(
130 mbedtls_gcm_setkey( &operation->ctx.gcm, cipher_id,
131 key_buffer, (unsigned int) key_bits ) );
132 if( status != PSA_SUCCESS )
133 return( status );
134 break;
135#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
136
137#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
138 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CHACHA20_POLY1305, 0 ):
139 operation->core_alg = PSA_ALG_CHACHA20_POLY1305;
Ronald Cronecbc0682021-03-26 13:25:17 +0100140 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +0100141 /* We only support the default tag length. */
142 if( alg != PSA_ALG_CHACHA20_POLY1305 )
143 return( PSA_ERROR_NOT_SUPPORTED );
144
145 mbedtls_chachapoly_init( &operation->ctx.chachapoly );
146 status = mbedtls_to_psa_error(
147 mbedtls_chachapoly_setkey( &operation->ctx.chachapoly,
148 key_buffer ) );
149 if( status != PSA_SUCCESS )
150 return( status );
151 break;
152#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
153
154 default:
Ronald Cron485559e2021-04-28 14:29:00 +0200155 (void) status;
156 (void) key_buffer;
Ronald Cron46f91782021-03-17 08:16:34 +0100157 return( PSA_ERROR_NOT_SUPPORTED );
158 }
159
Bence Szépkútiec174e22021-03-19 18:46:15 +0100160 if( PSA_AEAD_TAG_LENGTH( attributes->core.type,
161 key_bits, alg )
162 > full_tag_length )
Ronald Cron46f91782021-03-17 08:16:34 +0100163 return( PSA_ERROR_INVALID_ARGUMENT );
164
Bence Szépkútiec174e22021-03-19 18:46:15 +0100165 operation->tag_length = PSA_AEAD_TAG_LENGTH( attributes->core.type,
166 key_bits,
167 alg );
Ronald Cron46f91782021-03-17 08:16:34 +0100168
169 return( PSA_SUCCESS );
170}
171
172psa_status_t mbedtls_psa_aead_encrypt(
173 const psa_key_attributes_t *attributes,
174 const uint8_t *key_buffer, size_t key_buffer_size,
175 psa_algorithm_t alg,
176 const uint8_t *nonce, size_t nonce_length,
177 const uint8_t *additional_data, size_t additional_data_length,
178 const uint8_t *plaintext, size_t plaintext_length,
179 uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length )
180{
181 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
182 aead_operation_t operation = AEAD_OPERATION_INIT;
183 uint8_t *tag;
184 (void) key_buffer_size;
185
186 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
187 if( status != PSA_SUCCESS )
188 goto exit;
189
190 /* For all currently supported modes, the tag is at the end of the
191 * ciphertext. */
192 if( ciphertext_size < ( plaintext_length + operation.tag_length ) )
193 {
194 status = PSA_ERROR_BUFFER_TOO_SMALL;
195 goto exit;
196 }
197 tag = ciphertext + plaintext_length;
198
Ronald Cron46f91782021-03-17 08:16:34 +0100199#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
200 if( operation.core_alg == PSA_ALG_CCM )
201 {
202 status = mbedtls_to_psa_error(
203 mbedtls_ccm_encrypt_and_tag( &operation.ctx.ccm,
204 plaintext_length,
205 nonce, nonce_length,
206 additional_data,
207 additional_data_length,
208 plaintext, ciphertext,
209 tag, operation.tag_length ) );
210 }
211 else
212#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
Ronald Cron810eb162021-04-06 09:01:39 +0200213#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
214 if( operation.core_alg == PSA_ALG_GCM )
215 {
216 status = mbedtls_to_psa_error(
217 mbedtls_gcm_crypt_and_tag( &operation.ctx.gcm,
218 MBEDTLS_GCM_ENCRYPT,
219 plaintext_length,
220 nonce, nonce_length,
221 additional_data, additional_data_length,
222 plaintext, ciphertext,
223 operation.tag_length, tag ) );
224 }
225 else
226#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cron46f91782021-03-17 08:16:34 +0100227#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
228 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
229 {
Bence Szépkúti358e0ea2021-11-17 14:03:08 +0100230 if( nonce_length != 12 )
231 {
232 if( nonce_length == 8 )
233 status = PSA_ERROR_NOT_SUPPORTED;
234 else
235 status = PSA_ERROR_INVALID_ARGUMENT;
236 goto exit;
237 }
238
239 if( operation.tag_length != 16 )
Ronald Cron46f91782021-03-17 08:16:34 +0100240 {
241 status = PSA_ERROR_NOT_SUPPORTED;
242 goto exit;
243 }
244 status = mbedtls_to_psa_error(
245 mbedtls_chachapoly_encrypt_and_tag( &operation.ctx.chachapoly,
246 plaintext_length,
247 nonce,
248 additional_data,
249 additional_data_length,
250 plaintext,
251 ciphertext,
252 tag ) );
253 }
254 else
255#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
256 {
257 (void) tag;
Ronald Cron485559e2021-04-28 14:29:00 +0200258 (void) nonce;
259 (void) nonce_length;
260 (void) additional_data;
261 (void) additional_data_length;
262 (void) plaintext;
Ronald Cron46f91782021-03-17 08:16:34 +0100263 return( PSA_ERROR_NOT_SUPPORTED );
264 }
265
266 if( status == PSA_SUCCESS )
267 *ciphertext_length = plaintext_length + operation.tag_length;
268
269exit:
270 psa_aead_abort_internal( &operation );
271
272 return( status );
273}
274
275/* Locate the tag in a ciphertext buffer containing the encrypted data
276 * followed by the tag. Return the length of the part preceding the tag in
277 * *plaintext_length. This is the size of the plaintext in modes where
278 * the encrypted data has the same size as the plaintext, such as
279 * CCM and GCM. */
280static psa_status_t psa_aead_unpadded_locate_tag( size_t tag_length,
281 const uint8_t *ciphertext,
282 size_t ciphertext_length,
283 size_t plaintext_size,
284 const uint8_t **p_tag )
285{
286 size_t payload_length;
287 if( tag_length > ciphertext_length )
288 return( PSA_ERROR_INVALID_ARGUMENT );
289 payload_length = ciphertext_length - tag_length;
290 if( payload_length > plaintext_size )
291 return( PSA_ERROR_BUFFER_TOO_SMALL );
292 *p_tag = ciphertext + payload_length;
293 return( PSA_SUCCESS );
294}
295
296psa_status_t mbedtls_psa_aead_decrypt(
297 const psa_key_attributes_t *attributes,
298 const uint8_t *key_buffer, size_t key_buffer_size,
299 psa_algorithm_t alg,
300 const uint8_t *nonce, size_t nonce_length,
301 const uint8_t *additional_data, size_t additional_data_length,
302 const uint8_t *ciphertext, size_t ciphertext_length,
303 uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length )
304{
305 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
306 aead_operation_t operation = AEAD_OPERATION_INIT;
307 const uint8_t *tag = NULL;
308 (void) key_buffer_size;
309
310 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
311 if( status != PSA_SUCCESS )
312 goto exit;
313
314 status = psa_aead_unpadded_locate_tag( operation.tag_length,
315 ciphertext, ciphertext_length,
316 plaintext_size, &tag );
317 if( status != PSA_SUCCESS )
318 goto exit;
319
Ronald Cron46f91782021-03-17 08:16:34 +0100320#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
321 if( operation.core_alg == PSA_ALG_CCM )
322 {
323 status = mbedtls_to_psa_error(
324 mbedtls_ccm_auth_decrypt( &operation.ctx.ccm,
325 ciphertext_length - operation.tag_length,
326 nonce, nonce_length,
327 additional_data,
328 additional_data_length,
329 ciphertext, plaintext,
330 tag, operation.tag_length ) );
331 }
332 else
333#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
Ronald Cron810eb162021-04-06 09:01:39 +0200334#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
335 if( operation.core_alg == PSA_ALG_GCM )
336 {
337 status = mbedtls_to_psa_error(
338 mbedtls_gcm_auth_decrypt( &operation.ctx.gcm,
339 ciphertext_length - operation.tag_length,
340 nonce, nonce_length,
341 additional_data,
342 additional_data_length,
343 tag, operation.tag_length,
344 ciphertext, plaintext ) );
345 }
346 else
347#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cron46f91782021-03-17 08:16:34 +0100348#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
349 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
350 {
Bence Szépkúti358e0ea2021-11-17 14:03:08 +0100351 if( nonce_length != 12 )
352 {
353 if( nonce_length == 8 )
354 status = PSA_ERROR_NOT_SUPPORTED;
355 else
356 status = PSA_ERROR_INVALID_ARGUMENT;
357 goto exit;
358 }
359
360 if( operation.tag_length != 16 )
Ronald Cron46f91782021-03-17 08:16:34 +0100361 {
362 status = PSA_ERROR_NOT_SUPPORTED;
363 goto exit;
364 }
365 status = mbedtls_to_psa_error(
366 mbedtls_chachapoly_auth_decrypt( &operation.ctx.chachapoly,
367 ciphertext_length - operation.tag_length,
368 nonce,
369 additional_data,
370 additional_data_length,
371 tag,
372 ciphertext,
373 plaintext ) );
374 }
375 else
376#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
377 {
Ronald Cron485559e2021-04-28 14:29:00 +0200378 (void) nonce;
379 (void) nonce_length;
380 (void) additional_data;
381 (void) additional_data_length;
382 (void) plaintext;
Ronald Cron46f91782021-03-17 08:16:34 +0100383 return( PSA_ERROR_NOT_SUPPORTED );
384 }
385
386 if( status == PSA_SUCCESS )
387 *plaintext_length = ciphertext_length - operation.tag_length;
388
389exit:
390 psa_aead_abort_internal( &operation );
391
392 if( status == PSA_SUCCESS )
393 *plaintext_length = ciphertext_length - operation.tag_length;
394 return( status );
395}
Ronald Cron7ceee8d2021-03-17 16:55:43 +0100396
397#endif /* MBEDTLS_PSA_CRYPTO_C */
398