xref: /optee_os/lib/libmbedtls/mbedtls/library/cipher.c (revision 5b25c76ac40f830867e3d60800120ffd7874e8dc)
1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0
2817466cbSJens Wiklander /**
3817466cbSJens Wiklander  * \file cipher.c
4817466cbSJens Wiklander  *
5817466cbSJens Wiklander  * \brief Generic cipher wrapper for mbed TLS
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  * \author Adriaan de Jong <dejong@fox-it.com>
8817466cbSJens Wiklander  *
9817466cbSJens Wiklander  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
12817466cbSJens Wiklander  *  not use this file except in compliance with the License.
13817466cbSJens Wiklander  *  You may obtain a copy of the License at
14817466cbSJens Wiklander  *
15817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
16817466cbSJens Wiklander  *
17817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
18817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
19817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
21817466cbSJens Wiklander  *  limitations under the License.
22817466cbSJens Wiklander  *
23817466cbSJens Wiklander  *  This file is part of mbed TLS (https://tls.mbed.org)
24817466cbSJens Wiklander  */
25817466cbSJens Wiklander 
26817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
27817466cbSJens Wiklander #include "mbedtls/config.h"
28817466cbSJens Wiklander #else
29817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE
30817466cbSJens Wiklander #endif
31817466cbSJens Wiklander 
32817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_C)
33817466cbSJens Wiklander 
34817466cbSJens Wiklander #include "mbedtls/cipher.h"
35817466cbSJens Wiklander #include "mbedtls/cipher_internal.h"
363d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
37817466cbSJens Wiklander 
38817466cbSJens Wiklander #include <stdlib.h>
39817466cbSJens Wiklander #include <string.h>
40817466cbSJens Wiklander 
413d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
423d3b0591SJens Wiklander #include "mbedtls/chachapoly.h"
433d3b0591SJens Wiklander #endif
443d3b0591SJens Wiklander 
45817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C)
46817466cbSJens Wiklander #include "mbedtls/gcm.h"
47817466cbSJens Wiklander #endif
48817466cbSJens Wiklander 
49817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C)
50817466cbSJens Wiklander #include "mbedtls/ccm.h"
51817466cbSJens Wiklander #endif
52817466cbSJens Wiklander 
533d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHA20_C)
543d3b0591SJens Wiklander #include "mbedtls/chacha20.h"
553d3b0591SJens Wiklander #endif
563d3b0591SJens Wiklander 
57817466cbSJens Wiklander #if defined(MBEDTLS_CMAC_C)
58817466cbSJens Wiklander #include "mbedtls/cmac.h"
59817466cbSJens Wiklander #endif
60817466cbSJens Wiklander 
61817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
62817466cbSJens Wiklander #include "mbedtls/platform.h"
63817466cbSJens Wiklander #else
64817466cbSJens Wiklander #define mbedtls_calloc calloc
65817466cbSJens Wiklander #define mbedtls_free   free
66817466cbSJens Wiklander #endif
67817466cbSJens Wiklander 
683d3b0591SJens Wiklander #define CIPHER_VALIDATE_RET( cond )    \
693d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA )
703d3b0591SJens Wiklander #define CIPHER_VALIDATE( cond )        \
713d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE( cond )
72817466cbSJens Wiklander 
733d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
743d3b0591SJens Wiklander /* Compare the contents of two buffers in constant time.
753d3b0591SJens Wiklander  * Returns 0 if the contents are bitwise identical, otherwise returns
763d3b0591SJens Wiklander  * a non-zero value.
773d3b0591SJens Wiklander  * This is currently only used by GCM and ChaCha20+Poly1305.
783d3b0591SJens Wiklander  */
793d3b0591SJens Wiklander static int mbedtls_constant_time_memcmp( const void *v1, const void *v2, size_t len )
803d3b0591SJens Wiklander {
813d3b0591SJens Wiklander     const unsigned char *p1 = (const unsigned char*) v1;
823d3b0591SJens Wiklander     const unsigned char *p2 = (const unsigned char*) v2;
833d3b0591SJens Wiklander     size_t i;
843d3b0591SJens Wiklander     unsigned char diff;
853d3b0591SJens Wiklander 
863d3b0591SJens Wiklander     for( diff = 0, i = 0; i < len; i++ )
873d3b0591SJens Wiklander         diff |= p1[i] ^ p2[i];
883d3b0591SJens Wiklander 
893d3b0591SJens Wiklander     return( (int)diff );
90817466cbSJens Wiklander }
913d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */
92817466cbSJens Wiklander 
93817466cbSJens Wiklander static int supported_init = 0;
94817466cbSJens Wiklander 
95817466cbSJens Wiklander const int *mbedtls_cipher_list( void )
96817466cbSJens Wiklander {
97817466cbSJens Wiklander     const mbedtls_cipher_definition_t *def;
98817466cbSJens Wiklander     int *type;
99817466cbSJens Wiklander 
100817466cbSJens Wiklander     if( ! supported_init )
101817466cbSJens Wiklander     {
102817466cbSJens Wiklander         def = mbedtls_cipher_definitions;
103817466cbSJens Wiklander         type = mbedtls_cipher_supported;
104817466cbSJens Wiklander 
105817466cbSJens Wiklander         while( def->type != 0 )
106817466cbSJens Wiklander             *type++ = (*def++).type;
107817466cbSJens Wiklander 
108817466cbSJens Wiklander         *type = 0;
109817466cbSJens Wiklander 
110817466cbSJens Wiklander         supported_init = 1;
111817466cbSJens Wiklander     }
112817466cbSJens Wiklander 
113817466cbSJens Wiklander     return( mbedtls_cipher_supported );
114817466cbSJens Wiklander }
115817466cbSJens Wiklander 
116817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type )
117817466cbSJens Wiklander {
118817466cbSJens Wiklander     const mbedtls_cipher_definition_t *def;
119817466cbSJens Wiklander 
120817466cbSJens Wiklander     for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
121817466cbSJens Wiklander         if( def->type == cipher_type )
122817466cbSJens Wiklander             return( def->info );
123817466cbSJens Wiklander 
124817466cbSJens Wiklander     return( NULL );
125817466cbSJens Wiklander }
126817466cbSJens Wiklander 
127817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name )
128817466cbSJens Wiklander {
129817466cbSJens Wiklander     const mbedtls_cipher_definition_t *def;
130817466cbSJens Wiklander 
131817466cbSJens Wiklander     if( NULL == cipher_name )
132817466cbSJens Wiklander         return( NULL );
133817466cbSJens Wiklander 
134817466cbSJens Wiklander     for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
135817466cbSJens Wiklander         if( !  strcmp( def->info->name, cipher_name ) )
136817466cbSJens Wiklander             return( def->info );
137817466cbSJens Wiklander 
138817466cbSJens Wiklander     return( NULL );
139817466cbSJens Wiklander }
140817466cbSJens Wiklander 
141817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id,
142817466cbSJens Wiklander                                               int key_bitlen,
143817466cbSJens Wiklander                                               const mbedtls_cipher_mode_t mode )
144817466cbSJens Wiklander {
145817466cbSJens Wiklander     const mbedtls_cipher_definition_t *def;
146817466cbSJens Wiklander 
147817466cbSJens Wiklander     for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
148817466cbSJens Wiklander         if( def->info->base->cipher == cipher_id &&
149817466cbSJens Wiklander             def->info->key_bitlen == (unsigned) key_bitlen &&
150817466cbSJens Wiklander             def->info->mode == mode )
151817466cbSJens Wiklander             return( def->info );
152817466cbSJens Wiklander 
153817466cbSJens Wiklander     return( NULL );
154817466cbSJens Wiklander }
155817466cbSJens Wiklander 
156817466cbSJens Wiklander void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx )
157817466cbSJens Wiklander {
1583d3b0591SJens Wiklander     CIPHER_VALIDATE( ctx != NULL );
159817466cbSJens Wiklander     memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
160817466cbSJens Wiklander }
161817466cbSJens Wiklander 
162817466cbSJens Wiklander void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx )
163817466cbSJens Wiklander {
164817466cbSJens Wiklander     if( ctx == NULL )
165817466cbSJens Wiklander         return;
166817466cbSJens Wiklander 
167817466cbSJens Wiklander #if defined(MBEDTLS_CMAC_C)
168817466cbSJens Wiklander     if( ctx->cmac_ctx )
169817466cbSJens Wiklander     {
1703d3b0591SJens Wiklander        mbedtls_platform_zeroize( ctx->cmac_ctx,
1713d3b0591SJens Wiklander                                  sizeof( mbedtls_cmac_context_t ) );
172817466cbSJens Wiklander        mbedtls_free( ctx->cmac_ctx );
173817466cbSJens Wiklander     }
174817466cbSJens Wiklander #endif
175817466cbSJens Wiklander 
176817466cbSJens Wiklander     if( ctx->cipher_ctx )
177817466cbSJens Wiklander         ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx );
178817466cbSJens Wiklander 
1793d3b0591SJens Wiklander     mbedtls_platform_zeroize( ctx, sizeof(mbedtls_cipher_context_t) );
180817466cbSJens Wiklander }
181817466cbSJens Wiklander 
18212484fc7SEdison Ai int mbedtls_cipher_clone( mbedtls_cipher_context_t *dst,
18312484fc7SEdison Ai                           const mbedtls_cipher_context_t *src )
18412484fc7SEdison Ai {
18512484fc7SEdison Ai     if( dst == NULL || dst->cipher_info == NULL ||
18612484fc7SEdison Ai         src == NULL || src->cipher_info == NULL)
18712484fc7SEdison Ai     {
18812484fc7SEdison Ai         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
18912484fc7SEdison Ai     }
19012484fc7SEdison Ai 
19112484fc7SEdison Ai     dst->cipher_info = src->cipher_info;
19212484fc7SEdison Ai     dst->key_bitlen = src->key_bitlen;
19312484fc7SEdison Ai     dst->operation = src->operation;
19412484fc7SEdison Ai #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
19512484fc7SEdison Ai     dst->add_padding = src->add_padding;
19612484fc7SEdison Ai     dst->get_padding = src->get_padding;
19712484fc7SEdison Ai #endif
19812484fc7SEdison Ai     memcpy( dst->unprocessed_data, src->unprocessed_data, MBEDTLS_MAX_BLOCK_LENGTH );
19912484fc7SEdison Ai     dst->unprocessed_len = src->unprocessed_len;
20012484fc7SEdison Ai     memcpy( dst->iv, src->iv, MBEDTLS_MAX_IV_LENGTH );
20112484fc7SEdison Ai     dst->iv_size = src->iv_size;
20212484fc7SEdison Ai     if( dst->cipher_info->base->ctx_clone_func )
20312484fc7SEdison Ai         dst->cipher_info->base->ctx_clone_func( dst->cipher_ctx, src->cipher_ctx );
20412484fc7SEdison Ai 
20512484fc7SEdison Ai #if defined(MBEDTLS_CMAC_C)
20612484fc7SEdison Ai     if( dst->cmac_ctx != NULL && src->cmac_ctx != NULL )
20712484fc7SEdison Ai         memcpy( dst->cmac_ctx, src->cmac_ctx, sizeof( mbedtls_cmac_context_t ) );
20812484fc7SEdison Ai #endif
20912484fc7SEdison Ai     return( 0 );
21012484fc7SEdison Ai }
21112484fc7SEdison Ai 
212817466cbSJens Wiklander int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info )
213817466cbSJens Wiklander {
2143d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
2153d3b0591SJens Wiklander     if( cipher_info == NULL )
216817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
217817466cbSJens Wiklander 
218817466cbSJens Wiklander     memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
219817466cbSJens Wiklander 
220817466cbSJens Wiklander     if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) )
221817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED );
222817466cbSJens Wiklander 
223817466cbSJens Wiklander     ctx->cipher_info = cipher_info;
224817466cbSJens Wiklander 
225817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
226817466cbSJens Wiklander     /*
227817466cbSJens Wiklander      * Ignore possible errors caused by a cipher mode that doesn't use padding
228817466cbSJens Wiklander      */
229817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
230817466cbSJens Wiklander     (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 );
231817466cbSJens Wiklander #else
232817466cbSJens Wiklander     (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE );
233817466cbSJens Wiklander #endif
234817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
235817466cbSJens Wiklander 
236817466cbSJens Wiklander     return( 0 );
237817466cbSJens Wiklander }
238817466cbSJens Wiklander 
23912484fc7SEdison Ai int mbedtls_cipher_setup_info( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info )
24012484fc7SEdison Ai {
24112484fc7SEdison Ai     if( NULL == cipher_info || NULL == ctx )
24212484fc7SEdison Ai         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
24312484fc7SEdison Ai 
24412484fc7SEdison Ai     ctx->cipher_info = cipher_info;
24512484fc7SEdison Ai     return( 0 );
24612484fc7SEdison Ai }
24712484fc7SEdison Ai 
2483d3b0591SJens Wiklander int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx,
2493d3b0591SJens Wiklander                            const unsigned char *key,
2503d3b0591SJens Wiklander                            int key_bitlen,
2513d3b0591SJens Wiklander                            const mbedtls_operation_t operation )
252817466cbSJens Wiklander {
2533d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
2543d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( key != NULL );
2553d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( operation == MBEDTLS_ENCRYPT ||
2563d3b0591SJens Wiklander                          operation == MBEDTLS_DECRYPT );
2573d3b0591SJens Wiklander     if( ctx->cipher_info == NULL )
258817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
259817466cbSJens Wiklander 
260817466cbSJens Wiklander     if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 &&
261817466cbSJens Wiklander         (int) ctx->cipher_info->key_bitlen != key_bitlen )
262817466cbSJens Wiklander     {
263817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
264817466cbSJens Wiklander     }
265817466cbSJens Wiklander 
266817466cbSJens Wiklander     ctx->key_bitlen = key_bitlen;
267817466cbSJens Wiklander     ctx->operation = operation;
268817466cbSJens Wiklander 
269817466cbSJens Wiklander     /*
2703d3b0591SJens Wiklander      * For OFB, CFB and CTR mode always use the encryption key schedule
271817466cbSJens Wiklander      */
272817466cbSJens Wiklander     if( MBEDTLS_ENCRYPT == operation ||
273817466cbSJens Wiklander         MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
2743d3b0591SJens Wiklander         MBEDTLS_MODE_OFB == ctx->cipher_info->mode ||
275817466cbSJens Wiklander         MBEDTLS_MODE_CTR == ctx->cipher_info->mode )
276817466cbSJens Wiklander     {
2773d3b0591SJens Wiklander         return( ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key,
2783d3b0591SJens Wiklander                                                          ctx->key_bitlen ) );
279817466cbSJens Wiklander     }
280817466cbSJens Wiklander 
281817466cbSJens Wiklander     if( MBEDTLS_DECRYPT == operation )
2823d3b0591SJens Wiklander         return( ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key,
2833d3b0591SJens Wiklander                                                          ctx->key_bitlen ) );
284817466cbSJens Wiklander 
285817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
286817466cbSJens Wiklander }
287817466cbSJens Wiklander 
288817466cbSJens Wiklander int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx,
2893d3b0591SJens Wiklander                            const unsigned char *iv,
2903d3b0591SJens Wiklander                            size_t iv_len )
291817466cbSJens Wiklander {
292817466cbSJens Wiklander     size_t actual_iv_size;
293817466cbSJens Wiklander 
2943d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
2953d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL );
2963d3b0591SJens Wiklander     if( ctx->cipher_info == NULL )
297817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
298817466cbSJens Wiklander 
299817466cbSJens Wiklander     /* avoid buffer overflow in ctx->iv */
300817466cbSJens Wiklander     if( iv_len > MBEDTLS_MAX_IV_LENGTH )
301817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
302817466cbSJens Wiklander 
303817466cbSJens Wiklander     if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 )
304817466cbSJens Wiklander         actual_iv_size = iv_len;
305817466cbSJens Wiklander     else
306817466cbSJens Wiklander     {
307817466cbSJens Wiklander         actual_iv_size = ctx->cipher_info->iv_size;
308817466cbSJens Wiklander 
309817466cbSJens Wiklander         /* avoid reading past the end of input buffer */
310817466cbSJens Wiklander         if( actual_iv_size > iv_len )
311817466cbSJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
312817466cbSJens Wiklander     }
313817466cbSJens Wiklander 
3143d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHA20_C)
3153d3b0591SJens Wiklander     if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20 )
3163d3b0591SJens Wiklander     {
3173d3b0591SJens Wiklander         if ( 0 != mbedtls_chacha20_starts( (mbedtls_chacha20_context*)ctx->cipher_ctx,
3183d3b0591SJens Wiklander                                            iv,
3193d3b0591SJens Wiklander                                            0U ) ) /* Initial counter value */
3203d3b0591SJens Wiklander         {
3213d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
3223d3b0591SJens Wiklander         }
3233d3b0591SJens Wiklander     }
3243d3b0591SJens Wiklander #endif
3253d3b0591SJens Wiklander 
3263d3b0591SJens Wiklander     if ( actual_iv_size != 0 )
3273d3b0591SJens Wiklander     {
328817466cbSJens Wiklander         memcpy( ctx->iv, iv, actual_iv_size );
329817466cbSJens Wiklander         ctx->iv_size = actual_iv_size;
3303d3b0591SJens Wiklander     }
331817466cbSJens Wiklander 
332817466cbSJens Wiklander     return( 0 );
333817466cbSJens Wiklander }
334817466cbSJens Wiklander 
335817466cbSJens Wiklander int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx )
336817466cbSJens Wiklander {
3373d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
3383d3b0591SJens Wiklander     if( ctx->cipher_info == NULL )
339817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
340817466cbSJens Wiklander 
341817466cbSJens Wiklander     ctx->unprocessed_len = 0;
342817466cbSJens Wiklander 
343817466cbSJens Wiklander     return( 0 );
344817466cbSJens Wiklander }
345817466cbSJens Wiklander 
3463d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
347817466cbSJens Wiklander int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx,
348817466cbSJens Wiklander                       const unsigned char *ad, size_t ad_len )
349817466cbSJens Wiklander {
3503d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
3513d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
3523d3b0591SJens Wiklander     if( ctx->cipher_info == NULL )
353817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
354817466cbSJens Wiklander 
3553d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C)
356817466cbSJens Wiklander     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
357817466cbSJens Wiklander     {
3583d3b0591SJens Wiklander         return( mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation,
3593d3b0591SJens Wiklander                                     ctx->iv, ctx->iv_size, ad, ad_len ) );
360817466cbSJens Wiklander     }
3613d3b0591SJens Wiklander #endif
3623d3b0591SJens Wiklander 
3633d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
3643d3b0591SJens Wiklander     if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
3653d3b0591SJens Wiklander     {
3663d3b0591SJens Wiklander         int result;
3673d3b0591SJens Wiklander         mbedtls_chachapoly_mode_t mode;
3683d3b0591SJens Wiklander 
3693d3b0591SJens Wiklander         mode = ( ctx->operation == MBEDTLS_ENCRYPT )
3703d3b0591SJens Wiklander                 ? MBEDTLS_CHACHAPOLY_ENCRYPT
3713d3b0591SJens Wiklander                 : MBEDTLS_CHACHAPOLY_DECRYPT;
3723d3b0591SJens Wiklander 
3733d3b0591SJens Wiklander         result = mbedtls_chachapoly_starts( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
3743d3b0591SJens Wiklander                                                         ctx->iv,
3753d3b0591SJens Wiklander                                                         mode );
3763d3b0591SJens Wiklander         if ( result != 0 )
3773d3b0591SJens Wiklander             return( result );
3783d3b0591SJens Wiklander 
3793d3b0591SJens Wiklander         return( mbedtls_chachapoly_update_aad( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
3803d3b0591SJens Wiklander                                                ad, ad_len ) );
3813d3b0591SJens Wiklander     }
3823d3b0591SJens Wiklander #endif
383817466cbSJens Wiklander 
384817466cbSJens Wiklander     return( 0 );
385817466cbSJens Wiklander }
3863d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */
387817466cbSJens Wiklander 
388817466cbSJens Wiklander int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input,
389817466cbSJens Wiklander                    size_t ilen, unsigned char *output, size_t *olen )
390817466cbSJens Wiklander {
391817466cbSJens Wiklander     int ret;
3923d3b0591SJens Wiklander     size_t block_size;
393817466cbSJens Wiklander 
3943d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
3953d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
3963d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( output != NULL );
3973d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( olen != NULL );
3983d3b0591SJens Wiklander     if( ctx->cipher_info == NULL )
399817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
400817466cbSJens Wiklander 
401817466cbSJens Wiklander     *olen = 0;
402817466cbSJens Wiklander     block_size = mbedtls_cipher_get_block_size( ctx );
403*5b25c76aSJerome Forissier     if ( 0 == block_size )
404*5b25c76aSJerome Forissier     {
405*5b25c76aSJerome Forissier         return( MBEDTLS_ERR_CIPHER_INVALID_CONTEXT );
406*5b25c76aSJerome Forissier     }
407817466cbSJens Wiklander 
408817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB )
409817466cbSJens Wiklander     {
410817466cbSJens Wiklander         if( ilen != block_size )
411817466cbSJens Wiklander             return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
412817466cbSJens Wiklander 
413817466cbSJens Wiklander         *olen = ilen;
414817466cbSJens Wiklander 
415817466cbSJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx,
416817466cbSJens Wiklander                     ctx->operation, input, output ) ) )
417817466cbSJens Wiklander         {
418817466cbSJens Wiklander             return( ret );
419817466cbSJens Wiklander         }
420817466cbSJens Wiklander 
421817466cbSJens Wiklander         return( 0 );
422817466cbSJens Wiklander     }
423817466cbSJens Wiklander 
424817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C)
425817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM )
426817466cbSJens Wiklander     {
427817466cbSJens Wiklander         *olen = ilen;
4283d3b0591SJens Wiklander         return( mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input,
4293d3b0591SJens Wiklander                                     output ) );
4303d3b0591SJens Wiklander     }
4313d3b0591SJens Wiklander #endif
4323d3b0591SJens Wiklander 
4333d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
4343d3b0591SJens Wiklander     if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 )
4353d3b0591SJens Wiklander     {
4363d3b0591SJens Wiklander         *olen = ilen;
4373d3b0591SJens Wiklander         return( mbedtls_chachapoly_update( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
4383d3b0591SJens Wiklander                                            ilen, input, output ) );
439817466cbSJens Wiklander     }
440817466cbSJens Wiklander #endif
441817466cbSJens Wiklander 
442817466cbSJens Wiklander     if( input == output &&
443817466cbSJens Wiklander        ( ctx->unprocessed_len != 0 || ilen % block_size ) )
444817466cbSJens Wiklander     {
445817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
446817466cbSJens Wiklander     }
447817466cbSJens Wiklander 
448817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CBC)
449817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC )
450817466cbSJens Wiklander     {
451817466cbSJens Wiklander         size_t copy_len = 0;
452817466cbSJens Wiklander 
453817466cbSJens Wiklander         /*
454817466cbSJens Wiklander          * If there is not enough data for a full block, cache it.
455817466cbSJens Wiklander          */
4563d3b0591SJens Wiklander         if( ( ctx->operation == MBEDTLS_DECRYPT && NULL != ctx->add_padding &&
457817466cbSJens Wiklander                 ilen <= block_size - ctx->unprocessed_len ) ||
4583d3b0591SJens Wiklander             ( ctx->operation == MBEDTLS_DECRYPT && NULL == ctx->add_padding &&
4593d3b0591SJens Wiklander                 ilen < block_size - ctx->unprocessed_len ) ||
460817466cbSJens Wiklander              ( ctx->operation == MBEDTLS_ENCRYPT &&
461817466cbSJens Wiklander                 ilen < block_size - ctx->unprocessed_len ) )
462817466cbSJens Wiklander         {
463817466cbSJens Wiklander             memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
464817466cbSJens Wiklander                     ilen );
465817466cbSJens Wiklander 
466817466cbSJens Wiklander             ctx->unprocessed_len += ilen;
467817466cbSJens Wiklander             return( 0 );
468817466cbSJens Wiklander         }
469817466cbSJens Wiklander 
470817466cbSJens Wiklander         /*
471817466cbSJens Wiklander          * Process cached data first
472817466cbSJens Wiklander          */
473817466cbSJens Wiklander         if( 0 != ctx->unprocessed_len )
474817466cbSJens Wiklander         {
475817466cbSJens Wiklander             copy_len = block_size - ctx->unprocessed_len;
476817466cbSJens Wiklander 
477817466cbSJens Wiklander             memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
478817466cbSJens Wiklander                     copy_len );
479817466cbSJens Wiklander 
480817466cbSJens Wiklander             if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
481817466cbSJens Wiklander                     ctx->operation, block_size, ctx->iv,
482817466cbSJens Wiklander                     ctx->unprocessed_data, output ) ) )
483817466cbSJens Wiklander             {
484817466cbSJens Wiklander                 return( ret );
485817466cbSJens Wiklander             }
486817466cbSJens Wiklander 
487817466cbSJens Wiklander             *olen += block_size;
488817466cbSJens Wiklander             output += block_size;
489817466cbSJens Wiklander             ctx->unprocessed_len = 0;
490817466cbSJens Wiklander 
491817466cbSJens Wiklander             input += copy_len;
492817466cbSJens Wiklander             ilen -= copy_len;
493817466cbSJens Wiklander         }
494817466cbSJens Wiklander 
495817466cbSJens Wiklander         /*
496817466cbSJens Wiklander          * Cache final, incomplete block
497817466cbSJens Wiklander          */
498817466cbSJens Wiklander         if( 0 != ilen )
499817466cbSJens Wiklander         {
5003d3b0591SJens Wiklander             /* Encryption: only cache partial blocks
5013d3b0591SJens Wiklander              * Decryption w/ padding: always keep at least one whole block
5023d3b0591SJens Wiklander              * Decryption w/o padding: only cache partial blocks
5033d3b0591SJens Wiklander              */
504817466cbSJens Wiklander             copy_len = ilen % block_size;
5053d3b0591SJens Wiklander             if( copy_len == 0 &&
5063d3b0591SJens Wiklander                 ctx->operation == MBEDTLS_DECRYPT &&
5073d3b0591SJens Wiklander                 NULL != ctx->add_padding)
5083d3b0591SJens Wiklander             {
509817466cbSJens Wiklander                 copy_len = block_size;
5103d3b0591SJens Wiklander             }
511817466cbSJens Wiklander 
512817466cbSJens Wiklander             memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ),
513817466cbSJens Wiklander                     copy_len );
514817466cbSJens Wiklander 
515817466cbSJens Wiklander             ctx->unprocessed_len += copy_len;
516817466cbSJens Wiklander             ilen -= copy_len;
517817466cbSJens Wiklander         }
518817466cbSJens Wiklander 
519817466cbSJens Wiklander         /*
520817466cbSJens Wiklander          * Process remaining full blocks
521817466cbSJens Wiklander          */
522817466cbSJens Wiklander         if( ilen )
523817466cbSJens Wiklander         {
524817466cbSJens Wiklander             if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
525817466cbSJens Wiklander                     ctx->operation, ilen, ctx->iv, input, output ) ) )
526817466cbSJens Wiklander             {
527817466cbSJens Wiklander                 return( ret );
528817466cbSJens Wiklander             }
529817466cbSJens Wiklander 
530817466cbSJens Wiklander             *olen += ilen;
531817466cbSJens Wiklander         }
532817466cbSJens Wiklander 
533817466cbSJens Wiklander         return( 0 );
534817466cbSJens Wiklander     }
535817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CBC */
536817466cbSJens Wiklander 
537817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CFB)
538817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB )
539817466cbSJens Wiklander     {
540817466cbSJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx,
541817466cbSJens Wiklander                 ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv,
542817466cbSJens Wiklander                 input, output ) ) )
543817466cbSJens Wiklander         {
544817466cbSJens Wiklander             return( ret );
545817466cbSJens Wiklander         }
546817466cbSJens Wiklander 
547817466cbSJens Wiklander         *olen = ilen;
548817466cbSJens Wiklander 
549817466cbSJens Wiklander         return( 0 );
550817466cbSJens Wiklander     }
551817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CFB */
552817466cbSJens Wiklander 
5533d3b0591SJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_OFB)
5543d3b0591SJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_OFB )
5553d3b0591SJens Wiklander     {
5563d3b0591SJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->ofb_func( ctx->cipher_ctx,
5573d3b0591SJens Wiklander                 ilen, &ctx->unprocessed_len, ctx->iv, input, output ) ) )
5583d3b0591SJens Wiklander         {
5593d3b0591SJens Wiklander             return( ret );
5603d3b0591SJens Wiklander         }
5613d3b0591SJens Wiklander 
5623d3b0591SJens Wiklander         *olen = ilen;
5633d3b0591SJens Wiklander 
5643d3b0591SJens Wiklander         return( 0 );
5653d3b0591SJens Wiklander     }
5663d3b0591SJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_OFB */
5673d3b0591SJens Wiklander 
568817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CTR)
569817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR )
570817466cbSJens Wiklander     {
571817466cbSJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx,
572817466cbSJens Wiklander                 ilen, &ctx->unprocessed_len, ctx->iv,
573817466cbSJens Wiklander                 ctx->unprocessed_data, input, output ) ) )
574817466cbSJens Wiklander         {
575817466cbSJens Wiklander             return( ret );
576817466cbSJens Wiklander         }
577817466cbSJens Wiklander 
578817466cbSJens Wiklander         *olen = ilen;
579817466cbSJens Wiklander 
580817466cbSJens Wiklander         return( 0 );
581817466cbSJens Wiklander     }
582817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CTR */
583817466cbSJens Wiklander 
5843d3b0591SJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_XTS)
5853d3b0591SJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_XTS )
5863d3b0591SJens Wiklander     {
5873d3b0591SJens Wiklander         if( ctx->unprocessed_len > 0 ) {
5883d3b0591SJens Wiklander             /* We can only process an entire data unit at a time. */
5893d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
5903d3b0591SJens Wiklander         }
5913d3b0591SJens Wiklander 
5923d3b0591SJens Wiklander         ret = ctx->cipher_info->base->xts_func( ctx->cipher_ctx,
5933d3b0591SJens Wiklander                 ctx->operation, ilen, ctx->iv, input, output );
5943d3b0591SJens Wiklander         if( ret != 0 )
5953d3b0591SJens Wiklander         {
5963d3b0591SJens Wiklander             return( ret );
5973d3b0591SJens Wiklander         }
5983d3b0591SJens Wiklander 
5993d3b0591SJens Wiklander         *olen = ilen;
6003d3b0591SJens Wiklander 
6013d3b0591SJens Wiklander         return( 0 );
6023d3b0591SJens Wiklander     }
6033d3b0591SJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_XTS */
6043d3b0591SJens Wiklander 
605817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_STREAM)
606817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM )
607817466cbSJens Wiklander     {
608817466cbSJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx,
609817466cbSJens Wiklander                                                     ilen, input, output ) ) )
610817466cbSJens Wiklander         {
611817466cbSJens Wiklander             return( ret );
612817466cbSJens Wiklander         }
613817466cbSJens Wiklander 
614817466cbSJens Wiklander         *olen = ilen;
615817466cbSJens Wiklander 
616817466cbSJens Wiklander         return( 0 );
617817466cbSJens Wiklander     }
618817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_STREAM */
619817466cbSJens Wiklander 
620817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
621817466cbSJens Wiklander }
622817466cbSJens Wiklander 
623817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
624817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
625817466cbSJens Wiklander /*
626817466cbSJens Wiklander  * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len
627817466cbSJens Wiklander  */
628817466cbSJens Wiklander static void add_pkcs_padding( unsigned char *output, size_t output_len,
629817466cbSJens Wiklander         size_t data_len )
630817466cbSJens Wiklander {
631817466cbSJens Wiklander     size_t padding_len = output_len - data_len;
632817466cbSJens Wiklander     unsigned char i;
633817466cbSJens Wiklander 
634817466cbSJens Wiklander     for( i = 0; i < padding_len; i++ )
635817466cbSJens Wiklander         output[data_len + i] = (unsigned char) padding_len;
636817466cbSJens Wiklander }
637817466cbSJens Wiklander 
638817466cbSJens Wiklander static int get_pkcs_padding( unsigned char *input, size_t input_len,
639817466cbSJens Wiklander         size_t *data_len )
640817466cbSJens Wiklander {
641817466cbSJens Wiklander     size_t i, pad_idx;
642817466cbSJens Wiklander     unsigned char padding_len, bad = 0;
643817466cbSJens Wiklander 
644817466cbSJens Wiklander     if( NULL == input || NULL == data_len )
645817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
646817466cbSJens Wiklander 
647817466cbSJens Wiklander     padding_len = input[input_len - 1];
648817466cbSJens Wiklander     *data_len = input_len - padding_len;
649817466cbSJens Wiklander 
650817466cbSJens Wiklander     /* Avoid logical || since it results in a branch */
651817466cbSJens Wiklander     bad |= padding_len > input_len;
652817466cbSJens Wiklander     bad |= padding_len == 0;
653817466cbSJens Wiklander 
654817466cbSJens Wiklander     /* The number of bytes checked must be independent of padding_len,
655817466cbSJens Wiklander      * so pick input_len, which is usually 8 or 16 (one block) */
656817466cbSJens Wiklander     pad_idx = input_len - padding_len;
657817466cbSJens Wiklander     for( i = 0; i < input_len; i++ )
658817466cbSJens Wiklander         bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx );
659817466cbSJens Wiklander 
660817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
661817466cbSJens Wiklander }
662817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
663817466cbSJens Wiklander 
664817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
665817466cbSJens Wiklander /*
666817466cbSJens Wiklander  * One and zeros padding: fill with 80 00 ... 00
667817466cbSJens Wiklander  */
668817466cbSJens Wiklander static void add_one_and_zeros_padding( unsigned char *output,
669817466cbSJens Wiklander                                        size_t output_len, size_t data_len )
670817466cbSJens Wiklander {
671817466cbSJens Wiklander     size_t padding_len = output_len - data_len;
672817466cbSJens Wiklander     unsigned char i = 0;
673817466cbSJens Wiklander 
674817466cbSJens Wiklander     output[data_len] = 0x80;
675817466cbSJens Wiklander     for( i = 1; i < padding_len; i++ )
676817466cbSJens Wiklander         output[data_len + i] = 0x00;
677817466cbSJens Wiklander }
678817466cbSJens Wiklander 
679817466cbSJens Wiklander static int get_one_and_zeros_padding( unsigned char *input, size_t input_len,
680817466cbSJens Wiklander                                       size_t *data_len )
681817466cbSJens Wiklander {
682817466cbSJens Wiklander     size_t i;
683817466cbSJens Wiklander     unsigned char done = 0, prev_done, bad;
684817466cbSJens Wiklander 
685817466cbSJens Wiklander     if( NULL == input || NULL == data_len )
686817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
687817466cbSJens Wiklander 
6883d3b0591SJens Wiklander     bad = 0x80;
689817466cbSJens Wiklander     *data_len = 0;
690817466cbSJens Wiklander     for( i = input_len; i > 0; i-- )
691817466cbSJens Wiklander     {
692817466cbSJens Wiklander         prev_done = done;
693817466cbSJens Wiklander         done |= ( input[i - 1] != 0 );
694817466cbSJens Wiklander         *data_len |= ( i - 1 ) * ( done != prev_done );
6953d3b0591SJens Wiklander         bad ^= input[i - 1] * ( done != prev_done );
696817466cbSJens Wiklander     }
697817466cbSJens Wiklander 
698817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
699817466cbSJens Wiklander 
700817466cbSJens Wiklander }
701817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
702817466cbSJens Wiklander 
703817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
704817466cbSJens Wiklander /*
705817466cbSJens Wiklander  * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length
706817466cbSJens Wiklander  */
707817466cbSJens Wiklander static void add_zeros_and_len_padding( unsigned char *output,
708817466cbSJens Wiklander                                        size_t output_len, size_t data_len )
709817466cbSJens Wiklander {
710817466cbSJens Wiklander     size_t padding_len = output_len - data_len;
711817466cbSJens Wiklander     unsigned char i = 0;
712817466cbSJens Wiklander 
713817466cbSJens Wiklander     for( i = 1; i < padding_len; i++ )
714817466cbSJens Wiklander         output[data_len + i - 1] = 0x00;
715817466cbSJens Wiklander     output[output_len - 1] = (unsigned char) padding_len;
716817466cbSJens Wiklander }
717817466cbSJens Wiklander 
718817466cbSJens Wiklander static int get_zeros_and_len_padding( unsigned char *input, size_t input_len,
719817466cbSJens Wiklander                                       size_t *data_len )
720817466cbSJens Wiklander {
721817466cbSJens Wiklander     size_t i, pad_idx;
722817466cbSJens Wiklander     unsigned char padding_len, bad = 0;
723817466cbSJens Wiklander 
724817466cbSJens Wiklander     if( NULL == input || NULL == data_len )
725817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
726817466cbSJens Wiklander 
727817466cbSJens Wiklander     padding_len = input[input_len - 1];
728817466cbSJens Wiklander     *data_len = input_len - padding_len;
729817466cbSJens Wiklander 
730817466cbSJens Wiklander     /* Avoid logical || since it results in a branch */
731817466cbSJens Wiklander     bad |= padding_len > input_len;
732817466cbSJens Wiklander     bad |= padding_len == 0;
733817466cbSJens Wiklander 
734817466cbSJens Wiklander     /* The number of bytes checked must be independent of padding_len */
735817466cbSJens Wiklander     pad_idx = input_len - padding_len;
736817466cbSJens Wiklander     for( i = 0; i < input_len - 1; i++ )
737817466cbSJens Wiklander         bad |= input[i] * ( i >= pad_idx );
738817466cbSJens Wiklander 
739817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
740817466cbSJens Wiklander }
741817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
742817466cbSJens Wiklander 
743817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
744817466cbSJens Wiklander /*
745817466cbSJens Wiklander  * Zero padding: fill with 00 ... 00
746817466cbSJens Wiklander  */
747817466cbSJens Wiklander static void add_zeros_padding( unsigned char *output,
748817466cbSJens Wiklander                                size_t output_len, size_t data_len )
749817466cbSJens Wiklander {
750817466cbSJens Wiklander     size_t i;
751817466cbSJens Wiklander 
752817466cbSJens Wiklander     for( i = data_len; i < output_len; i++ )
753817466cbSJens Wiklander         output[i] = 0x00;
754817466cbSJens Wiklander }
755817466cbSJens Wiklander 
756817466cbSJens Wiklander static int get_zeros_padding( unsigned char *input, size_t input_len,
757817466cbSJens Wiklander                               size_t *data_len )
758817466cbSJens Wiklander {
759817466cbSJens Wiklander     size_t i;
760817466cbSJens Wiklander     unsigned char done = 0, prev_done;
761817466cbSJens Wiklander 
762817466cbSJens Wiklander     if( NULL == input || NULL == data_len )
763817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
764817466cbSJens Wiklander 
765817466cbSJens Wiklander     *data_len = 0;
766817466cbSJens Wiklander     for( i = input_len; i > 0; i-- )
767817466cbSJens Wiklander     {
768817466cbSJens Wiklander         prev_done = done;
769817466cbSJens Wiklander         done |= ( input[i-1] != 0 );
770817466cbSJens Wiklander         *data_len |= i * ( done != prev_done );
771817466cbSJens Wiklander     }
772817466cbSJens Wiklander 
773817466cbSJens Wiklander     return( 0 );
774817466cbSJens Wiklander }
775817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
776817466cbSJens Wiklander 
777817466cbSJens Wiklander /*
778817466cbSJens Wiklander  * No padding: don't pad :)
779817466cbSJens Wiklander  *
780817466cbSJens Wiklander  * There is no add_padding function (check for NULL in mbedtls_cipher_finish)
781817466cbSJens Wiklander  * but a trivial get_padding function
782817466cbSJens Wiklander  */
783817466cbSJens Wiklander static int get_no_padding( unsigned char *input, size_t input_len,
784817466cbSJens Wiklander                               size_t *data_len )
785817466cbSJens Wiklander {
786817466cbSJens Wiklander     if( NULL == input || NULL == data_len )
787817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
788817466cbSJens Wiklander 
789817466cbSJens Wiklander     *data_len = input_len;
790817466cbSJens Wiklander 
791817466cbSJens Wiklander     return( 0 );
792817466cbSJens Wiklander }
793817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
794817466cbSJens Wiklander 
795817466cbSJens Wiklander int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx,
796817466cbSJens Wiklander                    unsigned char *output, size_t *olen )
797817466cbSJens Wiklander {
7983d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
7993d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( output != NULL );
8003d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( olen != NULL );
8013d3b0591SJens Wiklander     if( ctx->cipher_info == NULL )
802817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
803817466cbSJens Wiklander 
804817466cbSJens Wiklander     *olen = 0;
805817466cbSJens Wiklander 
806817466cbSJens Wiklander     if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
8073d3b0591SJens Wiklander         MBEDTLS_MODE_OFB == ctx->cipher_info->mode ||
808817466cbSJens Wiklander         MBEDTLS_MODE_CTR == ctx->cipher_info->mode ||
809817466cbSJens Wiklander         MBEDTLS_MODE_GCM == ctx->cipher_info->mode ||
8103d3b0591SJens Wiklander         MBEDTLS_MODE_XTS == ctx->cipher_info->mode ||
811817466cbSJens Wiklander         MBEDTLS_MODE_STREAM == ctx->cipher_info->mode )
812817466cbSJens Wiklander     {
813817466cbSJens Wiklander         return( 0 );
814817466cbSJens Wiklander     }
815817466cbSJens Wiklander 
8163d3b0591SJens Wiklander     if ( ( MBEDTLS_CIPHER_CHACHA20          == ctx->cipher_info->type ) ||
8173d3b0591SJens Wiklander          ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) )
8183d3b0591SJens Wiklander     {
8193d3b0591SJens Wiklander         return( 0 );
8203d3b0591SJens Wiklander     }
8213d3b0591SJens Wiklander 
822817466cbSJens Wiklander     if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode )
823817466cbSJens Wiklander     {
824817466cbSJens Wiklander         if( ctx->unprocessed_len != 0 )
825817466cbSJens Wiklander             return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
826817466cbSJens Wiklander 
827817466cbSJens Wiklander         return( 0 );
828817466cbSJens Wiklander     }
829817466cbSJens Wiklander 
830817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CBC)
831817466cbSJens Wiklander     if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode )
832817466cbSJens Wiklander     {
833817466cbSJens Wiklander         int ret = 0;
834817466cbSJens Wiklander 
835817466cbSJens Wiklander         if( MBEDTLS_ENCRYPT == ctx->operation )
836817466cbSJens Wiklander         {
837817466cbSJens Wiklander             /* check for 'no padding' mode */
838817466cbSJens Wiklander             if( NULL == ctx->add_padding )
839817466cbSJens Wiklander             {
840817466cbSJens Wiklander                 if( 0 != ctx->unprocessed_len )
841817466cbSJens Wiklander                     return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
842817466cbSJens Wiklander 
843817466cbSJens Wiklander                 return( 0 );
844817466cbSJens Wiklander             }
845817466cbSJens Wiklander 
846817466cbSJens Wiklander             ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ),
847817466cbSJens Wiklander                     ctx->unprocessed_len );
848817466cbSJens Wiklander         }
849817466cbSJens Wiklander         else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len )
850817466cbSJens Wiklander         {
851817466cbSJens Wiklander             /*
852817466cbSJens Wiklander              * For decrypt operations, expect a full block,
853817466cbSJens Wiklander              * or an empty block if no padding
854817466cbSJens Wiklander              */
855817466cbSJens Wiklander             if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len )
856817466cbSJens Wiklander                 return( 0 );
857817466cbSJens Wiklander 
858817466cbSJens Wiklander             return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
859817466cbSJens Wiklander         }
860817466cbSJens Wiklander 
861817466cbSJens Wiklander         /* cipher block */
862817466cbSJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
863817466cbSJens Wiklander                 ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv,
864817466cbSJens Wiklander                 ctx->unprocessed_data, output ) ) )
865817466cbSJens Wiklander         {
866817466cbSJens Wiklander             return( ret );
867817466cbSJens Wiklander         }
868817466cbSJens Wiklander 
869817466cbSJens Wiklander         /* Set output size for decryption */
870817466cbSJens Wiklander         if( MBEDTLS_DECRYPT == ctx->operation )
8713d3b0591SJens Wiklander             return( ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ),
8723d3b0591SJens Wiklander                                       olen ) );
873817466cbSJens Wiklander 
874817466cbSJens Wiklander         /* Set output size for encryption */
875817466cbSJens Wiklander         *olen = mbedtls_cipher_get_block_size( ctx );
876817466cbSJens Wiklander         return( 0 );
877817466cbSJens Wiklander     }
878817466cbSJens Wiklander #else
879817466cbSJens Wiklander     ((void) output);
880817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CBC */
881817466cbSJens Wiklander 
882817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
883817466cbSJens Wiklander }
884817466cbSJens Wiklander 
885817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
8863d3b0591SJens Wiklander int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx,
8873d3b0591SJens Wiklander                                      mbedtls_cipher_padding_t mode )
888817466cbSJens Wiklander {
8893d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
8903d3b0591SJens Wiklander 
8913d3b0591SJens Wiklander     if( NULL == ctx->cipher_info || MBEDTLS_MODE_CBC != ctx->cipher_info->mode )
892817466cbSJens Wiklander     {
893817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
894817466cbSJens Wiklander     }
895817466cbSJens Wiklander 
896817466cbSJens Wiklander     switch( mode )
897817466cbSJens Wiklander     {
898817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
899817466cbSJens Wiklander     case MBEDTLS_PADDING_PKCS7:
900817466cbSJens Wiklander         ctx->add_padding = add_pkcs_padding;
901817466cbSJens Wiklander         ctx->get_padding = get_pkcs_padding;
902817466cbSJens Wiklander         break;
903817466cbSJens Wiklander #endif
904817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
905817466cbSJens Wiklander     case MBEDTLS_PADDING_ONE_AND_ZEROS:
906817466cbSJens Wiklander         ctx->add_padding = add_one_and_zeros_padding;
907817466cbSJens Wiklander         ctx->get_padding = get_one_and_zeros_padding;
908817466cbSJens Wiklander         break;
909817466cbSJens Wiklander #endif
910817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
911817466cbSJens Wiklander     case MBEDTLS_PADDING_ZEROS_AND_LEN:
912817466cbSJens Wiklander         ctx->add_padding = add_zeros_and_len_padding;
913817466cbSJens Wiklander         ctx->get_padding = get_zeros_and_len_padding;
914817466cbSJens Wiklander         break;
915817466cbSJens Wiklander #endif
916817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
917817466cbSJens Wiklander     case MBEDTLS_PADDING_ZEROS:
918817466cbSJens Wiklander         ctx->add_padding = add_zeros_padding;
919817466cbSJens Wiklander         ctx->get_padding = get_zeros_padding;
920817466cbSJens Wiklander         break;
921817466cbSJens Wiklander #endif
922817466cbSJens Wiklander     case MBEDTLS_PADDING_NONE:
923817466cbSJens Wiklander         ctx->add_padding = NULL;
924817466cbSJens Wiklander         ctx->get_padding = get_no_padding;
925817466cbSJens Wiklander         break;
926817466cbSJens Wiklander 
927817466cbSJens Wiklander     default:
928817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
929817466cbSJens Wiklander     }
930817466cbSJens Wiklander 
931817466cbSJens Wiklander     return( 0 );
932817466cbSJens Wiklander }
933817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
934817466cbSJens Wiklander 
9353d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
936817466cbSJens Wiklander int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx,
937817466cbSJens Wiklander                       unsigned char *tag, size_t tag_len )
938817466cbSJens Wiklander {
9393d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
9403d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
9413d3b0591SJens Wiklander     if( ctx->cipher_info == NULL )
942817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
943817466cbSJens Wiklander 
944817466cbSJens Wiklander     if( MBEDTLS_ENCRYPT != ctx->operation )
945817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
946817466cbSJens Wiklander 
9473d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C)
948817466cbSJens Wiklander     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
9493d3b0591SJens Wiklander         return( mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx,
9503d3b0591SJens Wiklander                                     tag, tag_len ) );
9513d3b0591SJens Wiklander #endif
9523d3b0591SJens Wiklander 
9533d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
9543d3b0591SJens Wiklander     if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
9553d3b0591SJens Wiklander     {
9563d3b0591SJens Wiklander         /* Don't allow truncated MAC for Poly1305 */
9573d3b0591SJens Wiklander         if ( tag_len != 16U )
9583d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
9593d3b0591SJens Wiklander 
9603d3b0591SJens Wiklander         return( mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
9613d3b0591SJens Wiklander                                            tag ) );
9623d3b0591SJens Wiklander     }
9633d3b0591SJens Wiklander #endif
964817466cbSJens Wiklander 
965817466cbSJens Wiklander     return( 0 );
966817466cbSJens Wiklander }
967817466cbSJens Wiklander 
968817466cbSJens Wiklander int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx,
969817466cbSJens Wiklander                       const unsigned char *tag, size_t tag_len )
970817466cbSJens Wiklander {
9713d3b0591SJens Wiklander     unsigned char check_tag[16];
972817466cbSJens Wiklander     int ret;
973817466cbSJens Wiklander 
9743d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
9753d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
9763d3b0591SJens Wiklander     if( ctx->cipher_info == NULL )
9773d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
9783d3b0591SJens Wiklander 
9793d3b0591SJens Wiklander     if( MBEDTLS_DECRYPT != ctx->operation )
980817466cbSJens Wiklander     {
981817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
982817466cbSJens Wiklander     }
983817466cbSJens Wiklander 
9843d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C)
985817466cbSJens Wiklander     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
986817466cbSJens Wiklander     {
987817466cbSJens Wiklander         if( tag_len > sizeof( check_tag ) )
988817466cbSJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
989817466cbSJens Wiklander 
990817466cbSJens Wiklander         if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx,
991817466cbSJens Wiklander                                      check_tag, tag_len ) ) )
992817466cbSJens Wiklander         {
993817466cbSJens Wiklander             return( ret );
994817466cbSJens Wiklander         }
995817466cbSJens Wiklander 
996817466cbSJens Wiklander         /* Check the tag in "constant-time" */
9973d3b0591SJens Wiklander         if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 )
998817466cbSJens Wiklander             return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
999817466cbSJens Wiklander 
1000817466cbSJens Wiklander         return( 0 );
1001817466cbSJens Wiklander     }
10023d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C */
10033d3b0591SJens Wiklander 
10043d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
10053d3b0591SJens Wiklander     if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
10063d3b0591SJens Wiklander     {
10073d3b0591SJens Wiklander         /* Don't allow truncated MAC for Poly1305 */
10083d3b0591SJens Wiklander         if ( tag_len != sizeof( check_tag ) )
10093d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
10103d3b0591SJens Wiklander 
10113d3b0591SJens Wiklander         ret = mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
10123d3b0591SJens Wiklander                                                      check_tag );
10133d3b0591SJens Wiklander         if ( ret != 0 )
10143d3b0591SJens Wiklander         {
10153d3b0591SJens Wiklander             return( ret );
10163d3b0591SJens Wiklander         }
10173d3b0591SJens Wiklander 
10183d3b0591SJens Wiklander         /* Check the tag in "constant-time" */
10193d3b0591SJens Wiklander         if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 )
10203d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
1021817466cbSJens Wiklander 
1022817466cbSJens Wiklander         return( 0 );
1023817466cbSJens Wiklander     }
10243d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */
10253d3b0591SJens Wiklander 
10263d3b0591SJens Wiklander     return( 0 );
10273d3b0591SJens Wiklander }
10283d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */
1029817466cbSJens Wiklander 
1030817466cbSJens Wiklander /*
1031817466cbSJens Wiklander  * Packet-oriented wrapper for non-AEAD modes
1032817466cbSJens Wiklander  */
1033817466cbSJens Wiklander int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx,
1034817466cbSJens Wiklander                   const unsigned char *iv, size_t iv_len,
1035817466cbSJens Wiklander                   const unsigned char *input, size_t ilen,
1036817466cbSJens Wiklander                   unsigned char *output, size_t *olen )
1037817466cbSJens Wiklander {
1038817466cbSJens Wiklander     int ret;
1039817466cbSJens Wiklander     size_t finish_olen;
1040817466cbSJens Wiklander 
10413d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
10423d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL );
10433d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
10443d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( output != NULL );
10453d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( olen != NULL );
10463d3b0591SJens Wiklander 
1047817466cbSJens Wiklander     if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 )
1048817466cbSJens Wiklander         return( ret );
1049817466cbSJens Wiklander 
1050817466cbSJens Wiklander     if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 )
1051817466cbSJens Wiklander         return( ret );
1052817466cbSJens Wiklander 
1053817466cbSJens Wiklander     if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 )
1054817466cbSJens Wiklander         return( ret );
1055817466cbSJens Wiklander 
1056817466cbSJens Wiklander     if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 )
1057817466cbSJens Wiklander         return( ret );
1058817466cbSJens Wiklander 
1059817466cbSJens Wiklander     *olen += finish_olen;
1060817466cbSJens Wiklander 
1061817466cbSJens Wiklander     return( 0 );
1062817466cbSJens Wiklander }
1063817466cbSJens Wiklander 
1064817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_AEAD)
1065817466cbSJens Wiklander /*
1066817466cbSJens Wiklander  * Packet-oriented encryption for AEAD modes
1067817466cbSJens Wiklander  */
1068817466cbSJens Wiklander int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
1069817466cbSJens Wiklander                          const unsigned char *iv, size_t iv_len,
1070817466cbSJens Wiklander                          const unsigned char *ad, size_t ad_len,
1071817466cbSJens Wiklander                          const unsigned char *input, size_t ilen,
1072817466cbSJens Wiklander                          unsigned char *output, size_t *olen,
1073817466cbSJens Wiklander                          unsigned char *tag, size_t tag_len )
1074817466cbSJens Wiklander {
10753d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
10763d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( iv != NULL );
10773d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
10783d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
10793d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( output != NULL );
10803d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( olen != NULL );
10813d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
10823d3b0591SJens Wiklander 
1083817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C)
1084817466cbSJens Wiklander     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
1085817466cbSJens Wiklander     {
1086817466cbSJens Wiklander         *olen = ilen;
1087817466cbSJens Wiklander         return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen,
1088817466cbSJens Wiklander                                    iv, iv_len, ad, ad_len, input, output,
1089817466cbSJens Wiklander                                    tag_len, tag ) );
1090817466cbSJens Wiklander     }
1091817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */
1092817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C)
1093817466cbSJens Wiklander     if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
1094817466cbSJens Wiklander     {
1095817466cbSJens Wiklander         *olen = ilen;
1096817466cbSJens Wiklander         return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen,
1097817466cbSJens Wiklander                                      iv, iv_len, ad, ad_len, input, output,
1098817466cbSJens Wiklander                                      tag, tag_len ) );
1099817466cbSJens Wiklander     }
1100817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */
11013d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
11023d3b0591SJens Wiklander     if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
11033d3b0591SJens Wiklander     {
11043d3b0591SJens Wiklander         /* ChachaPoly has fixed length nonce and MAC (tag) */
11053d3b0591SJens Wiklander         if ( ( iv_len != ctx->cipher_info->iv_size ) ||
11063d3b0591SJens Wiklander              ( tag_len != 16U ) )
11073d3b0591SJens Wiklander         {
11083d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
11093d3b0591SJens Wiklander         }
11103d3b0591SJens Wiklander 
11113d3b0591SJens Wiklander         *olen = ilen;
11123d3b0591SJens Wiklander         return( mbedtls_chachapoly_encrypt_and_tag( ctx->cipher_ctx,
11133d3b0591SJens Wiklander                                 ilen, iv, ad, ad_len, input, output, tag ) );
11143d3b0591SJens Wiklander     }
11153d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */
1116817466cbSJens Wiklander 
1117817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
1118817466cbSJens Wiklander }
1119817466cbSJens Wiklander 
1120817466cbSJens Wiklander /*
1121817466cbSJens Wiklander  * Packet-oriented decryption for AEAD modes
1122817466cbSJens Wiklander  */
1123817466cbSJens Wiklander int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
1124817466cbSJens Wiklander                          const unsigned char *iv, size_t iv_len,
1125817466cbSJens Wiklander                          const unsigned char *ad, size_t ad_len,
1126817466cbSJens Wiklander                          const unsigned char *input, size_t ilen,
1127817466cbSJens Wiklander                          unsigned char *output, size_t *olen,
1128817466cbSJens Wiklander                          const unsigned char *tag, size_t tag_len )
1129817466cbSJens Wiklander {
11303d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
11313d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( iv != NULL );
11323d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
11333d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
11343d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( output != NULL );
11353d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( olen != NULL );
11363d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
11373d3b0591SJens Wiklander 
1138817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C)
1139817466cbSJens Wiklander     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
1140817466cbSJens Wiklander     {
1141817466cbSJens Wiklander         int ret;
1142817466cbSJens Wiklander 
1143817466cbSJens Wiklander         *olen = ilen;
1144817466cbSJens Wiklander         ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen,
1145817466cbSJens Wiklander                                 iv, iv_len, ad, ad_len,
1146817466cbSJens Wiklander                                 tag, tag_len, input, output );
1147817466cbSJens Wiklander 
1148817466cbSJens Wiklander         if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED )
1149817466cbSJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
1150817466cbSJens Wiklander 
1151817466cbSJens Wiklander         return( ret );
1152817466cbSJens Wiklander     }
1153817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */
1154817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C)
1155817466cbSJens Wiklander     if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
1156817466cbSJens Wiklander     {
1157817466cbSJens Wiklander         int ret;
1158817466cbSJens Wiklander 
1159817466cbSJens Wiklander         *olen = ilen;
1160817466cbSJens Wiklander         ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen,
1161817466cbSJens Wiklander                                 iv, iv_len, ad, ad_len,
1162817466cbSJens Wiklander                                 input, output, tag, tag_len );
1163817466cbSJens Wiklander 
1164817466cbSJens Wiklander         if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED )
1165817466cbSJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
1166817466cbSJens Wiklander 
1167817466cbSJens Wiklander         return( ret );
1168817466cbSJens Wiklander     }
1169817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */
11703d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
11713d3b0591SJens Wiklander     if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
11723d3b0591SJens Wiklander     {
11733d3b0591SJens Wiklander         int ret;
11743d3b0591SJens Wiklander 
11753d3b0591SJens Wiklander         /* ChachaPoly has fixed length nonce and MAC (tag) */
11763d3b0591SJens Wiklander         if ( ( iv_len != ctx->cipher_info->iv_size ) ||
11773d3b0591SJens Wiklander              ( tag_len != 16U ) )
11783d3b0591SJens Wiklander         {
11793d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
11803d3b0591SJens Wiklander         }
11813d3b0591SJens Wiklander 
11823d3b0591SJens Wiklander         *olen = ilen;
11833d3b0591SJens Wiklander         ret = mbedtls_chachapoly_auth_decrypt( ctx->cipher_ctx, ilen,
11843d3b0591SJens Wiklander                                 iv, ad, ad_len, tag, input, output );
11853d3b0591SJens Wiklander 
11863d3b0591SJens Wiklander         if( ret == MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED )
11873d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
11883d3b0591SJens Wiklander 
11893d3b0591SJens Wiklander         return( ret );
11903d3b0591SJens Wiklander     }
11913d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */
1192817466cbSJens Wiklander 
1193817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
1194817466cbSJens Wiklander }
1195817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_AEAD */
1196817466cbSJens Wiklander 
1197817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_C */
1198