blob: 005dd33207c25ab3187c7c10b511e3006e9c1b19 [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
Ronald Cronecbc0682021-03-26 13:25:17 +0100157 if( PSA_AEAD_TAG_LENGTH( alg ) > full_tag_length )
Ronald Cron46f91782021-03-17 08:16:34 +0100158 return( PSA_ERROR_INVALID_ARGUMENT );
159
160 operation->tag_length = PSA_AEAD_TAG_LENGTH( alg );
161
162 return( PSA_SUCCESS );
163}
164
165psa_status_t mbedtls_psa_aead_encrypt(
166 const psa_key_attributes_t *attributes,
167 const uint8_t *key_buffer, size_t key_buffer_size,
168 psa_algorithm_t alg,
169 const uint8_t *nonce, size_t nonce_length,
170 const uint8_t *additional_data, size_t additional_data_length,
171 const uint8_t *plaintext, size_t plaintext_length,
172 uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length )
173{
174 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
175 aead_operation_t operation = AEAD_OPERATION_INIT;
176 uint8_t *tag;
177 (void) key_buffer_size;
178
179 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
180 if( status != PSA_SUCCESS )
181 goto exit;
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 {
187 status = PSA_ERROR_BUFFER_TOO_SMALL;
188 goto exit;
189 }
190 tag = ciphertext + plaintext_length;
191
192#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
193 if( operation.core_alg == PSA_ALG_GCM )
194 {
195 status = mbedtls_to_psa_error(
196 mbedtls_gcm_crypt_and_tag( &operation.ctx.gcm,
197 MBEDTLS_GCM_ENCRYPT,
198 plaintext_length,
199 nonce, nonce_length,
200 additional_data, additional_data_length,
201 plaintext, ciphertext,
202 operation.tag_length, tag ) );
203 }
204 else
205#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
206#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
207 if( operation.core_alg == PSA_ALG_CCM )
208 {
209 status = mbedtls_to_psa_error(
210 mbedtls_ccm_encrypt_and_tag( &operation.ctx.ccm,
211 plaintext_length,
212 nonce, nonce_length,
213 additional_data,
214 additional_data_length,
215 plaintext, ciphertext,
216 tag, operation.tag_length ) );
217 }
218 else
219#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
220#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
221 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
222 {
223 if( nonce_length != 12 || operation.tag_length != 16 )
224 {
225 status = PSA_ERROR_NOT_SUPPORTED;
226 goto exit;
227 }
228 status = mbedtls_to_psa_error(
229 mbedtls_chachapoly_encrypt_and_tag( &operation.ctx.chachapoly,
230 plaintext_length,
231 nonce,
232 additional_data,
233 additional_data_length,
234 plaintext,
235 ciphertext,
236 tag ) );
237 }
238 else
239#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
240 {
241 (void) tag;
242 return( PSA_ERROR_NOT_SUPPORTED );
243 }
244
245 if( status == PSA_SUCCESS )
246 *ciphertext_length = plaintext_length + operation.tag_length;
247
248exit:
249 psa_aead_abort_internal( &operation );
250
251 return( status );
252}
253
254/* Locate the tag in a ciphertext buffer containing the encrypted data
255 * followed by the tag. Return the length of the part preceding the tag in
256 * *plaintext_length. This is the size of the plaintext in modes where
257 * the encrypted data has the same size as the plaintext, such as
258 * CCM and GCM. */
259static psa_status_t psa_aead_unpadded_locate_tag( size_t tag_length,
260 const uint8_t *ciphertext,
261 size_t ciphertext_length,
262 size_t plaintext_size,
263 const uint8_t **p_tag )
264{
265 size_t payload_length;
266 if( tag_length > ciphertext_length )
267 return( PSA_ERROR_INVALID_ARGUMENT );
268 payload_length = ciphertext_length - tag_length;
269 if( payload_length > plaintext_size )
270 return( PSA_ERROR_BUFFER_TOO_SMALL );
271 *p_tag = ciphertext + payload_length;
272 return( PSA_SUCCESS );
273}
274
275psa_status_t mbedtls_psa_aead_decrypt(
276 const psa_key_attributes_t *attributes,
277 const uint8_t *key_buffer, size_t key_buffer_size,
278 psa_algorithm_t alg,
279 const uint8_t *nonce, size_t nonce_length,
280 const uint8_t *additional_data, size_t additional_data_length,
281 const uint8_t *ciphertext, size_t ciphertext_length,
282 uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length )
283{
284 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
285 aead_operation_t operation = AEAD_OPERATION_INIT;
286 const uint8_t *tag = NULL;
287 (void) key_buffer_size;
288
289 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
290 if( status != PSA_SUCCESS )
291 goto exit;
292
293 status = psa_aead_unpadded_locate_tag( operation.tag_length,
294 ciphertext, ciphertext_length,
295 plaintext_size, &tag );
296 if( status != PSA_SUCCESS )
297 goto exit;
298
299#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
300 if( operation.core_alg == PSA_ALG_GCM )
301 {
302 status = mbedtls_to_psa_error(
303 mbedtls_gcm_auth_decrypt( &operation.ctx.gcm,
304 ciphertext_length - operation.tag_length,
305 nonce, nonce_length,
306 additional_data,
307 additional_data_length,
308 tag, operation.tag_length,
309 ciphertext, plaintext ) );
310 }
311 else
312#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
313#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
314 if( operation.core_alg == PSA_ALG_CCM )
315 {
316 status = mbedtls_to_psa_error(
317 mbedtls_ccm_auth_decrypt( &operation.ctx.ccm,
318 ciphertext_length - operation.tag_length,
319 nonce, nonce_length,
320 additional_data,
321 additional_data_length,
322 ciphertext, plaintext,
323 tag, operation.tag_length ) );
324 }
325 else
326#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
327#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
328 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
329 {
330 if( nonce_length != 12 || operation.tag_length != 16 )
331 {
332 status = PSA_ERROR_NOT_SUPPORTED;
333 goto exit;
334 }
335 status = mbedtls_to_psa_error(
336 mbedtls_chachapoly_auth_decrypt( &operation.ctx.chachapoly,
337 ciphertext_length - operation.tag_length,
338 nonce,
339 additional_data,
340 additional_data_length,
341 tag,
342 ciphertext,
343 plaintext ) );
344 }
345 else
346#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
347 {
348 return( PSA_ERROR_NOT_SUPPORTED );
349 }
350
351 if( status == PSA_SUCCESS )
352 *plaintext_length = ciphertext_length - operation.tag_length;
353
354exit:
355 psa_aead_abort_internal( &operation );
356
357 if( status == PSA_SUCCESS )
358 *plaintext_length = ciphertext_length - operation.tag_length;
359 return( status );
360}
Ronald Cron7ceee8d2021-03-17 16:55:43 +0100361
362#endif /* MBEDTLS_PSA_CRYPTO_C */
363