1 /*
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"
26 #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
33 typedef struct
34 {
35 psa_algorithm_t core_alg;
36 uint8_t tag_length;
37 union
38 {
39 unsigned dummy; /* Make the union non-empty even with no supported algorithms. */
40 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
41 mbedtls_ccm_context ccm;
42 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
43 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
44 mbedtls_gcm_context gcm;
45 #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
46 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
47 mbedtls_chachapoly_context chachapoly;
48 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
49 } ctx;
50 } aead_operation_t;
51
52 #define AEAD_OPERATION_INIT {0, 0, {0}}
53
psa_aead_abort_internal(aead_operation_t * operation)54 static 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 */
68 #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 */
73 }
74 }
75
psa_aead_setup(aead_operation_t * operation,const psa_key_attributes_t * attributes,const uint8_t * key_buffer,psa_algorithm_t alg)76 static 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;
84 const mbedtls_cipher_info_t *cipher_info;
85 mbedtls_cipher_id_t cipher_id;
86 size_t full_tag_length = 0;
87
88 key_bits = attributes->core.bits;
89
90 cipher_info = mbedtls_cipher_info_from_psa( alg,
91 attributes->core.type, key_bits,
92 &cipher_id );
93 if( cipher_info == NULL )
94 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;
101 full_tag_length = 16;
102 /* 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;
120 full_tag_length = 16;
121 /* 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;
139 full_tag_length = 16;
140 /* 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 (void) status;
155 (void) key_buffer;
156 return( PSA_ERROR_NOT_SUPPORTED );
157 }
158
159 if( PSA_AEAD_TAG_LENGTH( attributes->core.type,
160 key_bits, alg )
161 > full_tag_length )
162 return( PSA_ERROR_INVALID_ARGUMENT );
163
164 operation->tag_length = PSA_AEAD_TAG_LENGTH( attributes->core.type,
165 key_bits,
166 alg );
167
168 return( PSA_SUCCESS );
169 }
170
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)171 psa_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
198 #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 */
212 #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 */
226 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
227 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
228 {
229 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 )
239 {
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;
257 (void) nonce;
258 (void) nonce_length;
259 (void) additional_data;
260 (void) additional_data_length;
261 (void) plaintext;
262 return( PSA_ERROR_NOT_SUPPORTED );
263 }
264
265 if( status == PSA_SUCCESS )
266 *ciphertext_length = plaintext_length + operation.tag_length;
267
268 exit:
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. */
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)279 static 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
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)295 psa_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
319 #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 */
333 #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 */
347 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
348 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
349 {
350 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 )
360 {
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 {
377 (void) nonce;
378 (void) nonce_length;
379 (void) additional_data;
380 (void) additional_data_length;
381 (void) plaintext;
382 return( PSA_ERROR_NOT_SUPPORTED );
383 }
384
385 if( status == PSA_SUCCESS )
386 *plaintext_length = ciphertext_length - operation.tag_length;
387
388 exit:
389 psa_aead_abort_internal( &operation );
390
391 if( status == PSA_SUCCESS )
392 *plaintext_length = ciphertext_length - operation.tag_length;
393 return( status );
394 }
395
396 #endif /* MBEDTLS_PSA_CRYPTO_C */
397
398