1*c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /** 3817466cbSJens Wiklander * \file cipher.c 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * \brief Generic cipher wrapper for mbed TLS 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * \author Adriaan de Jong <dejong@fox-it.com> 8817466cbSJens Wiklander * 9817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 12817466cbSJens Wiklander * not use this file except in compliance with the License. 13817466cbSJens Wiklander * You may obtain a copy of the License at 14817466cbSJens Wiklander * 15817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 16817466cbSJens Wiklander * 17817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 18817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 19817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20817466cbSJens Wiklander * See the License for the specific language governing permissions and 21817466cbSJens Wiklander * limitations under the License. 22817466cbSJens Wiklander * 23817466cbSJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 24817466cbSJens Wiklander */ 25817466cbSJens Wiklander 26817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 27817466cbSJens Wiklander #include "mbedtls/config.h" 28817466cbSJens Wiklander #else 29817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 30817466cbSJens Wiklander #endif 31817466cbSJens Wiklander 32817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_C) 33817466cbSJens Wiklander 34817466cbSJens Wiklander #include "mbedtls/cipher.h" 35817466cbSJens Wiklander #include "mbedtls/cipher_internal.h" 36817466cbSJens Wiklander 37817466cbSJens Wiklander #include <stdlib.h> 38817466cbSJens Wiklander #include <string.h> 39817466cbSJens Wiklander 40817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 41817466cbSJens Wiklander #include "mbedtls/gcm.h" 42817466cbSJens Wiklander #endif 43817466cbSJens Wiklander 44817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C) 45817466cbSJens Wiklander #include "mbedtls/ccm.h" 46817466cbSJens Wiklander #endif 47817466cbSJens Wiklander 48817466cbSJens Wiklander #if defined(MBEDTLS_CMAC_C) 49817466cbSJens Wiklander #include "mbedtls/cmac.h" 50817466cbSJens Wiklander #endif 51817466cbSJens Wiklander 52817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 53817466cbSJens Wiklander #include "mbedtls/platform.h" 54817466cbSJens Wiklander #else 55817466cbSJens Wiklander #define mbedtls_calloc calloc 56817466cbSJens Wiklander #define mbedtls_free free 57817466cbSJens Wiklander #endif 58817466cbSJens Wiklander 59817466cbSJens Wiklander #if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) 60817466cbSJens Wiklander #define MBEDTLS_CIPHER_MODE_STREAM 61817466cbSJens Wiklander #endif 62817466cbSJens Wiklander 63817466cbSJens Wiklander /* Implementation that should never be optimized out by the compiler */ 64817466cbSJens Wiklander static void mbedtls_zeroize( void *v, size_t n ) { 65817466cbSJens Wiklander volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; 66817466cbSJens Wiklander } 67817466cbSJens Wiklander 68817466cbSJens Wiklander static int supported_init = 0; 69817466cbSJens Wiklander 70817466cbSJens Wiklander const int *mbedtls_cipher_list( void ) 71817466cbSJens Wiklander { 72817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 73817466cbSJens Wiklander int *type; 74817466cbSJens Wiklander 75817466cbSJens Wiklander if( ! supported_init ) 76817466cbSJens Wiklander { 77817466cbSJens Wiklander def = mbedtls_cipher_definitions; 78817466cbSJens Wiklander type = mbedtls_cipher_supported; 79817466cbSJens Wiklander 80817466cbSJens Wiklander while( def->type != 0 ) 81817466cbSJens Wiklander *type++ = (*def++).type; 82817466cbSJens Wiklander 83817466cbSJens Wiklander *type = 0; 84817466cbSJens Wiklander 85817466cbSJens Wiklander supported_init = 1; 86817466cbSJens Wiklander } 87817466cbSJens Wiklander 88817466cbSJens Wiklander return( mbedtls_cipher_supported ); 89817466cbSJens Wiklander } 90817466cbSJens Wiklander 91817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ) 92817466cbSJens Wiklander { 93817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 94817466cbSJens Wiklander 95817466cbSJens Wiklander for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) 96817466cbSJens Wiklander if( def->type == cipher_type ) 97817466cbSJens Wiklander return( def->info ); 98817466cbSJens Wiklander 99817466cbSJens Wiklander return( NULL ); 100817466cbSJens Wiklander } 101817466cbSJens Wiklander 102817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ) 103817466cbSJens Wiklander { 104817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 105817466cbSJens Wiklander 106817466cbSJens Wiklander if( NULL == cipher_name ) 107817466cbSJens Wiklander return( NULL ); 108817466cbSJens Wiklander 109817466cbSJens Wiklander for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) 110817466cbSJens Wiklander if( ! strcmp( def->info->name, cipher_name ) ) 111817466cbSJens Wiklander return( def->info ); 112817466cbSJens Wiklander 113817466cbSJens Wiklander return( NULL ); 114817466cbSJens Wiklander } 115817466cbSJens Wiklander 116817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id, 117817466cbSJens Wiklander int key_bitlen, 118817466cbSJens Wiklander const mbedtls_cipher_mode_t mode ) 119817466cbSJens Wiklander { 120817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 121817466cbSJens Wiklander 122817466cbSJens Wiklander for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) 123817466cbSJens Wiklander if( def->info->base->cipher == cipher_id && 124817466cbSJens Wiklander def->info->key_bitlen == (unsigned) key_bitlen && 125817466cbSJens Wiklander def->info->mode == mode ) 126817466cbSJens Wiklander return( def->info ); 127817466cbSJens Wiklander 128817466cbSJens Wiklander return( NULL ); 129817466cbSJens Wiklander } 130817466cbSJens Wiklander 131817466cbSJens Wiklander void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ) 132817466cbSJens Wiklander { 133817466cbSJens Wiklander memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); 134817466cbSJens Wiklander } 135817466cbSJens Wiklander 136817466cbSJens Wiklander void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ) 137817466cbSJens Wiklander { 138817466cbSJens Wiklander if( ctx == NULL ) 139817466cbSJens Wiklander return; 140817466cbSJens Wiklander 141817466cbSJens Wiklander #if defined(MBEDTLS_CMAC_C) 142817466cbSJens Wiklander if( ctx->cmac_ctx ) 143817466cbSJens Wiklander { 144817466cbSJens Wiklander mbedtls_zeroize( ctx->cmac_ctx, sizeof( mbedtls_cmac_context_t ) ); 145817466cbSJens Wiklander mbedtls_free( ctx->cmac_ctx ); 146817466cbSJens Wiklander } 147817466cbSJens Wiklander #endif 148817466cbSJens Wiklander 149817466cbSJens Wiklander if( ctx->cipher_ctx ) 150817466cbSJens Wiklander ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx ); 151817466cbSJens Wiklander 152817466cbSJens Wiklander mbedtls_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); 153817466cbSJens Wiklander } 154817466cbSJens Wiklander 155817466cbSJens Wiklander int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ) 156817466cbSJens Wiklander { 157817466cbSJens Wiklander if( NULL == cipher_info || NULL == ctx ) 158817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 159817466cbSJens Wiklander 160817466cbSJens Wiklander memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); 161817466cbSJens Wiklander 162817466cbSJens Wiklander if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) ) 163817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED ); 164817466cbSJens Wiklander 165817466cbSJens Wiklander ctx->cipher_info = cipher_info; 166817466cbSJens Wiklander 167817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) 168817466cbSJens Wiklander /* 169817466cbSJens Wiklander * Ignore possible errors caused by a cipher mode that doesn't use padding 170817466cbSJens Wiklander */ 171817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7) 172817466cbSJens Wiklander (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 ); 173817466cbSJens Wiklander #else 174817466cbSJens Wiklander (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE ); 175817466cbSJens Wiklander #endif 176817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ 177817466cbSJens Wiklander 178817466cbSJens Wiklander return( 0 ); 179817466cbSJens Wiklander } 180817466cbSJens Wiklander 181817466cbSJens Wiklander int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key, 182817466cbSJens Wiklander int key_bitlen, const mbedtls_operation_t operation ) 183817466cbSJens Wiklander { 184817466cbSJens Wiklander if( NULL == ctx || NULL == ctx->cipher_info ) 185817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 186817466cbSJens Wiklander 187817466cbSJens Wiklander if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 && 188817466cbSJens Wiklander (int) ctx->cipher_info->key_bitlen != key_bitlen ) 189817466cbSJens Wiklander { 190817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 191817466cbSJens Wiklander } 192817466cbSJens Wiklander 193817466cbSJens Wiklander ctx->key_bitlen = key_bitlen; 194817466cbSJens Wiklander ctx->operation = operation; 195817466cbSJens Wiklander 196817466cbSJens Wiklander /* 197817466cbSJens Wiklander * For CFB and CTR mode always use the encryption key schedule 198817466cbSJens Wiklander */ 199817466cbSJens Wiklander if( MBEDTLS_ENCRYPT == operation || 200817466cbSJens Wiklander MBEDTLS_MODE_CFB == ctx->cipher_info->mode || 201817466cbSJens Wiklander MBEDTLS_MODE_CTR == ctx->cipher_info->mode ) 202817466cbSJens Wiklander { 203817466cbSJens Wiklander return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key, 204817466cbSJens Wiklander ctx->key_bitlen ); 205817466cbSJens Wiklander } 206817466cbSJens Wiklander 207817466cbSJens Wiklander if( MBEDTLS_DECRYPT == operation ) 208817466cbSJens Wiklander return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key, 209817466cbSJens Wiklander ctx->key_bitlen ); 210817466cbSJens Wiklander 211817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 212817466cbSJens Wiklander } 213817466cbSJens Wiklander 214817466cbSJens Wiklander int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, 215817466cbSJens Wiklander const unsigned char *iv, size_t iv_len ) 216817466cbSJens Wiklander { 217817466cbSJens Wiklander size_t actual_iv_size; 218817466cbSJens Wiklander 219817466cbSJens Wiklander if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv ) 220817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 221817466cbSJens Wiklander 222817466cbSJens Wiklander /* avoid buffer overflow in ctx->iv */ 223817466cbSJens Wiklander if( iv_len > MBEDTLS_MAX_IV_LENGTH ) 224817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 225817466cbSJens Wiklander 226817466cbSJens Wiklander if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 ) 227817466cbSJens Wiklander actual_iv_size = iv_len; 228817466cbSJens Wiklander else 229817466cbSJens Wiklander { 230817466cbSJens Wiklander actual_iv_size = ctx->cipher_info->iv_size; 231817466cbSJens Wiklander 232817466cbSJens Wiklander /* avoid reading past the end of input buffer */ 233817466cbSJens Wiklander if( actual_iv_size > iv_len ) 234817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 235817466cbSJens Wiklander } 236817466cbSJens Wiklander 237817466cbSJens Wiklander memcpy( ctx->iv, iv, actual_iv_size ); 238817466cbSJens Wiklander ctx->iv_size = actual_iv_size; 239817466cbSJens Wiklander 240817466cbSJens Wiklander return( 0 ); 241817466cbSJens Wiklander } 242817466cbSJens Wiklander 243817466cbSJens Wiklander int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ) 244817466cbSJens Wiklander { 245817466cbSJens Wiklander if( NULL == ctx || NULL == ctx->cipher_info ) 246817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 247817466cbSJens Wiklander 248817466cbSJens Wiklander ctx->unprocessed_len = 0; 249817466cbSJens Wiklander 250817466cbSJens Wiklander return( 0 ); 251817466cbSJens Wiklander } 252817466cbSJens Wiklander 253817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 254817466cbSJens Wiklander int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, 255817466cbSJens Wiklander const unsigned char *ad, size_t ad_len ) 256817466cbSJens Wiklander { 257817466cbSJens Wiklander if( NULL == ctx || NULL == ctx->cipher_info ) 258817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 259817466cbSJens Wiklander 260817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 261817466cbSJens Wiklander { 262817466cbSJens Wiklander return mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation, 263817466cbSJens Wiklander ctx->iv, ctx->iv_size, ad, ad_len ); 264817466cbSJens Wiklander } 265817466cbSJens Wiklander 266817466cbSJens Wiklander return( 0 ); 267817466cbSJens Wiklander } 268817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */ 269817466cbSJens Wiklander 270817466cbSJens Wiklander int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, 271817466cbSJens Wiklander size_t ilen, unsigned char *output, size_t *olen ) 272817466cbSJens Wiklander { 273817466cbSJens Wiklander int ret; 274817466cbSJens Wiklander size_t block_size = 0; 275817466cbSJens Wiklander 276817466cbSJens Wiklander if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) 277817466cbSJens Wiklander { 278817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 279817466cbSJens Wiklander } 280817466cbSJens Wiklander 281817466cbSJens Wiklander *olen = 0; 282817466cbSJens Wiklander block_size = mbedtls_cipher_get_block_size( ctx ); 283817466cbSJens Wiklander 284817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB ) 285817466cbSJens Wiklander { 286817466cbSJens Wiklander if( ilen != block_size ) 287817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 288817466cbSJens Wiklander 289817466cbSJens Wiklander *olen = ilen; 290817466cbSJens Wiklander 291817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx, 292817466cbSJens Wiklander ctx->operation, input, output ) ) ) 293817466cbSJens Wiklander { 294817466cbSJens Wiklander return( ret ); 295817466cbSJens Wiklander } 296817466cbSJens Wiklander 297817466cbSJens Wiklander return( 0 ); 298817466cbSJens Wiklander } 299817466cbSJens Wiklander 300817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 301817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM ) 302817466cbSJens Wiklander { 303817466cbSJens Wiklander *olen = ilen; 304817466cbSJens Wiklander return mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input, 305817466cbSJens Wiklander output ); 306817466cbSJens Wiklander } 307817466cbSJens Wiklander #endif 308817466cbSJens Wiklander 309817466cbSJens Wiklander if ( 0 == block_size ) 310817466cbSJens Wiklander { 311817466cbSJens Wiklander return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT; 312817466cbSJens Wiklander } 313817466cbSJens Wiklander 314817466cbSJens Wiklander if( input == output && 315817466cbSJens Wiklander ( ctx->unprocessed_len != 0 || ilen % block_size ) ) 316817466cbSJens Wiklander { 317817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 318817466cbSJens Wiklander } 319817466cbSJens Wiklander 320817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CBC) 321817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC ) 322817466cbSJens Wiklander { 323817466cbSJens Wiklander size_t copy_len = 0; 324817466cbSJens Wiklander 325817466cbSJens Wiklander /* 326817466cbSJens Wiklander * If there is not enough data for a full block, cache it. 327817466cbSJens Wiklander */ 328817466cbSJens Wiklander if( ( ctx->operation == MBEDTLS_DECRYPT && 329817466cbSJens Wiklander ilen <= block_size - ctx->unprocessed_len ) || 330817466cbSJens Wiklander ( ctx->operation == MBEDTLS_ENCRYPT && 331817466cbSJens Wiklander ilen < block_size - ctx->unprocessed_len ) ) 332817466cbSJens Wiklander { 333817466cbSJens Wiklander memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, 334817466cbSJens Wiklander ilen ); 335817466cbSJens Wiklander 336817466cbSJens Wiklander ctx->unprocessed_len += ilen; 337817466cbSJens Wiklander return( 0 ); 338817466cbSJens Wiklander } 339817466cbSJens Wiklander 340817466cbSJens Wiklander /* 341817466cbSJens Wiklander * Process cached data first 342817466cbSJens Wiklander */ 343817466cbSJens Wiklander if( 0 != ctx->unprocessed_len ) 344817466cbSJens Wiklander { 345817466cbSJens Wiklander copy_len = block_size - ctx->unprocessed_len; 346817466cbSJens Wiklander 347817466cbSJens Wiklander memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, 348817466cbSJens Wiklander copy_len ); 349817466cbSJens Wiklander 350817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, 351817466cbSJens Wiklander ctx->operation, block_size, ctx->iv, 352817466cbSJens Wiklander ctx->unprocessed_data, output ) ) ) 353817466cbSJens Wiklander { 354817466cbSJens Wiklander return( ret ); 355817466cbSJens Wiklander } 356817466cbSJens Wiklander 357817466cbSJens Wiklander *olen += block_size; 358817466cbSJens Wiklander output += block_size; 359817466cbSJens Wiklander ctx->unprocessed_len = 0; 360817466cbSJens Wiklander 361817466cbSJens Wiklander input += copy_len; 362817466cbSJens Wiklander ilen -= copy_len; 363817466cbSJens Wiklander } 364817466cbSJens Wiklander 365817466cbSJens Wiklander /* 366817466cbSJens Wiklander * Cache final, incomplete block 367817466cbSJens Wiklander */ 368817466cbSJens Wiklander if( 0 != ilen ) 369817466cbSJens Wiklander { 370817466cbSJens Wiklander if( 0 == block_size ) 371817466cbSJens Wiklander { 372817466cbSJens Wiklander return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT; 373817466cbSJens Wiklander } 374817466cbSJens Wiklander 375817466cbSJens Wiklander copy_len = ilen % block_size; 376817466cbSJens Wiklander if( copy_len == 0 && ctx->operation == MBEDTLS_DECRYPT ) 377817466cbSJens Wiklander copy_len = block_size; 378817466cbSJens Wiklander 379817466cbSJens Wiklander memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ), 380817466cbSJens Wiklander copy_len ); 381817466cbSJens Wiklander 382817466cbSJens Wiklander ctx->unprocessed_len += copy_len; 383817466cbSJens Wiklander ilen -= copy_len; 384817466cbSJens Wiklander } 385817466cbSJens Wiklander 386817466cbSJens Wiklander /* 387817466cbSJens Wiklander * Process remaining full blocks 388817466cbSJens Wiklander */ 389817466cbSJens Wiklander if( ilen ) 390817466cbSJens Wiklander { 391817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, 392817466cbSJens Wiklander ctx->operation, ilen, ctx->iv, input, output ) ) ) 393817466cbSJens Wiklander { 394817466cbSJens Wiklander return( ret ); 395817466cbSJens Wiklander } 396817466cbSJens Wiklander 397817466cbSJens Wiklander *olen += ilen; 398817466cbSJens Wiklander } 399817466cbSJens Wiklander 400817466cbSJens Wiklander return( 0 ); 401817466cbSJens Wiklander } 402817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CBC */ 403817466cbSJens Wiklander 404817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CFB) 405817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB ) 406817466cbSJens Wiklander { 407817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx, 408817466cbSJens Wiklander ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv, 409817466cbSJens Wiklander input, output ) ) ) 410817466cbSJens Wiklander { 411817466cbSJens Wiklander return( ret ); 412817466cbSJens Wiklander } 413817466cbSJens Wiklander 414817466cbSJens Wiklander *olen = ilen; 415817466cbSJens Wiklander 416817466cbSJens Wiklander return( 0 ); 417817466cbSJens Wiklander } 418817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CFB */ 419817466cbSJens Wiklander 420817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CTR) 421817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR ) 422817466cbSJens Wiklander { 423817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx, 424817466cbSJens Wiklander ilen, &ctx->unprocessed_len, ctx->iv, 425817466cbSJens Wiklander ctx->unprocessed_data, input, output ) ) ) 426817466cbSJens Wiklander { 427817466cbSJens Wiklander return( ret ); 428817466cbSJens Wiklander } 429817466cbSJens Wiklander 430817466cbSJens Wiklander *olen = ilen; 431817466cbSJens Wiklander 432817466cbSJens Wiklander return( 0 ); 433817466cbSJens Wiklander } 434817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CTR */ 435817466cbSJens Wiklander 436817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_STREAM) 437817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM ) 438817466cbSJens Wiklander { 439817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx, 440817466cbSJens Wiklander ilen, input, output ) ) ) 441817466cbSJens Wiklander { 442817466cbSJens Wiklander return( ret ); 443817466cbSJens Wiklander } 444817466cbSJens Wiklander 445817466cbSJens Wiklander *olen = ilen; 446817466cbSJens Wiklander 447817466cbSJens Wiklander return( 0 ); 448817466cbSJens Wiklander } 449817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_STREAM */ 450817466cbSJens Wiklander 451817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 452817466cbSJens Wiklander } 453817466cbSJens Wiklander 454817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) 455817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7) 456817466cbSJens Wiklander /* 457817466cbSJens Wiklander * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len 458817466cbSJens Wiklander */ 459817466cbSJens Wiklander static void add_pkcs_padding( unsigned char *output, size_t output_len, 460817466cbSJens Wiklander size_t data_len ) 461817466cbSJens Wiklander { 462817466cbSJens Wiklander size_t padding_len = output_len - data_len; 463817466cbSJens Wiklander unsigned char i; 464817466cbSJens Wiklander 465817466cbSJens Wiklander for( i = 0; i < padding_len; i++ ) 466817466cbSJens Wiklander output[data_len + i] = (unsigned char) padding_len; 467817466cbSJens Wiklander } 468817466cbSJens Wiklander 469817466cbSJens Wiklander static int get_pkcs_padding( unsigned char *input, size_t input_len, 470817466cbSJens Wiklander size_t *data_len ) 471817466cbSJens Wiklander { 472817466cbSJens Wiklander size_t i, pad_idx; 473817466cbSJens Wiklander unsigned char padding_len, bad = 0; 474817466cbSJens Wiklander 475817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 476817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 477817466cbSJens Wiklander 478817466cbSJens Wiklander padding_len = input[input_len - 1]; 479817466cbSJens Wiklander *data_len = input_len - padding_len; 480817466cbSJens Wiklander 481817466cbSJens Wiklander /* Avoid logical || since it results in a branch */ 482817466cbSJens Wiklander bad |= padding_len > input_len; 483817466cbSJens Wiklander bad |= padding_len == 0; 484817466cbSJens Wiklander 485817466cbSJens Wiklander /* The number of bytes checked must be independent of padding_len, 486817466cbSJens Wiklander * so pick input_len, which is usually 8 or 16 (one block) */ 487817466cbSJens Wiklander pad_idx = input_len - padding_len; 488817466cbSJens Wiklander for( i = 0; i < input_len; i++ ) 489817466cbSJens Wiklander bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx ); 490817466cbSJens Wiklander 491817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); 492817466cbSJens Wiklander } 493817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ 494817466cbSJens Wiklander 495817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) 496817466cbSJens Wiklander /* 497817466cbSJens Wiklander * One and zeros padding: fill with 80 00 ... 00 498817466cbSJens Wiklander */ 499817466cbSJens Wiklander static void add_one_and_zeros_padding( unsigned char *output, 500817466cbSJens Wiklander size_t output_len, size_t data_len ) 501817466cbSJens Wiklander { 502817466cbSJens Wiklander size_t padding_len = output_len - data_len; 503817466cbSJens Wiklander unsigned char i = 0; 504817466cbSJens Wiklander 505817466cbSJens Wiklander output[data_len] = 0x80; 506817466cbSJens Wiklander for( i = 1; i < padding_len; i++ ) 507817466cbSJens Wiklander output[data_len + i] = 0x00; 508817466cbSJens Wiklander } 509817466cbSJens Wiklander 510817466cbSJens Wiklander static int get_one_and_zeros_padding( unsigned char *input, size_t input_len, 511817466cbSJens Wiklander size_t *data_len ) 512817466cbSJens Wiklander { 513817466cbSJens Wiklander size_t i; 514817466cbSJens Wiklander unsigned char done = 0, prev_done, bad; 515817466cbSJens Wiklander 516817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 517817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 518817466cbSJens Wiklander 519817466cbSJens Wiklander bad = 0xFF; 520817466cbSJens Wiklander *data_len = 0; 521817466cbSJens Wiklander for( i = input_len; i > 0; i-- ) 522817466cbSJens Wiklander { 523817466cbSJens Wiklander prev_done = done; 524817466cbSJens Wiklander done |= ( input[i-1] != 0 ); 525817466cbSJens Wiklander *data_len |= ( i - 1 ) * ( done != prev_done ); 526817466cbSJens Wiklander bad &= ( input[i-1] ^ 0x80 ) | ( done == prev_done ); 527817466cbSJens Wiklander } 528817466cbSJens Wiklander 529817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); 530817466cbSJens Wiklander 531817466cbSJens Wiklander } 532817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ 533817466cbSJens Wiklander 534817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) 535817466cbSJens Wiklander /* 536817466cbSJens Wiklander * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length 537817466cbSJens Wiklander */ 538817466cbSJens Wiklander static void add_zeros_and_len_padding( unsigned char *output, 539817466cbSJens Wiklander size_t output_len, size_t data_len ) 540817466cbSJens Wiklander { 541817466cbSJens Wiklander size_t padding_len = output_len - data_len; 542817466cbSJens Wiklander unsigned char i = 0; 543817466cbSJens Wiklander 544817466cbSJens Wiklander for( i = 1; i < padding_len; i++ ) 545817466cbSJens Wiklander output[data_len + i - 1] = 0x00; 546817466cbSJens Wiklander output[output_len - 1] = (unsigned char) padding_len; 547817466cbSJens Wiklander } 548817466cbSJens Wiklander 549817466cbSJens Wiklander static int get_zeros_and_len_padding( unsigned char *input, size_t input_len, 550817466cbSJens Wiklander size_t *data_len ) 551817466cbSJens Wiklander { 552817466cbSJens Wiklander size_t i, pad_idx; 553817466cbSJens Wiklander unsigned char padding_len, bad = 0; 554817466cbSJens Wiklander 555817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 556817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 557817466cbSJens Wiklander 558817466cbSJens Wiklander padding_len = input[input_len - 1]; 559817466cbSJens Wiklander *data_len = input_len - padding_len; 560817466cbSJens Wiklander 561817466cbSJens Wiklander /* Avoid logical || since it results in a branch */ 562817466cbSJens Wiklander bad |= padding_len > input_len; 563817466cbSJens Wiklander bad |= padding_len == 0; 564817466cbSJens Wiklander 565817466cbSJens Wiklander /* The number of bytes checked must be independent of padding_len */ 566817466cbSJens Wiklander pad_idx = input_len - padding_len; 567817466cbSJens Wiklander for( i = 0; i < input_len - 1; i++ ) 568817466cbSJens Wiklander bad |= input[i] * ( i >= pad_idx ); 569817466cbSJens Wiklander 570817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); 571817466cbSJens Wiklander } 572817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ 573817466cbSJens Wiklander 574817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS) 575817466cbSJens Wiklander /* 576817466cbSJens Wiklander * Zero padding: fill with 00 ... 00 577817466cbSJens Wiklander */ 578817466cbSJens Wiklander static void add_zeros_padding( unsigned char *output, 579817466cbSJens Wiklander size_t output_len, size_t data_len ) 580817466cbSJens Wiklander { 581817466cbSJens Wiklander size_t i; 582817466cbSJens Wiklander 583817466cbSJens Wiklander for( i = data_len; i < output_len; i++ ) 584817466cbSJens Wiklander output[i] = 0x00; 585817466cbSJens Wiklander } 586817466cbSJens Wiklander 587817466cbSJens Wiklander static int get_zeros_padding( unsigned char *input, size_t input_len, 588817466cbSJens Wiklander size_t *data_len ) 589817466cbSJens Wiklander { 590817466cbSJens Wiklander size_t i; 591817466cbSJens Wiklander unsigned char done = 0, prev_done; 592817466cbSJens Wiklander 593817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 594817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 595817466cbSJens Wiklander 596817466cbSJens Wiklander *data_len = 0; 597817466cbSJens Wiklander for( i = input_len; i > 0; i-- ) 598817466cbSJens Wiklander { 599817466cbSJens Wiklander prev_done = done; 600817466cbSJens Wiklander done |= ( input[i-1] != 0 ); 601817466cbSJens Wiklander *data_len |= i * ( done != prev_done ); 602817466cbSJens Wiklander } 603817466cbSJens Wiklander 604817466cbSJens Wiklander return( 0 ); 605817466cbSJens Wiklander } 606817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ 607817466cbSJens Wiklander 608817466cbSJens Wiklander /* 609817466cbSJens Wiklander * No padding: don't pad :) 610817466cbSJens Wiklander * 611817466cbSJens Wiklander * There is no add_padding function (check for NULL in mbedtls_cipher_finish) 612817466cbSJens Wiklander * but a trivial get_padding function 613817466cbSJens Wiklander */ 614817466cbSJens Wiklander static int get_no_padding( unsigned char *input, size_t input_len, 615817466cbSJens Wiklander size_t *data_len ) 616817466cbSJens Wiklander { 617817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 618817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 619817466cbSJens Wiklander 620817466cbSJens Wiklander *data_len = input_len; 621817466cbSJens Wiklander 622817466cbSJens Wiklander return( 0 ); 623817466cbSJens Wiklander } 624817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ 625817466cbSJens Wiklander 626817466cbSJens Wiklander int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, 627817466cbSJens Wiklander unsigned char *output, size_t *olen ) 628817466cbSJens Wiklander { 629817466cbSJens Wiklander if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) 630817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 631817466cbSJens Wiklander 632817466cbSJens Wiklander *olen = 0; 633817466cbSJens Wiklander 634817466cbSJens Wiklander if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode || 635817466cbSJens Wiklander MBEDTLS_MODE_CTR == ctx->cipher_info->mode || 636817466cbSJens Wiklander MBEDTLS_MODE_GCM == ctx->cipher_info->mode || 637817466cbSJens Wiklander MBEDTLS_MODE_STREAM == ctx->cipher_info->mode ) 638817466cbSJens Wiklander { 639817466cbSJens Wiklander return( 0 ); 640817466cbSJens Wiklander } 641817466cbSJens Wiklander 642817466cbSJens Wiklander if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode ) 643817466cbSJens Wiklander { 644817466cbSJens Wiklander if( ctx->unprocessed_len != 0 ) 645817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 646817466cbSJens Wiklander 647817466cbSJens Wiklander return( 0 ); 648817466cbSJens Wiklander } 649817466cbSJens Wiklander 650817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CBC) 651817466cbSJens Wiklander if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode ) 652817466cbSJens Wiklander { 653817466cbSJens Wiklander int ret = 0; 654817466cbSJens Wiklander 655817466cbSJens Wiklander if( MBEDTLS_ENCRYPT == ctx->operation ) 656817466cbSJens Wiklander { 657817466cbSJens Wiklander /* check for 'no padding' mode */ 658817466cbSJens Wiklander if( NULL == ctx->add_padding ) 659817466cbSJens Wiklander { 660817466cbSJens Wiklander if( 0 != ctx->unprocessed_len ) 661817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 662817466cbSJens Wiklander 663817466cbSJens Wiklander return( 0 ); 664817466cbSJens Wiklander } 665817466cbSJens Wiklander 666817466cbSJens Wiklander ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ), 667817466cbSJens Wiklander ctx->unprocessed_len ); 668817466cbSJens Wiklander } 669817466cbSJens Wiklander else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len ) 670817466cbSJens Wiklander { 671817466cbSJens Wiklander /* 672817466cbSJens Wiklander * For decrypt operations, expect a full block, 673817466cbSJens Wiklander * or an empty block if no padding 674817466cbSJens Wiklander */ 675817466cbSJens Wiklander if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len ) 676817466cbSJens Wiklander return( 0 ); 677817466cbSJens Wiklander 678817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 679817466cbSJens Wiklander } 680817466cbSJens Wiklander 681817466cbSJens Wiklander /* cipher block */ 682817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, 683817466cbSJens Wiklander ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv, 684817466cbSJens Wiklander ctx->unprocessed_data, output ) ) ) 685817466cbSJens Wiklander { 686817466cbSJens Wiklander return( ret ); 687817466cbSJens Wiklander } 688817466cbSJens Wiklander 689817466cbSJens Wiklander /* Set output size for decryption */ 690817466cbSJens Wiklander if( MBEDTLS_DECRYPT == ctx->operation ) 691817466cbSJens Wiklander return ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ), 692817466cbSJens Wiklander olen ); 693817466cbSJens Wiklander 694817466cbSJens Wiklander /* Set output size for encryption */ 695817466cbSJens Wiklander *olen = mbedtls_cipher_get_block_size( ctx ); 696817466cbSJens Wiklander return( 0 ); 697817466cbSJens Wiklander } 698817466cbSJens Wiklander #else 699817466cbSJens Wiklander ((void) output); 700817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CBC */ 701817466cbSJens Wiklander 702817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 703817466cbSJens Wiklander } 704817466cbSJens Wiklander 705817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) 706817466cbSJens Wiklander int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode ) 707817466cbSJens Wiklander { 708817466cbSJens Wiklander if( NULL == ctx || 709817466cbSJens Wiklander MBEDTLS_MODE_CBC != ctx->cipher_info->mode ) 710817466cbSJens Wiklander { 711817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 712817466cbSJens Wiklander } 713817466cbSJens Wiklander 714817466cbSJens Wiklander switch( mode ) 715817466cbSJens Wiklander { 716817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7) 717817466cbSJens Wiklander case MBEDTLS_PADDING_PKCS7: 718817466cbSJens Wiklander ctx->add_padding = add_pkcs_padding; 719817466cbSJens Wiklander ctx->get_padding = get_pkcs_padding; 720817466cbSJens Wiklander break; 721817466cbSJens Wiklander #endif 722817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) 723817466cbSJens Wiklander case MBEDTLS_PADDING_ONE_AND_ZEROS: 724817466cbSJens Wiklander ctx->add_padding = add_one_and_zeros_padding; 725817466cbSJens Wiklander ctx->get_padding = get_one_and_zeros_padding; 726817466cbSJens Wiklander break; 727817466cbSJens Wiklander #endif 728817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) 729817466cbSJens Wiklander case MBEDTLS_PADDING_ZEROS_AND_LEN: 730817466cbSJens Wiklander ctx->add_padding = add_zeros_and_len_padding; 731817466cbSJens Wiklander ctx->get_padding = get_zeros_and_len_padding; 732817466cbSJens Wiklander break; 733817466cbSJens Wiklander #endif 734817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS) 735817466cbSJens Wiklander case MBEDTLS_PADDING_ZEROS: 736817466cbSJens Wiklander ctx->add_padding = add_zeros_padding; 737817466cbSJens Wiklander ctx->get_padding = get_zeros_padding; 738817466cbSJens Wiklander break; 739817466cbSJens Wiklander #endif 740817466cbSJens Wiklander case MBEDTLS_PADDING_NONE: 741817466cbSJens Wiklander ctx->add_padding = NULL; 742817466cbSJens Wiklander ctx->get_padding = get_no_padding; 743817466cbSJens Wiklander break; 744817466cbSJens Wiklander 745817466cbSJens Wiklander default: 746817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 747817466cbSJens Wiklander } 748817466cbSJens Wiklander 749817466cbSJens Wiklander return( 0 ); 750817466cbSJens Wiklander } 751817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ 752817466cbSJens Wiklander 753817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 754817466cbSJens Wiklander int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, 755817466cbSJens Wiklander unsigned char *tag, size_t tag_len ) 756817466cbSJens Wiklander { 757817466cbSJens Wiklander if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag ) 758817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 759817466cbSJens Wiklander 760817466cbSJens Wiklander if( MBEDTLS_ENCRYPT != ctx->operation ) 761817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 762817466cbSJens Wiklander 763817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 764817466cbSJens Wiklander return mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, tag, tag_len ); 765817466cbSJens Wiklander 766817466cbSJens Wiklander return( 0 ); 767817466cbSJens Wiklander } 768817466cbSJens Wiklander 769817466cbSJens Wiklander int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, 770817466cbSJens Wiklander const unsigned char *tag, size_t tag_len ) 771817466cbSJens Wiklander { 772817466cbSJens Wiklander int ret; 773817466cbSJens Wiklander 774817466cbSJens Wiklander if( NULL == ctx || NULL == ctx->cipher_info || 775817466cbSJens Wiklander MBEDTLS_DECRYPT != ctx->operation ) 776817466cbSJens Wiklander { 777817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 778817466cbSJens Wiklander } 779817466cbSJens Wiklander 780817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 781817466cbSJens Wiklander { 782817466cbSJens Wiklander unsigned char check_tag[16]; 783817466cbSJens Wiklander size_t i; 784817466cbSJens Wiklander int diff; 785817466cbSJens Wiklander 786817466cbSJens Wiklander if( tag_len > sizeof( check_tag ) ) 787817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 788817466cbSJens Wiklander 789817466cbSJens Wiklander if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, 790817466cbSJens Wiklander check_tag, tag_len ) ) ) 791817466cbSJens Wiklander { 792817466cbSJens Wiklander return( ret ); 793817466cbSJens Wiklander } 794817466cbSJens Wiklander 795817466cbSJens Wiklander /* Check the tag in "constant-time" */ 796817466cbSJens Wiklander for( diff = 0, i = 0; i < tag_len; i++ ) 797817466cbSJens Wiklander diff |= tag[i] ^ check_tag[i]; 798817466cbSJens Wiklander 799817466cbSJens Wiklander if( diff != 0 ) 800817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); 801817466cbSJens Wiklander 802817466cbSJens Wiklander return( 0 ); 803817466cbSJens Wiklander } 804817466cbSJens Wiklander 805817466cbSJens Wiklander return( 0 ); 806817466cbSJens Wiklander } 807817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */ 808817466cbSJens Wiklander 809817466cbSJens Wiklander /* 810817466cbSJens Wiklander * Packet-oriented wrapper for non-AEAD modes 811817466cbSJens Wiklander */ 812817466cbSJens Wiklander int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, 813817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 814817466cbSJens Wiklander const unsigned char *input, size_t ilen, 815817466cbSJens Wiklander unsigned char *output, size_t *olen ) 816817466cbSJens Wiklander { 817817466cbSJens Wiklander int ret; 818817466cbSJens Wiklander size_t finish_olen; 819817466cbSJens Wiklander 820817466cbSJens Wiklander if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 ) 821817466cbSJens Wiklander return( ret ); 822817466cbSJens Wiklander 823817466cbSJens Wiklander if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 ) 824817466cbSJens Wiklander return( ret ); 825817466cbSJens Wiklander 826817466cbSJens Wiklander if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 ) 827817466cbSJens Wiklander return( ret ); 828817466cbSJens Wiklander 829817466cbSJens Wiklander if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 ) 830817466cbSJens Wiklander return( ret ); 831817466cbSJens Wiklander 832817466cbSJens Wiklander *olen += finish_olen; 833817466cbSJens Wiklander 834817466cbSJens Wiklander return( 0 ); 835817466cbSJens Wiklander } 836817466cbSJens Wiklander 837817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_AEAD) 838817466cbSJens Wiklander /* 839817466cbSJens Wiklander * Packet-oriented encryption for AEAD modes 840817466cbSJens Wiklander */ 841817466cbSJens Wiklander int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, 842817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 843817466cbSJens Wiklander const unsigned char *ad, size_t ad_len, 844817466cbSJens Wiklander const unsigned char *input, size_t ilen, 845817466cbSJens Wiklander unsigned char *output, size_t *olen, 846817466cbSJens Wiklander unsigned char *tag, size_t tag_len ) 847817466cbSJens Wiklander { 848817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 849817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 850817466cbSJens Wiklander { 851817466cbSJens Wiklander *olen = ilen; 852817466cbSJens Wiklander return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen, 853817466cbSJens Wiklander iv, iv_len, ad, ad_len, input, output, 854817466cbSJens Wiklander tag_len, tag ) ); 855817466cbSJens Wiklander } 856817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */ 857817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C) 858817466cbSJens Wiklander if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) 859817466cbSJens Wiklander { 860817466cbSJens Wiklander *olen = ilen; 861817466cbSJens Wiklander return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen, 862817466cbSJens Wiklander iv, iv_len, ad, ad_len, input, output, 863817466cbSJens Wiklander tag, tag_len ) ); 864817466cbSJens Wiklander } 865817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */ 866817466cbSJens Wiklander 867817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 868817466cbSJens Wiklander } 869817466cbSJens Wiklander 870817466cbSJens Wiklander /* 871817466cbSJens Wiklander * Packet-oriented decryption for AEAD modes 872817466cbSJens Wiklander */ 873817466cbSJens Wiklander int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, 874817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 875817466cbSJens Wiklander const unsigned char *ad, size_t ad_len, 876817466cbSJens Wiklander const unsigned char *input, size_t ilen, 877817466cbSJens Wiklander unsigned char *output, size_t *olen, 878817466cbSJens Wiklander const unsigned char *tag, size_t tag_len ) 879817466cbSJens Wiklander { 880817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 881817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 882817466cbSJens Wiklander { 883817466cbSJens Wiklander int ret; 884817466cbSJens Wiklander 885817466cbSJens Wiklander *olen = ilen; 886817466cbSJens Wiklander ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen, 887817466cbSJens Wiklander iv, iv_len, ad, ad_len, 888817466cbSJens Wiklander tag, tag_len, input, output ); 889817466cbSJens Wiklander 890817466cbSJens Wiklander if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED ) 891817466cbSJens Wiklander ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; 892817466cbSJens Wiklander 893817466cbSJens Wiklander return( ret ); 894817466cbSJens Wiklander } 895817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */ 896817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C) 897817466cbSJens Wiklander if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) 898817466cbSJens Wiklander { 899817466cbSJens Wiklander int ret; 900817466cbSJens Wiklander 901817466cbSJens Wiklander *olen = ilen; 902817466cbSJens Wiklander ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen, 903817466cbSJens Wiklander iv, iv_len, ad, ad_len, 904817466cbSJens Wiklander input, output, tag, tag_len ); 905817466cbSJens Wiklander 906817466cbSJens Wiklander if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED ) 907817466cbSJens Wiklander ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; 908817466cbSJens Wiklander 909817466cbSJens Wiklander return( ret ); 910817466cbSJens Wiklander } 911817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */ 912817466cbSJens Wiklander 913817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 914817466cbSJens Wiklander } 915817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_AEAD */ 916817466cbSJens Wiklander 917817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_C */ 918