xref: /optee_os/lib/libmbedtls/mbedtls/library/cipher.c (revision 12484fc76d224d174b691b211fff84265077ff1b)
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 
182*12484fc7SEdison Ai int mbedtls_cipher_clone( mbedtls_cipher_context_t *dst,
183*12484fc7SEdison Ai                           const mbedtls_cipher_context_t *src )
184*12484fc7SEdison Ai {
185*12484fc7SEdison Ai     if( dst == NULL || dst->cipher_info == NULL ||
186*12484fc7SEdison Ai         src == NULL || src->cipher_info == NULL)
187*12484fc7SEdison Ai     {
188*12484fc7SEdison Ai         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
189*12484fc7SEdison Ai     }
190*12484fc7SEdison Ai 
191*12484fc7SEdison Ai     dst->cipher_info = src->cipher_info;
192*12484fc7SEdison Ai     dst->key_bitlen = src->key_bitlen;
193*12484fc7SEdison Ai     dst->operation = src->operation;
194*12484fc7SEdison Ai #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
195*12484fc7SEdison Ai     dst->add_padding = src->add_padding;
196*12484fc7SEdison Ai     dst->get_padding = src->get_padding;
197*12484fc7SEdison Ai #endif
198*12484fc7SEdison Ai     memcpy( dst->unprocessed_data, src->unprocessed_data, MBEDTLS_MAX_BLOCK_LENGTH );
199*12484fc7SEdison Ai     dst->unprocessed_len = src->unprocessed_len;
200*12484fc7SEdison Ai     memcpy( dst->iv, src->iv, MBEDTLS_MAX_IV_LENGTH );
201*12484fc7SEdison Ai     dst->iv_size = src->iv_size;
202*12484fc7SEdison Ai     if( dst->cipher_info->base->ctx_clone_func )
203*12484fc7SEdison Ai         dst->cipher_info->base->ctx_clone_func( dst->cipher_ctx, src->cipher_ctx );
204*12484fc7SEdison Ai 
205*12484fc7SEdison Ai #if defined(MBEDTLS_CMAC_C)
206*12484fc7SEdison Ai     if( dst->cmac_ctx != NULL && src->cmac_ctx != NULL )
207*12484fc7SEdison Ai         memcpy( dst->cmac_ctx, src->cmac_ctx, sizeof( mbedtls_cmac_context_t ) );
208*12484fc7SEdison Ai #endif
209*12484fc7SEdison Ai     return( 0 );
210*12484fc7SEdison Ai }
211*12484fc7SEdison 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 
239*12484fc7SEdison Ai int mbedtls_cipher_setup_info( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info )
240*12484fc7SEdison Ai {
241*12484fc7SEdison Ai     if( NULL == cipher_info || NULL == ctx )
242*12484fc7SEdison Ai         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
243*12484fc7SEdison Ai 
244*12484fc7SEdison Ai     ctx->cipher_info = cipher_info;
245*12484fc7SEdison Ai     return( 0 );
246*12484fc7SEdison Ai }
247*12484fc7SEdison 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 );
403817466cbSJens Wiklander 
404817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB )
405817466cbSJens Wiklander     {
406817466cbSJens Wiklander         if( ilen != block_size )
407817466cbSJens Wiklander             return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
408817466cbSJens Wiklander 
409817466cbSJens Wiklander         *olen = ilen;
410817466cbSJens Wiklander 
411817466cbSJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx,
412817466cbSJens Wiklander                     ctx->operation, input, output ) ) )
413817466cbSJens Wiklander         {
414817466cbSJens Wiklander             return( ret );
415817466cbSJens Wiklander         }
416817466cbSJens Wiklander 
417817466cbSJens Wiklander         return( 0 );
418817466cbSJens Wiklander     }
419817466cbSJens Wiklander 
420817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C)
421817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM )
422817466cbSJens Wiklander     {
423817466cbSJens Wiklander         *olen = ilen;
4243d3b0591SJens Wiklander         return( mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input,
4253d3b0591SJens Wiklander                                     output ) );
4263d3b0591SJens Wiklander     }
4273d3b0591SJens Wiklander #endif
4283d3b0591SJens Wiklander 
4293d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
4303d3b0591SJens Wiklander     if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 )
4313d3b0591SJens Wiklander     {
4323d3b0591SJens Wiklander         *olen = ilen;
4333d3b0591SJens Wiklander         return( mbedtls_chachapoly_update( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
4343d3b0591SJens Wiklander                                            ilen, input, output ) );
435817466cbSJens Wiklander     }
436817466cbSJens Wiklander #endif
437817466cbSJens Wiklander 
438817466cbSJens Wiklander     if ( 0 == block_size )
439817466cbSJens Wiklander     {
4403d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_INVALID_CONTEXT );
441817466cbSJens Wiklander     }
442817466cbSJens Wiklander 
443817466cbSJens Wiklander     if( input == output &&
444817466cbSJens Wiklander        ( ctx->unprocessed_len != 0 || ilen % block_size ) )
445817466cbSJens Wiklander     {
446817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
447817466cbSJens Wiklander     }
448817466cbSJens Wiklander 
449817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CBC)
450817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC )
451817466cbSJens Wiklander     {
452817466cbSJens Wiklander         size_t copy_len = 0;
453817466cbSJens Wiklander 
454817466cbSJens Wiklander         /*
455817466cbSJens Wiklander          * If there is not enough data for a full block, cache it.
456817466cbSJens Wiklander          */
4573d3b0591SJens Wiklander         if( ( ctx->operation == MBEDTLS_DECRYPT && NULL != ctx->add_padding &&
458817466cbSJens Wiklander                 ilen <= block_size - ctx->unprocessed_len ) ||
4593d3b0591SJens Wiklander             ( ctx->operation == MBEDTLS_DECRYPT && NULL == ctx->add_padding &&
4603d3b0591SJens Wiklander                 ilen < block_size - ctx->unprocessed_len ) ||
461817466cbSJens Wiklander              ( ctx->operation == MBEDTLS_ENCRYPT &&
462817466cbSJens Wiklander                 ilen < block_size - ctx->unprocessed_len ) )
463817466cbSJens Wiklander         {
464817466cbSJens Wiklander             memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
465817466cbSJens Wiklander                     ilen );
466817466cbSJens Wiklander 
467817466cbSJens Wiklander             ctx->unprocessed_len += ilen;
468817466cbSJens Wiklander             return( 0 );
469817466cbSJens Wiklander         }
470817466cbSJens Wiklander 
471817466cbSJens Wiklander         /*
472817466cbSJens Wiklander          * Process cached data first
473817466cbSJens Wiklander          */
474817466cbSJens Wiklander         if( 0 != ctx->unprocessed_len )
475817466cbSJens Wiklander         {
476817466cbSJens Wiklander             copy_len = block_size - ctx->unprocessed_len;
477817466cbSJens Wiklander 
478817466cbSJens Wiklander             memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
479817466cbSJens Wiklander                     copy_len );
480817466cbSJens Wiklander 
481817466cbSJens Wiklander             if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
482817466cbSJens Wiklander                     ctx->operation, block_size, ctx->iv,
483817466cbSJens Wiklander                     ctx->unprocessed_data, output ) ) )
484817466cbSJens Wiklander             {
485817466cbSJens Wiklander                 return( ret );
486817466cbSJens Wiklander             }
487817466cbSJens Wiklander 
488817466cbSJens Wiklander             *olen += block_size;
489817466cbSJens Wiklander             output += block_size;
490817466cbSJens Wiklander             ctx->unprocessed_len = 0;
491817466cbSJens Wiklander 
492817466cbSJens Wiklander             input += copy_len;
493817466cbSJens Wiklander             ilen -= copy_len;
494817466cbSJens Wiklander         }
495817466cbSJens Wiklander 
496817466cbSJens Wiklander         /*
497817466cbSJens Wiklander          * Cache final, incomplete block
498817466cbSJens Wiklander          */
499817466cbSJens Wiklander         if( 0 != ilen )
500817466cbSJens Wiklander         {
501817466cbSJens Wiklander             if( 0 == block_size )
502817466cbSJens Wiklander             {
5033d3b0591SJens Wiklander                 return( MBEDTLS_ERR_CIPHER_INVALID_CONTEXT );
504817466cbSJens Wiklander             }
505817466cbSJens Wiklander 
5063d3b0591SJens Wiklander             /* Encryption: only cache partial blocks
5073d3b0591SJens Wiklander              * Decryption w/ padding: always keep at least one whole block
5083d3b0591SJens Wiklander              * Decryption w/o padding: only cache partial blocks
5093d3b0591SJens Wiklander              */
510817466cbSJens Wiklander             copy_len = ilen % block_size;
5113d3b0591SJens Wiklander             if( copy_len == 0 &&
5123d3b0591SJens Wiklander                 ctx->operation == MBEDTLS_DECRYPT &&
5133d3b0591SJens Wiklander                 NULL != ctx->add_padding)
5143d3b0591SJens Wiklander             {
515817466cbSJens Wiklander                 copy_len = block_size;
5163d3b0591SJens Wiklander             }
517817466cbSJens Wiklander 
518817466cbSJens Wiklander             memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ),
519817466cbSJens Wiklander                     copy_len );
520817466cbSJens Wiklander 
521817466cbSJens Wiklander             ctx->unprocessed_len += copy_len;
522817466cbSJens Wiklander             ilen -= copy_len;
523817466cbSJens Wiklander         }
524817466cbSJens Wiklander 
525817466cbSJens Wiklander         /*
526817466cbSJens Wiklander          * Process remaining full blocks
527817466cbSJens Wiklander          */
528817466cbSJens Wiklander         if( ilen )
529817466cbSJens Wiklander         {
530817466cbSJens Wiklander             if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
531817466cbSJens Wiklander                     ctx->operation, ilen, ctx->iv, input, output ) ) )
532817466cbSJens Wiklander             {
533817466cbSJens Wiklander                 return( ret );
534817466cbSJens Wiklander             }
535817466cbSJens Wiklander 
536817466cbSJens Wiklander             *olen += ilen;
537817466cbSJens Wiklander         }
538817466cbSJens Wiklander 
539817466cbSJens Wiklander         return( 0 );
540817466cbSJens Wiklander     }
541817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CBC */
542817466cbSJens Wiklander 
543817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CFB)
544817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB )
545817466cbSJens Wiklander     {
546817466cbSJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx,
547817466cbSJens Wiklander                 ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv,
548817466cbSJens Wiklander                 input, output ) ) )
549817466cbSJens Wiklander         {
550817466cbSJens Wiklander             return( ret );
551817466cbSJens Wiklander         }
552817466cbSJens Wiklander 
553817466cbSJens Wiklander         *olen = ilen;
554817466cbSJens Wiklander 
555817466cbSJens Wiklander         return( 0 );
556817466cbSJens Wiklander     }
557817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CFB */
558817466cbSJens Wiklander 
5593d3b0591SJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_OFB)
5603d3b0591SJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_OFB )
5613d3b0591SJens Wiklander     {
5623d3b0591SJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->ofb_func( ctx->cipher_ctx,
5633d3b0591SJens Wiklander                 ilen, &ctx->unprocessed_len, ctx->iv, input, output ) ) )
5643d3b0591SJens Wiklander         {
5653d3b0591SJens Wiklander             return( ret );
5663d3b0591SJens Wiklander         }
5673d3b0591SJens Wiklander 
5683d3b0591SJens Wiklander         *olen = ilen;
5693d3b0591SJens Wiklander 
5703d3b0591SJens Wiklander         return( 0 );
5713d3b0591SJens Wiklander     }
5723d3b0591SJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_OFB */
5733d3b0591SJens Wiklander 
574817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CTR)
575817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR )
576817466cbSJens Wiklander     {
577817466cbSJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx,
578817466cbSJens Wiklander                 ilen, &ctx->unprocessed_len, ctx->iv,
579817466cbSJens Wiklander                 ctx->unprocessed_data, input, output ) ) )
580817466cbSJens Wiklander         {
581817466cbSJens Wiklander             return( ret );
582817466cbSJens Wiklander         }
583817466cbSJens Wiklander 
584817466cbSJens Wiklander         *olen = ilen;
585817466cbSJens Wiklander 
586817466cbSJens Wiklander         return( 0 );
587817466cbSJens Wiklander     }
588817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CTR */
589817466cbSJens Wiklander 
5903d3b0591SJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_XTS)
5913d3b0591SJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_XTS )
5923d3b0591SJens Wiklander     {
5933d3b0591SJens Wiklander         if( ctx->unprocessed_len > 0 ) {
5943d3b0591SJens Wiklander             /* We can only process an entire data unit at a time. */
5953d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
5963d3b0591SJens Wiklander         }
5973d3b0591SJens Wiklander 
5983d3b0591SJens Wiklander         ret = ctx->cipher_info->base->xts_func( ctx->cipher_ctx,
5993d3b0591SJens Wiklander                 ctx->operation, ilen, ctx->iv, input, output );
6003d3b0591SJens Wiklander         if( ret != 0 )
6013d3b0591SJens Wiklander         {
6023d3b0591SJens Wiklander             return( ret );
6033d3b0591SJens Wiklander         }
6043d3b0591SJens Wiklander 
6053d3b0591SJens Wiklander         *olen = ilen;
6063d3b0591SJens Wiklander 
6073d3b0591SJens Wiklander         return( 0 );
6083d3b0591SJens Wiklander     }
6093d3b0591SJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_XTS */
6103d3b0591SJens Wiklander 
611817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_STREAM)
612817466cbSJens Wiklander     if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM )
613817466cbSJens Wiklander     {
614817466cbSJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx,
615817466cbSJens Wiklander                                                     ilen, input, output ) ) )
616817466cbSJens Wiklander         {
617817466cbSJens Wiklander             return( ret );
618817466cbSJens Wiklander         }
619817466cbSJens Wiklander 
620817466cbSJens Wiklander         *olen = ilen;
621817466cbSJens Wiklander 
622817466cbSJens Wiklander         return( 0 );
623817466cbSJens Wiklander     }
624817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_STREAM */
625817466cbSJens Wiklander 
626817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
627817466cbSJens Wiklander }
628817466cbSJens Wiklander 
629817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
630817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
631817466cbSJens Wiklander /*
632817466cbSJens Wiklander  * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len
633817466cbSJens Wiklander  */
634817466cbSJens Wiklander static void add_pkcs_padding( unsigned char *output, size_t output_len,
635817466cbSJens Wiklander         size_t data_len )
636817466cbSJens Wiklander {
637817466cbSJens Wiklander     size_t padding_len = output_len - data_len;
638817466cbSJens Wiklander     unsigned char i;
639817466cbSJens Wiklander 
640817466cbSJens Wiklander     for( i = 0; i < padding_len; i++ )
641817466cbSJens Wiklander         output[data_len + i] = (unsigned char) padding_len;
642817466cbSJens Wiklander }
643817466cbSJens Wiklander 
644817466cbSJens Wiklander static int get_pkcs_padding( unsigned char *input, size_t input_len,
645817466cbSJens Wiklander         size_t *data_len )
646817466cbSJens Wiklander {
647817466cbSJens Wiklander     size_t i, pad_idx;
648817466cbSJens Wiklander     unsigned char padding_len, bad = 0;
649817466cbSJens Wiklander 
650817466cbSJens Wiklander     if( NULL == input || NULL == data_len )
651817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
652817466cbSJens Wiklander 
653817466cbSJens Wiklander     padding_len = input[input_len - 1];
654817466cbSJens Wiklander     *data_len = input_len - padding_len;
655817466cbSJens Wiklander 
656817466cbSJens Wiklander     /* Avoid logical || since it results in a branch */
657817466cbSJens Wiklander     bad |= padding_len > input_len;
658817466cbSJens Wiklander     bad |= padding_len == 0;
659817466cbSJens Wiklander 
660817466cbSJens Wiklander     /* The number of bytes checked must be independent of padding_len,
661817466cbSJens Wiklander      * so pick input_len, which is usually 8 or 16 (one block) */
662817466cbSJens Wiklander     pad_idx = input_len - padding_len;
663817466cbSJens Wiklander     for( i = 0; i < input_len; i++ )
664817466cbSJens Wiklander         bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx );
665817466cbSJens Wiklander 
666817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
667817466cbSJens Wiklander }
668817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
669817466cbSJens Wiklander 
670817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
671817466cbSJens Wiklander /*
672817466cbSJens Wiklander  * One and zeros padding: fill with 80 00 ... 00
673817466cbSJens Wiklander  */
674817466cbSJens Wiklander static void add_one_and_zeros_padding( unsigned char *output,
675817466cbSJens Wiklander                                        size_t output_len, size_t data_len )
676817466cbSJens Wiklander {
677817466cbSJens Wiklander     size_t padding_len = output_len - data_len;
678817466cbSJens Wiklander     unsigned char i = 0;
679817466cbSJens Wiklander 
680817466cbSJens Wiklander     output[data_len] = 0x80;
681817466cbSJens Wiklander     for( i = 1; i < padding_len; i++ )
682817466cbSJens Wiklander         output[data_len + i] = 0x00;
683817466cbSJens Wiklander }
684817466cbSJens Wiklander 
685817466cbSJens Wiklander static int get_one_and_zeros_padding( unsigned char *input, size_t input_len,
686817466cbSJens Wiklander                                       size_t *data_len )
687817466cbSJens Wiklander {
688817466cbSJens Wiklander     size_t i;
689817466cbSJens Wiklander     unsigned char done = 0, prev_done, bad;
690817466cbSJens Wiklander 
691817466cbSJens Wiklander     if( NULL == input || NULL == data_len )
692817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
693817466cbSJens Wiklander 
6943d3b0591SJens Wiklander     bad = 0x80;
695817466cbSJens Wiklander     *data_len = 0;
696817466cbSJens Wiklander     for( i = input_len; i > 0; i-- )
697817466cbSJens Wiklander     {
698817466cbSJens Wiklander         prev_done = done;
699817466cbSJens Wiklander         done |= ( input[i - 1] != 0 );
700817466cbSJens Wiklander         *data_len |= ( i - 1 ) * ( done != prev_done );
7013d3b0591SJens Wiklander         bad ^= input[i - 1] * ( done != prev_done );
702817466cbSJens Wiklander     }
703817466cbSJens Wiklander 
704817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
705817466cbSJens Wiklander 
706817466cbSJens Wiklander }
707817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
708817466cbSJens Wiklander 
709817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
710817466cbSJens Wiklander /*
711817466cbSJens Wiklander  * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length
712817466cbSJens Wiklander  */
713817466cbSJens Wiklander static void add_zeros_and_len_padding( unsigned char *output,
714817466cbSJens Wiklander                                        size_t output_len, size_t data_len )
715817466cbSJens Wiklander {
716817466cbSJens Wiklander     size_t padding_len = output_len - data_len;
717817466cbSJens Wiklander     unsigned char i = 0;
718817466cbSJens Wiklander 
719817466cbSJens Wiklander     for( i = 1; i < padding_len; i++ )
720817466cbSJens Wiklander         output[data_len + i - 1] = 0x00;
721817466cbSJens Wiklander     output[output_len - 1] = (unsigned char) padding_len;
722817466cbSJens Wiklander }
723817466cbSJens Wiklander 
724817466cbSJens Wiklander static int get_zeros_and_len_padding( unsigned char *input, size_t input_len,
725817466cbSJens Wiklander                                       size_t *data_len )
726817466cbSJens Wiklander {
727817466cbSJens Wiklander     size_t i, pad_idx;
728817466cbSJens Wiklander     unsigned char padding_len, bad = 0;
729817466cbSJens Wiklander 
730817466cbSJens Wiklander     if( NULL == input || NULL == data_len )
731817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
732817466cbSJens Wiklander 
733817466cbSJens Wiklander     padding_len = input[input_len - 1];
734817466cbSJens Wiklander     *data_len = input_len - padding_len;
735817466cbSJens Wiklander 
736817466cbSJens Wiklander     /* Avoid logical || since it results in a branch */
737817466cbSJens Wiklander     bad |= padding_len > input_len;
738817466cbSJens Wiklander     bad |= padding_len == 0;
739817466cbSJens Wiklander 
740817466cbSJens Wiklander     /* The number of bytes checked must be independent of padding_len */
741817466cbSJens Wiklander     pad_idx = input_len - padding_len;
742817466cbSJens Wiklander     for( i = 0; i < input_len - 1; i++ )
743817466cbSJens Wiklander         bad |= input[i] * ( i >= pad_idx );
744817466cbSJens Wiklander 
745817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
746817466cbSJens Wiklander }
747817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
748817466cbSJens Wiklander 
749817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
750817466cbSJens Wiklander /*
751817466cbSJens Wiklander  * Zero padding: fill with 00 ... 00
752817466cbSJens Wiklander  */
753817466cbSJens Wiklander static void add_zeros_padding( unsigned char *output,
754817466cbSJens Wiklander                                size_t output_len, size_t data_len )
755817466cbSJens Wiklander {
756817466cbSJens Wiklander     size_t i;
757817466cbSJens Wiklander 
758817466cbSJens Wiklander     for( i = data_len; i < output_len; i++ )
759817466cbSJens Wiklander         output[i] = 0x00;
760817466cbSJens Wiklander }
761817466cbSJens Wiklander 
762817466cbSJens Wiklander static int get_zeros_padding( unsigned char *input, size_t input_len,
763817466cbSJens Wiklander                               size_t *data_len )
764817466cbSJens Wiklander {
765817466cbSJens Wiklander     size_t i;
766817466cbSJens Wiklander     unsigned char done = 0, prev_done;
767817466cbSJens Wiklander 
768817466cbSJens Wiklander     if( NULL == input || NULL == data_len )
769817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
770817466cbSJens Wiklander 
771817466cbSJens Wiklander     *data_len = 0;
772817466cbSJens Wiklander     for( i = input_len; i > 0; i-- )
773817466cbSJens Wiklander     {
774817466cbSJens Wiklander         prev_done = done;
775817466cbSJens Wiklander         done |= ( input[i-1] != 0 );
776817466cbSJens Wiklander         *data_len |= i * ( done != prev_done );
777817466cbSJens Wiklander     }
778817466cbSJens Wiklander 
779817466cbSJens Wiklander     return( 0 );
780817466cbSJens Wiklander }
781817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
782817466cbSJens Wiklander 
783817466cbSJens Wiklander /*
784817466cbSJens Wiklander  * No padding: don't pad :)
785817466cbSJens Wiklander  *
786817466cbSJens Wiklander  * There is no add_padding function (check for NULL in mbedtls_cipher_finish)
787817466cbSJens Wiklander  * but a trivial get_padding function
788817466cbSJens Wiklander  */
789817466cbSJens Wiklander static int get_no_padding( unsigned char *input, size_t input_len,
790817466cbSJens Wiklander                               size_t *data_len )
791817466cbSJens Wiklander {
792817466cbSJens Wiklander     if( NULL == input || NULL == data_len )
793817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
794817466cbSJens Wiklander 
795817466cbSJens Wiklander     *data_len = input_len;
796817466cbSJens Wiklander 
797817466cbSJens Wiklander     return( 0 );
798817466cbSJens Wiklander }
799817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
800817466cbSJens Wiklander 
801817466cbSJens Wiklander int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx,
802817466cbSJens Wiklander                    unsigned char *output, size_t *olen )
803817466cbSJens Wiklander {
8043d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
8053d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( output != NULL );
8063d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( olen != NULL );
8073d3b0591SJens Wiklander     if( ctx->cipher_info == NULL )
808817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
809817466cbSJens Wiklander 
810817466cbSJens Wiklander     *olen = 0;
811817466cbSJens Wiklander 
812817466cbSJens Wiklander     if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
8133d3b0591SJens Wiklander         MBEDTLS_MODE_OFB == ctx->cipher_info->mode ||
814817466cbSJens Wiklander         MBEDTLS_MODE_CTR == ctx->cipher_info->mode ||
815817466cbSJens Wiklander         MBEDTLS_MODE_GCM == ctx->cipher_info->mode ||
8163d3b0591SJens Wiklander         MBEDTLS_MODE_XTS == ctx->cipher_info->mode ||
817817466cbSJens Wiklander         MBEDTLS_MODE_STREAM == ctx->cipher_info->mode )
818817466cbSJens Wiklander     {
819817466cbSJens Wiklander         return( 0 );
820817466cbSJens Wiklander     }
821817466cbSJens Wiklander 
8223d3b0591SJens Wiklander     if ( ( MBEDTLS_CIPHER_CHACHA20          == ctx->cipher_info->type ) ||
8233d3b0591SJens Wiklander          ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) )
8243d3b0591SJens Wiklander     {
8253d3b0591SJens Wiklander         return( 0 );
8263d3b0591SJens Wiklander     }
8273d3b0591SJens Wiklander 
828817466cbSJens Wiklander     if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode )
829817466cbSJens Wiklander     {
830817466cbSJens Wiklander         if( ctx->unprocessed_len != 0 )
831817466cbSJens Wiklander             return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
832817466cbSJens Wiklander 
833817466cbSJens Wiklander         return( 0 );
834817466cbSJens Wiklander     }
835817466cbSJens Wiklander 
836817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CBC)
837817466cbSJens Wiklander     if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode )
838817466cbSJens Wiklander     {
839817466cbSJens Wiklander         int ret = 0;
840817466cbSJens Wiklander 
841817466cbSJens Wiklander         if( MBEDTLS_ENCRYPT == ctx->operation )
842817466cbSJens Wiklander         {
843817466cbSJens Wiklander             /* check for 'no padding' mode */
844817466cbSJens Wiklander             if( NULL == ctx->add_padding )
845817466cbSJens Wiklander             {
846817466cbSJens Wiklander                 if( 0 != ctx->unprocessed_len )
847817466cbSJens Wiklander                     return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
848817466cbSJens Wiklander 
849817466cbSJens Wiklander                 return( 0 );
850817466cbSJens Wiklander             }
851817466cbSJens Wiklander 
852817466cbSJens Wiklander             ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ),
853817466cbSJens Wiklander                     ctx->unprocessed_len );
854817466cbSJens Wiklander         }
855817466cbSJens Wiklander         else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len )
856817466cbSJens Wiklander         {
857817466cbSJens Wiklander             /*
858817466cbSJens Wiklander              * For decrypt operations, expect a full block,
859817466cbSJens Wiklander              * or an empty block if no padding
860817466cbSJens Wiklander              */
861817466cbSJens Wiklander             if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len )
862817466cbSJens Wiklander                 return( 0 );
863817466cbSJens Wiklander 
864817466cbSJens Wiklander             return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
865817466cbSJens Wiklander         }
866817466cbSJens Wiklander 
867817466cbSJens Wiklander         /* cipher block */
868817466cbSJens Wiklander         if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
869817466cbSJens Wiklander                 ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv,
870817466cbSJens Wiklander                 ctx->unprocessed_data, output ) ) )
871817466cbSJens Wiklander         {
872817466cbSJens Wiklander             return( ret );
873817466cbSJens Wiklander         }
874817466cbSJens Wiklander 
875817466cbSJens Wiklander         /* Set output size for decryption */
876817466cbSJens Wiklander         if( MBEDTLS_DECRYPT == ctx->operation )
8773d3b0591SJens Wiklander             return( ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ),
8783d3b0591SJens Wiklander                                       olen ) );
879817466cbSJens Wiklander 
880817466cbSJens Wiklander         /* Set output size for encryption */
881817466cbSJens Wiklander         *olen = mbedtls_cipher_get_block_size( ctx );
882817466cbSJens Wiklander         return( 0 );
883817466cbSJens Wiklander     }
884817466cbSJens Wiklander #else
885817466cbSJens Wiklander     ((void) output);
886817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CBC */
887817466cbSJens Wiklander 
888817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
889817466cbSJens Wiklander }
890817466cbSJens Wiklander 
891817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
8923d3b0591SJens Wiklander int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx,
8933d3b0591SJens Wiklander                                      mbedtls_cipher_padding_t mode )
894817466cbSJens Wiklander {
8953d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
8963d3b0591SJens Wiklander 
8973d3b0591SJens Wiklander     if( NULL == ctx->cipher_info || MBEDTLS_MODE_CBC != ctx->cipher_info->mode )
898817466cbSJens Wiklander     {
899817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
900817466cbSJens Wiklander     }
901817466cbSJens Wiklander 
902817466cbSJens Wiklander     switch( mode )
903817466cbSJens Wiklander     {
904817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
905817466cbSJens Wiklander     case MBEDTLS_PADDING_PKCS7:
906817466cbSJens Wiklander         ctx->add_padding = add_pkcs_padding;
907817466cbSJens Wiklander         ctx->get_padding = get_pkcs_padding;
908817466cbSJens Wiklander         break;
909817466cbSJens Wiklander #endif
910817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
911817466cbSJens Wiklander     case MBEDTLS_PADDING_ONE_AND_ZEROS:
912817466cbSJens Wiklander         ctx->add_padding = add_one_and_zeros_padding;
913817466cbSJens Wiklander         ctx->get_padding = get_one_and_zeros_padding;
914817466cbSJens Wiklander         break;
915817466cbSJens Wiklander #endif
916817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
917817466cbSJens Wiklander     case MBEDTLS_PADDING_ZEROS_AND_LEN:
918817466cbSJens Wiklander         ctx->add_padding = add_zeros_and_len_padding;
919817466cbSJens Wiklander         ctx->get_padding = get_zeros_and_len_padding;
920817466cbSJens Wiklander         break;
921817466cbSJens Wiklander #endif
922817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
923817466cbSJens Wiklander     case MBEDTLS_PADDING_ZEROS:
924817466cbSJens Wiklander         ctx->add_padding = add_zeros_padding;
925817466cbSJens Wiklander         ctx->get_padding = get_zeros_padding;
926817466cbSJens Wiklander         break;
927817466cbSJens Wiklander #endif
928817466cbSJens Wiklander     case MBEDTLS_PADDING_NONE:
929817466cbSJens Wiklander         ctx->add_padding = NULL;
930817466cbSJens Wiklander         ctx->get_padding = get_no_padding;
931817466cbSJens Wiklander         break;
932817466cbSJens Wiklander 
933817466cbSJens Wiklander     default:
934817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
935817466cbSJens Wiklander     }
936817466cbSJens Wiklander 
937817466cbSJens Wiklander     return( 0 );
938817466cbSJens Wiklander }
939817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
940817466cbSJens Wiklander 
9413d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
942817466cbSJens Wiklander int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx,
943817466cbSJens Wiklander                       unsigned char *tag, size_t tag_len )
944817466cbSJens Wiklander {
9453d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
9463d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
9473d3b0591SJens Wiklander     if( ctx->cipher_info == NULL )
948817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
949817466cbSJens Wiklander 
950817466cbSJens Wiklander     if( MBEDTLS_ENCRYPT != ctx->operation )
951817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
952817466cbSJens Wiklander 
9533d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C)
954817466cbSJens Wiklander     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
9553d3b0591SJens Wiklander         return( mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx,
9563d3b0591SJens Wiklander                                     tag, tag_len ) );
9573d3b0591SJens Wiklander #endif
9583d3b0591SJens Wiklander 
9593d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
9603d3b0591SJens Wiklander     if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
9613d3b0591SJens Wiklander     {
9623d3b0591SJens Wiklander         /* Don't allow truncated MAC for Poly1305 */
9633d3b0591SJens Wiklander         if ( tag_len != 16U )
9643d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
9653d3b0591SJens Wiklander 
9663d3b0591SJens Wiklander         return( mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
9673d3b0591SJens Wiklander                                            tag ) );
9683d3b0591SJens Wiklander     }
9693d3b0591SJens Wiklander #endif
970817466cbSJens Wiklander 
971817466cbSJens Wiklander     return( 0 );
972817466cbSJens Wiklander }
973817466cbSJens Wiklander 
974817466cbSJens Wiklander int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx,
975817466cbSJens Wiklander                       const unsigned char *tag, size_t tag_len )
976817466cbSJens Wiklander {
9773d3b0591SJens Wiklander     unsigned char check_tag[16];
978817466cbSJens Wiklander     int ret;
979817466cbSJens Wiklander 
9803d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
9813d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
9823d3b0591SJens Wiklander     if( ctx->cipher_info == NULL )
9833d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
9843d3b0591SJens Wiklander 
9853d3b0591SJens Wiklander     if( MBEDTLS_DECRYPT != ctx->operation )
986817466cbSJens Wiklander     {
987817466cbSJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
988817466cbSJens Wiklander     }
989817466cbSJens Wiklander 
9903d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C)
991817466cbSJens Wiklander     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
992817466cbSJens Wiklander     {
993817466cbSJens Wiklander         if( tag_len > sizeof( check_tag ) )
994817466cbSJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
995817466cbSJens Wiklander 
996817466cbSJens Wiklander         if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx,
997817466cbSJens Wiklander                                      check_tag, tag_len ) ) )
998817466cbSJens Wiklander         {
999817466cbSJens Wiklander             return( ret );
1000817466cbSJens Wiklander         }
1001817466cbSJens Wiklander 
1002817466cbSJens Wiklander         /* Check the tag in "constant-time" */
10033d3b0591SJens Wiklander         if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 )
1004817466cbSJens Wiklander             return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
1005817466cbSJens Wiklander 
1006817466cbSJens Wiklander         return( 0 );
1007817466cbSJens Wiklander     }
10083d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C */
10093d3b0591SJens Wiklander 
10103d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
10113d3b0591SJens Wiklander     if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
10123d3b0591SJens Wiklander     {
10133d3b0591SJens Wiklander         /* Don't allow truncated MAC for Poly1305 */
10143d3b0591SJens Wiklander         if ( tag_len != sizeof( check_tag ) )
10153d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
10163d3b0591SJens Wiklander 
10173d3b0591SJens Wiklander         ret = mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
10183d3b0591SJens Wiklander                                                      check_tag );
10193d3b0591SJens Wiklander         if ( ret != 0 )
10203d3b0591SJens Wiklander         {
10213d3b0591SJens Wiklander             return( ret );
10223d3b0591SJens Wiklander         }
10233d3b0591SJens Wiklander 
10243d3b0591SJens Wiklander         /* Check the tag in "constant-time" */
10253d3b0591SJens Wiklander         if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 )
10263d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
1027817466cbSJens Wiklander 
1028817466cbSJens Wiklander         return( 0 );
1029817466cbSJens Wiklander     }
10303d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */
10313d3b0591SJens Wiklander 
10323d3b0591SJens Wiklander     return( 0 );
10333d3b0591SJens Wiklander }
10343d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */
1035817466cbSJens Wiklander 
1036817466cbSJens Wiklander /*
1037817466cbSJens Wiklander  * Packet-oriented wrapper for non-AEAD modes
1038817466cbSJens Wiklander  */
1039817466cbSJens Wiklander int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx,
1040817466cbSJens Wiklander                   const unsigned char *iv, size_t iv_len,
1041817466cbSJens Wiklander                   const unsigned char *input, size_t ilen,
1042817466cbSJens Wiklander                   unsigned char *output, size_t *olen )
1043817466cbSJens Wiklander {
1044817466cbSJens Wiklander     int ret;
1045817466cbSJens Wiklander     size_t finish_olen;
1046817466cbSJens Wiklander 
10473d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
10483d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL );
10493d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
10503d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( output != NULL );
10513d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( olen != NULL );
10523d3b0591SJens Wiklander 
1053817466cbSJens Wiklander     if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 )
1054817466cbSJens Wiklander         return( ret );
1055817466cbSJens Wiklander 
1056817466cbSJens Wiklander     if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 )
1057817466cbSJens Wiklander         return( ret );
1058817466cbSJens Wiklander 
1059817466cbSJens Wiklander     if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 )
1060817466cbSJens Wiklander         return( ret );
1061817466cbSJens Wiklander 
1062817466cbSJens Wiklander     if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 )
1063817466cbSJens Wiklander         return( ret );
1064817466cbSJens Wiklander 
1065817466cbSJens Wiklander     *olen += finish_olen;
1066817466cbSJens Wiklander 
1067817466cbSJens Wiklander     return( 0 );
1068817466cbSJens Wiklander }
1069817466cbSJens Wiklander 
1070817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_AEAD)
1071817466cbSJens Wiklander /*
1072817466cbSJens Wiklander  * Packet-oriented encryption for AEAD modes
1073817466cbSJens Wiklander  */
1074817466cbSJens Wiklander int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
1075817466cbSJens Wiklander                          const unsigned char *iv, size_t iv_len,
1076817466cbSJens Wiklander                          const unsigned char *ad, size_t ad_len,
1077817466cbSJens Wiklander                          const unsigned char *input, size_t ilen,
1078817466cbSJens Wiklander                          unsigned char *output, size_t *olen,
1079817466cbSJens Wiklander                          unsigned char *tag, size_t tag_len )
1080817466cbSJens Wiklander {
10813d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
10823d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( iv != NULL );
10833d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
10843d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
10853d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( output != NULL );
10863d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( olen != NULL );
10873d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
10883d3b0591SJens Wiklander 
1089817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C)
1090817466cbSJens Wiklander     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
1091817466cbSJens Wiklander     {
1092817466cbSJens Wiklander         *olen = ilen;
1093817466cbSJens Wiklander         return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen,
1094817466cbSJens Wiklander                                    iv, iv_len, ad, ad_len, input, output,
1095817466cbSJens Wiklander                                    tag_len, tag ) );
1096817466cbSJens Wiklander     }
1097817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */
1098817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C)
1099817466cbSJens Wiklander     if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
1100817466cbSJens Wiklander     {
1101817466cbSJens Wiklander         *olen = ilen;
1102817466cbSJens Wiklander         return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen,
1103817466cbSJens Wiklander                                      iv, iv_len, ad, ad_len, input, output,
1104817466cbSJens Wiklander                                      tag, tag_len ) );
1105817466cbSJens Wiklander     }
1106817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */
11073d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
11083d3b0591SJens Wiklander     if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
11093d3b0591SJens Wiklander     {
11103d3b0591SJens Wiklander         /* ChachaPoly has fixed length nonce and MAC (tag) */
11113d3b0591SJens Wiklander         if ( ( iv_len != ctx->cipher_info->iv_size ) ||
11123d3b0591SJens Wiklander              ( tag_len != 16U ) )
11133d3b0591SJens Wiklander         {
11143d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
11153d3b0591SJens Wiklander         }
11163d3b0591SJens Wiklander 
11173d3b0591SJens Wiklander         *olen = ilen;
11183d3b0591SJens Wiklander         return( mbedtls_chachapoly_encrypt_and_tag( ctx->cipher_ctx,
11193d3b0591SJens Wiklander                                 ilen, iv, ad, ad_len, input, output, tag ) );
11203d3b0591SJens Wiklander     }
11213d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */
1122817466cbSJens Wiklander 
1123817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
1124817466cbSJens Wiklander }
1125817466cbSJens Wiklander 
1126817466cbSJens Wiklander /*
1127817466cbSJens Wiklander  * Packet-oriented decryption for AEAD modes
1128817466cbSJens Wiklander  */
1129817466cbSJens Wiklander int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
1130817466cbSJens Wiklander                          const unsigned char *iv, size_t iv_len,
1131817466cbSJens Wiklander                          const unsigned char *ad, size_t ad_len,
1132817466cbSJens Wiklander                          const unsigned char *input, size_t ilen,
1133817466cbSJens Wiklander                          unsigned char *output, size_t *olen,
1134817466cbSJens Wiklander                          const unsigned char *tag, size_t tag_len )
1135817466cbSJens Wiklander {
11363d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ctx != NULL );
11373d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( iv != NULL );
11383d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
11393d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
11403d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( output != NULL );
11413d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( olen != NULL );
11423d3b0591SJens Wiklander     CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
11433d3b0591SJens Wiklander 
1144817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C)
1145817466cbSJens Wiklander     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
1146817466cbSJens Wiklander     {
1147817466cbSJens Wiklander         int ret;
1148817466cbSJens Wiklander 
1149817466cbSJens Wiklander         *olen = ilen;
1150817466cbSJens Wiklander         ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen,
1151817466cbSJens Wiklander                                 iv, iv_len, ad, ad_len,
1152817466cbSJens Wiklander                                 tag, tag_len, input, output );
1153817466cbSJens Wiklander 
1154817466cbSJens Wiklander         if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED )
1155817466cbSJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
1156817466cbSJens Wiklander 
1157817466cbSJens Wiklander         return( ret );
1158817466cbSJens Wiklander     }
1159817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */
1160817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C)
1161817466cbSJens Wiklander     if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
1162817466cbSJens Wiklander     {
1163817466cbSJens Wiklander         int ret;
1164817466cbSJens Wiklander 
1165817466cbSJens Wiklander         *olen = ilen;
1166817466cbSJens Wiklander         ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen,
1167817466cbSJens Wiklander                                 iv, iv_len, ad, ad_len,
1168817466cbSJens Wiklander                                 input, output, tag, tag_len );
1169817466cbSJens Wiklander 
1170817466cbSJens Wiklander         if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED )
1171817466cbSJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
1172817466cbSJens Wiklander 
1173817466cbSJens Wiklander         return( ret );
1174817466cbSJens Wiklander     }
1175817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */
11763d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
11773d3b0591SJens Wiklander     if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
11783d3b0591SJens Wiklander     {
11793d3b0591SJens Wiklander         int ret;
11803d3b0591SJens Wiklander 
11813d3b0591SJens Wiklander         /* ChachaPoly has fixed length nonce and MAC (tag) */
11823d3b0591SJens Wiklander         if ( ( iv_len != ctx->cipher_info->iv_size ) ||
11833d3b0591SJens Wiklander              ( tag_len != 16U ) )
11843d3b0591SJens Wiklander         {
11853d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
11863d3b0591SJens Wiklander         }
11873d3b0591SJens Wiklander 
11883d3b0591SJens Wiklander         *olen = ilen;
11893d3b0591SJens Wiklander         ret = mbedtls_chachapoly_auth_decrypt( ctx->cipher_ctx, ilen,
11903d3b0591SJens Wiklander                                 iv, ad, ad_len, tag, input, output );
11913d3b0591SJens Wiklander 
11923d3b0591SJens Wiklander         if( ret == MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED )
11933d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
11943d3b0591SJens Wiklander 
11953d3b0591SJens Wiklander         return( ret );
11963d3b0591SJens Wiklander     }
11973d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */
1198817466cbSJens Wiklander 
1199817466cbSJens Wiklander     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
1200817466cbSJens Wiklander }
1201817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_AEAD */
1202817466cbSJens Wiklander 
1203817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_C */
1204