blob: 99f2e4d3ae371f291e092ac4eec03e48382a5bdc [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:
154 return( PSA_ERROR_NOT_SUPPORTED );
155 }
156
Bence Szépkútiec174e22021-03-19 18:46:15 +0100157 if( PSA_AEAD_TAG_LENGTH( attributes->core.type,
158 key_bits, alg )
159 > full_tag_length )
Ronald Cron46f91782021-03-17 08:16:34 +0100160 return( PSA_ERROR_INVALID_ARGUMENT );
161
Bence Szépkútiec174e22021-03-19 18:46:15 +0100162 operation->tag_length = PSA_AEAD_TAG_LENGTH( attributes->core.type,
163 key_bits,
164 alg );
Ronald Cron46f91782021-03-17 08:16:34 +0100165
166 return( PSA_SUCCESS );
167}
168
169psa_status_t mbedtls_psa_aead_encrypt(
170 const psa_key_attributes_t *attributes,
171 const uint8_t *key_buffer, size_t key_buffer_size,
172 psa_algorithm_t alg,
173 const uint8_t *nonce, size_t nonce_length,
174 const uint8_t *additional_data, size_t additional_data_length,
175 const uint8_t *plaintext, size_t plaintext_length,
176 uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length )
177{
178 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
179 aead_operation_t operation = AEAD_OPERATION_INIT;
180 uint8_t *tag;
181 (void) key_buffer_size;
182
183 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
184 if( status != PSA_SUCCESS )
185 goto exit;
186
187 /* For all currently supported modes, the tag is at the end of the
188 * ciphertext. */
189 if( ciphertext_size < ( plaintext_length + operation.tag_length ) )
190 {
191 status = PSA_ERROR_BUFFER_TOO_SMALL;
192 goto exit;
193 }
194 tag = ciphertext + plaintext_length;
195
Ronald Cron46f91782021-03-17 08:16:34 +0100196#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
197 if( operation.core_alg == PSA_ALG_CCM )
198 {
199 status = mbedtls_to_psa_error(
200 mbedtls_ccm_encrypt_and_tag( &operation.ctx.ccm,
201 plaintext_length,
202 nonce, nonce_length,
203 additional_data,
204 additional_data_length,
205 plaintext, ciphertext,
206 tag, operation.tag_length ) );
207 }
208 else
209#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
Ronald Cron810eb162021-04-06 09:01:39 +0200210#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
211 if( operation.core_alg == PSA_ALG_GCM )
212 {
213 status = mbedtls_to_psa_error(
214 mbedtls_gcm_crypt_and_tag( &operation.ctx.gcm,
215 MBEDTLS_GCM_ENCRYPT,
216 plaintext_length,
217 nonce, nonce_length,
218 additional_data, additional_data_length,
219 plaintext, ciphertext,
220 operation.tag_length, tag ) );
221 }
222 else
223#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cron46f91782021-03-17 08:16:34 +0100224#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
225 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
226 {
Bence Szépkúti358e0ea2021-11-17 14:03:08 +0100227 if( nonce_length != 12 )
228 {
229 if( nonce_length == 8 )
230 status = PSA_ERROR_NOT_SUPPORTED;
231 else
232 status = PSA_ERROR_INVALID_ARGUMENT;
233 goto exit;
234 }
235
236 if( operation.tag_length != 16 )
Ronald Cron46f91782021-03-17 08:16:34 +0100237 {
238 status = PSA_ERROR_NOT_SUPPORTED;
239 goto exit;
240 }
241 status = mbedtls_to_psa_error(
242 mbedtls_chachapoly_encrypt_and_tag( &operation.ctx.chachapoly,
243 plaintext_length,
244 nonce,
245 additional_data,
246 additional_data_length,
247 plaintext,
248 ciphertext,
249 tag ) );
250 }
251 else
252#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
253 {
254 (void) tag;
255 return( PSA_ERROR_NOT_SUPPORTED );
256 }
257
258 if( status == PSA_SUCCESS )
259 *ciphertext_length = plaintext_length + operation.tag_length;
260
261exit:
262 psa_aead_abort_internal( &operation );
263
264 return( status );
265}
266
267/* Locate the tag in a ciphertext buffer containing the encrypted data
268 * followed by the tag. Return the length of the part preceding the tag in
269 * *plaintext_length. This is the size of the plaintext in modes where
270 * the encrypted data has the same size as the plaintext, such as
271 * CCM and GCM. */
272static psa_status_t psa_aead_unpadded_locate_tag( size_t tag_length,
273 const uint8_t *ciphertext,
274 size_t ciphertext_length,
275 size_t plaintext_size,
276 const uint8_t **p_tag )
277{
278 size_t payload_length;
279 if( tag_length > ciphertext_length )
280 return( PSA_ERROR_INVALID_ARGUMENT );
281 payload_length = ciphertext_length - tag_length;
282 if( payload_length > plaintext_size )
283 return( PSA_ERROR_BUFFER_TOO_SMALL );
284 *p_tag = ciphertext + payload_length;
285 return( PSA_SUCCESS );
286}
287
288psa_status_t mbedtls_psa_aead_decrypt(
289 const psa_key_attributes_t *attributes,
290 const uint8_t *key_buffer, size_t key_buffer_size,
291 psa_algorithm_t alg,
292 const uint8_t *nonce, size_t nonce_length,
293 const uint8_t *additional_data, size_t additional_data_length,
294 const uint8_t *ciphertext, size_t ciphertext_length,
295 uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length )
296{
297 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
298 aead_operation_t operation = AEAD_OPERATION_INIT;
299 const uint8_t *tag = NULL;
300 (void) key_buffer_size;
301
302 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
303 if( status != PSA_SUCCESS )
304 goto exit;
305
306 status = psa_aead_unpadded_locate_tag( operation.tag_length,
307 ciphertext, ciphertext_length,
308 plaintext_size, &tag );
309 if( status != PSA_SUCCESS )
310 goto exit;
311
Ronald Cron46f91782021-03-17 08:16:34 +0100312#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
313 if( operation.core_alg == PSA_ALG_CCM )
314 {
315 status = mbedtls_to_psa_error(
316 mbedtls_ccm_auth_decrypt( &operation.ctx.ccm,
317 ciphertext_length - operation.tag_length,
318 nonce, nonce_length,
319 additional_data,
320 additional_data_length,
321 ciphertext, plaintext,
322 tag, operation.tag_length ) );
323 }
324 else
325#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
Ronald Cron810eb162021-04-06 09:01:39 +0200326#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
327 if( operation.core_alg == PSA_ALG_GCM )
328 {
329 status = mbedtls_to_psa_error(
330 mbedtls_gcm_auth_decrypt( &operation.ctx.gcm,
331 ciphertext_length - operation.tag_length,
332 nonce, nonce_length,
333 additional_data,
334 additional_data_length,
335 tag, operation.tag_length,
336 ciphertext, plaintext ) );
337 }
338 else
339#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cron46f91782021-03-17 08:16:34 +0100340#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
341 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
342 {
Bence Szépkúti358e0ea2021-11-17 14:03:08 +0100343 if( nonce_length != 12 )
344 {
345 if( nonce_length == 8 )
346 status = PSA_ERROR_NOT_SUPPORTED;
347 else
348 status = PSA_ERROR_INVALID_ARGUMENT;
349 goto exit;
350 }
351
352 if( operation.tag_length != 16 )
Ronald Cron46f91782021-03-17 08:16:34 +0100353 {
354 status = PSA_ERROR_NOT_SUPPORTED;
355 goto exit;
356 }
357 status = mbedtls_to_psa_error(
358 mbedtls_chachapoly_auth_decrypt( &operation.ctx.chachapoly,
359 ciphertext_length - operation.tag_length,
360 nonce,
361 additional_data,
362 additional_data_length,
363 tag,
364 ciphertext,
365 plaintext ) );
366 }
367 else
368#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
369 {
370 return( PSA_ERROR_NOT_SUPPORTED );
371 }
372
373 if( status == PSA_SUCCESS )
374 *plaintext_length = ciphertext_length - operation.tag_length;
375
376exit:
377 psa_aead_abort_internal( &operation );
378
379 if( status == PSA_SUCCESS )
380 *plaintext_length = ciphertext_length - operation.tag_length;
381 return( status );
382}
Ronald Cron7ceee8d2021-03-17 16:55:43 +0100383
384#endif /* MBEDTLS_PSA_CRYPTO_C */
385