blob: 2769028d0bdd1ebf94a231ab77f89964a2fbcfd8 [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{
Gilles Peskinef5d7eef2021-11-08 22:12:47 +010035 psa_algorithm_t core_alg;
36 uint8_t tag_length;
Ronald Cron46f91782021-03-17 08:16:34 +010037 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;
Ronald Cron46f91782021-03-17 08:16:34 +010050} aead_operation_t;
51
Gilles Peskinef5d7eef2021-11-08 22:12:47 +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 {
227 if( nonce_length != 12 || operation.tag_length != 16 )
228 {
229 status = PSA_ERROR_NOT_SUPPORTED;
230 goto exit;
231 }
232 status = mbedtls_to_psa_error(
233 mbedtls_chachapoly_encrypt_and_tag( &operation.ctx.chachapoly,
234 plaintext_length,
235 nonce,
236 additional_data,
237 additional_data_length,
238 plaintext,
239 ciphertext,
240 tag ) );
241 }
242 else
243#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
244 {
245 (void) tag;
246 return( PSA_ERROR_NOT_SUPPORTED );
247 }
248
249 if( status == PSA_SUCCESS )
250 *ciphertext_length = plaintext_length + operation.tag_length;
251
252exit:
253 psa_aead_abort_internal( &operation );
254
255 return( status );
256}
257
258/* Locate the tag in a ciphertext buffer containing the encrypted data
259 * followed by the tag. Return the length of the part preceding the tag in
260 * *plaintext_length. This is the size of the plaintext in modes where
261 * the encrypted data has the same size as the plaintext, such as
262 * CCM and GCM. */
263static psa_status_t psa_aead_unpadded_locate_tag( size_t tag_length,
264 const uint8_t *ciphertext,
265 size_t ciphertext_length,
266 size_t plaintext_size,
267 const uint8_t **p_tag )
268{
269 size_t payload_length;
270 if( tag_length > ciphertext_length )
271 return( PSA_ERROR_INVALID_ARGUMENT );
272 payload_length = ciphertext_length - tag_length;
273 if( payload_length > plaintext_size )
274 return( PSA_ERROR_BUFFER_TOO_SMALL );
275 *p_tag = ciphertext + payload_length;
276 return( PSA_SUCCESS );
277}
278
279psa_status_t mbedtls_psa_aead_decrypt(
280 const psa_key_attributes_t *attributes,
281 const uint8_t *key_buffer, size_t key_buffer_size,
282 psa_algorithm_t alg,
283 const uint8_t *nonce, size_t nonce_length,
284 const uint8_t *additional_data, size_t additional_data_length,
285 const uint8_t *ciphertext, size_t ciphertext_length,
286 uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length )
287{
288 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
289 aead_operation_t operation = AEAD_OPERATION_INIT;
290 const uint8_t *tag = NULL;
291 (void) key_buffer_size;
292
293 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
294 if( status != PSA_SUCCESS )
295 goto exit;
296
297 status = psa_aead_unpadded_locate_tag( operation.tag_length,
298 ciphertext, ciphertext_length,
299 plaintext_size, &tag );
300 if( status != PSA_SUCCESS )
301 goto exit;
302
Ronald Cron46f91782021-03-17 08:16:34 +0100303#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
304 if( operation.core_alg == PSA_ALG_CCM )
305 {
306 status = mbedtls_to_psa_error(
307 mbedtls_ccm_auth_decrypt( &operation.ctx.ccm,
308 ciphertext_length - operation.tag_length,
309 nonce, nonce_length,
310 additional_data,
311 additional_data_length,
312 ciphertext, plaintext,
313 tag, operation.tag_length ) );
314 }
315 else
316#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
Ronald Cron810eb162021-04-06 09:01:39 +0200317#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
318 if( operation.core_alg == PSA_ALG_GCM )
319 {
320 status = mbedtls_to_psa_error(
321 mbedtls_gcm_auth_decrypt( &operation.ctx.gcm,
322 ciphertext_length - operation.tag_length,
323 nonce, nonce_length,
324 additional_data,
325 additional_data_length,
326 tag, operation.tag_length,
327 ciphertext, plaintext ) );
328 }
329 else
330#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cron46f91782021-03-17 08:16:34 +0100331#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
332 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
333 {
334 if( nonce_length != 12 || operation.tag_length != 16 )
335 {
336 status = PSA_ERROR_NOT_SUPPORTED;
337 goto exit;
338 }
339 status = mbedtls_to_psa_error(
340 mbedtls_chachapoly_auth_decrypt( &operation.ctx.chachapoly,
341 ciphertext_length - operation.tag_length,
342 nonce,
343 additional_data,
344 additional_data_length,
345 tag,
346 ciphertext,
347 plaintext ) );
348 }
349 else
350#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
351 {
352 return( PSA_ERROR_NOT_SUPPORTED );
353 }
354
355 if( status == PSA_SUCCESS )
356 *plaintext_length = ciphertext_length - operation.tag_length;
357
358exit:
359 psa_aead_abort_internal( &operation );
360
361 if( status == PSA_SUCCESS )
362 *plaintext_length = ciphertext_length - operation.tag_length;
363 return( status );
364}
Ronald Cron7ceee8d2021-03-17 16:55:43 +0100365
366#endif /* MBEDTLS_PSA_CRYPTO_C */
367