xref: /reactos/dll/3rdparty/mbedtls/cipher.c (revision 1b00a1f5)
1c2c66affSColin Finck /**
2c2c66affSColin Finck  * \file cipher.c
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * \brief Generic cipher wrapper for mbed TLS
5c2c66affSColin Finck  *
6c2c66affSColin Finck  * \author Adriaan de Jong <dejong@fox-it.com>
7c2c66affSColin Finck  *
8c2c66affSColin Finck  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
9c2c66affSColin Finck  *  SPDX-License-Identifier: GPL-2.0
10c2c66affSColin Finck  *
11c2c66affSColin Finck  *  This program is free software; you can redistribute it and/or modify
12c2c66affSColin Finck  *  it under the terms of the GNU General Public License as published by
13c2c66affSColin Finck  *  the Free Software Foundation; either version 2 of the License, or
14c2c66affSColin Finck  *  (at your option) any later version.
15c2c66affSColin Finck  *
16c2c66affSColin Finck  *  This program is distributed in the hope that it will be useful,
17c2c66affSColin Finck  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18c2c66affSColin Finck  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19c2c66affSColin Finck  *  GNU General Public License for more details.
20c2c66affSColin Finck  *
21c2c66affSColin Finck  *  You should have received a copy of the GNU General Public License along
22c2c66affSColin Finck  *  with this program; if not, write to the Free Software Foundation, Inc.,
23c2c66affSColin Finck  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24c2c66affSColin Finck  *
25c2c66affSColin Finck  *  This file is part of mbed TLS (https://tls.mbed.org)
26c2c66affSColin Finck  */
27c2c66affSColin Finck 
28c2c66affSColin Finck #if !defined(MBEDTLS_CONFIG_FILE)
29c2c66affSColin Finck #include "mbedtls/config.h"
30c2c66affSColin Finck #else
31c2c66affSColin Finck #include MBEDTLS_CONFIG_FILE
32c2c66affSColin Finck #endif
33c2c66affSColin Finck 
34c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_C)
35c2c66affSColin Finck 
36c2c66affSColin Finck #include "mbedtls/cipher.h"
37c2c66affSColin Finck #include "mbedtls/cipher_internal.h"
38c2c66affSColin Finck 
39c2c66affSColin Finck #include <stdlib.h>
40c2c66affSColin Finck #include <string.h>
41c2c66affSColin Finck 
42c2c66affSColin Finck #if defined(MBEDTLS_GCM_C)
43c2c66affSColin Finck #include "mbedtls/gcm.h"
44c2c66affSColin Finck #endif
45c2c66affSColin Finck 
46c2c66affSColin Finck #if defined(MBEDTLS_CCM_C)
47c2c66affSColin Finck #include "mbedtls/ccm.h"
48c2c66affSColin Finck #endif
49c2c66affSColin Finck 
50c2c66affSColin Finck #if defined(MBEDTLS_CMAC_C)
51c2c66affSColin Finck #include "mbedtls/cmac.h"
52c2c66affSColin Finck #endif
53c2c66affSColin Finck 
54c2c66affSColin Finck #if defined(MBEDTLS_PLATFORM_C)
55c2c66affSColin Finck #include "mbedtls/platform.h"
56c2c66affSColin Finck #else
57c2c66affSColin Finck #define mbedtls_calloc calloc
58c2c66affSColin Finck #define mbedtls_free   free
59c2c66affSColin Finck #endif
60c2c66affSColin Finck 
61c2c66affSColin Finck /* Implementation that should never be optimized out by the compiler */
62c2c66affSColin Finck static void mbedtls_zeroize( void *v, size_t n ) {
63c2c66affSColin Finck     volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
64c2c66affSColin Finck }
65c2c66affSColin Finck 
66c2c66affSColin Finck static int supported_init = 0;
67c2c66affSColin Finck 
68c2c66affSColin Finck const int *mbedtls_cipher_list( void )
69c2c66affSColin Finck {
70c2c66affSColin Finck     const mbedtls_cipher_definition_t *def;
71c2c66affSColin Finck     int *type;
72c2c66affSColin Finck 
73c2c66affSColin Finck     if( ! supported_init )
74c2c66affSColin Finck     {
75c2c66affSColin Finck         def = mbedtls_cipher_definitions;
76c2c66affSColin Finck         type = mbedtls_cipher_supported;
77c2c66affSColin Finck 
78c2c66affSColin Finck         while( def->type != 0 )
79c2c66affSColin Finck             *type++ = (*def++).type;
80c2c66affSColin Finck 
81c2c66affSColin Finck         *type = 0;
82c2c66affSColin Finck 
83c2c66affSColin Finck         supported_init = 1;
84c2c66affSColin Finck     }
85c2c66affSColin Finck 
86c2c66affSColin Finck     return( mbedtls_cipher_supported );
87c2c66affSColin Finck }
88c2c66affSColin Finck 
89c2c66affSColin Finck const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type )
90c2c66affSColin Finck {
91c2c66affSColin Finck     const mbedtls_cipher_definition_t *def;
92c2c66affSColin Finck 
93c2c66affSColin Finck     for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
94c2c66affSColin Finck         if( def->type == cipher_type )
95c2c66affSColin Finck             return( def->info );
96c2c66affSColin Finck 
97c2c66affSColin Finck     return( NULL );
98c2c66affSColin Finck }
99c2c66affSColin Finck 
100c2c66affSColin Finck const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name )
101c2c66affSColin Finck {
102c2c66affSColin Finck     const mbedtls_cipher_definition_t *def;
103c2c66affSColin Finck 
104c2c66affSColin Finck     if( NULL == cipher_name )
105c2c66affSColin Finck         return( NULL );
106c2c66affSColin Finck 
107c2c66affSColin Finck     for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
108c2c66affSColin Finck         if( !  strcmp( def->info->name, cipher_name ) )
109c2c66affSColin Finck             return( def->info );
110c2c66affSColin Finck 
111c2c66affSColin Finck     return( NULL );
112c2c66affSColin Finck }
113c2c66affSColin Finck 
114c2c66affSColin Finck const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id,
115c2c66affSColin Finck                                               int key_bitlen,
116c2c66affSColin Finck                                               const mbedtls_cipher_mode_t mode )
117c2c66affSColin Finck {
118c2c66affSColin Finck     const mbedtls_cipher_definition_t *def;
119c2c66affSColin Finck 
120c2c66affSColin Finck     for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
121c2c66affSColin Finck         if( def->info->base->cipher == cipher_id &&
122c2c66affSColin Finck             def->info->key_bitlen == (unsigned) key_bitlen &&
123c2c66affSColin Finck             def->info->mode == mode )
124c2c66affSColin Finck             return( def->info );
125c2c66affSColin Finck 
126c2c66affSColin Finck     return( NULL );
127c2c66affSColin Finck }
128c2c66affSColin Finck 
129c2c66affSColin Finck void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx )
130c2c66affSColin Finck {
131c2c66affSColin Finck     memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
132c2c66affSColin Finck }
133c2c66affSColin Finck 
134c2c66affSColin Finck void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx )
135c2c66affSColin Finck {
136c2c66affSColin Finck     if( ctx == NULL )
137c2c66affSColin Finck         return;
138c2c66affSColin Finck 
139c2c66affSColin Finck #if defined(MBEDTLS_CMAC_C)
140c2c66affSColin Finck     if( ctx->cmac_ctx )
141c2c66affSColin Finck     {
142c2c66affSColin Finck        mbedtls_zeroize( ctx->cmac_ctx, sizeof( mbedtls_cmac_context_t ) );
143c2c66affSColin Finck        mbedtls_free( ctx->cmac_ctx );
144c2c66affSColin Finck     }
145c2c66affSColin Finck #endif
146c2c66affSColin Finck 
147c2c66affSColin Finck     if( ctx->cipher_ctx )
148c2c66affSColin Finck         ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx );
149c2c66affSColin Finck 
150c2c66affSColin Finck     mbedtls_zeroize( ctx, sizeof(mbedtls_cipher_context_t) );
151c2c66affSColin Finck }
152c2c66affSColin Finck 
153c2c66affSColin Finck int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info )
154c2c66affSColin Finck {
155c2c66affSColin Finck     if( NULL == cipher_info || NULL == ctx )
156c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
157c2c66affSColin Finck 
158c2c66affSColin Finck     memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
159c2c66affSColin Finck 
160c2c66affSColin Finck     if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) )
161c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED );
162c2c66affSColin Finck 
163c2c66affSColin Finck     ctx->cipher_info = cipher_info;
164c2c66affSColin Finck 
165c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
166c2c66affSColin Finck     /*
167c2c66affSColin Finck      * Ignore possible errors caused by a cipher mode that doesn't use padding
168c2c66affSColin Finck      */
169c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
170c2c66affSColin Finck     (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 );
171c2c66affSColin Finck #else
172c2c66affSColin Finck     (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE );
173c2c66affSColin Finck #endif
174c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
175c2c66affSColin Finck 
176c2c66affSColin Finck     return( 0 );
177c2c66affSColin Finck }
178c2c66affSColin Finck 
179c2c66affSColin Finck int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key,
180c2c66affSColin Finck         int key_bitlen, const mbedtls_operation_t operation )
181c2c66affSColin Finck {
182c2c66affSColin Finck     if( NULL == ctx || NULL == ctx->cipher_info )
183c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
184c2c66affSColin Finck 
185c2c66affSColin Finck     if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 &&
186c2c66affSColin Finck         (int) ctx->cipher_info->key_bitlen != key_bitlen )
187c2c66affSColin Finck     {
188c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
189c2c66affSColin Finck     }
190c2c66affSColin Finck 
191c2c66affSColin Finck     ctx->key_bitlen = key_bitlen;
192c2c66affSColin Finck     ctx->operation = operation;
193c2c66affSColin Finck 
194c2c66affSColin Finck     /*
195c2c66affSColin Finck      * For CFB and CTR mode always use the encryption key schedule
196c2c66affSColin Finck      */
197c2c66affSColin Finck     if( MBEDTLS_ENCRYPT == operation ||
198c2c66affSColin Finck         MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
199c2c66affSColin Finck         MBEDTLS_MODE_CTR == ctx->cipher_info->mode )
200c2c66affSColin Finck     {
201c2c66affSColin Finck         return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key,
202c2c66affSColin Finck                 ctx->key_bitlen );
203c2c66affSColin Finck     }
204c2c66affSColin Finck 
205c2c66affSColin Finck     if( MBEDTLS_DECRYPT == operation )
206c2c66affSColin Finck         return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key,
207c2c66affSColin Finck                 ctx->key_bitlen );
208c2c66affSColin Finck 
209c2c66affSColin Finck     return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
210c2c66affSColin Finck }
211c2c66affSColin Finck 
212c2c66affSColin Finck int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx,
213c2c66affSColin Finck                    const unsigned char *iv, size_t iv_len )
214c2c66affSColin Finck {
215c2c66affSColin Finck     size_t actual_iv_size;
2160ba5bc40SThomas Faber     if( NULL == ctx || NULL == ctx->cipher_info )
217c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
2180ba5bc40SThomas Faber     else if( NULL == iv && iv_len != 0  )
2190ba5bc40SThomas Faber         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
2200ba5bc40SThomas Faber 
2210ba5bc40SThomas Faber     if( NULL == iv && iv_len == 0 )
2220ba5bc40SThomas Faber         ctx->iv_size = 0;
223c2c66affSColin Finck 
224c2c66affSColin Finck     /* avoid buffer overflow in ctx->iv */
225c2c66affSColin Finck     if( iv_len > MBEDTLS_MAX_IV_LENGTH )
226c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
227c2c66affSColin Finck 
228c2c66affSColin Finck     if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 )
229c2c66affSColin Finck         actual_iv_size = iv_len;
230c2c66affSColin Finck     else
231c2c66affSColin Finck     {
232c2c66affSColin Finck         actual_iv_size = ctx->cipher_info->iv_size;
233c2c66affSColin Finck 
234c2c66affSColin Finck         /* avoid reading past the end of input buffer */
235c2c66affSColin Finck         if( actual_iv_size > iv_len )
236c2c66affSColin Finck             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
237c2c66affSColin Finck     }
2380ba5bc40SThomas Faber     if ( actual_iv_size != 0 )
2390ba5bc40SThomas Faber     {
240c2c66affSColin Finck         memcpy( ctx->iv, iv, actual_iv_size );
241c2c66affSColin Finck         ctx->iv_size = actual_iv_size;
2420ba5bc40SThomas Faber     }
243c2c66affSColin Finck 
244c2c66affSColin Finck     return( 0 );
245c2c66affSColin Finck }
246c2c66affSColin Finck 
247c2c66affSColin Finck int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx )
248c2c66affSColin Finck {
249c2c66affSColin Finck     if( NULL == ctx || NULL == ctx->cipher_info )
250c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
251c2c66affSColin Finck 
252c2c66affSColin Finck     ctx->unprocessed_len = 0;
253c2c66affSColin Finck 
254c2c66affSColin Finck     return( 0 );
255c2c66affSColin Finck }
256c2c66affSColin Finck 
257c2c66affSColin Finck #if defined(MBEDTLS_GCM_C)
258c2c66affSColin Finck int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx,
259c2c66affSColin Finck                       const unsigned char *ad, size_t ad_len )
260c2c66affSColin Finck {
261c2c66affSColin Finck     if( NULL == ctx || NULL == ctx->cipher_info )
262c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
263c2c66affSColin Finck 
264c2c66affSColin Finck     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
265c2c66affSColin Finck     {
266c2c66affSColin Finck         return mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation,
267c2c66affSColin Finck                            ctx->iv, ctx->iv_size, ad, ad_len );
268c2c66affSColin Finck     }
269c2c66affSColin Finck 
270c2c66affSColin Finck     return( 0 );
271c2c66affSColin Finck }
272c2c66affSColin Finck #endif /* MBEDTLS_GCM_C */
273c2c66affSColin Finck 
274c2c66affSColin Finck int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input,
275c2c66affSColin Finck                    size_t ilen, unsigned char *output, size_t *olen )
276c2c66affSColin Finck {
277c2c66affSColin Finck     int ret;
278c2c66affSColin Finck     size_t block_size = 0;
279c2c66affSColin Finck 
280c2c66affSColin Finck     if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
281c2c66affSColin Finck     {
282c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
283c2c66affSColin Finck     }
284c2c66affSColin Finck 
285c2c66affSColin Finck     *olen = 0;
286c2c66affSColin Finck     block_size = mbedtls_cipher_get_block_size( ctx );
287*1b00a1f5SThomas Faber     if ( 0 == block_size )
288*1b00a1f5SThomas Faber     {
289*1b00a1f5SThomas Faber         return( MBEDTLS_ERR_CIPHER_INVALID_CONTEXT );
290*1b00a1f5SThomas Faber     }
291c2c66affSColin Finck 
292c2c66affSColin Finck     if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB )
293c2c66affSColin Finck     {
294c2c66affSColin Finck         if( ilen != block_size )
295c2c66affSColin Finck             return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
296c2c66affSColin Finck 
297c2c66affSColin Finck         *olen = ilen;
298c2c66affSColin Finck 
299c2c66affSColin Finck         if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx,
300c2c66affSColin Finck                     ctx->operation, input, output ) ) )
301c2c66affSColin Finck         {
302c2c66affSColin Finck             return( ret );
303c2c66affSColin Finck         }
304c2c66affSColin Finck 
305c2c66affSColin Finck         return( 0 );
306c2c66affSColin Finck     }
307c2c66affSColin Finck 
308c2c66affSColin Finck #if defined(MBEDTLS_GCM_C)
309c2c66affSColin Finck     if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM )
310c2c66affSColin Finck     {
311c2c66affSColin Finck         *olen = ilen;
312c2c66affSColin Finck         return mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input,
313c2c66affSColin Finck                            output );
314c2c66affSColin Finck     }
315c2c66affSColin Finck #endif
316c2c66affSColin Finck 
317c2c66affSColin Finck     if( input == output &&
318c2c66affSColin Finck        ( ctx->unprocessed_len != 0 || ilen % block_size ) )
319c2c66affSColin Finck     {
320c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
321c2c66affSColin Finck     }
322c2c66affSColin Finck 
323c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_MODE_CBC)
324c2c66affSColin Finck     if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC )
325c2c66affSColin Finck     {
326c2c66affSColin Finck         size_t copy_len = 0;
327c2c66affSColin Finck 
328c2c66affSColin Finck         /*
329c2c66affSColin Finck          * If there is not enough data for a full block, cache it.
330c2c66affSColin Finck          */
331d9e6c9b5SThomas Faber         if( ( ctx->operation == MBEDTLS_DECRYPT && NULL != ctx->add_padding &&
332c2c66affSColin Finck                 ilen <= block_size - ctx->unprocessed_len ) ||
333d9e6c9b5SThomas Faber             ( ctx->operation == MBEDTLS_DECRYPT && NULL == ctx->add_padding &&
334d9e6c9b5SThomas Faber                 ilen < block_size - ctx->unprocessed_len ) ||
335c2c66affSColin Finck              ( ctx->operation == MBEDTLS_ENCRYPT &&
336c2c66affSColin Finck                 ilen < block_size - ctx->unprocessed_len ) )
337c2c66affSColin Finck         {
338c2c66affSColin Finck             memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
339c2c66affSColin Finck                     ilen );
340c2c66affSColin Finck 
341c2c66affSColin Finck             ctx->unprocessed_len += ilen;
342c2c66affSColin Finck             return( 0 );
343c2c66affSColin Finck         }
344c2c66affSColin Finck 
345c2c66affSColin Finck         /*
346c2c66affSColin Finck          * Process cached data first
347c2c66affSColin Finck          */
348c2c66affSColin Finck         if( 0 != ctx->unprocessed_len )
349c2c66affSColin Finck         {
350c2c66affSColin Finck             copy_len = block_size - ctx->unprocessed_len;
351c2c66affSColin Finck 
352c2c66affSColin Finck             memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
353c2c66affSColin Finck                     copy_len );
354c2c66affSColin Finck 
355c2c66affSColin Finck             if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
356c2c66affSColin Finck                     ctx->operation, block_size, ctx->iv,
357c2c66affSColin Finck                     ctx->unprocessed_data, output ) ) )
358c2c66affSColin Finck             {
359c2c66affSColin Finck                 return( ret );
360c2c66affSColin Finck             }
361c2c66affSColin Finck 
362c2c66affSColin Finck             *olen += block_size;
363c2c66affSColin Finck             output += block_size;
364c2c66affSColin Finck             ctx->unprocessed_len = 0;
365c2c66affSColin Finck 
366c2c66affSColin Finck             input += copy_len;
367c2c66affSColin Finck             ilen -= copy_len;
368c2c66affSColin Finck         }
369c2c66affSColin Finck 
370c2c66affSColin Finck         /*
371c2c66affSColin Finck          * Cache final, incomplete block
372c2c66affSColin Finck          */
373c2c66affSColin Finck         if( 0 != ilen )
374c2c66affSColin Finck         {
375d9e6c9b5SThomas Faber             /* Encryption: only cache partial blocks
376d9e6c9b5SThomas Faber              * Decryption w/ padding: always keep at least one whole block
377d9e6c9b5SThomas Faber              * Decryption w/o padding: only cache partial blocks
378d9e6c9b5SThomas Faber              */
379c2c66affSColin Finck             copy_len = ilen % block_size;
380d9e6c9b5SThomas Faber             if( copy_len == 0 &&
381d9e6c9b5SThomas Faber                 ctx->operation == MBEDTLS_DECRYPT &&
382d9e6c9b5SThomas Faber                 NULL != ctx->add_padding)
383d9e6c9b5SThomas Faber             {
384c2c66affSColin Finck                 copy_len = block_size;
385d9e6c9b5SThomas Faber             }
386c2c66affSColin Finck 
387c2c66affSColin Finck             memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ),
388c2c66affSColin Finck                     copy_len );
389c2c66affSColin Finck 
390c2c66affSColin Finck             ctx->unprocessed_len += copy_len;
391c2c66affSColin Finck             ilen -= copy_len;
392c2c66affSColin Finck         }
393c2c66affSColin Finck 
394c2c66affSColin Finck         /*
395c2c66affSColin Finck          * Process remaining full blocks
396c2c66affSColin Finck          */
397c2c66affSColin Finck         if( ilen )
398c2c66affSColin Finck         {
399c2c66affSColin Finck             if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
400c2c66affSColin Finck                     ctx->operation, ilen, ctx->iv, input, output ) ) )
401c2c66affSColin Finck             {
402c2c66affSColin Finck                 return( ret );
403c2c66affSColin Finck             }
404c2c66affSColin Finck 
405c2c66affSColin Finck             *olen += ilen;
406c2c66affSColin Finck         }
407c2c66affSColin Finck 
408c2c66affSColin Finck         return( 0 );
409c2c66affSColin Finck     }
410c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_MODE_CBC */
411c2c66affSColin Finck 
412c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_MODE_CFB)
413c2c66affSColin Finck     if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB )
414c2c66affSColin Finck     {
415c2c66affSColin Finck         if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx,
416c2c66affSColin Finck                 ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv,
417c2c66affSColin Finck                 input, output ) ) )
418c2c66affSColin Finck         {
419c2c66affSColin Finck             return( ret );
420c2c66affSColin Finck         }
421c2c66affSColin Finck 
422c2c66affSColin Finck         *olen = ilen;
423c2c66affSColin Finck 
424c2c66affSColin Finck         return( 0 );
425c2c66affSColin Finck     }
426c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_MODE_CFB */
427c2c66affSColin Finck 
428c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_MODE_CTR)
429c2c66affSColin Finck     if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR )
430c2c66affSColin Finck     {
431c2c66affSColin Finck         if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx,
432c2c66affSColin Finck                 ilen, &ctx->unprocessed_len, ctx->iv,
433c2c66affSColin Finck                 ctx->unprocessed_data, input, output ) ) )
434c2c66affSColin Finck         {
435c2c66affSColin Finck             return( ret );
436c2c66affSColin Finck         }
437c2c66affSColin Finck 
438c2c66affSColin Finck         *olen = ilen;
439c2c66affSColin Finck 
440c2c66affSColin Finck         return( 0 );
441c2c66affSColin Finck     }
442c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_MODE_CTR */
443c2c66affSColin Finck 
444c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_MODE_STREAM)
445c2c66affSColin Finck     if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM )
446c2c66affSColin Finck     {
447c2c66affSColin Finck         if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx,
448c2c66affSColin Finck                                                     ilen, input, output ) ) )
449c2c66affSColin Finck         {
450c2c66affSColin Finck             return( ret );
451c2c66affSColin Finck         }
452c2c66affSColin Finck 
453c2c66affSColin Finck         *olen = ilen;
454c2c66affSColin Finck 
455c2c66affSColin Finck         return( 0 );
456c2c66affSColin Finck     }
457c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_MODE_STREAM */
458c2c66affSColin Finck 
459c2c66affSColin Finck     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
460c2c66affSColin Finck }
461c2c66affSColin Finck 
462c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
463c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
464c2c66affSColin Finck /*
465c2c66affSColin Finck  * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len
466c2c66affSColin Finck  */
467c2c66affSColin Finck static void add_pkcs_padding( unsigned char *output, size_t output_len,
468c2c66affSColin Finck         size_t data_len )
469c2c66affSColin Finck {
470c2c66affSColin Finck     size_t padding_len = output_len - data_len;
471c2c66affSColin Finck     unsigned char i;
472c2c66affSColin Finck 
473c2c66affSColin Finck     for( i = 0; i < padding_len; i++ )
474c2c66affSColin Finck         output[data_len + i] = (unsigned char) padding_len;
475c2c66affSColin Finck }
476c2c66affSColin Finck 
477c2c66affSColin Finck static int get_pkcs_padding( unsigned char *input, size_t input_len,
478c2c66affSColin Finck         size_t *data_len )
479c2c66affSColin Finck {
480c2c66affSColin Finck     size_t i, pad_idx;
481c2c66affSColin Finck     unsigned char padding_len, bad = 0;
482c2c66affSColin Finck 
483c2c66affSColin Finck     if( NULL == input || NULL == data_len )
484c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
485c2c66affSColin Finck 
486c2c66affSColin Finck     padding_len = input[input_len - 1];
487c2c66affSColin Finck     *data_len = input_len - padding_len;
488c2c66affSColin Finck 
489c2c66affSColin Finck     /* Avoid logical || since it results in a branch */
490c2c66affSColin Finck     bad |= padding_len > input_len;
491c2c66affSColin Finck     bad |= padding_len == 0;
492c2c66affSColin Finck 
493c2c66affSColin Finck     /* The number of bytes checked must be independent of padding_len,
494c2c66affSColin Finck      * so pick input_len, which is usually 8 or 16 (one block) */
495c2c66affSColin Finck     pad_idx = input_len - padding_len;
496c2c66affSColin Finck     for( i = 0; i < input_len; i++ )
497c2c66affSColin Finck         bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx );
498c2c66affSColin Finck 
499c2c66affSColin Finck     return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
500c2c66affSColin Finck }
501c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
502c2c66affSColin Finck 
503c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
504c2c66affSColin Finck /*
505c2c66affSColin Finck  * One and zeros padding: fill with 80 00 ... 00
506c2c66affSColin Finck  */
507c2c66affSColin Finck static void add_one_and_zeros_padding( unsigned char *output,
508c2c66affSColin Finck                                        size_t output_len, size_t data_len )
509c2c66affSColin Finck {
510c2c66affSColin Finck     size_t padding_len = output_len - data_len;
511c2c66affSColin Finck     unsigned char i = 0;
512c2c66affSColin Finck 
513c2c66affSColin Finck     output[data_len] = 0x80;
514c2c66affSColin Finck     for( i = 1; i < padding_len; i++ )
515c2c66affSColin Finck         output[data_len + i] = 0x00;
516c2c66affSColin Finck }
517c2c66affSColin Finck 
518c2c66affSColin Finck static int get_one_and_zeros_padding( unsigned char *input, size_t input_len,
519c2c66affSColin Finck                                       size_t *data_len )
520c2c66affSColin Finck {
521c2c66affSColin Finck     size_t i;
522c2c66affSColin Finck     unsigned char done = 0, prev_done, bad;
523c2c66affSColin Finck 
524c2c66affSColin Finck     if( NULL == input || NULL == data_len )
525c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
526c2c66affSColin Finck 
527d9e6c9b5SThomas Faber     bad = 0x80;
528c2c66affSColin Finck     *data_len = 0;
529c2c66affSColin Finck     for( i = input_len; i > 0; i-- )
530c2c66affSColin Finck     {
531c2c66affSColin Finck         prev_done = done;
532c2c66affSColin Finck         done |= ( input[i - 1] != 0 );
533c2c66affSColin Finck         *data_len |= ( i - 1 ) * ( done != prev_done );
534d9e6c9b5SThomas Faber         bad ^= input[i - 1] * ( done != prev_done );
535c2c66affSColin Finck     }
536c2c66affSColin Finck 
537c2c66affSColin Finck     return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
538c2c66affSColin Finck 
539c2c66affSColin Finck }
540c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
541c2c66affSColin Finck 
542c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
543c2c66affSColin Finck /*
544c2c66affSColin Finck  * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length
545c2c66affSColin Finck  */
546c2c66affSColin Finck static void add_zeros_and_len_padding( unsigned char *output,
547c2c66affSColin Finck                                        size_t output_len, size_t data_len )
548c2c66affSColin Finck {
549c2c66affSColin Finck     size_t padding_len = output_len - data_len;
550c2c66affSColin Finck     unsigned char i = 0;
551c2c66affSColin Finck 
552c2c66affSColin Finck     for( i = 1; i < padding_len; i++ )
553c2c66affSColin Finck         output[data_len + i - 1] = 0x00;
554c2c66affSColin Finck     output[output_len - 1] = (unsigned char) padding_len;
555c2c66affSColin Finck }
556c2c66affSColin Finck 
557c2c66affSColin Finck static int get_zeros_and_len_padding( unsigned char *input, size_t input_len,
558c2c66affSColin Finck                                       size_t *data_len )
559c2c66affSColin Finck {
560c2c66affSColin Finck     size_t i, pad_idx;
561c2c66affSColin Finck     unsigned char padding_len, bad = 0;
562c2c66affSColin Finck 
563c2c66affSColin Finck     if( NULL == input || NULL == data_len )
564c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
565c2c66affSColin Finck 
566c2c66affSColin Finck     padding_len = input[input_len - 1];
567c2c66affSColin Finck     *data_len = input_len - padding_len;
568c2c66affSColin Finck 
569c2c66affSColin Finck     /* Avoid logical || since it results in a branch */
570c2c66affSColin Finck     bad |= padding_len > input_len;
571c2c66affSColin Finck     bad |= padding_len == 0;
572c2c66affSColin Finck 
573c2c66affSColin Finck     /* The number of bytes checked must be independent of padding_len */
574c2c66affSColin Finck     pad_idx = input_len - padding_len;
575c2c66affSColin Finck     for( i = 0; i < input_len - 1; i++ )
576c2c66affSColin Finck         bad |= input[i] * ( i >= pad_idx );
577c2c66affSColin Finck 
578c2c66affSColin Finck     return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
579c2c66affSColin Finck }
580c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
581c2c66affSColin Finck 
582c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
583c2c66affSColin Finck /*
584c2c66affSColin Finck  * Zero padding: fill with 00 ... 00
585c2c66affSColin Finck  */
586c2c66affSColin Finck static void add_zeros_padding( unsigned char *output,
587c2c66affSColin Finck                                size_t output_len, size_t data_len )
588c2c66affSColin Finck {
589c2c66affSColin Finck     size_t i;
590c2c66affSColin Finck 
591c2c66affSColin Finck     for( i = data_len; i < output_len; i++ )
592c2c66affSColin Finck         output[i] = 0x00;
593c2c66affSColin Finck }
594c2c66affSColin Finck 
595c2c66affSColin Finck static int get_zeros_padding( unsigned char *input, size_t input_len,
596c2c66affSColin Finck                               size_t *data_len )
597c2c66affSColin Finck {
598c2c66affSColin Finck     size_t i;
599c2c66affSColin Finck     unsigned char done = 0, prev_done;
600c2c66affSColin Finck 
601c2c66affSColin Finck     if( NULL == input || NULL == data_len )
602c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
603c2c66affSColin Finck 
604c2c66affSColin Finck     *data_len = 0;
605c2c66affSColin Finck     for( i = input_len; i > 0; i-- )
606c2c66affSColin Finck     {
607c2c66affSColin Finck         prev_done = done;
608c2c66affSColin Finck         done |= ( input[i-1] != 0 );
609c2c66affSColin Finck         *data_len |= i * ( done != prev_done );
610c2c66affSColin Finck     }
611c2c66affSColin Finck 
612c2c66affSColin Finck     return( 0 );
613c2c66affSColin Finck }
614c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
615c2c66affSColin Finck 
616c2c66affSColin Finck /*
617c2c66affSColin Finck  * No padding: don't pad :)
618c2c66affSColin Finck  *
619c2c66affSColin Finck  * There is no add_padding function (check for NULL in mbedtls_cipher_finish)
620c2c66affSColin Finck  * but a trivial get_padding function
621c2c66affSColin Finck  */
622c2c66affSColin Finck static int get_no_padding( unsigned char *input, size_t input_len,
623c2c66affSColin Finck                               size_t *data_len )
624c2c66affSColin Finck {
625c2c66affSColin Finck     if( NULL == input || NULL == data_len )
626c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
627c2c66affSColin Finck 
628c2c66affSColin Finck     *data_len = input_len;
629c2c66affSColin Finck 
630c2c66affSColin Finck     return( 0 );
631c2c66affSColin Finck }
632c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
633c2c66affSColin Finck 
634c2c66affSColin Finck int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx,
635c2c66affSColin Finck                    unsigned char *output, size_t *olen )
636c2c66affSColin Finck {
637c2c66affSColin Finck     if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
638c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
639c2c66affSColin Finck 
640c2c66affSColin Finck     *olen = 0;
641c2c66affSColin Finck 
642c2c66affSColin Finck     if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
643c2c66affSColin Finck         MBEDTLS_MODE_CTR == ctx->cipher_info->mode ||
644c2c66affSColin Finck         MBEDTLS_MODE_GCM == ctx->cipher_info->mode ||
645c2c66affSColin Finck         MBEDTLS_MODE_STREAM == ctx->cipher_info->mode )
646c2c66affSColin Finck     {
647c2c66affSColin Finck         return( 0 );
648c2c66affSColin Finck     }
649c2c66affSColin Finck 
650c2c66affSColin Finck     if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode )
651c2c66affSColin Finck     {
652c2c66affSColin Finck         if( ctx->unprocessed_len != 0 )
653c2c66affSColin Finck             return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
654c2c66affSColin Finck 
655c2c66affSColin Finck         return( 0 );
656c2c66affSColin Finck     }
657c2c66affSColin Finck 
658c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_MODE_CBC)
659c2c66affSColin Finck     if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode )
660c2c66affSColin Finck     {
661c2c66affSColin Finck         int ret = 0;
662c2c66affSColin Finck 
663c2c66affSColin Finck         if( MBEDTLS_ENCRYPT == ctx->operation )
664c2c66affSColin Finck         {
665c2c66affSColin Finck             /* check for 'no padding' mode */
666c2c66affSColin Finck             if( NULL == ctx->add_padding )
667c2c66affSColin Finck             {
668c2c66affSColin Finck                 if( 0 != ctx->unprocessed_len )
669c2c66affSColin Finck                     return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
670c2c66affSColin Finck 
671c2c66affSColin Finck                 return( 0 );
672c2c66affSColin Finck             }
673c2c66affSColin Finck 
674c2c66affSColin Finck             ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ),
675c2c66affSColin Finck                     ctx->unprocessed_len );
676c2c66affSColin Finck         }
677c2c66affSColin Finck         else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len )
678c2c66affSColin Finck         {
679c2c66affSColin Finck             /*
680c2c66affSColin Finck              * For decrypt operations, expect a full block,
681c2c66affSColin Finck              * or an empty block if no padding
682c2c66affSColin Finck              */
683c2c66affSColin Finck             if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len )
684c2c66affSColin Finck                 return( 0 );
685c2c66affSColin Finck 
686c2c66affSColin Finck             return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
687c2c66affSColin Finck         }
688c2c66affSColin Finck 
689c2c66affSColin Finck         /* cipher block */
690c2c66affSColin Finck         if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
691c2c66affSColin Finck                 ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv,
692c2c66affSColin Finck                 ctx->unprocessed_data, output ) ) )
693c2c66affSColin Finck         {
694c2c66affSColin Finck             return( ret );
695c2c66affSColin Finck         }
696c2c66affSColin Finck 
697c2c66affSColin Finck         /* Set output size for decryption */
698c2c66affSColin Finck         if( MBEDTLS_DECRYPT == ctx->operation )
699c2c66affSColin Finck             return ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ),
700c2c66affSColin Finck                                      olen );
701c2c66affSColin Finck 
702c2c66affSColin Finck         /* Set output size for encryption */
703c2c66affSColin Finck         *olen = mbedtls_cipher_get_block_size( ctx );
704c2c66affSColin Finck         return( 0 );
705c2c66affSColin Finck     }
706c2c66affSColin Finck #else
707c2c66affSColin Finck     ((void) output);
708c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_MODE_CBC */
709c2c66affSColin Finck 
710c2c66affSColin Finck     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
711c2c66affSColin Finck }
712c2c66affSColin Finck 
713c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
714c2c66affSColin Finck int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode )
715c2c66affSColin Finck {
716c2c66affSColin Finck     if( NULL == ctx ||
717c2c66affSColin Finck         MBEDTLS_MODE_CBC != ctx->cipher_info->mode )
718c2c66affSColin Finck     {
719c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
720c2c66affSColin Finck     }
721c2c66affSColin Finck 
722c2c66affSColin Finck     switch( mode )
723c2c66affSColin Finck     {
724c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
725c2c66affSColin Finck     case MBEDTLS_PADDING_PKCS7:
726c2c66affSColin Finck         ctx->add_padding = add_pkcs_padding;
727c2c66affSColin Finck         ctx->get_padding = get_pkcs_padding;
728c2c66affSColin Finck         break;
729c2c66affSColin Finck #endif
730c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
731c2c66affSColin Finck     case MBEDTLS_PADDING_ONE_AND_ZEROS:
732c2c66affSColin Finck         ctx->add_padding = add_one_and_zeros_padding;
733c2c66affSColin Finck         ctx->get_padding = get_one_and_zeros_padding;
734c2c66affSColin Finck         break;
735c2c66affSColin Finck #endif
736c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
737c2c66affSColin Finck     case MBEDTLS_PADDING_ZEROS_AND_LEN:
738c2c66affSColin Finck         ctx->add_padding = add_zeros_and_len_padding;
739c2c66affSColin Finck         ctx->get_padding = get_zeros_and_len_padding;
740c2c66affSColin Finck         break;
741c2c66affSColin Finck #endif
742c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
743c2c66affSColin Finck     case MBEDTLS_PADDING_ZEROS:
744c2c66affSColin Finck         ctx->add_padding = add_zeros_padding;
745c2c66affSColin Finck         ctx->get_padding = get_zeros_padding;
746c2c66affSColin Finck         break;
747c2c66affSColin Finck #endif
748c2c66affSColin Finck     case MBEDTLS_PADDING_NONE:
749c2c66affSColin Finck         ctx->add_padding = NULL;
750c2c66affSColin Finck         ctx->get_padding = get_no_padding;
751c2c66affSColin Finck         break;
752c2c66affSColin Finck 
753c2c66affSColin Finck     default:
754c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
755c2c66affSColin Finck     }
756c2c66affSColin Finck 
757c2c66affSColin Finck     return( 0 );
758c2c66affSColin Finck }
759c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
760c2c66affSColin Finck 
761c2c66affSColin Finck #if defined(MBEDTLS_GCM_C)
762c2c66affSColin Finck int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx,
763c2c66affSColin Finck                       unsigned char *tag, size_t tag_len )
764c2c66affSColin Finck {
765c2c66affSColin Finck     if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag )
766c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
767c2c66affSColin Finck 
768c2c66affSColin Finck     if( MBEDTLS_ENCRYPT != ctx->operation )
769c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
770c2c66affSColin Finck 
771c2c66affSColin Finck     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
772c2c66affSColin Finck         return mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, tag, tag_len );
773c2c66affSColin Finck 
774c2c66affSColin Finck     return( 0 );
775c2c66affSColin Finck }
776c2c66affSColin Finck 
777c2c66affSColin Finck int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx,
778c2c66affSColin Finck                       const unsigned char *tag, size_t tag_len )
779c2c66affSColin Finck {
780c2c66affSColin Finck     int ret;
781c2c66affSColin Finck 
782c2c66affSColin Finck     if( NULL == ctx || NULL == ctx->cipher_info ||
783c2c66affSColin Finck         MBEDTLS_DECRYPT != ctx->operation )
784c2c66affSColin Finck     {
785c2c66affSColin Finck         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
786c2c66affSColin Finck     }
787c2c66affSColin Finck 
788c2c66affSColin Finck     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
789c2c66affSColin Finck     {
790c2c66affSColin Finck         unsigned char check_tag[16];
791c2c66affSColin Finck         size_t i;
792c2c66affSColin Finck         int diff;
793c2c66affSColin Finck 
794c2c66affSColin Finck         if( tag_len > sizeof( check_tag ) )
795c2c66affSColin Finck             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
796c2c66affSColin Finck 
797c2c66affSColin Finck         if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx,
798c2c66affSColin Finck                                      check_tag, tag_len ) ) )
799c2c66affSColin Finck         {
800c2c66affSColin Finck             return( ret );
801c2c66affSColin Finck         }
802c2c66affSColin Finck 
803c2c66affSColin Finck         /* Check the tag in "constant-time" */
804c2c66affSColin Finck         for( diff = 0, i = 0; i < tag_len; i++ )
805c2c66affSColin Finck             diff |= tag[i] ^ check_tag[i];
806c2c66affSColin Finck 
807c2c66affSColin Finck         if( diff != 0 )
808c2c66affSColin Finck             return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
809c2c66affSColin Finck 
810c2c66affSColin Finck         return( 0 );
811c2c66affSColin Finck     }
812c2c66affSColin Finck 
813c2c66affSColin Finck     return( 0 );
814c2c66affSColin Finck }
815c2c66affSColin Finck #endif /* MBEDTLS_GCM_C */
816c2c66affSColin Finck 
817c2c66affSColin Finck /*
818c2c66affSColin Finck  * Packet-oriented wrapper for non-AEAD modes
819c2c66affSColin Finck  */
820c2c66affSColin Finck int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx,
821c2c66affSColin Finck                   const unsigned char *iv, size_t iv_len,
822c2c66affSColin Finck                   const unsigned char *input, size_t ilen,
823c2c66affSColin Finck                   unsigned char *output, size_t *olen )
824c2c66affSColin Finck {
825c2c66affSColin Finck     int ret;
826c2c66affSColin Finck     size_t finish_olen;
827c2c66affSColin Finck 
828c2c66affSColin Finck     if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 )
829c2c66affSColin Finck         return( ret );
830c2c66affSColin Finck 
831c2c66affSColin Finck     if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 )
832c2c66affSColin Finck         return( ret );
833c2c66affSColin Finck 
834c2c66affSColin Finck     if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 )
835c2c66affSColin Finck         return( ret );
836c2c66affSColin Finck 
837c2c66affSColin Finck     if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 )
838c2c66affSColin Finck         return( ret );
839c2c66affSColin Finck 
840c2c66affSColin Finck     *olen += finish_olen;
841c2c66affSColin Finck 
842c2c66affSColin Finck     return( 0 );
843c2c66affSColin Finck }
844c2c66affSColin Finck 
845c2c66affSColin Finck #if defined(MBEDTLS_CIPHER_MODE_AEAD)
846c2c66affSColin Finck /*
847c2c66affSColin Finck  * Packet-oriented encryption for AEAD modes
848c2c66affSColin Finck  */
849c2c66affSColin Finck int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
850c2c66affSColin Finck                          const unsigned char *iv, size_t iv_len,
851c2c66affSColin Finck                          const unsigned char *ad, size_t ad_len,
852c2c66affSColin Finck                          const unsigned char *input, size_t ilen,
853c2c66affSColin Finck                          unsigned char *output, size_t *olen,
854c2c66affSColin Finck                          unsigned char *tag, size_t tag_len )
855c2c66affSColin Finck {
856c2c66affSColin Finck #if defined(MBEDTLS_GCM_C)
857c2c66affSColin Finck     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
858c2c66affSColin Finck     {
859c2c66affSColin Finck         *olen = ilen;
860c2c66affSColin Finck         return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen,
861c2c66affSColin Finck                                    iv, iv_len, ad, ad_len, input, output,
862c2c66affSColin Finck                                    tag_len, tag ) );
863c2c66affSColin Finck     }
864c2c66affSColin Finck #endif /* MBEDTLS_GCM_C */
865c2c66affSColin Finck #if defined(MBEDTLS_CCM_C)
866c2c66affSColin Finck     if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
867c2c66affSColin Finck     {
868c2c66affSColin Finck         *olen = ilen;
869c2c66affSColin Finck         return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen,
870c2c66affSColin Finck                                      iv, iv_len, ad, ad_len, input, output,
871c2c66affSColin Finck                                      tag, tag_len ) );
872c2c66affSColin Finck     }
873c2c66affSColin Finck #endif /* MBEDTLS_CCM_C */
874c2c66affSColin Finck 
875c2c66affSColin Finck     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
876c2c66affSColin Finck }
877c2c66affSColin Finck 
878c2c66affSColin Finck /*
879c2c66affSColin Finck  * Packet-oriented decryption for AEAD modes
880c2c66affSColin Finck  */
881c2c66affSColin Finck int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
882c2c66affSColin Finck                          const unsigned char *iv, size_t iv_len,
883c2c66affSColin Finck                          const unsigned char *ad, size_t ad_len,
884c2c66affSColin Finck                          const unsigned char *input, size_t ilen,
885c2c66affSColin Finck                          unsigned char *output, size_t *olen,
886c2c66affSColin Finck                          const unsigned char *tag, size_t tag_len )
887c2c66affSColin Finck {
888c2c66affSColin Finck #if defined(MBEDTLS_GCM_C)
889c2c66affSColin Finck     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
890c2c66affSColin Finck     {
891c2c66affSColin Finck         int ret;
892c2c66affSColin Finck 
893c2c66affSColin Finck         *olen = ilen;
894c2c66affSColin Finck         ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen,
895c2c66affSColin Finck                                 iv, iv_len, ad, ad_len,
896c2c66affSColin Finck                                 tag, tag_len, input, output );
897c2c66affSColin Finck 
898c2c66affSColin Finck         if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED )
899c2c66affSColin Finck             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
900c2c66affSColin Finck 
901c2c66affSColin Finck         return( ret );
902c2c66affSColin Finck     }
903c2c66affSColin Finck #endif /* MBEDTLS_GCM_C */
904c2c66affSColin Finck #if defined(MBEDTLS_CCM_C)
905c2c66affSColin Finck     if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
906c2c66affSColin Finck     {
907c2c66affSColin Finck         int ret;
908c2c66affSColin Finck 
909c2c66affSColin Finck         *olen = ilen;
910c2c66affSColin Finck         ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen,
911c2c66affSColin Finck                                 iv, iv_len, ad, ad_len,
912c2c66affSColin Finck                                 input, output, tag, tag_len );
913c2c66affSColin Finck 
914c2c66affSColin Finck         if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED )
915c2c66affSColin Finck             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
916c2c66affSColin Finck 
917c2c66affSColin Finck         return( ret );
918c2c66affSColin Finck     }
919c2c66affSColin Finck #endif /* MBEDTLS_CCM_C */
920c2c66affSColin Finck 
921c2c66affSColin Finck     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
922c2c66affSColin Finck }
923c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_MODE_AEAD */
924c2c66affSColin Finck 
925c2c66affSColin Finck #endif /* MBEDTLS_CIPHER_C */
926