RTC auf true

Committer:
kevman
Date:
Wed Nov 28 15:10:15 2018 +0000
Revision:
0:38ceb79fef03
RTC modified

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kevman 0:38ceb79fef03 1 /**
kevman 0:38ceb79fef03 2 * \file cipher.c
kevman 0:38ceb79fef03 3 *
kevman 0:38ceb79fef03 4 * \brief Generic cipher wrapper for mbed TLS
kevman 0:38ceb79fef03 5 *
kevman 0:38ceb79fef03 6 * \author Adriaan de Jong <dejong@fox-it.com>
kevman 0:38ceb79fef03 7 *
kevman 0:38ceb79fef03 8 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
kevman 0:38ceb79fef03 9 * SPDX-License-Identifier: Apache-2.0
kevman 0:38ceb79fef03 10 *
kevman 0:38ceb79fef03 11 * Licensed under the Apache License, Version 2.0 (the "License"); you may
kevman 0:38ceb79fef03 12 * not use this file except in compliance with the License.
kevman 0:38ceb79fef03 13 * You may obtain a copy of the License at
kevman 0:38ceb79fef03 14 *
kevman 0:38ceb79fef03 15 * http://www.apache.org/licenses/LICENSE-2.0
kevman 0:38ceb79fef03 16 *
kevman 0:38ceb79fef03 17 * Unless required by applicable law or agreed to in writing, software
kevman 0:38ceb79fef03 18 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
kevman 0:38ceb79fef03 19 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
kevman 0:38ceb79fef03 20 * See the License for the specific language governing permissions and
kevman 0:38ceb79fef03 21 * limitations under the License.
kevman 0:38ceb79fef03 22 *
kevman 0:38ceb79fef03 23 * This file is part of mbed TLS (https://tls.mbed.org)
kevman 0:38ceb79fef03 24 */
kevman 0:38ceb79fef03 25
kevman 0:38ceb79fef03 26 #if !defined(MBEDTLS_CONFIG_FILE)
kevman 0:38ceb79fef03 27 #include "mbedtls/config.h"
kevman 0:38ceb79fef03 28 #else
kevman 0:38ceb79fef03 29 #include MBEDTLS_CONFIG_FILE
kevman 0:38ceb79fef03 30 #endif
kevman 0:38ceb79fef03 31
kevman 0:38ceb79fef03 32 #if defined(MBEDTLS_CIPHER_C)
kevman 0:38ceb79fef03 33
kevman 0:38ceb79fef03 34 #include "mbedtls/cipher.h"
kevman 0:38ceb79fef03 35 #include "mbedtls/cipher_internal.h"
kevman 0:38ceb79fef03 36 #include "mbedtls/platform_util.h"
kevman 0:38ceb79fef03 37
kevman 0:38ceb79fef03 38 #include <stdlib.h>
kevman 0:38ceb79fef03 39 #include <string.h>
kevman 0:38ceb79fef03 40
kevman 0:38ceb79fef03 41 #if defined(MBEDTLS_CHACHAPOLY_C)
kevman 0:38ceb79fef03 42 #include "mbedtls/chachapoly.h"
kevman 0:38ceb79fef03 43 #endif
kevman 0:38ceb79fef03 44
kevman 0:38ceb79fef03 45 #if defined(MBEDTLS_GCM_C)
kevman 0:38ceb79fef03 46 #include "mbedtls/gcm.h"
kevman 0:38ceb79fef03 47 #endif
kevman 0:38ceb79fef03 48
kevman 0:38ceb79fef03 49 #if defined(MBEDTLS_CCM_C)
kevman 0:38ceb79fef03 50 #include "mbedtls/ccm.h"
kevman 0:38ceb79fef03 51 #endif
kevman 0:38ceb79fef03 52
kevman 0:38ceb79fef03 53 #if defined(MBEDTLS_CHACHA20_C)
kevman 0:38ceb79fef03 54 #include "mbedtls/chacha20.h"
kevman 0:38ceb79fef03 55 #endif
kevman 0:38ceb79fef03 56
kevman 0:38ceb79fef03 57 #if defined(MBEDTLS_CMAC_C)
kevman 0:38ceb79fef03 58 #include "mbedtls/cmac.h"
kevman 0:38ceb79fef03 59 #endif
kevman 0:38ceb79fef03 60
kevman 0:38ceb79fef03 61 #if defined(MBEDTLS_PLATFORM_C)
kevman 0:38ceb79fef03 62 #include "mbedtls/platform.h"
kevman 0:38ceb79fef03 63 #else
kevman 0:38ceb79fef03 64 #define mbedtls_calloc calloc
kevman 0:38ceb79fef03 65 #define mbedtls_free free
kevman 0:38ceb79fef03 66 #endif
kevman 0:38ceb79fef03 67
kevman 0:38ceb79fef03 68 #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
kevman 0:38ceb79fef03 69 /* Compare the contents of two buffers in constant time.
kevman 0:38ceb79fef03 70 * Returns 0 if the contents are bitwise identical, otherwise returns
kevman 0:38ceb79fef03 71 * a non-zero value.
kevman 0:38ceb79fef03 72 * This is currently only used by GCM and ChaCha20+Poly1305.
kevman 0:38ceb79fef03 73 */
kevman 0:38ceb79fef03 74 static int mbedtls_constant_time_memcmp( const void *v1, const void *v2, size_t len )
kevman 0:38ceb79fef03 75 {
kevman 0:38ceb79fef03 76 const unsigned char *p1 = (const unsigned char*) v1;
kevman 0:38ceb79fef03 77 const unsigned char *p2 = (const unsigned char*) v2;
kevman 0:38ceb79fef03 78 size_t i;
kevman 0:38ceb79fef03 79 unsigned char diff;
kevman 0:38ceb79fef03 80
kevman 0:38ceb79fef03 81 for( diff = 0, i = 0; i < len; i++ )
kevman 0:38ceb79fef03 82 diff |= p1[i] ^ p2[i];
kevman 0:38ceb79fef03 83
kevman 0:38ceb79fef03 84 return (int)diff;
kevman 0:38ceb79fef03 85 }
kevman 0:38ceb79fef03 86 #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */
kevman 0:38ceb79fef03 87
kevman 0:38ceb79fef03 88 static int supported_init = 0;
kevman 0:38ceb79fef03 89
kevman 0:38ceb79fef03 90 const int *mbedtls_cipher_list( void )
kevman 0:38ceb79fef03 91 {
kevman 0:38ceb79fef03 92 const mbedtls_cipher_definition_t *def;
kevman 0:38ceb79fef03 93 int *type;
kevman 0:38ceb79fef03 94
kevman 0:38ceb79fef03 95 if( ! supported_init )
kevman 0:38ceb79fef03 96 {
kevman 0:38ceb79fef03 97 def = mbedtls_cipher_definitions;
kevman 0:38ceb79fef03 98 type = mbedtls_cipher_supported;
kevman 0:38ceb79fef03 99
kevman 0:38ceb79fef03 100 while( def->type != 0 )
kevman 0:38ceb79fef03 101 *type++ = (*def++).type;
kevman 0:38ceb79fef03 102
kevman 0:38ceb79fef03 103 *type = 0;
kevman 0:38ceb79fef03 104
kevman 0:38ceb79fef03 105 supported_init = 1;
kevman 0:38ceb79fef03 106 }
kevman 0:38ceb79fef03 107
kevman 0:38ceb79fef03 108 return( mbedtls_cipher_supported );
kevman 0:38ceb79fef03 109 }
kevman 0:38ceb79fef03 110
kevman 0:38ceb79fef03 111 const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type )
kevman 0:38ceb79fef03 112 {
kevman 0:38ceb79fef03 113 const mbedtls_cipher_definition_t *def;
kevman 0:38ceb79fef03 114
kevman 0:38ceb79fef03 115 for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
kevman 0:38ceb79fef03 116 if( def->type == cipher_type )
kevman 0:38ceb79fef03 117 return( def->info );
kevman 0:38ceb79fef03 118
kevman 0:38ceb79fef03 119 return( NULL );
kevman 0:38ceb79fef03 120 }
kevman 0:38ceb79fef03 121
kevman 0:38ceb79fef03 122 const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name )
kevman 0:38ceb79fef03 123 {
kevman 0:38ceb79fef03 124 const mbedtls_cipher_definition_t *def;
kevman 0:38ceb79fef03 125
kevman 0:38ceb79fef03 126 if( NULL == cipher_name )
kevman 0:38ceb79fef03 127 return( NULL );
kevman 0:38ceb79fef03 128
kevman 0:38ceb79fef03 129 for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
kevman 0:38ceb79fef03 130 if( ! strcmp( def->info->name, cipher_name ) )
kevman 0:38ceb79fef03 131 return( def->info );
kevman 0:38ceb79fef03 132
kevman 0:38ceb79fef03 133 return( NULL );
kevman 0:38ceb79fef03 134 }
kevman 0:38ceb79fef03 135
kevman 0:38ceb79fef03 136 const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id,
kevman 0:38ceb79fef03 137 int key_bitlen,
kevman 0:38ceb79fef03 138 const mbedtls_cipher_mode_t mode )
kevman 0:38ceb79fef03 139 {
kevman 0:38ceb79fef03 140 const mbedtls_cipher_definition_t *def;
kevman 0:38ceb79fef03 141
kevman 0:38ceb79fef03 142 for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
kevman 0:38ceb79fef03 143 if( def->info->base->cipher == cipher_id &&
kevman 0:38ceb79fef03 144 def->info->key_bitlen == (unsigned) key_bitlen &&
kevman 0:38ceb79fef03 145 def->info->mode == mode )
kevman 0:38ceb79fef03 146 return( def->info );
kevman 0:38ceb79fef03 147
kevman 0:38ceb79fef03 148 return( NULL );
kevman 0:38ceb79fef03 149 }
kevman 0:38ceb79fef03 150
kevman 0:38ceb79fef03 151 void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx )
kevman 0:38ceb79fef03 152 {
kevman 0:38ceb79fef03 153 memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
kevman 0:38ceb79fef03 154 }
kevman 0:38ceb79fef03 155
kevman 0:38ceb79fef03 156 void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx )
kevman 0:38ceb79fef03 157 {
kevman 0:38ceb79fef03 158 if( ctx == NULL )
kevman 0:38ceb79fef03 159 return;
kevman 0:38ceb79fef03 160
kevman 0:38ceb79fef03 161 #if defined(MBEDTLS_CMAC_C)
kevman 0:38ceb79fef03 162 if( ctx->cmac_ctx )
kevman 0:38ceb79fef03 163 {
kevman 0:38ceb79fef03 164 mbedtls_platform_zeroize( ctx->cmac_ctx,
kevman 0:38ceb79fef03 165 sizeof( mbedtls_cmac_context_t ) );
kevman 0:38ceb79fef03 166 mbedtls_free( ctx->cmac_ctx );
kevman 0:38ceb79fef03 167 }
kevman 0:38ceb79fef03 168 #endif
kevman 0:38ceb79fef03 169
kevman 0:38ceb79fef03 170 if( ctx->cipher_ctx )
kevman 0:38ceb79fef03 171 ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx );
kevman 0:38ceb79fef03 172
kevman 0:38ceb79fef03 173 mbedtls_platform_zeroize( ctx, sizeof(mbedtls_cipher_context_t) );
kevman 0:38ceb79fef03 174 }
kevman 0:38ceb79fef03 175
kevman 0:38ceb79fef03 176 int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info )
kevman 0:38ceb79fef03 177 {
kevman 0:38ceb79fef03 178 if( NULL == cipher_info || NULL == ctx )
kevman 0:38ceb79fef03 179 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 180
kevman 0:38ceb79fef03 181 memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
kevman 0:38ceb79fef03 182
kevman 0:38ceb79fef03 183 if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) )
kevman 0:38ceb79fef03 184 return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED );
kevman 0:38ceb79fef03 185
kevman 0:38ceb79fef03 186 ctx->cipher_info = cipher_info;
kevman 0:38ceb79fef03 187
kevman 0:38ceb79fef03 188 #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
kevman 0:38ceb79fef03 189 /*
kevman 0:38ceb79fef03 190 * Ignore possible errors caused by a cipher mode that doesn't use padding
kevman 0:38ceb79fef03 191 */
kevman 0:38ceb79fef03 192 #if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
kevman 0:38ceb79fef03 193 (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 );
kevman 0:38ceb79fef03 194 #else
kevman 0:38ceb79fef03 195 (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE );
kevman 0:38ceb79fef03 196 #endif
kevman 0:38ceb79fef03 197 #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
kevman 0:38ceb79fef03 198
kevman 0:38ceb79fef03 199 return( 0 );
kevman 0:38ceb79fef03 200 }
kevman 0:38ceb79fef03 201
kevman 0:38ceb79fef03 202 int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key,
kevman 0:38ceb79fef03 203 int key_bitlen, const mbedtls_operation_t operation )
kevman 0:38ceb79fef03 204 {
kevman 0:38ceb79fef03 205 if( NULL == ctx || NULL == ctx->cipher_info )
kevman 0:38ceb79fef03 206 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 207
kevman 0:38ceb79fef03 208 if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 &&
kevman 0:38ceb79fef03 209 (int) ctx->cipher_info->key_bitlen != key_bitlen )
kevman 0:38ceb79fef03 210 {
kevman 0:38ceb79fef03 211 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 212 }
kevman 0:38ceb79fef03 213
kevman 0:38ceb79fef03 214 ctx->key_bitlen = key_bitlen;
kevman 0:38ceb79fef03 215 ctx->operation = operation;
kevman 0:38ceb79fef03 216
kevman 0:38ceb79fef03 217 /*
kevman 0:38ceb79fef03 218 * For OFB, CFB and CTR mode always use the encryption key schedule
kevman 0:38ceb79fef03 219 */
kevman 0:38ceb79fef03 220 if( MBEDTLS_ENCRYPT == operation ||
kevman 0:38ceb79fef03 221 MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
kevman 0:38ceb79fef03 222 MBEDTLS_MODE_OFB == ctx->cipher_info->mode ||
kevman 0:38ceb79fef03 223 MBEDTLS_MODE_CTR == ctx->cipher_info->mode )
kevman 0:38ceb79fef03 224 {
kevman 0:38ceb79fef03 225 return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key,
kevman 0:38ceb79fef03 226 ctx->key_bitlen );
kevman 0:38ceb79fef03 227 }
kevman 0:38ceb79fef03 228
kevman 0:38ceb79fef03 229 if( MBEDTLS_DECRYPT == operation )
kevman 0:38ceb79fef03 230 return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key,
kevman 0:38ceb79fef03 231 ctx->key_bitlen );
kevman 0:38ceb79fef03 232
kevman 0:38ceb79fef03 233 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 234 }
kevman 0:38ceb79fef03 235
kevman 0:38ceb79fef03 236 int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx,
kevman 0:38ceb79fef03 237 const unsigned char *iv, size_t iv_len )
kevman 0:38ceb79fef03 238 {
kevman 0:38ceb79fef03 239 size_t actual_iv_size;
kevman 0:38ceb79fef03 240
kevman 0:38ceb79fef03 241 if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv )
kevman 0:38ceb79fef03 242 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 243
kevman 0:38ceb79fef03 244 /* avoid buffer overflow in ctx->iv */
kevman 0:38ceb79fef03 245 if( iv_len > MBEDTLS_MAX_IV_LENGTH )
kevman 0:38ceb79fef03 246 return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
kevman 0:38ceb79fef03 247
kevman 0:38ceb79fef03 248 if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 )
kevman 0:38ceb79fef03 249 actual_iv_size = iv_len;
kevman 0:38ceb79fef03 250 else
kevman 0:38ceb79fef03 251 {
kevman 0:38ceb79fef03 252 actual_iv_size = ctx->cipher_info->iv_size;
kevman 0:38ceb79fef03 253
kevman 0:38ceb79fef03 254 /* avoid reading past the end of input buffer */
kevman 0:38ceb79fef03 255 if( actual_iv_size > iv_len )
kevman 0:38ceb79fef03 256 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 257 }
kevman 0:38ceb79fef03 258
kevman 0:38ceb79fef03 259 #if defined(MBEDTLS_CHACHA20_C)
kevman 0:38ceb79fef03 260 if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20 )
kevman 0:38ceb79fef03 261 {
kevman 0:38ceb79fef03 262 if ( 0 != mbedtls_chacha20_starts( (mbedtls_chacha20_context*)ctx->cipher_ctx,
kevman 0:38ceb79fef03 263 iv,
kevman 0:38ceb79fef03 264 0U ) ) /* Initial counter value */
kevman 0:38ceb79fef03 265 {
kevman 0:38ceb79fef03 266 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 267 }
kevman 0:38ceb79fef03 268 }
kevman 0:38ceb79fef03 269 #endif
kevman 0:38ceb79fef03 270
kevman 0:38ceb79fef03 271 memcpy( ctx->iv, iv, actual_iv_size );
kevman 0:38ceb79fef03 272 ctx->iv_size = actual_iv_size;
kevman 0:38ceb79fef03 273
kevman 0:38ceb79fef03 274 return( 0 );
kevman 0:38ceb79fef03 275 }
kevman 0:38ceb79fef03 276
kevman 0:38ceb79fef03 277 int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx )
kevman 0:38ceb79fef03 278 {
kevman 0:38ceb79fef03 279 if( NULL == ctx || NULL == ctx->cipher_info )
kevman 0:38ceb79fef03 280 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 281
kevman 0:38ceb79fef03 282 ctx->unprocessed_len = 0;
kevman 0:38ceb79fef03 283
kevman 0:38ceb79fef03 284 return( 0 );
kevman 0:38ceb79fef03 285 }
kevman 0:38ceb79fef03 286
kevman 0:38ceb79fef03 287 #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
kevman 0:38ceb79fef03 288 int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx,
kevman 0:38ceb79fef03 289 const unsigned char *ad, size_t ad_len )
kevman 0:38ceb79fef03 290 {
kevman 0:38ceb79fef03 291 if( NULL == ctx || NULL == ctx->cipher_info )
kevman 0:38ceb79fef03 292 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 293
kevman 0:38ceb79fef03 294 #if defined(MBEDTLS_GCM_C)
kevman 0:38ceb79fef03 295 if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
kevman 0:38ceb79fef03 296 {
kevman 0:38ceb79fef03 297 return mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation,
kevman 0:38ceb79fef03 298 ctx->iv, ctx->iv_size, ad, ad_len );
kevman 0:38ceb79fef03 299 }
kevman 0:38ceb79fef03 300 #endif
kevman 0:38ceb79fef03 301
kevman 0:38ceb79fef03 302 #if defined(MBEDTLS_CHACHAPOLY_C)
kevman 0:38ceb79fef03 303 if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
kevman 0:38ceb79fef03 304 {
kevman 0:38ceb79fef03 305 int result;
kevman 0:38ceb79fef03 306 mbedtls_chachapoly_mode_t mode;
kevman 0:38ceb79fef03 307
kevman 0:38ceb79fef03 308 mode = ( ctx->operation == MBEDTLS_ENCRYPT )
kevman 0:38ceb79fef03 309 ? MBEDTLS_CHACHAPOLY_ENCRYPT
kevman 0:38ceb79fef03 310 : MBEDTLS_CHACHAPOLY_DECRYPT;
kevman 0:38ceb79fef03 311
kevman 0:38ceb79fef03 312 result = mbedtls_chachapoly_starts( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
kevman 0:38ceb79fef03 313 ctx->iv,
kevman 0:38ceb79fef03 314 mode );
kevman 0:38ceb79fef03 315 if ( result != 0 )
kevman 0:38ceb79fef03 316 return( result );
kevman 0:38ceb79fef03 317
kevman 0:38ceb79fef03 318 return mbedtls_chachapoly_update_aad( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
kevman 0:38ceb79fef03 319 ad, ad_len );
kevman 0:38ceb79fef03 320 }
kevman 0:38ceb79fef03 321 #endif
kevman 0:38ceb79fef03 322
kevman 0:38ceb79fef03 323 return( 0 );
kevman 0:38ceb79fef03 324 }
kevman 0:38ceb79fef03 325 #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */
kevman 0:38ceb79fef03 326
kevman 0:38ceb79fef03 327 int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input,
kevman 0:38ceb79fef03 328 size_t ilen, unsigned char *output, size_t *olen )
kevman 0:38ceb79fef03 329 {
kevman 0:38ceb79fef03 330 int ret;
kevman 0:38ceb79fef03 331 size_t block_size = 0;
kevman 0:38ceb79fef03 332
kevman 0:38ceb79fef03 333 if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
kevman 0:38ceb79fef03 334 {
kevman 0:38ceb79fef03 335 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 336 }
kevman 0:38ceb79fef03 337
kevman 0:38ceb79fef03 338 *olen = 0;
kevman 0:38ceb79fef03 339 block_size = mbedtls_cipher_get_block_size( ctx );
kevman 0:38ceb79fef03 340
kevman 0:38ceb79fef03 341 if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB )
kevman 0:38ceb79fef03 342 {
kevman 0:38ceb79fef03 343 if( ilen != block_size )
kevman 0:38ceb79fef03 344 return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
kevman 0:38ceb79fef03 345
kevman 0:38ceb79fef03 346 *olen = ilen;
kevman 0:38ceb79fef03 347
kevman 0:38ceb79fef03 348 if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx,
kevman 0:38ceb79fef03 349 ctx->operation, input, output ) ) )
kevman 0:38ceb79fef03 350 {
kevman 0:38ceb79fef03 351 return( ret );
kevman 0:38ceb79fef03 352 }
kevman 0:38ceb79fef03 353
kevman 0:38ceb79fef03 354 return( 0 );
kevman 0:38ceb79fef03 355 }
kevman 0:38ceb79fef03 356
kevman 0:38ceb79fef03 357 #if defined(MBEDTLS_GCM_C)
kevman 0:38ceb79fef03 358 if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM )
kevman 0:38ceb79fef03 359 {
kevman 0:38ceb79fef03 360 *olen = ilen;
kevman 0:38ceb79fef03 361 return mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input,
kevman 0:38ceb79fef03 362 output );
kevman 0:38ceb79fef03 363 }
kevman 0:38ceb79fef03 364 #endif
kevman 0:38ceb79fef03 365
kevman 0:38ceb79fef03 366 #if defined(MBEDTLS_CHACHAPOLY_C)
kevman 0:38ceb79fef03 367 if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 )
kevman 0:38ceb79fef03 368 {
kevman 0:38ceb79fef03 369 *olen = ilen;
kevman 0:38ceb79fef03 370 return mbedtls_chachapoly_update( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
kevman 0:38ceb79fef03 371 ilen, input, output );
kevman 0:38ceb79fef03 372 }
kevman 0:38ceb79fef03 373 #endif
kevman 0:38ceb79fef03 374
kevman 0:38ceb79fef03 375 if ( 0 == block_size )
kevman 0:38ceb79fef03 376 {
kevman 0:38ceb79fef03 377 return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT;
kevman 0:38ceb79fef03 378 }
kevman 0:38ceb79fef03 379
kevman 0:38ceb79fef03 380 if( input == output &&
kevman 0:38ceb79fef03 381 ( ctx->unprocessed_len != 0 || ilen % block_size ) )
kevman 0:38ceb79fef03 382 {
kevman 0:38ceb79fef03 383 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 384 }
kevman 0:38ceb79fef03 385
kevman 0:38ceb79fef03 386 #if defined(MBEDTLS_CIPHER_MODE_CBC)
kevman 0:38ceb79fef03 387 if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC )
kevman 0:38ceb79fef03 388 {
kevman 0:38ceb79fef03 389 size_t copy_len = 0;
kevman 0:38ceb79fef03 390
kevman 0:38ceb79fef03 391 /*
kevman 0:38ceb79fef03 392 * If there is not enough data for a full block, cache it.
kevman 0:38ceb79fef03 393 */
kevman 0:38ceb79fef03 394 if( ( ctx->operation == MBEDTLS_DECRYPT && NULL != ctx->add_padding &&
kevman 0:38ceb79fef03 395 ilen <= block_size - ctx->unprocessed_len ) ||
kevman 0:38ceb79fef03 396 ( ctx->operation == MBEDTLS_DECRYPT && NULL == ctx->add_padding &&
kevman 0:38ceb79fef03 397 ilen < block_size - ctx->unprocessed_len ) ||
kevman 0:38ceb79fef03 398 ( ctx->operation == MBEDTLS_ENCRYPT &&
kevman 0:38ceb79fef03 399 ilen < block_size - ctx->unprocessed_len ) )
kevman 0:38ceb79fef03 400 {
kevman 0:38ceb79fef03 401 memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
kevman 0:38ceb79fef03 402 ilen );
kevman 0:38ceb79fef03 403
kevman 0:38ceb79fef03 404 ctx->unprocessed_len += ilen;
kevman 0:38ceb79fef03 405 return( 0 );
kevman 0:38ceb79fef03 406 }
kevman 0:38ceb79fef03 407
kevman 0:38ceb79fef03 408 /*
kevman 0:38ceb79fef03 409 * Process cached data first
kevman 0:38ceb79fef03 410 */
kevman 0:38ceb79fef03 411 if( 0 != ctx->unprocessed_len )
kevman 0:38ceb79fef03 412 {
kevman 0:38ceb79fef03 413 copy_len = block_size - ctx->unprocessed_len;
kevman 0:38ceb79fef03 414
kevman 0:38ceb79fef03 415 memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
kevman 0:38ceb79fef03 416 copy_len );
kevman 0:38ceb79fef03 417
kevman 0:38ceb79fef03 418 if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
kevman 0:38ceb79fef03 419 ctx->operation, block_size, ctx->iv,
kevman 0:38ceb79fef03 420 ctx->unprocessed_data, output ) ) )
kevman 0:38ceb79fef03 421 {
kevman 0:38ceb79fef03 422 return( ret );
kevman 0:38ceb79fef03 423 }
kevman 0:38ceb79fef03 424
kevman 0:38ceb79fef03 425 *olen += block_size;
kevman 0:38ceb79fef03 426 output += block_size;
kevman 0:38ceb79fef03 427 ctx->unprocessed_len = 0;
kevman 0:38ceb79fef03 428
kevman 0:38ceb79fef03 429 input += copy_len;
kevman 0:38ceb79fef03 430 ilen -= copy_len;
kevman 0:38ceb79fef03 431 }
kevman 0:38ceb79fef03 432
kevman 0:38ceb79fef03 433 /*
kevman 0:38ceb79fef03 434 * Cache final, incomplete block
kevman 0:38ceb79fef03 435 */
kevman 0:38ceb79fef03 436 if( 0 != ilen )
kevman 0:38ceb79fef03 437 {
kevman 0:38ceb79fef03 438 if( 0 == block_size )
kevman 0:38ceb79fef03 439 {
kevman 0:38ceb79fef03 440 return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT;
kevman 0:38ceb79fef03 441 }
kevman 0:38ceb79fef03 442
kevman 0:38ceb79fef03 443 /* Encryption: only cache partial blocks
kevman 0:38ceb79fef03 444 * Decryption w/ padding: always keep at least one whole block
kevman 0:38ceb79fef03 445 * Decryption w/o padding: only cache partial blocks
kevman 0:38ceb79fef03 446 */
kevman 0:38ceb79fef03 447 copy_len = ilen % block_size;
kevman 0:38ceb79fef03 448 if( copy_len == 0 &&
kevman 0:38ceb79fef03 449 ctx->operation == MBEDTLS_DECRYPT &&
kevman 0:38ceb79fef03 450 NULL != ctx->add_padding)
kevman 0:38ceb79fef03 451 {
kevman 0:38ceb79fef03 452 copy_len = block_size;
kevman 0:38ceb79fef03 453 }
kevman 0:38ceb79fef03 454
kevman 0:38ceb79fef03 455 memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ),
kevman 0:38ceb79fef03 456 copy_len );
kevman 0:38ceb79fef03 457
kevman 0:38ceb79fef03 458 ctx->unprocessed_len += copy_len;
kevman 0:38ceb79fef03 459 ilen -= copy_len;
kevman 0:38ceb79fef03 460 }
kevman 0:38ceb79fef03 461
kevman 0:38ceb79fef03 462 /*
kevman 0:38ceb79fef03 463 * Process remaining full blocks
kevman 0:38ceb79fef03 464 */
kevman 0:38ceb79fef03 465 if( ilen )
kevman 0:38ceb79fef03 466 {
kevman 0:38ceb79fef03 467 if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
kevman 0:38ceb79fef03 468 ctx->operation, ilen, ctx->iv, input, output ) ) )
kevman 0:38ceb79fef03 469 {
kevman 0:38ceb79fef03 470 return( ret );
kevman 0:38ceb79fef03 471 }
kevman 0:38ceb79fef03 472
kevman 0:38ceb79fef03 473 *olen += ilen;
kevman 0:38ceb79fef03 474 }
kevman 0:38ceb79fef03 475
kevman 0:38ceb79fef03 476 return( 0 );
kevman 0:38ceb79fef03 477 }
kevman 0:38ceb79fef03 478 #endif /* MBEDTLS_CIPHER_MODE_CBC */
kevman 0:38ceb79fef03 479
kevman 0:38ceb79fef03 480 #if defined(MBEDTLS_CIPHER_MODE_CFB)
kevman 0:38ceb79fef03 481 if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB )
kevman 0:38ceb79fef03 482 {
kevman 0:38ceb79fef03 483 if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx,
kevman 0:38ceb79fef03 484 ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv,
kevman 0:38ceb79fef03 485 input, output ) ) )
kevman 0:38ceb79fef03 486 {
kevman 0:38ceb79fef03 487 return( ret );
kevman 0:38ceb79fef03 488 }
kevman 0:38ceb79fef03 489
kevman 0:38ceb79fef03 490 *olen = ilen;
kevman 0:38ceb79fef03 491
kevman 0:38ceb79fef03 492 return( 0 );
kevman 0:38ceb79fef03 493 }
kevman 0:38ceb79fef03 494 #endif /* MBEDTLS_CIPHER_MODE_CFB */
kevman 0:38ceb79fef03 495
kevman 0:38ceb79fef03 496 #if defined(MBEDTLS_CIPHER_MODE_OFB)
kevman 0:38ceb79fef03 497 if( ctx->cipher_info->mode == MBEDTLS_MODE_OFB )
kevman 0:38ceb79fef03 498 {
kevman 0:38ceb79fef03 499 if( 0 != ( ret = ctx->cipher_info->base->ofb_func( ctx->cipher_ctx,
kevman 0:38ceb79fef03 500 ilen, &ctx->unprocessed_len, ctx->iv, input, output ) ) )
kevman 0:38ceb79fef03 501 {
kevman 0:38ceb79fef03 502 return( ret );
kevman 0:38ceb79fef03 503 }
kevman 0:38ceb79fef03 504
kevman 0:38ceb79fef03 505 *olen = ilen;
kevman 0:38ceb79fef03 506
kevman 0:38ceb79fef03 507 return( 0 );
kevman 0:38ceb79fef03 508 }
kevman 0:38ceb79fef03 509 #endif /* MBEDTLS_CIPHER_MODE_OFB */
kevman 0:38ceb79fef03 510
kevman 0:38ceb79fef03 511 #if defined(MBEDTLS_CIPHER_MODE_CTR)
kevman 0:38ceb79fef03 512 if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR )
kevman 0:38ceb79fef03 513 {
kevman 0:38ceb79fef03 514 if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx,
kevman 0:38ceb79fef03 515 ilen, &ctx->unprocessed_len, ctx->iv,
kevman 0:38ceb79fef03 516 ctx->unprocessed_data, input, output ) ) )
kevman 0:38ceb79fef03 517 {
kevman 0:38ceb79fef03 518 return( ret );
kevman 0:38ceb79fef03 519 }
kevman 0:38ceb79fef03 520
kevman 0:38ceb79fef03 521 *olen = ilen;
kevman 0:38ceb79fef03 522
kevman 0:38ceb79fef03 523 return( 0 );
kevman 0:38ceb79fef03 524 }
kevman 0:38ceb79fef03 525 #endif /* MBEDTLS_CIPHER_MODE_CTR */
kevman 0:38ceb79fef03 526
kevman 0:38ceb79fef03 527 #if defined(MBEDTLS_CIPHER_MODE_XTS)
kevman 0:38ceb79fef03 528 if( ctx->cipher_info->mode == MBEDTLS_MODE_XTS )
kevman 0:38ceb79fef03 529 {
kevman 0:38ceb79fef03 530 if( ctx->unprocessed_len > 0 ) {
kevman 0:38ceb79fef03 531 /* We can only process an entire data unit at a time. */
kevman 0:38ceb79fef03 532 return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
kevman 0:38ceb79fef03 533 }
kevman 0:38ceb79fef03 534
kevman 0:38ceb79fef03 535 ret = ctx->cipher_info->base->xts_func( ctx->cipher_ctx,
kevman 0:38ceb79fef03 536 ctx->operation, ilen, ctx->iv, input, output );
kevman 0:38ceb79fef03 537 if( ret != 0 )
kevman 0:38ceb79fef03 538 {
kevman 0:38ceb79fef03 539 return( ret );
kevman 0:38ceb79fef03 540 }
kevman 0:38ceb79fef03 541
kevman 0:38ceb79fef03 542 *olen = ilen;
kevman 0:38ceb79fef03 543
kevman 0:38ceb79fef03 544 return( 0 );
kevman 0:38ceb79fef03 545 }
kevman 0:38ceb79fef03 546 #endif /* MBEDTLS_CIPHER_MODE_XTS */
kevman 0:38ceb79fef03 547
kevman 0:38ceb79fef03 548 #if defined(MBEDTLS_CIPHER_MODE_STREAM)
kevman 0:38ceb79fef03 549 if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM )
kevman 0:38ceb79fef03 550 {
kevman 0:38ceb79fef03 551 if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx,
kevman 0:38ceb79fef03 552 ilen, input, output ) ) )
kevman 0:38ceb79fef03 553 {
kevman 0:38ceb79fef03 554 return( ret );
kevman 0:38ceb79fef03 555 }
kevman 0:38ceb79fef03 556
kevman 0:38ceb79fef03 557 *olen = ilen;
kevman 0:38ceb79fef03 558
kevman 0:38ceb79fef03 559 return( 0 );
kevman 0:38ceb79fef03 560 }
kevman 0:38ceb79fef03 561 #endif /* MBEDTLS_CIPHER_MODE_STREAM */
kevman 0:38ceb79fef03 562
kevman 0:38ceb79fef03 563 return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
kevman 0:38ceb79fef03 564 }
kevman 0:38ceb79fef03 565
kevman 0:38ceb79fef03 566 #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
kevman 0:38ceb79fef03 567 #if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
kevman 0:38ceb79fef03 568 /*
kevman 0:38ceb79fef03 569 * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len
kevman 0:38ceb79fef03 570 */
kevman 0:38ceb79fef03 571 static void add_pkcs_padding( unsigned char *output, size_t output_len,
kevman 0:38ceb79fef03 572 size_t data_len )
kevman 0:38ceb79fef03 573 {
kevman 0:38ceb79fef03 574 size_t padding_len = output_len - data_len;
kevman 0:38ceb79fef03 575 unsigned char i;
kevman 0:38ceb79fef03 576
kevman 0:38ceb79fef03 577 for( i = 0; i < padding_len; i++ )
kevman 0:38ceb79fef03 578 output[data_len + i] = (unsigned char) padding_len;
kevman 0:38ceb79fef03 579 }
kevman 0:38ceb79fef03 580
kevman 0:38ceb79fef03 581 static int get_pkcs_padding( unsigned char *input, size_t input_len,
kevman 0:38ceb79fef03 582 size_t *data_len )
kevman 0:38ceb79fef03 583 {
kevman 0:38ceb79fef03 584 size_t i, pad_idx;
kevman 0:38ceb79fef03 585 unsigned char padding_len, bad = 0;
kevman 0:38ceb79fef03 586
kevman 0:38ceb79fef03 587 if( NULL == input || NULL == data_len )
kevman 0:38ceb79fef03 588 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 589
kevman 0:38ceb79fef03 590 padding_len = input[input_len - 1];
kevman 0:38ceb79fef03 591 *data_len = input_len - padding_len;
kevman 0:38ceb79fef03 592
kevman 0:38ceb79fef03 593 /* Avoid logical || since it results in a branch */
kevman 0:38ceb79fef03 594 bad |= padding_len > input_len;
kevman 0:38ceb79fef03 595 bad |= padding_len == 0;
kevman 0:38ceb79fef03 596
kevman 0:38ceb79fef03 597 /* The number of bytes checked must be independent of padding_len,
kevman 0:38ceb79fef03 598 * so pick input_len, which is usually 8 or 16 (one block) */
kevman 0:38ceb79fef03 599 pad_idx = input_len - padding_len;
kevman 0:38ceb79fef03 600 for( i = 0; i < input_len; i++ )
kevman 0:38ceb79fef03 601 bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx );
kevman 0:38ceb79fef03 602
kevman 0:38ceb79fef03 603 return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
kevman 0:38ceb79fef03 604 }
kevman 0:38ceb79fef03 605 #endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
kevman 0:38ceb79fef03 606
kevman 0:38ceb79fef03 607 #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
kevman 0:38ceb79fef03 608 /*
kevman 0:38ceb79fef03 609 * One and zeros padding: fill with 80 00 ... 00
kevman 0:38ceb79fef03 610 */
kevman 0:38ceb79fef03 611 static void add_one_and_zeros_padding( unsigned char *output,
kevman 0:38ceb79fef03 612 size_t output_len, size_t data_len )
kevman 0:38ceb79fef03 613 {
kevman 0:38ceb79fef03 614 size_t padding_len = output_len - data_len;
kevman 0:38ceb79fef03 615 unsigned char i = 0;
kevman 0:38ceb79fef03 616
kevman 0:38ceb79fef03 617 output[data_len] = 0x80;
kevman 0:38ceb79fef03 618 for( i = 1; i < padding_len; i++ )
kevman 0:38ceb79fef03 619 output[data_len + i] = 0x00;
kevman 0:38ceb79fef03 620 }
kevman 0:38ceb79fef03 621
kevman 0:38ceb79fef03 622 static int get_one_and_zeros_padding( unsigned char *input, size_t input_len,
kevman 0:38ceb79fef03 623 size_t *data_len )
kevman 0:38ceb79fef03 624 {
kevman 0:38ceb79fef03 625 size_t i;
kevman 0:38ceb79fef03 626 unsigned char done = 0, prev_done, bad;
kevman 0:38ceb79fef03 627
kevman 0:38ceb79fef03 628 if( NULL == input || NULL == data_len )
kevman 0:38ceb79fef03 629 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 630
kevman 0:38ceb79fef03 631 bad = 0x80;
kevman 0:38ceb79fef03 632 *data_len = 0;
kevman 0:38ceb79fef03 633 for( i = input_len; i > 0; i-- )
kevman 0:38ceb79fef03 634 {
kevman 0:38ceb79fef03 635 prev_done = done;
kevman 0:38ceb79fef03 636 done |= ( input[i - 1] != 0 );
kevman 0:38ceb79fef03 637 *data_len |= ( i - 1 ) * ( done != prev_done );
kevman 0:38ceb79fef03 638 bad ^= input[i - 1] * ( done != prev_done );
kevman 0:38ceb79fef03 639 }
kevman 0:38ceb79fef03 640
kevman 0:38ceb79fef03 641 return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
kevman 0:38ceb79fef03 642
kevman 0:38ceb79fef03 643 }
kevman 0:38ceb79fef03 644 #endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
kevman 0:38ceb79fef03 645
kevman 0:38ceb79fef03 646 #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
kevman 0:38ceb79fef03 647 /*
kevman 0:38ceb79fef03 648 * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length
kevman 0:38ceb79fef03 649 */
kevman 0:38ceb79fef03 650 static void add_zeros_and_len_padding( unsigned char *output,
kevman 0:38ceb79fef03 651 size_t output_len, size_t data_len )
kevman 0:38ceb79fef03 652 {
kevman 0:38ceb79fef03 653 size_t padding_len = output_len - data_len;
kevman 0:38ceb79fef03 654 unsigned char i = 0;
kevman 0:38ceb79fef03 655
kevman 0:38ceb79fef03 656 for( i = 1; i < padding_len; i++ )
kevman 0:38ceb79fef03 657 output[data_len + i - 1] = 0x00;
kevman 0:38ceb79fef03 658 output[output_len - 1] = (unsigned char) padding_len;
kevman 0:38ceb79fef03 659 }
kevman 0:38ceb79fef03 660
kevman 0:38ceb79fef03 661 static int get_zeros_and_len_padding( unsigned char *input, size_t input_len,
kevman 0:38ceb79fef03 662 size_t *data_len )
kevman 0:38ceb79fef03 663 {
kevman 0:38ceb79fef03 664 size_t i, pad_idx;
kevman 0:38ceb79fef03 665 unsigned char padding_len, bad = 0;
kevman 0:38ceb79fef03 666
kevman 0:38ceb79fef03 667 if( NULL == input || NULL == data_len )
kevman 0:38ceb79fef03 668 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 669
kevman 0:38ceb79fef03 670 padding_len = input[input_len - 1];
kevman 0:38ceb79fef03 671 *data_len = input_len - padding_len;
kevman 0:38ceb79fef03 672
kevman 0:38ceb79fef03 673 /* Avoid logical || since it results in a branch */
kevman 0:38ceb79fef03 674 bad |= padding_len > input_len;
kevman 0:38ceb79fef03 675 bad |= padding_len == 0;
kevman 0:38ceb79fef03 676
kevman 0:38ceb79fef03 677 /* The number of bytes checked must be independent of padding_len */
kevman 0:38ceb79fef03 678 pad_idx = input_len - padding_len;
kevman 0:38ceb79fef03 679 for( i = 0; i < input_len - 1; i++ )
kevman 0:38ceb79fef03 680 bad |= input[i] * ( i >= pad_idx );
kevman 0:38ceb79fef03 681
kevman 0:38ceb79fef03 682 return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
kevman 0:38ceb79fef03 683 }
kevman 0:38ceb79fef03 684 #endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
kevman 0:38ceb79fef03 685
kevman 0:38ceb79fef03 686 #if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
kevman 0:38ceb79fef03 687 /*
kevman 0:38ceb79fef03 688 * Zero padding: fill with 00 ... 00
kevman 0:38ceb79fef03 689 */
kevman 0:38ceb79fef03 690 static void add_zeros_padding( unsigned char *output,
kevman 0:38ceb79fef03 691 size_t output_len, size_t data_len )
kevman 0:38ceb79fef03 692 {
kevman 0:38ceb79fef03 693 size_t i;
kevman 0:38ceb79fef03 694
kevman 0:38ceb79fef03 695 for( i = data_len; i < output_len; i++ )
kevman 0:38ceb79fef03 696 output[i] = 0x00;
kevman 0:38ceb79fef03 697 }
kevman 0:38ceb79fef03 698
kevman 0:38ceb79fef03 699 static int get_zeros_padding( unsigned char *input, size_t input_len,
kevman 0:38ceb79fef03 700 size_t *data_len )
kevman 0:38ceb79fef03 701 {
kevman 0:38ceb79fef03 702 size_t i;
kevman 0:38ceb79fef03 703 unsigned char done = 0, prev_done;
kevman 0:38ceb79fef03 704
kevman 0:38ceb79fef03 705 if( NULL == input || NULL == data_len )
kevman 0:38ceb79fef03 706 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 707
kevman 0:38ceb79fef03 708 *data_len = 0;
kevman 0:38ceb79fef03 709 for( i = input_len; i > 0; i-- )
kevman 0:38ceb79fef03 710 {
kevman 0:38ceb79fef03 711 prev_done = done;
kevman 0:38ceb79fef03 712 done |= ( input[i-1] != 0 );
kevman 0:38ceb79fef03 713 *data_len |= i * ( done != prev_done );
kevman 0:38ceb79fef03 714 }
kevman 0:38ceb79fef03 715
kevman 0:38ceb79fef03 716 return( 0 );
kevman 0:38ceb79fef03 717 }
kevman 0:38ceb79fef03 718 #endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
kevman 0:38ceb79fef03 719
kevman 0:38ceb79fef03 720 /*
kevman 0:38ceb79fef03 721 * No padding: don't pad :)
kevman 0:38ceb79fef03 722 *
kevman 0:38ceb79fef03 723 * There is no add_padding function (check for NULL in mbedtls_cipher_finish)
kevman 0:38ceb79fef03 724 * but a trivial get_padding function
kevman 0:38ceb79fef03 725 */
kevman 0:38ceb79fef03 726 static int get_no_padding( unsigned char *input, size_t input_len,
kevman 0:38ceb79fef03 727 size_t *data_len )
kevman 0:38ceb79fef03 728 {
kevman 0:38ceb79fef03 729 if( NULL == input || NULL == data_len )
kevman 0:38ceb79fef03 730 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 731
kevman 0:38ceb79fef03 732 *data_len = input_len;
kevman 0:38ceb79fef03 733
kevman 0:38ceb79fef03 734 return( 0 );
kevman 0:38ceb79fef03 735 }
kevman 0:38ceb79fef03 736 #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
kevman 0:38ceb79fef03 737
kevman 0:38ceb79fef03 738 int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx,
kevman 0:38ceb79fef03 739 unsigned char *output, size_t *olen )
kevman 0:38ceb79fef03 740 {
kevman 0:38ceb79fef03 741 if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
kevman 0:38ceb79fef03 742 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 743
kevman 0:38ceb79fef03 744 *olen = 0;
kevman 0:38ceb79fef03 745
kevman 0:38ceb79fef03 746 if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
kevman 0:38ceb79fef03 747 MBEDTLS_MODE_OFB == ctx->cipher_info->mode ||
kevman 0:38ceb79fef03 748 MBEDTLS_MODE_CTR == ctx->cipher_info->mode ||
kevman 0:38ceb79fef03 749 MBEDTLS_MODE_GCM == ctx->cipher_info->mode ||
kevman 0:38ceb79fef03 750 MBEDTLS_MODE_XTS == ctx->cipher_info->mode ||
kevman 0:38ceb79fef03 751 MBEDTLS_MODE_STREAM == ctx->cipher_info->mode )
kevman 0:38ceb79fef03 752 {
kevman 0:38ceb79fef03 753 return( 0 );
kevman 0:38ceb79fef03 754 }
kevman 0:38ceb79fef03 755
kevman 0:38ceb79fef03 756 if ( ( MBEDTLS_CIPHER_CHACHA20 == ctx->cipher_info->type ) ||
kevman 0:38ceb79fef03 757 ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) )
kevman 0:38ceb79fef03 758 {
kevman 0:38ceb79fef03 759 return( 0 );
kevman 0:38ceb79fef03 760 }
kevman 0:38ceb79fef03 761
kevman 0:38ceb79fef03 762 if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode )
kevman 0:38ceb79fef03 763 {
kevman 0:38ceb79fef03 764 if( ctx->unprocessed_len != 0 )
kevman 0:38ceb79fef03 765 return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
kevman 0:38ceb79fef03 766
kevman 0:38ceb79fef03 767 return( 0 );
kevman 0:38ceb79fef03 768 }
kevman 0:38ceb79fef03 769
kevman 0:38ceb79fef03 770 #if defined(MBEDTLS_CIPHER_MODE_CBC)
kevman 0:38ceb79fef03 771 if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode )
kevman 0:38ceb79fef03 772 {
kevman 0:38ceb79fef03 773 int ret = 0;
kevman 0:38ceb79fef03 774
kevman 0:38ceb79fef03 775 if( MBEDTLS_ENCRYPT == ctx->operation )
kevman 0:38ceb79fef03 776 {
kevman 0:38ceb79fef03 777 /* check for 'no padding' mode */
kevman 0:38ceb79fef03 778 if( NULL == ctx->add_padding )
kevman 0:38ceb79fef03 779 {
kevman 0:38ceb79fef03 780 if( 0 != ctx->unprocessed_len )
kevman 0:38ceb79fef03 781 return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
kevman 0:38ceb79fef03 782
kevman 0:38ceb79fef03 783 return( 0 );
kevman 0:38ceb79fef03 784 }
kevman 0:38ceb79fef03 785
kevman 0:38ceb79fef03 786 ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ),
kevman 0:38ceb79fef03 787 ctx->unprocessed_len );
kevman 0:38ceb79fef03 788 }
kevman 0:38ceb79fef03 789 else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len )
kevman 0:38ceb79fef03 790 {
kevman 0:38ceb79fef03 791 /*
kevman 0:38ceb79fef03 792 * For decrypt operations, expect a full block,
kevman 0:38ceb79fef03 793 * or an empty block if no padding
kevman 0:38ceb79fef03 794 */
kevman 0:38ceb79fef03 795 if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len )
kevman 0:38ceb79fef03 796 return( 0 );
kevman 0:38ceb79fef03 797
kevman 0:38ceb79fef03 798 return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
kevman 0:38ceb79fef03 799 }
kevman 0:38ceb79fef03 800
kevman 0:38ceb79fef03 801 /* cipher block */
kevman 0:38ceb79fef03 802 if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
kevman 0:38ceb79fef03 803 ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv,
kevman 0:38ceb79fef03 804 ctx->unprocessed_data, output ) ) )
kevman 0:38ceb79fef03 805 {
kevman 0:38ceb79fef03 806 return( ret );
kevman 0:38ceb79fef03 807 }
kevman 0:38ceb79fef03 808
kevman 0:38ceb79fef03 809 /* Set output size for decryption */
kevman 0:38ceb79fef03 810 if( MBEDTLS_DECRYPT == ctx->operation )
kevman 0:38ceb79fef03 811 return ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ),
kevman 0:38ceb79fef03 812 olen );
kevman 0:38ceb79fef03 813
kevman 0:38ceb79fef03 814 /* Set output size for encryption */
kevman 0:38ceb79fef03 815 *olen = mbedtls_cipher_get_block_size( ctx );
kevman 0:38ceb79fef03 816 return( 0 );
kevman 0:38ceb79fef03 817 }
kevman 0:38ceb79fef03 818 #else
kevman 0:38ceb79fef03 819 ((void) output);
kevman 0:38ceb79fef03 820 #endif /* MBEDTLS_CIPHER_MODE_CBC */
kevman 0:38ceb79fef03 821
kevman 0:38ceb79fef03 822 return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
kevman 0:38ceb79fef03 823 }
kevman 0:38ceb79fef03 824
kevman 0:38ceb79fef03 825 #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
kevman 0:38ceb79fef03 826 int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode )
kevman 0:38ceb79fef03 827 {
kevman 0:38ceb79fef03 828 if( NULL == ctx ||
kevman 0:38ceb79fef03 829 MBEDTLS_MODE_CBC != ctx->cipher_info->mode )
kevman 0:38ceb79fef03 830 {
kevman 0:38ceb79fef03 831 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 832 }
kevman 0:38ceb79fef03 833
kevman 0:38ceb79fef03 834 switch( mode )
kevman 0:38ceb79fef03 835 {
kevman 0:38ceb79fef03 836 #if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
kevman 0:38ceb79fef03 837 case MBEDTLS_PADDING_PKCS7:
kevman 0:38ceb79fef03 838 ctx->add_padding = add_pkcs_padding;
kevman 0:38ceb79fef03 839 ctx->get_padding = get_pkcs_padding;
kevman 0:38ceb79fef03 840 break;
kevman 0:38ceb79fef03 841 #endif
kevman 0:38ceb79fef03 842 #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
kevman 0:38ceb79fef03 843 case MBEDTLS_PADDING_ONE_AND_ZEROS:
kevman 0:38ceb79fef03 844 ctx->add_padding = add_one_and_zeros_padding;
kevman 0:38ceb79fef03 845 ctx->get_padding = get_one_and_zeros_padding;
kevman 0:38ceb79fef03 846 break;
kevman 0:38ceb79fef03 847 #endif
kevman 0:38ceb79fef03 848 #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
kevman 0:38ceb79fef03 849 case MBEDTLS_PADDING_ZEROS_AND_LEN:
kevman 0:38ceb79fef03 850 ctx->add_padding = add_zeros_and_len_padding;
kevman 0:38ceb79fef03 851 ctx->get_padding = get_zeros_and_len_padding;
kevman 0:38ceb79fef03 852 break;
kevman 0:38ceb79fef03 853 #endif
kevman 0:38ceb79fef03 854 #if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
kevman 0:38ceb79fef03 855 case MBEDTLS_PADDING_ZEROS:
kevman 0:38ceb79fef03 856 ctx->add_padding = add_zeros_padding;
kevman 0:38ceb79fef03 857 ctx->get_padding = get_zeros_padding;
kevman 0:38ceb79fef03 858 break;
kevman 0:38ceb79fef03 859 #endif
kevman 0:38ceb79fef03 860 case MBEDTLS_PADDING_NONE:
kevman 0:38ceb79fef03 861 ctx->add_padding = NULL;
kevman 0:38ceb79fef03 862 ctx->get_padding = get_no_padding;
kevman 0:38ceb79fef03 863 break;
kevman 0:38ceb79fef03 864
kevman 0:38ceb79fef03 865 default:
kevman 0:38ceb79fef03 866 return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
kevman 0:38ceb79fef03 867 }
kevman 0:38ceb79fef03 868
kevman 0:38ceb79fef03 869 return( 0 );
kevman 0:38ceb79fef03 870 }
kevman 0:38ceb79fef03 871 #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
kevman 0:38ceb79fef03 872
kevman 0:38ceb79fef03 873 #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
kevman 0:38ceb79fef03 874 int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx,
kevman 0:38ceb79fef03 875 unsigned char *tag, size_t tag_len )
kevman 0:38ceb79fef03 876 {
kevman 0:38ceb79fef03 877 if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag )
kevman 0:38ceb79fef03 878 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 879
kevman 0:38ceb79fef03 880 if( MBEDTLS_ENCRYPT != ctx->operation )
kevman 0:38ceb79fef03 881 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 882
kevman 0:38ceb79fef03 883 #if defined(MBEDTLS_GCM_C)
kevman 0:38ceb79fef03 884 if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
kevman 0:38ceb79fef03 885 return mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, tag, tag_len );
kevman 0:38ceb79fef03 886 #endif
kevman 0:38ceb79fef03 887
kevman 0:38ceb79fef03 888 #if defined(MBEDTLS_CHACHAPOLY_C)
kevman 0:38ceb79fef03 889 if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
kevman 0:38ceb79fef03 890 {
kevman 0:38ceb79fef03 891 /* Don't allow truncated MAC for Poly1305 */
kevman 0:38ceb79fef03 892 if ( tag_len != 16U )
kevman 0:38ceb79fef03 893 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 894
kevman 0:38ceb79fef03 895 return mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
kevman 0:38ceb79fef03 896 tag );
kevman 0:38ceb79fef03 897 }
kevman 0:38ceb79fef03 898 #endif
kevman 0:38ceb79fef03 899
kevman 0:38ceb79fef03 900 return( 0 );
kevman 0:38ceb79fef03 901 }
kevman 0:38ceb79fef03 902
kevman 0:38ceb79fef03 903 int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx,
kevman 0:38ceb79fef03 904 const unsigned char *tag, size_t tag_len )
kevman 0:38ceb79fef03 905 {
kevman 0:38ceb79fef03 906 unsigned char check_tag[16];
kevman 0:38ceb79fef03 907 int ret;
kevman 0:38ceb79fef03 908
kevman 0:38ceb79fef03 909 if( NULL == ctx || NULL == ctx->cipher_info ||
kevman 0:38ceb79fef03 910 MBEDTLS_DECRYPT != ctx->operation )
kevman 0:38ceb79fef03 911 {
kevman 0:38ceb79fef03 912 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 913 }
kevman 0:38ceb79fef03 914
kevman 0:38ceb79fef03 915 #if defined(MBEDTLS_GCM_C)
kevman 0:38ceb79fef03 916 if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
kevman 0:38ceb79fef03 917 {
kevman 0:38ceb79fef03 918 if( tag_len > sizeof( check_tag ) )
kevman 0:38ceb79fef03 919 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 920
kevman 0:38ceb79fef03 921 if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx,
kevman 0:38ceb79fef03 922 check_tag, tag_len ) ) )
kevman 0:38ceb79fef03 923 {
kevman 0:38ceb79fef03 924 return( ret );
kevman 0:38ceb79fef03 925 }
kevman 0:38ceb79fef03 926
kevman 0:38ceb79fef03 927 /* Check the tag in "constant-time" */
kevman 0:38ceb79fef03 928 if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 )
kevman 0:38ceb79fef03 929 return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
kevman 0:38ceb79fef03 930
kevman 0:38ceb79fef03 931 return( 0 );
kevman 0:38ceb79fef03 932 }
kevman 0:38ceb79fef03 933 #endif /* MBEDTLS_GCM_C */
kevman 0:38ceb79fef03 934
kevman 0:38ceb79fef03 935 #if defined(MBEDTLS_CHACHAPOLY_C)
kevman 0:38ceb79fef03 936 if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
kevman 0:38ceb79fef03 937 {
kevman 0:38ceb79fef03 938 /* Don't allow truncated MAC for Poly1305 */
kevman 0:38ceb79fef03 939 if ( tag_len != sizeof( check_tag ) )
kevman 0:38ceb79fef03 940 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 941
kevman 0:38ceb79fef03 942 ret = mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
kevman 0:38ceb79fef03 943 check_tag );
kevman 0:38ceb79fef03 944 if ( ret != 0 )
kevman 0:38ceb79fef03 945 {
kevman 0:38ceb79fef03 946 return( ret );
kevman 0:38ceb79fef03 947 }
kevman 0:38ceb79fef03 948
kevman 0:38ceb79fef03 949 /* Check the tag in "constant-time" */
kevman 0:38ceb79fef03 950 if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 )
kevman 0:38ceb79fef03 951 return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
kevman 0:38ceb79fef03 952
kevman 0:38ceb79fef03 953 return( 0 );
kevman 0:38ceb79fef03 954 }
kevman 0:38ceb79fef03 955 #endif /* MBEDTLS_CHACHAPOLY_C */
kevman 0:38ceb79fef03 956
kevman 0:38ceb79fef03 957 return( 0 );
kevman 0:38ceb79fef03 958 }
kevman 0:38ceb79fef03 959 #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */
kevman 0:38ceb79fef03 960
kevman 0:38ceb79fef03 961 /*
kevman 0:38ceb79fef03 962 * Packet-oriented wrapper for non-AEAD modes
kevman 0:38ceb79fef03 963 */
kevman 0:38ceb79fef03 964 int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx,
kevman 0:38ceb79fef03 965 const unsigned char *iv, size_t iv_len,
kevman 0:38ceb79fef03 966 const unsigned char *input, size_t ilen,
kevman 0:38ceb79fef03 967 unsigned char *output, size_t *olen )
kevman 0:38ceb79fef03 968 {
kevman 0:38ceb79fef03 969 int ret;
kevman 0:38ceb79fef03 970 size_t finish_olen;
kevman 0:38ceb79fef03 971
kevman 0:38ceb79fef03 972 if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 )
kevman 0:38ceb79fef03 973 return( ret );
kevman 0:38ceb79fef03 974
kevman 0:38ceb79fef03 975 if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 )
kevman 0:38ceb79fef03 976 return( ret );
kevman 0:38ceb79fef03 977
kevman 0:38ceb79fef03 978 if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 )
kevman 0:38ceb79fef03 979 return( ret );
kevman 0:38ceb79fef03 980
kevman 0:38ceb79fef03 981 if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 )
kevman 0:38ceb79fef03 982 return( ret );
kevman 0:38ceb79fef03 983
kevman 0:38ceb79fef03 984 *olen += finish_olen;
kevman 0:38ceb79fef03 985
kevman 0:38ceb79fef03 986 return( 0 );
kevman 0:38ceb79fef03 987 }
kevman 0:38ceb79fef03 988
kevman 0:38ceb79fef03 989 #if defined(MBEDTLS_CIPHER_MODE_AEAD)
kevman 0:38ceb79fef03 990 /*
kevman 0:38ceb79fef03 991 * Packet-oriented encryption for AEAD modes
kevman 0:38ceb79fef03 992 */
kevman 0:38ceb79fef03 993 int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
kevman 0:38ceb79fef03 994 const unsigned char *iv, size_t iv_len,
kevman 0:38ceb79fef03 995 const unsigned char *ad, size_t ad_len,
kevman 0:38ceb79fef03 996 const unsigned char *input, size_t ilen,
kevman 0:38ceb79fef03 997 unsigned char *output, size_t *olen,
kevman 0:38ceb79fef03 998 unsigned char *tag, size_t tag_len )
kevman 0:38ceb79fef03 999 {
kevman 0:38ceb79fef03 1000 #if defined(MBEDTLS_GCM_C)
kevman 0:38ceb79fef03 1001 if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
kevman 0:38ceb79fef03 1002 {
kevman 0:38ceb79fef03 1003 *olen = ilen;
kevman 0:38ceb79fef03 1004 return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen,
kevman 0:38ceb79fef03 1005 iv, iv_len, ad, ad_len, input, output,
kevman 0:38ceb79fef03 1006 tag_len, tag ) );
kevman 0:38ceb79fef03 1007 }
kevman 0:38ceb79fef03 1008 #endif /* MBEDTLS_GCM_C */
kevman 0:38ceb79fef03 1009 #if defined(MBEDTLS_CCM_C)
kevman 0:38ceb79fef03 1010 if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
kevman 0:38ceb79fef03 1011 {
kevman 0:38ceb79fef03 1012 *olen = ilen;
kevman 0:38ceb79fef03 1013 return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen,
kevman 0:38ceb79fef03 1014 iv, iv_len, ad, ad_len, input, output,
kevman 0:38ceb79fef03 1015 tag, tag_len ) );
kevman 0:38ceb79fef03 1016 }
kevman 0:38ceb79fef03 1017 #endif /* MBEDTLS_CCM_C */
kevman 0:38ceb79fef03 1018 #if defined(MBEDTLS_CHACHAPOLY_C)
kevman 0:38ceb79fef03 1019 if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
kevman 0:38ceb79fef03 1020 {
kevman 0:38ceb79fef03 1021 /* ChachaPoly has fixed length nonce and MAC (tag) */
kevman 0:38ceb79fef03 1022 if ( ( iv_len != ctx->cipher_info->iv_size ) ||
kevman 0:38ceb79fef03 1023 ( tag_len != 16U ) )
kevman 0:38ceb79fef03 1024 {
kevman 0:38ceb79fef03 1025 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 1026 }
kevman 0:38ceb79fef03 1027
kevman 0:38ceb79fef03 1028 *olen = ilen;
kevman 0:38ceb79fef03 1029 return( mbedtls_chachapoly_encrypt_and_tag( ctx->cipher_ctx,
kevman 0:38ceb79fef03 1030 ilen, iv, ad, ad_len, input, output, tag ) );
kevman 0:38ceb79fef03 1031 }
kevman 0:38ceb79fef03 1032 #endif /* MBEDTLS_CHACHAPOLY_C */
kevman 0:38ceb79fef03 1033
kevman 0:38ceb79fef03 1034 return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
kevman 0:38ceb79fef03 1035 }
kevman 0:38ceb79fef03 1036
kevman 0:38ceb79fef03 1037 /*
kevman 0:38ceb79fef03 1038 * Packet-oriented decryption for AEAD modes
kevman 0:38ceb79fef03 1039 */
kevman 0:38ceb79fef03 1040 int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
kevman 0:38ceb79fef03 1041 const unsigned char *iv, size_t iv_len,
kevman 0:38ceb79fef03 1042 const unsigned char *ad, size_t ad_len,
kevman 0:38ceb79fef03 1043 const unsigned char *input, size_t ilen,
kevman 0:38ceb79fef03 1044 unsigned char *output, size_t *olen,
kevman 0:38ceb79fef03 1045 const unsigned char *tag, size_t tag_len )
kevman 0:38ceb79fef03 1046 {
kevman 0:38ceb79fef03 1047 #if defined(MBEDTLS_GCM_C)
kevman 0:38ceb79fef03 1048 if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
kevman 0:38ceb79fef03 1049 {
kevman 0:38ceb79fef03 1050 int ret;
kevman 0:38ceb79fef03 1051
kevman 0:38ceb79fef03 1052 *olen = ilen;
kevman 0:38ceb79fef03 1053 ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen,
kevman 0:38ceb79fef03 1054 iv, iv_len, ad, ad_len,
kevman 0:38ceb79fef03 1055 tag, tag_len, input, output );
kevman 0:38ceb79fef03 1056
kevman 0:38ceb79fef03 1057 if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED )
kevman 0:38ceb79fef03 1058 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
kevman 0:38ceb79fef03 1059
kevman 0:38ceb79fef03 1060 return( ret );
kevman 0:38ceb79fef03 1061 }
kevman 0:38ceb79fef03 1062 #endif /* MBEDTLS_GCM_C */
kevman 0:38ceb79fef03 1063 #if defined(MBEDTLS_CCM_C)
kevman 0:38ceb79fef03 1064 if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
kevman 0:38ceb79fef03 1065 {
kevman 0:38ceb79fef03 1066 int ret;
kevman 0:38ceb79fef03 1067
kevman 0:38ceb79fef03 1068 *olen = ilen;
kevman 0:38ceb79fef03 1069 ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen,
kevman 0:38ceb79fef03 1070 iv, iv_len, ad, ad_len,
kevman 0:38ceb79fef03 1071 input, output, tag, tag_len );
kevman 0:38ceb79fef03 1072
kevman 0:38ceb79fef03 1073 if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED )
kevman 0:38ceb79fef03 1074 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
kevman 0:38ceb79fef03 1075
kevman 0:38ceb79fef03 1076 return( ret );
kevman 0:38ceb79fef03 1077 }
kevman 0:38ceb79fef03 1078 #endif /* MBEDTLS_CCM_C */
kevman 0:38ceb79fef03 1079 #if defined(MBEDTLS_CHACHAPOLY_C)
kevman 0:38ceb79fef03 1080 if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type )
kevman 0:38ceb79fef03 1081 {
kevman 0:38ceb79fef03 1082 int ret;
kevman 0:38ceb79fef03 1083
kevman 0:38ceb79fef03 1084 /* ChachaPoly has fixed length nonce and MAC (tag) */
kevman 0:38ceb79fef03 1085 if ( ( iv_len != ctx->cipher_info->iv_size ) ||
kevman 0:38ceb79fef03 1086 ( tag_len != 16U ) )
kevman 0:38ceb79fef03 1087 {
kevman 0:38ceb79fef03 1088 return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
kevman 0:38ceb79fef03 1089 }
kevman 0:38ceb79fef03 1090
kevman 0:38ceb79fef03 1091 *olen = ilen;
kevman 0:38ceb79fef03 1092 ret = mbedtls_chachapoly_auth_decrypt( ctx->cipher_ctx, ilen,
kevman 0:38ceb79fef03 1093 iv, ad, ad_len, tag, input, output );
kevman 0:38ceb79fef03 1094
kevman 0:38ceb79fef03 1095 if( ret == MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED )
kevman 0:38ceb79fef03 1096 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
kevman 0:38ceb79fef03 1097
kevman 0:38ceb79fef03 1098 return( ret );
kevman 0:38ceb79fef03 1099 }
kevman 0:38ceb79fef03 1100 #endif /* MBEDTLS_CHACHAPOLY_C */
kevman 0:38ceb79fef03 1101
kevman 0:38ceb79fef03 1102 return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
kevman 0:38ceb79fef03 1103 }
kevman 0:38ceb79fef03 1104 #endif /* MBEDTLS_CIPHER_MODE_AEAD */
kevman 0:38ceb79fef03 1105
kevman 0:38ceb79fef03 1106 #endif /* MBEDTLS_CIPHER_C */