blob: 91d471b2f1ee9ef599155d9bbc0ed569e8801b89 [file] [log] [blame]
Ronald Cron0ff57952021-03-08 16:46:35 +01001/*
2 * PSA cipher driver 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_cipher.h>
Ronald Crond6d28882020-12-14 14:56:02 +010026#include "psa_crypto_core.h"
Ronald Cron6d051732020-10-01 14:10:20 +020027#include "psa_crypto_random_impl.h"
28
Ronald Crond6d28882020-12-14 14:56:02 +010029#include "mbedtls/cipher.h"
Ronald Cron6d051732020-10-01 14:10:20 +020030#include "mbedtls/error.h"
Ronald Cron0ff57952021-03-08 16:46:35 +010031
Ronald Crond6d28882020-12-14 14:56:02 +010032#include <string.h>
33
34static psa_status_t cipher_setup(
35 psa_cipher_operation_t *operation,
36 const psa_key_attributes_t *attributes,
37 const uint8_t *key_buffer, size_t key_buffer_size,
38 psa_algorithm_t alg,
39 mbedtls_operation_t cipher_operation )
40{
41 int ret = 0;
42 size_t key_bits;
43 const mbedtls_cipher_info_t *cipher_info = NULL;
44 psa_key_type_t key_type = attributes->core.type;
45
46 (void)key_buffer_size;
47
48 /* Proceed with initializing an mbed TLS cipher context if no driver is
49 * available for the given algorithm & key. */
50 mbedtls_cipher_init( &operation->ctx.cipher );
51
52 /* Once the cipher context is initialised, it needs to be freed using
53 * psa_cipher_abort. Indicate there is something to be freed through setting
54 * alg, and indicate the operation is being done using mbedtls crypto through
55 * setting mbedtls_in_use. */
56 operation->alg = alg;
57 operation->mbedtls_in_use = 1;
58
59 key_bits = attributes->core.bits;
60 cipher_info = mbedtls_cipher_info_from_psa( alg, key_type,
61 key_bits, NULL );
62 if( cipher_info == NULL )
63 return( PSA_ERROR_NOT_SUPPORTED );
64
65 ret = mbedtls_cipher_setup( &operation->ctx.cipher, cipher_info );
66 if( ret != 0 )
67 goto exit;
68
69#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DES)
70 if( key_type == PSA_KEY_TYPE_DES && key_bits == 128 )
71 {
72 /* Two-key Triple-DES is 3-key Triple-DES with K1=K3 */
73 uint8_t keys[24];
74 memcpy( keys, key_buffer, 16 );
75 memcpy( keys + 16, key_buffer, 8 );
76 ret = mbedtls_cipher_setkey( &operation->ctx.cipher,
77 keys,
78 192, cipher_operation );
79 }
80 else
81#endif
82 {
83 ret = mbedtls_cipher_setkey( &operation->ctx.cipher, key_buffer,
84 (int) key_bits, cipher_operation );
85 }
86 if( ret != 0 )
87 goto exit;
88
89#if defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING) || \
90 defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7)
91 switch( alg )
92 {
93 case PSA_ALG_CBC_NO_PADDING:
94 ret = mbedtls_cipher_set_padding_mode( &operation->ctx.cipher,
95 MBEDTLS_PADDING_NONE );
96 break;
97 case PSA_ALG_CBC_PKCS7:
98 ret = mbedtls_cipher_set_padding_mode( &operation->ctx.cipher,
99 MBEDTLS_PADDING_PKCS7 );
100 break;
101 default:
102 /* The algorithm doesn't involve padding. */
103 ret = 0;
104 break;
105 }
106 if( ret != 0 )
107 goto exit;
108#endif /* MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING || MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7 */
109
110 operation->block_size = ( PSA_ALG_IS_STREAM_CIPHER( alg ) ? 1 :
111 PSA_BLOCK_CIPHER_BLOCK_LENGTH( key_type ) );
112 if( ( alg & PSA_ALG_CIPHER_FROM_BLOCK_FLAG ) != 0 &&
113 alg != PSA_ALG_ECB_NO_PADDING )
114 {
115 operation->iv_size = PSA_BLOCK_CIPHER_BLOCK_LENGTH( key_type );
116 }
117#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_CHACHA20)
118 else
119 if( ( alg == PSA_ALG_STREAM_CIPHER ) &&
120 ( key_type == PSA_KEY_TYPE_CHACHA20 ) )
121 operation->iv_size = 12;
122#endif
123
124exit:
125 return( mbedtls_to_psa_error( ret ) );
126}
127
128psa_status_t mbedtls_psa_cipher_encrypt_setup(
129 psa_cipher_operation_t *operation,
130 const psa_key_attributes_t *attributes,
131 const uint8_t *key_buffer, size_t key_buffer_size,
132 psa_algorithm_t alg )
133{
134 return( cipher_setup( operation, attributes,
135 key_buffer, key_buffer_size,
136 alg, MBEDTLS_ENCRYPT ) );
137}
138
139psa_status_t mbedtls_psa_cipher_decrypt_setup(
140 psa_cipher_operation_t *operation,
141 const psa_key_attributes_t *attributes,
142 const uint8_t *key_buffer, size_t key_buffer_size,
143 psa_algorithm_t alg )
144{
145 return( cipher_setup( operation, attributes,
146 key_buffer, key_buffer_size,
147 alg, MBEDTLS_DECRYPT ) );
148}
Ronald Cron6d051732020-10-01 14:10:20 +0200149
150psa_status_t mbedtls_psa_cipher_generate_iv(
151 psa_cipher_operation_t *operation,
152 uint8_t *iv, size_t iv_size, size_t *iv_length )
153{
154 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
155
156 if( iv_size < operation->iv_size )
157 return( PSA_ERROR_BUFFER_TOO_SMALL );
158
159 ret = mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
160 iv, operation->iv_size );
161 if( ret != 0 )
162 return( mbedtls_to_psa_error( ret ) );
163
164 *iv_length = operation->iv_size;
165
166 return( mbedtls_psa_cipher_set_iv( operation, iv, *iv_length ) );
167}
168
169psa_status_t mbedtls_psa_cipher_set_iv( psa_cipher_operation_t *operation,
170 const uint8_t *iv,
171 size_t iv_length )
172{
173 if( iv_length != operation->iv_size )
174 return( PSA_ERROR_INVALID_ARGUMENT );
175
176 return( mbedtls_to_psa_error(
177 mbedtls_cipher_set_iv( &operation->ctx.cipher,
178 iv, iv_length ) ) );
179}
180
181/* Process input for which the algorithm is set to ECB mode. This requires
182 * manual processing, since the PSA API is defined as being able to process
183 * arbitrary-length calls to psa_cipher_update() with ECB mode, but the
184 * underlying mbedtls_cipher_update only takes full blocks. */
185static psa_status_t psa_cipher_update_ecb(
186 mbedtls_cipher_context_t *ctx,
187 const uint8_t *input,
188 size_t input_length,
189 uint8_t *output,
190 size_t output_size,
191 size_t *output_length )
192{
193 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
194 size_t block_size = ctx->cipher_info->block_size;
195 size_t internal_output_length = 0;
196 *output_length = 0;
197
198 if( input_length == 0 )
199 {
200 status = PSA_SUCCESS;
201 goto exit;
202 }
203
204 if( ctx->unprocessed_len > 0 )
205 {
206 /* Fill up to block size, and run the block if there's a full one. */
207 size_t bytes_to_copy = block_size - ctx->unprocessed_len;
208
209 if( input_length < bytes_to_copy )
210 bytes_to_copy = input_length;
211
212 memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ),
213 input, bytes_to_copy );
214 input_length -= bytes_to_copy;
215 input += bytes_to_copy;
216 ctx->unprocessed_len += bytes_to_copy;
217
218 if( ctx->unprocessed_len == block_size )
219 {
220 status = mbedtls_to_psa_error(
221 mbedtls_cipher_update( ctx,
222 ctx->unprocessed_data,
223 block_size,
224 output, &internal_output_length ) );
225
226 if( status != PSA_SUCCESS )
227 goto exit;
228
229 output += internal_output_length;
230 output_size -= internal_output_length;
231 *output_length += internal_output_length;
232 ctx->unprocessed_len = 0;
233 }
234 }
235
236 while( input_length >= block_size )
237 {
238 /* Run all full blocks we have, one by one */
239 status = mbedtls_to_psa_error(
240 mbedtls_cipher_update( ctx, input,
241 block_size,
242 output, &internal_output_length ) );
243
244 if( status != PSA_SUCCESS )
245 goto exit;
246
247 input_length -= block_size;
248 input += block_size;
249
250 output += internal_output_length;
251 output_size -= internal_output_length;
252 *output_length += internal_output_length;
253 }
254
255 if( input_length > 0 )
256 {
257 /* Save unprocessed bytes for later processing */
258 memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ),
259 input, input_length );
260 ctx->unprocessed_len += input_length;
261 }
262
263 status = PSA_SUCCESS;
264
265exit:
266 return( status );
267}
268
269psa_status_t mbedtls_psa_cipher_update( psa_cipher_operation_t *operation,
270 const uint8_t *input,
271 size_t input_length,
272 uint8_t *output,
273 size_t output_size,
274 size_t *output_length )
275{
276 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
277 size_t expected_output_size;
278
279 if( ! PSA_ALG_IS_STREAM_CIPHER( operation->alg ) )
280 {
281 /* Take the unprocessed partial block left over from previous
282 * update calls, if any, plus the input to this call. Remove
283 * the last partial block, if any. You get the data that will be
284 * output in this call. */
285 expected_output_size =
286 ( operation->ctx.cipher.unprocessed_len + input_length )
287 / operation->block_size * operation->block_size;
288 }
289 else
290 {
291 expected_output_size = input_length;
292 }
293
294 if( output_size < expected_output_size )
295 return( PSA_ERROR_BUFFER_TOO_SMALL );
296
297 if( operation->alg == PSA_ALG_ECB_NO_PADDING )
298 {
299 /* mbedtls_cipher_update has an API inconsistency: it will only
300 * process a single block at a time in ECB mode. Abstract away that
301 * inconsistency here to match the PSA API behaviour. */
302 status = psa_cipher_update_ecb( &operation->ctx.cipher,
303 input,
304 input_length,
305 output,
306 output_size,
307 output_length );
308 }
309 else
310 {
311 status = mbedtls_to_psa_error(
312 mbedtls_cipher_update( &operation->ctx.cipher, input,
313 input_length, output, output_length ) );
314 }
315
316 return( status );
317}
318
319psa_status_t mbedtls_psa_cipher_finish( psa_cipher_operation_t *operation,
320 uint8_t *output,
321 size_t output_size,
322 size_t *output_length )
323{
324 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
325 uint8_t temp_output_buffer[MBEDTLS_MAX_BLOCK_LENGTH];
326
327 if( operation->ctx.cipher.unprocessed_len != 0 )
328 {
329 if( operation->alg == PSA_ALG_ECB_NO_PADDING ||
330 operation->alg == PSA_ALG_CBC_NO_PADDING )
331 {
332 status = PSA_ERROR_INVALID_ARGUMENT;
333 goto exit;
334 }
335 }
336
337 status = mbedtls_to_psa_error(
338 mbedtls_cipher_finish( &operation->ctx.cipher,
339 temp_output_buffer,
340 output_length ) );
341 if( status != PSA_SUCCESS )
342 goto exit;
343
344 if( *output_length == 0 )
345 ; /* Nothing to copy. Note that output may be NULL in this case. */
346 else if( output_size >= *output_length )
347 memcpy( output, temp_output_buffer, *output_length );
348 else
349 status = PSA_ERROR_BUFFER_TOO_SMALL;
350
351exit:
352 mbedtls_platform_zeroize( temp_output_buffer,
353 sizeof( temp_output_buffer ) );
354
355 return( status );
356}
357
358psa_status_t mbedtls_psa_cipher_abort( psa_cipher_operation_t *operation )
359{
360 mbedtls_cipher_free( &operation->ctx.cipher );
361
362 return( PSA_SUCCESS );
363}
364
Ronald Cron0ff57952021-03-08 16:46:35 +0100365#endif /* MBEDTLS_PSA_CRYPTO_C */