blob: 18ea1766784c13bc4c66e0442e561c6e56df8fa2 [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{
35 const mbedtls_cipher_info_t *cipher_info;
36 union
37 {
38 unsigned dummy; /* Make the union non-empty even with no supported algorithms. */
39#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
40 mbedtls_ccm_context ccm;
41#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
42#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
43 mbedtls_gcm_context gcm;
44#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
45#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
46 mbedtls_chachapoly_context chachapoly;
47#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
48 } ctx;
49 psa_algorithm_t core_alg;
50 uint8_t full_tag_length;
51 uint8_t tag_length;
52} aead_operation_t;
53
54#define AEAD_OPERATION_INIT {0, {0}, 0, 0, 0}
55
56static void psa_aead_abort_internal( aead_operation_t *operation )
57{
58 switch( operation->core_alg )
59 {
60#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
61 case PSA_ALG_CCM:
62 mbedtls_ccm_free( &operation->ctx.ccm );
63 break;
64#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
65#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
66 case PSA_ALG_GCM:
67 mbedtls_gcm_free( &operation->ctx.gcm );
68 break;
69#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
70 }
71}
72
73static psa_status_t psa_aead_setup(
74 aead_operation_t *operation,
75 const psa_key_attributes_t *attributes,
76 const uint8_t *key_buffer,
77 psa_algorithm_t alg )
78{
79 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
80 size_t key_bits;
81 mbedtls_cipher_id_t cipher_id;
82
83 key_bits = attributes->core.bits;
84
85 operation->cipher_info =
86 mbedtls_cipher_info_from_psa( alg, attributes->core.type, key_bits,
87 &cipher_id );
88 if( operation->cipher_info == NULL )
89 return( PSA_ERROR_NOT_SUPPORTED );
90
91 switch( PSA_ALG_AEAD_WITH_SHORTENED_TAG( alg, 0 ) )
92 {
93#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
94 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, 0 ):
95 operation->core_alg = PSA_ALG_CCM;
96 operation->full_tag_length = 16;
97 /* CCM allows the following tag lengths: 4, 6, 8, 10, 12, 14, 16.
98 * The call to mbedtls_ccm_encrypt_and_tag or
99 * mbedtls_ccm_auth_decrypt will validate the tag length. */
100 if( PSA_BLOCK_CIPHER_BLOCK_LENGTH( attributes->core.type ) != 16 )
101 return( PSA_ERROR_INVALID_ARGUMENT );
102
103 mbedtls_ccm_init( &operation->ctx.ccm );
104 status = mbedtls_to_psa_error(
105 mbedtls_ccm_setkey( &operation->ctx.ccm, cipher_id,
106 key_buffer, (unsigned int) key_bits ) );
107 if( status != PSA_SUCCESS )
108 return( status );
109 break;
110#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
111
112#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
113 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_GCM, 0 ):
114 operation->core_alg = PSA_ALG_GCM;
115 operation->full_tag_length = 16;
116 /* GCM allows the following tag lengths: 4, 8, 12, 13, 14, 15, 16.
117 * The call to mbedtls_gcm_crypt_and_tag or
118 * mbedtls_gcm_auth_decrypt will validate the tag length. */
119 if( PSA_BLOCK_CIPHER_BLOCK_LENGTH( attributes->core.type ) != 16 )
120 return( PSA_ERROR_INVALID_ARGUMENT );
121
122 mbedtls_gcm_init( &operation->ctx.gcm );
123 status = mbedtls_to_psa_error(
124 mbedtls_gcm_setkey( &operation->ctx.gcm, cipher_id,
125 key_buffer, (unsigned int) key_bits ) );
126 if( status != PSA_SUCCESS )
127 return( status );
128 break;
129#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
130
131#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
132 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CHACHA20_POLY1305, 0 ):
133 operation->core_alg = PSA_ALG_CHACHA20_POLY1305;
134 operation->full_tag_length = 16;
135 /* We only support the default tag length. */
136 if( alg != PSA_ALG_CHACHA20_POLY1305 )
137 return( PSA_ERROR_NOT_SUPPORTED );
138
139 mbedtls_chachapoly_init( &operation->ctx.chachapoly );
140 status = mbedtls_to_psa_error(
141 mbedtls_chachapoly_setkey( &operation->ctx.chachapoly,
142 key_buffer ) );
143 if( status != PSA_SUCCESS )
144 return( status );
145 break;
146#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
147
148 default:
149 return( PSA_ERROR_NOT_SUPPORTED );
150 }
151
152 if( PSA_AEAD_TAG_LENGTH( alg ) > operation->full_tag_length )
153 return( PSA_ERROR_INVALID_ARGUMENT );
154
155 operation->tag_length = PSA_AEAD_TAG_LENGTH( alg );
156
157 return( PSA_SUCCESS );
158}
159
160psa_status_t mbedtls_psa_aead_encrypt(
161 const psa_key_attributes_t *attributes,
162 const uint8_t *key_buffer, size_t key_buffer_size,
163 psa_algorithm_t alg,
164 const uint8_t *nonce, size_t nonce_length,
165 const uint8_t *additional_data, size_t additional_data_length,
166 const uint8_t *plaintext, size_t plaintext_length,
167 uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length )
168{
169 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
170 aead_operation_t operation = AEAD_OPERATION_INIT;
171 uint8_t *tag;
172 (void) key_buffer_size;
173
174 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
175 if( status != PSA_SUCCESS )
176 goto exit;
177
178 /* For all currently supported modes, the tag is at the end of the
179 * ciphertext. */
180 if( ciphertext_size < ( plaintext_length + operation.tag_length ) )
181 {
182 status = PSA_ERROR_BUFFER_TOO_SMALL;
183 goto exit;
184 }
185 tag = ciphertext + plaintext_length;
186
187#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
188 if( operation.core_alg == PSA_ALG_GCM )
189 {
190 status = mbedtls_to_psa_error(
191 mbedtls_gcm_crypt_and_tag( &operation.ctx.gcm,
192 MBEDTLS_GCM_ENCRYPT,
193 plaintext_length,
194 nonce, nonce_length,
195 additional_data, additional_data_length,
196 plaintext, ciphertext,
197 operation.tag_length, tag ) );
198 }
199 else
200#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
201#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
202 if( operation.core_alg == PSA_ALG_CCM )
203 {
204 status = mbedtls_to_psa_error(
205 mbedtls_ccm_encrypt_and_tag( &operation.ctx.ccm,
206 plaintext_length,
207 nonce, nonce_length,
208 additional_data,
209 additional_data_length,
210 plaintext, ciphertext,
211 tag, operation.tag_length ) );
212 }
213 else
214#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
215#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
216 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
217 {
218 if( nonce_length != 12 || operation.tag_length != 16 )
219 {
220 status = PSA_ERROR_NOT_SUPPORTED;
221 goto exit;
222 }
223 status = mbedtls_to_psa_error(
224 mbedtls_chachapoly_encrypt_and_tag( &operation.ctx.chachapoly,
225 plaintext_length,
226 nonce,
227 additional_data,
228 additional_data_length,
229 plaintext,
230 ciphertext,
231 tag ) );
232 }
233 else
234#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
235 {
236 (void) tag;
237 return( PSA_ERROR_NOT_SUPPORTED );
238 }
239
240 if( status == PSA_SUCCESS )
241 *ciphertext_length = plaintext_length + operation.tag_length;
242
243exit:
244 psa_aead_abort_internal( &operation );
245
246 return( status );
247}
248
249/* Locate the tag in a ciphertext buffer containing the encrypted data
250 * followed by the tag. Return the length of the part preceding the tag in
251 * *plaintext_length. This is the size of the plaintext in modes where
252 * the encrypted data has the same size as the plaintext, such as
253 * CCM and GCM. */
254static psa_status_t psa_aead_unpadded_locate_tag( size_t tag_length,
255 const uint8_t *ciphertext,
256 size_t ciphertext_length,
257 size_t plaintext_size,
258 const uint8_t **p_tag )
259{
260 size_t payload_length;
261 if( tag_length > ciphertext_length )
262 return( PSA_ERROR_INVALID_ARGUMENT );
263 payload_length = ciphertext_length - tag_length;
264 if( payload_length > plaintext_size )
265 return( PSA_ERROR_BUFFER_TOO_SMALL );
266 *p_tag = ciphertext + payload_length;
267 return( PSA_SUCCESS );
268}
269
270psa_status_t mbedtls_psa_aead_decrypt(
271 const psa_key_attributes_t *attributes,
272 const uint8_t *key_buffer, size_t key_buffer_size,
273 psa_algorithm_t alg,
274 const uint8_t *nonce, size_t nonce_length,
275 const uint8_t *additional_data, size_t additional_data_length,
276 const uint8_t *ciphertext, size_t ciphertext_length,
277 uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length )
278{
279 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
280 aead_operation_t operation = AEAD_OPERATION_INIT;
281 const uint8_t *tag = NULL;
282 (void) key_buffer_size;
283
284 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
285 if( status != PSA_SUCCESS )
286 goto exit;
287
288 status = psa_aead_unpadded_locate_tag( operation.tag_length,
289 ciphertext, ciphertext_length,
290 plaintext_size, &tag );
291 if( status != PSA_SUCCESS )
292 goto exit;
293
294#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
295 if( operation.core_alg == PSA_ALG_GCM )
296 {
297 status = mbedtls_to_psa_error(
298 mbedtls_gcm_auth_decrypt( &operation.ctx.gcm,
299 ciphertext_length - operation.tag_length,
300 nonce, nonce_length,
301 additional_data,
302 additional_data_length,
303 tag, operation.tag_length,
304 ciphertext, plaintext ) );
305 }
306 else
307#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
308#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
309 if( operation.core_alg == PSA_ALG_CCM )
310 {
311 status = mbedtls_to_psa_error(
312 mbedtls_ccm_auth_decrypt( &operation.ctx.ccm,
313 ciphertext_length - operation.tag_length,
314 nonce, nonce_length,
315 additional_data,
316 additional_data_length,
317 ciphertext, plaintext,
318 tag, operation.tag_length ) );
319 }
320 else
321#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
322#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
323 if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
324 {
325 if( nonce_length != 12 || operation.tag_length != 16 )
326 {
327 status = PSA_ERROR_NOT_SUPPORTED;
328 goto exit;
329 }
330 status = mbedtls_to_psa_error(
331 mbedtls_chachapoly_auth_decrypt( &operation.ctx.chachapoly,
332 ciphertext_length - operation.tag_length,
333 nonce,
334 additional_data,
335 additional_data_length,
336 tag,
337 ciphertext,
338 plaintext ) );
339 }
340 else
341#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
342 {
343 return( PSA_ERROR_NOT_SUPPORTED );
344 }
345
346 if( status == PSA_SUCCESS )
347 *plaintext_length = ciphertext_length - operation.tag_length;
348
349exit:
350 psa_aead_abort_internal( &operation );
351
352 if( status == PSA_SUCCESS )
353 *plaintext_length = ciphertext_length - operation.tag_length;
354 return( status );
355}
Ronald Cron7ceee8d2021-03-17 16:55:43 +0100356
357#endif /* MBEDTLS_PSA_CRYPTO_C */
358