1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /** 3817466cbSJens Wiklander * \file cipher.c 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * \brief Generic cipher wrapper for mbed TLS 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * \author Adriaan de Jong <dejong@fox-it.com> 8817466cbSJens Wiklander * 9817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 12817466cbSJens Wiklander * not use this file except in compliance with the License. 13817466cbSJens Wiklander * You may obtain a copy of the License at 14817466cbSJens Wiklander * 15817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 16817466cbSJens Wiklander * 17817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 18817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 19817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20817466cbSJens Wiklander * See the License for the specific language governing permissions and 21817466cbSJens Wiklander * limitations under the License. 22817466cbSJens Wiklander * 23817466cbSJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 24817466cbSJens Wiklander */ 25817466cbSJens Wiklander 26817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 27817466cbSJens Wiklander #include "mbedtls/config.h" 28817466cbSJens Wiklander #else 29817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 30817466cbSJens Wiklander #endif 31817466cbSJens Wiklander 32817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_C) 33817466cbSJens Wiklander 34817466cbSJens Wiklander #include "mbedtls/cipher.h" 35817466cbSJens Wiklander #include "mbedtls/cipher_internal.h" 36*3d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 37817466cbSJens Wiklander 38817466cbSJens Wiklander #include <stdlib.h> 39817466cbSJens Wiklander #include <string.h> 40817466cbSJens Wiklander 41*3d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 42*3d3b0591SJens Wiklander #include "mbedtls/chachapoly.h" 43*3d3b0591SJens Wiklander #endif 44*3d3b0591SJens Wiklander 45817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 46817466cbSJens Wiklander #include "mbedtls/gcm.h" 47817466cbSJens Wiklander #endif 48817466cbSJens Wiklander 49817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C) 50817466cbSJens Wiklander #include "mbedtls/ccm.h" 51817466cbSJens Wiklander #endif 52817466cbSJens Wiklander 53*3d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHA20_C) 54*3d3b0591SJens Wiklander #include "mbedtls/chacha20.h" 55*3d3b0591SJens Wiklander #endif 56*3d3b0591SJens Wiklander 57817466cbSJens Wiklander #if defined(MBEDTLS_CMAC_C) 58817466cbSJens Wiklander #include "mbedtls/cmac.h" 59817466cbSJens Wiklander #endif 60817466cbSJens Wiklander 61817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 62817466cbSJens Wiklander #include "mbedtls/platform.h" 63817466cbSJens Wiklander #else 64817466cbSJens Wiklander #define mbedtls_calloc calloc 65817466cbSJens Wiklander #define mbedtls_free free 66817466cbSJens Wiklander #endif 67817466cbSJens Wiklander 68*3d3b0591SJens Wiklander #define CIPHER_VALIDATE_RET( cond ) \ 69*3d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ) 70*3d3b0591SJens Wiklander #define CIPHER_VALIDATE( cond ) \ 71*3d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE( cond ) 72817466cbSJens Wiklander 73*3d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) 74*3d3b0591SJens Wiklander /* Compare the contents of two buffers in constant time. 75*3d3b0591SJens Wiklander * Returns 0 if the contents are bitwise identical, otherwise returns 76*3d3b0591SJens Wiklander * a non-zero value. 77*3d3b0591SJens Wiklander * This is currently only used by GCM and ChaCha20+Poly1305. 78*3d3b0591SJens Wiklander */ 79*3d3b0591SJens Wiklander static int mbedtls_constant_time_memcmp( const void *v1, const void *v2, size_t len ) 80*3d3b0591SJens Wiklander { 81*3d3b0591SJens Wiklander const unsigned char *p1 = (const unsigned char*) v1; 82*3d3b0591SJens Wiklander const unsigned char *p2 = (const unsigned char*) v2; 83*3d3b0591SJens Wiklander size_t i; 84*3d3b0591SJens Wiklander unsigned char diff; 85*3d3b0591SJens Wiklander 86*3d3b0591SJens Wiklander for( diff = 0, i = 0; i < len; i++ ) 87*3d3b0591SJens Wiklander diff |= p1[i] ^ p2[i]; 88*3d3b0591SJens Wiklander 89*3d3b0591SJens Wiklander return( (int)diff ); 90817466cbSJens Wiklander } 91*3d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ 92817466cbSJens Wiklander 93817466cbSJens Wiklander static int supported_init = 0; 94817466cbSJens Wiklander 95817466cbSJens Wiklander const int *mbedtls_cipher_list( void ) 96817466cbSJens Wiklander { 97817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 98817466cbSJens Wiklander int *type; 99817466cbSJens Wiklander 100817466cbSJens Wiklander if( ! supported_init ) 101817466cbSJens Wiklander { 102817466cbSJens Wiklander def = mbedtls_cipher_definitions; 103817466cbSJens Wiklander type = mbedtls_cipher_supported; 104817466cbSJens Wiklander 105817466cbSJens Wiklander while( def->type != 0 ) 106817466cbSJens Wiklander *type++ = (*def++).type; 107817466cbSJens Wiklander 108817466cbSJens Wiklander *type = 0; 109817466cbSJens Wiklander 110817466cbSJens Wiklander supported_init = 1; 111817466cbSJens Wiklander } 112817466cbSJens Wiklander 113817466cbSJens Wiklander return( mbedtls_cipher_supported ); 114817466cbSJens Wiklander } 115817466cbSJens Wiklander 116817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ) 117817466cbSJens Wiklander { 118817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 119817466cbSJens Wiklander 120817466cbSJens Wiklander for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) 121817466cbSJens Wiklander if( def->type == cipher_type ) 122817466cbSJens Wiklander return( def->info ); 123817466cbSJens Wiklander 124817466cbSJens Wiklander return( NULL ); 125817466cbSJens Wiklander } 126817466cbSJens Wiklander 127817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ) 128817466cbSJens Wiklander { 129817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 130817466cbSJens Wiklander 131817466cbSJens Wiklander if( NULL == cipher_name ) 132817466cbSJens Wiklander return( NULL ); 133817466cbSJens Wiklander 134817466cbSJens Wiklander for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) 135817466cbSJens Wiklander if( ! strcmp( def->info->name, cipher_name ) ) 136817466cbSJens Wiklander return( def->info ); 137817466cbSJens Wiklander 138817466cbSJens Wiklander return( NULL ); 139817466cbSJens Wiklander } 140817466cbSJens Wiklander 141817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id, 142817466cbSJens Wiklander int key_bitlen, 143817466cbSJens Wiklander const mbedtls_cipher_mode_t mode ) 144817466cbSJens Wiklander { 145817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 146817466cbSJens Wiklander 147817466cbSJens Wiklander for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) 148817466cbSJens Wiklander if( def->info->base->cipher == cipher_id && 149817466cbSJens Wiklander def->info->key_bitlen == (unsigned) key_bitlen && 150817466cbSJens Wiklander def->info->mode == mode ) 151817466cbSJens Wiklander return( def->info ); 152817466cbSJens Wiklander 153817466cbSJens Wiklander return( NULL ); 154817466cbSJens Wiklander } 155817466cbSJens Wiklander 156817466cbSJens Wiklander void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ) 157817466cbSJens Wiklander { 158*3d3b0591SJens Wiklander CIPHER_VALIDATE( ctx != NULL ); 159817466cbSJens Wiklander memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); 160817466cbSJens Wiklander } 161817466cbSJens Wiklander 162817466cbSJens Wiklander void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ) 163817466cbSJens Wiklander { 164817466cbSJens Wiklander if( ctx == NULL ) 165817466cbSJens Wiklander return; 166817466cbSJens Wiklander 167817466cbSJens Wiklander #if defined(MBEDTLS_CMAC_C) 168817466cbSJens Wiklander if( ctx->cmac_ctx ) 169817466cbSJens Wiklander { 170*3d3b0591SJens Wiklander mbedtls_platform_zeroize( ctx->cmac_ctx, 171*3d3b0591SJens Wiklander sizeof( mbedtls_cmac_context_t ) ); 172817466cbSJens Wiklander mbedtls_free( ctx->cmac_ctx ); 173817466cbSJens Wiklander } 174817466cbSJens Wiklander #endif 175817466cbSJens Wiklander 176817466cbSJens Wiklander if( ctx->cipher_ctx ) 177817466cbSJens Wiklander ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx ); 178817466cbSJens Wiklander 179*3d3b0591SJens Wiklander mbedtls_platform_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); 180817466cbSJens Wiklander } 181817466cbSJens Wiklander 182817466cbSJens Wiklander int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ) 183817466cbSJens Wiklander { 184*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 185*3d3b0591SJens Wiklander if( cipher_info == NULL ) 186817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 187817466cbSJens Wiklander 188817466cbSJens Wiklander memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); 189817466cbSJens Wiklander 190817466cbSJens Wiklander if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) ) 191817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED ); 192817466cbSJens Wiklander 193817466cbSJens Wiklander ctx->cipher_info = cipher_info; 194817466cbSJens Wiklander 195817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) 196817466cbSJens Wiklander /* 197817466cbSJens Wiklander * Ignore possible errors caused by a cipher mode that doesn't use padding 198817466cbSJens Wiklander */ 199817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7) 200817466cbSJens Wiklander (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 ); 201817466cbSJens Wiklander #else 202817466cbSJens Wiklander (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE ); 203817466cbSJens Wiklander #endif 204817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ 205817466cbSJens Wiklander 206817466cbSJens Wiklander return( 0 ); 207817466cbSJens Wiklander } 208817466cbSJens Wiklander 209*3d3b0591SJens Wiklander int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, 210*3d3b0591SJens Wiklander const unsigned char *key, 211*3d3b0591SJens Wiklander int key_bitlen, 212*3d3b0591SJens Wiklander const mbedtls_operation_t operation ) 213817466cbSJens Wiklander { 214*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 215*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( key != NULL ); 216*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( operation == MBEDTLS_ENCRYPT || 217*3d3b0591SJens Wiklander operation == MBEDTLS_DECRYPT ); 218*3d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 219817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 220817466cbSJens Wiklander 221817466cbSJens Wiklander if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 && 222817466cbSJens Wiklander (int) ctx->cipher_info->key_bitlen != key_bitlen ) 223817466cbSJens Wiklander { 224817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 225817466cbSJens Wiklander } 226817466cbSJens Wiklander 227817466cbSJens Wiklander ctx->key_bitlen = key_bitlen; 228817466cbSJens Wiklander ctx->operation = operation; 229817466cbSJens Wiklander 230817466cbSJens Wiklander /* 231*3d3b0591SJens Wiklander * For OFB, CFB and CTR mode always use the encryption key schedule 232817466cbSJens Wiklander */ 233817466cbSJens Wiklander if( MBEDTLS_ENCRYPT == operation || 234817466cbSJens Wiklander MBEDTLS_MODE_CFB == ctx->cipher_info->mode || 235*3d3b0591SJens Wiklander MBEDTLS_MODE_OFB == ctx->cipher_info->mode || 236817466cbSJens Wiklander MBEDTLS_MODE_CTR == ctx->cipher_info->mode ) 237817466cbSJens Wiklander { 238*3d3b0591SJens Wiklander return( ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key, 239*3d3b0591SJens Wiklander ctx->key_bitlen ) ); 240817466cbSJens Wiklander } 241817466cbSJens Wiklander 242817466cbSJens Wiklander if( MBEDTLS_DECRYPT == operation ) 243*3d3b0591SJens Wiklander return( ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key, 244*3d3b0591SJens Wiklander ctx->key_bitlen ) ); 245817466cbSJens Wiklander 246817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 247817466cbSJens Wiklander } 248817466cbSJens Wiklander 249817466cbSJens Wiklander int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, 250*3d3b0591SJens Wiklander const unsigned char *iv, 251*3d3b0591SJens Wiklander size_t iv_len ) 252817466cbSJens Wiklander { 253817466cbSJens Wiklander size_t actual_iv_size; 254817466cbSJens Wiklander 255*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 256*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL ); 257*3d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 258817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 259817466cbSJens Wiklander 260817466cbSJens Wiklander /* avoid buffer overflow in ctx->iv */ 261817466cbSJens Wiklander if( iv_len > MBEDTLS_MAX_IV_LENGTH ) 262817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 263817466cbSJens Wiklander 264817466cbSJens Wiklander if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 ) 265817466cbSJens Wiklander actual_iv_size = iv_len; 266817466cbSJens Wiklander else 267817466cbSJens Wiklander { 268817466cbSJens Wiklander actual_iv_size = ctx->cipher_info->iv_size; 269817466cbSJens Wiklander 270817466cbSJens Wiklander /* avoid reading past the end of input buffer */ 271817466cbSJens Wiklander if( actual_iv_size > iv_len ) 272817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 273817466cbSJens Wiklander } 274817466cbSJens Wiklander 275*3d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHA20_C) 276*3d3b0591SJens Wiklander if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20 ) 277*3d3b0591SJens Wiklander { 278*3d3b0591SJens Wiklander if ( 0 != mbedtls_chacha20_starts( (mbedtls_chacha20_context*)ctx->cipher_ctx, 279*3d3b0591SJens Wiklander iv, 280*3d3b0591SJens Wiklander 0U ) ) /* Initial counter value */ 281*3d3b0591SJens Wiklander { 282*3d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 283*3d3b0591SJens Wiklander } 284*3d3b0591SJens Wiklander } 285*3d3b0591SJens Wiklander #endif 286*3d3b0591SJens Wiklander 287*3d3b0591SJens Wiklander if ( actual_iv_size != 0 ) 288*3d3b0591SJens Wiklander { 289817466cbSJens Wiklander memcpy( ctx->iv, iv, actual_iv_size ); 290817466cbSJens Wiklander ctx->iv_size = actual_iv_size; 291*3d3b0591SJens Wiklander } 292817466cbSJens Wiklander 293817466cbSJens Wiklander return( 0 ); 294817466cbSJens Wiklander } 295817466cbSJens Wiklander 296817466cbSJens Wiklander int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ) 297817466cbSJens Wiklander { 298*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 299*3d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 300817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 301817466cbSJens Wiklander 302817466cbSJens Wiklander ctx->unprocessed_len = 0; 303817466cbSJens Wiklander 304817466cbSJens Wiklander return( 0 ); 305817466cbSJens Wiklander } 306817466cbSJens Wiklander 307*3d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) 308817466cbSJens Wiklander int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, 309817466cbSJens Wiklander const unsigned char *ad, size_t ad_len ) 310817466cbSJens Wiklander { 311*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 312*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); 313*3d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 314817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 315817466cbSJens Wiklander 316*3d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) 317817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 318817466cbSJens Wiklander { 319*3d3b0591SJens Wiklander return( mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation, 320*3d3b0591SJens Wiklander ctx->iv, ctx->iv_size, ad, ad_len ) ); 321817466cbSJens Wiklander } 322*3d3b0591SJens Wiklander #endif 323*3d3b0591SJens Wiklander 324*3d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 325*3d3b0591SJens Wiklander if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) 326*3d3b0591SJens Wiklander { 327*3d3b0591SJens Wiklander int result; 328*3d3b0591SJens Wiklander mbedtls_chachapoly_mode_t mode; 329*3d3b0591SJens Wiklander 330*3d3b0591SJens Wiklander mode = ( ctx->operation == MBEDTLS_ENCRYPT ) 331*3d3b0591SJens Wiklander ? MBEDTLS_CHACHAPOLY_ENCRYPT 332*3d3b0591SJens Wiklander : MBEDTLS_CHACHAPOLY_DECRYPT; 333*3d3b0591SJens Wiklander 334*3d3b0591SJens Wiklander result = mbedtls_chachapoly_starts( (mbedtls_chachapoly_context*) ctx->cipher_ctx, 335*3d3b0591SJens Wiklander ctx->iv, 336*3d3b0591SJens Wiklander mode ); 337*3d3b0591SJens Wiklander if ( result != 0 ) 338*3d3b0591SJens Wiklander return( result ); 339*3d3b0591SJens Wiklander 340*3d3b0591SJens Wiklander return( mbedtls_chachapoly_update_aad( (mbedtls_chachapoly_context*) ctx->cipher_ctx, 341*3d3b0591SJens Wiklander ad, ad_len ) ); 342*3d3b0591SJens Wiklander } 343*3d3b0591SJens Wiklander #endif 344817466cbSJens Wiklander 345817466cbSJens Wiklander return( 0 ); 346817466cbSJens Wiklander } 347*3d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ 348817466cbSJens Wiklander 349817466cbSJens Wiklander int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, 350817466cbSJens Wiklander size_t ilen, unsigned char *output, size_t *olen ) 351817466cbSJens Wiklander { 352817466cbSJens Wiklander int ret; 353*3d3b0591SJens Wiklander size_t block_size; 354817466cbSJens Wiklander 355*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 356*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); 357*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( output != NULL ); 358*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( olen != NULL ); 359*3d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 360817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 361817466cbSJens Wiklander 362817466cbSJens Wiklander *olen = 0; 363817466cbSJens Wiklander block_size = mbedtls_cipher_get_block_size( ctx ); 364817466cbSJens Wiklander 365817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB ) 366817466cbSJens Wiklander { 367817466cbSJens Wiklander if( ilen != block_size ) 368817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 369817466cbSJens Wiklander 370817466cbSJens Wiklander *olen = ilen; 371817466cbSJens Wiklander 372817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx, 373817466cbSJens Wiklander ctx->operation, input, output ) ) ) 374817466cbSJens Wiklander { 375817466cbSJens Wiklander return( ret ); 376817466cbSJens Wiklander } 377817466cbSJens Wiklander 378817466cbSJens Wiklander return( 0 ); 379817466cbSJens Wiklander } 380817466cbSJens Wiklander 381817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 382817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM ) 383817466cbSJens Wiklander { 384817466cbSJens Wiklander *olen = ilen; 385*3d3b0591SJens Wiklander return( mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input, 386*3d3b0591SJens Wiklander output ) ); 387*3d3b0591SJens Wiklander } 388*3d3b0591SJens Wiklander #endif 389*3d3b0591SJens Wiklander 390*3d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 391*3d3b0591SJens Wiklander if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) 392*3d3b0591SJens Wiklander { 393*3d3b0591SJens Wiklander *olen = ilen; 394*3d3b0591SJens Wiklander return( mbedtls_chachapoly_update( (mbedtls_chachapoly_context*) ctx->cipher_ctx, 395*3d3b0591SJens Wiklander ilen, input, output ) ); 396817466cbSJens Wiklander } 397817466cbSJens Wiklander #endif 398817466cbSJens Wiklander 399817466cbSJens Wiklander if ( 0 == block_size ) 400817466cbSJens Wiklander { 401*3d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_INVALID_CONTEXT ); 402817466cbSJens Wiklander } 403817466cbSJens Wiklander 404817466cbSJens Wiklander if( input == output && 405817466cbSJens Wiklander ( ctx->unprocessed_len != 0 || ilen % block_size ) ) 406817466cbSJens Wiklander { 407817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 408817466cbSJens Wiklander } 409817466cbSJens Wiklander 410817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CBC) 411817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC ) 412817466cbSJens Wiklander { 413817466cbSJens Wiklander size_t copy_len = 0; 414817466cbSJens Wiklander 415817466cbSJens Wiklander /* 416817466cbSJens Wiklander * If there is not enough data for a full block, cache it. 417817466cbSJens Wiklander */ 418*3d3b0591SJens Wiklander if( ( ctx->operation == MBEDTLS_DECRYPT && NULL != ctx->add_padding && 419817466cbSJens Wiklander ilen <= block_size - ctx->unprocessed_len ) || 420*3d3b0591SJens Wiklander ( ctx->operation == MBEDTLS_DECRYPT && NULL == ctx->add_padding && 421*3d3b0591SJens Wiklander ilen < block_size - ctx->unprocessed_len ) || 422817466cbSJens Wiklander ( ctx->operation == MBEDTLS_ENCRYPT && 423817466cbSJens Wiklander ilen < block_size - ctx->unprocessed_len ) ) 424817466cbSJens Wiklander { 425817466cbSJens Wiklander memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, 426817466cbSJens Wiklander ilen ); 427817466cbSJens Wiklander 428817466cbSJens Wiklander ctx->unprocessed_len += ilen; 429817466cbSJens Wiklander return( 0 ); 430817466cbSJens Wiklander } 431817466cbSJens Wiklander 432817466cbSJens Wiklander /* 433817466cbSJens Wiklander * Process cached data first 434817466cbSJens Wiklander */ 435817466cbSJens Wiklander if( 0 != ctx->unprocessed_len ) 436817466cbSJens Wiklander { 437817466cbSJens Wiklander copy_len = block_size - ctx->unprocessed_len; 438817466cbSJens Wiklander 439817466cbSJens Wiklander memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, 440817466cbSJens Wiklander copy_len ); 441817466cbSJens Wiklander 442817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, 443817466cbSJens Wiklander ctx->operation, block_size, ctx->iv, 444817466cbSJens Wiklander ctx->unprocessed_data, output ) ) ) 445817466cbSJens Wiklander { 446817466cbSJens Wiklander return( ret ); 447817466cbSJens Wiklander } 448817466cbSJens Wiklander 449817466cbSJens Wiklander *olen += block_size; 450817466cbSJens Wiklander output += block_size; 451817466cbSJens Wiklander ctx->unprocessed_len = 0; 452817466cbSJens Wiklander 453817466cbSJens Wiklander input += copy_len; 454817466cbSJens Wiklander ilen -= copy_len; 455817466cbSJens Wiklander } 456817466cbSJens Wiklander 457817466cbSJens Wiklander /* 458817466cbSJens Wiklander * Cache final, incomplete block 459817466cbSJens Wiklander */ 460817466cbSJens Wiklander if( 0 != ilen ) 461817466cbSJens Wiklander { 462817466cbSJens Wiklander if( 0 == block_size ) 463817466cbSJens Wiklander { 464*3d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_INVALID_CONTEXT ); 465817466cbSJens Wiklander } 466817466cbSJens Wiklander 467*3d3b0591SJens Wiklander /* Encryption: only cache partial blocks 468*3d3b0591SJens Wiklander * Decryption w/ padding: always keep at least one whole block 469*3d3b0591SJens Wiklander * Decryption w/o padding: only cache partial blocks 470*3d3b0591SJens Wiklander */ 471817466cbSJens Wiklander copy_len = ilen % block_size; 472*3d3b0591SJens Wiklander if( copy_len == 0 && 473*3d3b0591SJens Wiklander ctx->operation == MBEDTLS_DECRYPT && 474*3d3b0591SJens Wiklander NULL != ctx->add_padding) 475*3d3b0591SJens Wiklander { 476817466cbSJens Wiklander copy_len = block_size; 477*3d3b0591SJens Wiklander } 478817466cbSJens Wiklander 479817466cbSJens Wiklander memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ), 480817466cbSJens Wiklander copy_len ); 481817466cbSJens Wiklander 482817466cbSJens Wiklander ctx->unprocessed_len += copy_len; 483817466cbSJens Wiklander ilen -= copy_len; 484817466cbSJens Wiklander } 485817466cbSJens Wiklander 486817466cbSJens Wiklander /* 487817466cbSJens Wiklander * Process remaining full blocks 488817466cbSJens Wiklander */ 489817466cbSJens Wiklander if( ilen ) 490817466cbSJens Wiklander { 491817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, 492817466cbSJens Wiklander ctx->operation, ilen, ctx->iv, input, output ) ) ) 493817466cbSJens Wiklander { 494817466cbSJens Wiklander return( ret ); 495817466cbSJens Wiklander } 496817466cbSJens Wiklander 497817466cbSJens Wiklander *olen += ilen; 498817466cbSJens Wiklander } 499817466cbSJens Wiklander 500817466cbSJens Wiklander return( 0 ); 501817466cbSJens Wiklander } 502817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CBC */ 503817466cbSJens Wiklander 504817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CFB) 505817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB ) 506817466cbSJens Wiklander { 507817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx, 508817466cbSJens Wiklander ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv, 509817466cbSJens Wiklander input, output ) ) ) 510817466cbSJens Wiklander { 511817466cbSJens Wiklander return( ret ); 512817466cbSJens Wiklander } 513817466cbSJens Wiklander 514817466cbSJens Wiklander *olen = ilen; 515817466cbSJens Wiklander 516817466cbSJens Wiklander return( 0 ); 517817466cbSJens Wiklander } 518817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CFB */ 519817466cbSJens Wiklander 520*3d3b0591SJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_OFB) 521*3d3b0591SJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_OFB ) 522*3d3b0591SJens Wiklander { 523*3d3b0591SJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->ofb_func( ctx->cipher_ctx, 524*3d3b0591SJens Wiklander ilen, &ctx->unprocessed_len, ctx->iv, input, output ) ) ) 525*3d3b0591SJens Wiklander { 526*3d3b0591SJens Wiklander return( ret ); 527*3d3b0591SJens Wiklander } 528*3d3b0591SJens Wiklander 529*3d3b0591SJens Wiklander *olen = ilen; 530*3d3b0591SJens Wiklander 531*3d3b0591SJens Wiklander return( 0 ); 532*3d3b0591SJens Wiklander } 533*3d3b0591SJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_OFB */ 534*3d3b0591SJens Wiklander 535817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CTR) 536817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR ) 537817466cbSJens Wiklander { 538817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx, 539817466cbSJens Wiklander ilen, &ctx->unprocessed_len, ctx->iv, 540817466cbSJens Wiklander ctx->unprocessed_data, input, output ) ) ) 541817466cbSJens Wiklander { 542817466cbSJens Wiklander return( ret ); 543817466cbSJens Wiklander } 544817466cbSJens Wiklander 545817466cbSJens Wiklander *olen = ilen; 546817466cbSJens Wiklander 547817466cbSJens Wiklander return( 0 ); 548817466cbSJens Wiklander } 549817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CTR */ 550817466cbSJens Wiklander 551*3d3b0591SJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_XTS) 552*3d3b0591SJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_XTS ) 553*3d3b0591SJens Wiklander { 554*3d3b0591SJens Wiklander if( ctx->unprocessed_len > 0 ) { 555*3d3b0591SJens Wiklander /* We can only process an entire data unit at a time. */ 556*3d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 557*3d3b0591SJens Wiklander } 558*3d3b0591SJens Wiklander 559*3d3b0591SJens Wiklander ret = ctx->cipher_info->base->xts_func( ctx->cipher_ctx, 560*3d3b0591SJens Wiklander ctx->operation, ilen, ctx->iv, input, output ); 561*3d3b0591SJens Wiklander if( ret != 0 ) 562*3d3b0591SJens Wiklander { 563*3d3b0591SJens Wiklander return( ret ); 564*3d3b0591SJens Wiklander } 565*3d3b0591SJens Wiklander 566*3d3b0591SJens Wiklander *olen = ilen; 567*3d3b0591SJens Wiklander 568*3d3b0591SJens Wiklander return( 0 ); 569*3d3b0591SJens Wiklander } 570*3d3b0591SJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_XTS */ 571*3d3b0591SJens Wiklander 572817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_STREAM) 573817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM ) 574817466cbSJens Wiklander { 575817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx, 576817466cbSJens Wiklander ilen, input, output ) ) ) 577817466cbSJens Wiklander { 578817466cbSJens Wiklander return( ret ); 579817466cbSJens Wiklander } 580817466cbSJens Wiklander 581817466cbSJens Wiklander *olen = ilen; 582817466cbSJens Wiklander 583817466cbSJens Wiklander return( 0 ); 584817466cbSJens Wiklander } 585817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_STREAM */ 586817466cbSJens Wiklander 587817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 588817466cbSJens Wiklander } 589817466cbSJens Wiklander 590817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) 591817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7) 592817466cbSJens Wiklander /* 593817466cbSJens Wiklander * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len 594817466cbSJens Wiklander */ 595817466cbSJens Wiklander static void add_pkcs_padding( unsigned char *output, size_t output_len, 596817466cbSJens Wiklander size_t data_len ) 597817466cbSJens Wiklander { 598817466cbSJens Wiklander size_t padding_len = output_len - data_len; 599817466cbSJens Wiklander unsigned char i; 600817466cbSJens Wiklander 601817466cbSJens Wiklander for( i = 0; i < padding_len; i++ ) 602817466cbSJens Wiklander output[data_len + i] = (unsigned char) padding_len; 603817466cbSJens Wiklander } 604817466cbSJens Wiklander 605817466cbSJens Wiklander static int get_pkcs_padding( unsigned char *input, size_t input_len, 606817466cbSJens Wiklander size_t *data_len ) 607817466cbSJens Wiklander { 608817466cbSJens Wiklander size_t i, pad_idx; 609817466cbSJens Wiklander unsigned char padding_len, bad = 0; 610817466cbSJens Wiklander 611817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 612817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 613817466cbSJens Wiklander 614817466cbSJens Wiklander padding_len = input[input_len - 1]; 615817466cbSJens Wiklander *data_len = input_len - padding_len; 616817466cbSJens Wiklander 617817466cbSJens Wiklander /* Avoid logical || since it results in a branch */ 618817466cbSJens Wiklander bad |= padding_len > input_len; 619817466cbSJens Wiklander bad |= padding_len == 0; 620817466cbSJens Wiklander 621817466cbSJens Wiklander /* The number of bytes checked must be independent of padding_len, 622817466cbSJens Wiklander * so pick input_len, which is usually 8 or 16 (one block) */ 623817466cbSJens Wiklander pad_idx = input_len - padding_len; 624817466cbSJens Wiklander for( i = 0; i < input_len; i++ ) 625817466cbSJens Wiklander bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx ); 626817466cbSJens Wiklander 627817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); 628817466cbSJens Wiklander } 629817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ 630817466cbSJens Wiklander 631817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) 632817466cbSJens Wiklander /* 633817466cbSJens Wiklander * One and zeros padding: fill with 80 00 ... 00 634817466cbSJens Wiklander */ 635817466cbSJens Wiklander static void add_one_and_zeros_padding( unsigned char *output, 636817466cbSJens Wiklander size_t output_len, size_t data_len ) 637817466cbSJens Wiklander { 638817466cbSJens Wiklander size_t padding_len = output_len - data_len; 639817466cbSJens Wiklander unsigned char i = 0; 640817466cbSJens Wiklander 641817466cbSJens Wiklander output[data_len] = 0x80; 642817466cbSJens Wiklander for( i = 1; i < padding_len; i++ ) 643817466cbSJens Wiklander output[data_len + i] = 0x00; 644817466cbSJens Wiklander } 645817466cbSJens Wiklander 646817466cbSJens Wiklander static int get_one_and_zeros_padding( unsigned char *input, size_t input_len, 647817466cbSJens Wiklander size_t *data_len ) 648817466cbSJens Wiklander { 649817466cbSJens Wiklander size_t i; 650817466cbSJens Wiklander unsigned char done = 0, prev_done, bad; 651817466cbSJens Wiklander 652817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 653817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 654817466cbSJens Wiklander 655*3d3b0591SJens Wiklander bad = 0x80; 656817466cbSJens Wiklander *data_len = 0; 657817466cbSJens Wiklander for( i = input_len; i > 0; i-- ) 658817466cbSJens Wiklander { 659817466cbSJens Wiklander prev_done = done; 660817466cbSJens Wiklander done |= ( input[i - 1] != 0 ); 661817466cbSJens Wiklander *data_len |= ( i - 1 ) * ( done != prev_done ); 662*3d3b0591SJens Wiklander bad ^= input[i - 1] * ( done != prev_done ); 663817466cbSJens Wiklander } 664817466cbSJens Wiklander 665817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); 666817466cbSJens Wiklander 667817466cbSJens Wiklander } 668817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ 669817466cbSJens Wiklander 670817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) 671817466cbSJens Wiklander /* 672817466cbSJens Wiklander * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length 673817466cbSJens Wiklander */ 674817466cbSJens Wiklander static void add_zeros_and_len_padding( unsigned char *output, 675817466cbSJens Wiklander size_t output_len, size_t data_len ) 676817466cbSJens Wiklander { 677817466cbSJens Wiklander size_t padding_len = output_len - data_len; 678817466cbSJens Wiklander unsigned char i = 0; 679817466cbSJens Wiklander 680817466cbSJens Wiklander for( i = 1; i < padding_len; i++ ) 681817466cbSJens Wiklander output[data_len + i - 1] = 0x00; 682817466cbSJens Wiklander output[output_len - 1] = (unsigned char) padding_len; 683817466cbSJens Wiklander } 684817466cbSJens Wiklander 685817466cbSJens Wiklander static int get_zeros_and_len_padding( unsigned char *input, size_t input_len, 686817466cbSJens Wiklander size_t *data_len ) 687817466cbSJens Wiklander { 688817466cbSJens Wiklander size_t i, pad_idx; 689817466cbSJens Wiklander unsigned char padding_len, bad = 0; 690817466cbSJens Wiklander 691817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 692817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 693817466cbSJens Wiklander 694817466cbSJens Wiklander padding_len = input[input_len - 1]; 695817466cbSJens Wiklander *data_len = input_len - padding_len; 696817466cbSJens Wiklander 697817466cbSJens Wiklander /* Avoid logical || since it results in a branch */ 698817466cbSJens Wiklander bad |= padding_len > input_len; 699817466cbSJens Wiklander bad |= padding_len == 0; 700817466cbSJens Wiklander 701817466cbSJens Wiklander /* The number of bytes checked must be independent of padding_len */ 702817466cbSJens Wiklander pad_idx = input_len - padding_len; 703817466cbSJens Wiklander for( i = 0; i < input_len - 1; i++ ) 704817466cbSJens Wiklander bad |= input[i] * ( i >= pad_idx ); 705817466cbSJens Wiklander 706817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); 707817466cbSJens Wiklander } 708817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ 709817466cbSJens Wiklander 710817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS) 711817466cbSJens Wiklander /* 712817466cbSJens Wiklander * Zero padding: fill with 00 ... 00 713817466cbSJens Wiklander */ 714817466cbSJens Wiklander static void add_zeros_padding( unsigned char *output, 715817466cbSJens Wiklander size_t output_len, size_t data_len ) 716817466cbSJens Wiklander { 717817466cbSJens Wiklander size_t i; 718817466cbSJens Wiklander 719817466cbSJens Wiklander for( i = data_len; i < output_len; i++ ) 720817466cbSJens Wiklander output[i] = 0x00; 721817466cbSJens Wiklander } 722817466cbSJens Wiklander 723817466cbSJens Wiklander static int get_zeros_padding( unsigned char *input, size_t input_len, 724817466cbSJens Wiklander size_t *data_len ) 725817466cbSJens Wiklander { 726817466cbSJens Wiklander size_t i; 727817466cbSJens Wiklander unsigned char done = 0, prev_done; 728817466cbSJens Wiklander 729817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 730817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 731817466cbSJens Wiklander 732817466cbSJens Wiklander *data_len = 0; 733817466cbSJens Wiklander for( i = input_len; i > 0; i-- ) 734817466cbSJens Wiklander { 735817466cbSJens Wiklander prev_done = done; 736817466cbSJens Wiklander done |= ( input[i-1] != 0 ); 737817466cbSJens Wiklander *data_len |= i * ( done != prev_done ); 738817466cbSJens Wiklander } 739817466cbSJens Wiklander 740817466cbSJens Wiklander return( 0 ); 741817466cbSJens Wiklander } 742817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ 743817466cbSJens Wiklander 744817466cbSJens Wiklander /* 745817466cbSJens Wiklander * No padding: don't pad :) 746817466cbSJens Wiklander * 747817466cbSJens Wiklander * There is no add_padding function (check for NULL in mbedtls_cipher_finish) 748817466cbSJens Wiklander * but a trivial get_padding function 749817466cbSJens Wiklander */ 750817466cbSJens Wiklander static int get_no_padding( unsigned char *input, size_t input_len, 751817466cbSJens Wiklander size_t *data_len ) 752817466cbSJens Wiklander { 753817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 754817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 755817466cbSJens Wiklander 756817466cbSJens Wiklander *data_len = input_len; 757817466cbSJens Wiklander 758817466cbSJens Wiklander return( 0 ); 759817466cbSJens Wiklander } 760817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ 761817466cbSJens Wiklander 762817466cbSJens Wiklander int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, 763817466cbSJens Wiklander unsigned char *output, size_t *olen ) 764817466cbSJens Wiklander { 765*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 766*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( output != NULL ); 767*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( olen != NULL ); 768*3d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 769817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 770817466cbSJens Wiklander 771817466cbSJens Wiklander *olen = 0; 772817466cbSJens Wiklander 773817466cbSJens Wiklander if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode || 774*3d3b0591SJens Wiklander MBEDTLS_MODE_OFB == ctx->cipher_info->mode || 775817466cbSJens Wiklander MBEDTLS_MODE_CTR == ctx->cipher_info->mode || 776817466cbSJens Wiklander MBEDTLS_MODE_GCM == ctx->cipher_info->mode || 777*3d3b0591SJens Wiklander MBEDTLS_MODE_XTS == ctx->cipher_info->mode || 778817466cbSJens Wiklander MBEDTLS_MODE_STREAM == ctx->cipher_info->mode ) 779817466cbSJens Wiklander { 780817466cbSJens Wiklander return( 0 ); 781817466cbSJens Wiklander } 782817466cbSJens Wiklander 783*3d3b0591SJens Wiklander if ( ( MBEDTLS_CIPHER_CHACHA20 == ctx->cipher_info->type ) || 784*3d3b0591SJens Wiklander ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) ) 785*3d3b0591SJens Wiklander { 786*3d3b0591SJens Wiklander return( 0 ); 787*3d3b0591SJens Wiklander } 788*3d3b0591SJens Wiklander 789817466cbSJens Wiklander if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode ) 790817466cbSJens Wiklander { 791817466cbSJens Wiklander if( ctx->unprocessed_len != 0 ) 792817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 793817466cbSJens Wiklander 794817466cbSJens Wiklander return( 0 ); 795817466cbSJens Wiklander } 796817466cbSJens Wiklander 797817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CBC) 798817466cbSJens Wiklander if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode ) 799817466cbSJens Wiklander { 800817466cbSJens Wiklander int ret = 0; 801817466cbSJens Wiklander 802817466cbSJens Wiklander if( MBEDTLS_ENCRYPT == ctx->operation ) 803817466cbSJens Wiklander { 804817466cbSJens Wiklander /* check for 'no padding' mode */ 805817466cbSJens Wiklander if( NULL == ctx->add_padding ) 806817466cbSJens Wiklander { 807817466cbSJens Wiklander if( 0 != ctx->unprocessed_len ) 808817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 809817466cbSJens Wiklander 810817466cbSJens Wiklander return( 0 ); 811817466cbSJens Wiklander } 812817466cbSJens Wiklander 813817466cbSJens Wiklander ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ), 814817466cbSJens Wiklander ctx->unprocessed_len ); 815817466cbSJens Wiklander } 816817466cbSJens Wiklander else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len ) 817817466cbSJens Wiklander { 818817466cbSJens Wiklander /* 819817466cbSJens Wiklander * For decrypt operations, expect a full block, 820817466cbSJens Wiklander * or an empty block if no padding 821817466cbSJens Wiklander */ 822817466cbSJens Wiklander if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len ) 823817466cbSJens Wiklander return( 0 ); 824817466cbSJens Wiklander 825817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 826817466cbSJens Wiklander } 827817466cbSJens Wiklander 828817466cbSJens Wiklander /* cipher block */ 829817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, 830817466cbSJens Wiklander ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv, 831817466cbSJens Wiklander ctx->unprocessed_data, output ) ) ) 832817466cbSJens Wiklander { 833817466cbSJens Wiklander return( ret ); 834817466cbSJens Wiklander } 835817466cbSJens Wiklander 836817466cbSJens Wiklander /* Set output size for decryption */ 837817466cbSJens Wiklander if( MBEDTLS_DECRYPT == ctx->operation ) 838*3d3b0591SJens Wiklander return( ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ), 839*3d3b0591SJens Wiklander olen ) ); 840817466cbSJens Wiklander 841817466cbSJens Wiklander /* Set output size for encryption */ 842817466cbSJens Wiklander *olen = mbedtls_cipher_get_block_size( ctx ); 843817466cbSJens Wiklander return( 0 ); 844817466cbSJens Wiklander } 845817466cbSJens Wiklander #else 846817466cbSJens Wiklander ((void) output); 847817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CBC */ 848817466cbSJens Wiklander 849817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 850817466cbSJens Wiklander } 851817466cbSJens Wiklander 852817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) 853*3d3b0591SJens Wiklander int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, 854*3d3b0591SJens Wiklander mbedtls_cipher_padding_t mode ) 855817466cbSJens Wiklander { 856*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 857*3d3b0591SJens Wiklander 858*3d3b0591SJens Wiklander if( NULL == ctx->cipher_info || MBEDTLS_MODE_CBC != ctx->cipher_info->mode ) 859817466cbSJens Wiklander { 860817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 861817466cbSJens Wiklander } 862817466cbSJens Wiklander 863817466cbSJens Wiklander switch( mode ) 864817466cbSJens Wiklander { 865817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7) 866817466cbSJens Wiklander case MBEDTLS_PADDING_PKCS7: 867817466cbSJens Wiklander ctx->add_padding = add_pkcs_padding; 868817466cbSJens Wiklander ctx->get_padding = get_pkcs_padding; 869817466cbSJens Wiklander break; 870817466cbSJens Wiklander #endif 871817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) 872817466cbSJens Wiklander case MBEDTLS_PADDING_ONE_AND_ZEROS: 873817466cbSJens Wiklander ctx->add_padding = add_one_and_zeros_padding; 874817466cbSJens Wiklander ctx->get_padding = get_one_and_zeros_padding; 875817466cbSJens Wiklander break; 876817466cbSJens Wiklander #endif 877817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) 878817466cbSJens Wiklander case MBEDTLS_PADDING_ZEROS_AND_LEN: 879817466cbSJens Wiklander ctx->add_padding = add_zeros_and_len_padding; 880817466cbSJens Wiklander ctx->get_padding = get_zeros_and_len_padding; 881817466cbSJens Wiklander break; 882817466cbSJens Wiklander #endif 883817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS) 884817466cbSJens Wiklander case MBEDTLS_PADDING_ZEROS: 885817466cbSJens Wiklander ctx->add_padding = add_zeros_padding; 886817466cbSJens Wiklander ctx->get_padding = get_zeros_padding; 887817466cbSJens Wiklander break; 888817466cbSJens Wiklander #endif 889817466cbSJens Wiklander case MBEDTLS_PADDING_NONE: 890817466cbSJens Wiklander ctx->add_padding = NULL; 891817466cbSJens Wiklander ctx->get_padding = get_no_padding; 892817466cbSJens Wiklander break; 893817466cbSJens Wiklander 894817466cbSJens Wiklander default: 895817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 896817466cbSJens Wiklander } 897817466cbSJens Wiklander 898817466cbSJens Wiklander return( 0 ); 899817466cbSJens Wiklander } 900817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ 901817466cbSJens Wiklander 902*3d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) 903817466cbSJens Wiklander int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, 904817466cbSJens Wiklander unsigned char *tag, size_t tag_len ) 905817466cbSJens Wiklander { 906*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 907*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); 908*3d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 909817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 910817466cbSJens Wiklander 911817466cbSJens Wiklander if( MBEDTLS_ENCRYPT != ctx->operation ) 912817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 913817466cbSJens Wiklander 914*3d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) 915817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 916*3d3b0591SJens Wiklander return( mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, 917*3d3b0591SJens Wiklander tag, tag_len ) ); 918*3d3b0591SJens Wiklander #endif 919*3d3b0591SJens Wiklander 920*3d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 921*3d3b0591SJens Wiklander if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) 922*3d3b0591SJens Wiklander { 923*3d3b0591SJens Wiklander /* Don't allow truncated MAC for Poly1305 */ 924*3d3b0591SJens Wiklander if ( tag_len != 16U ) 925*3d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 926*3d3b0591SJens Wiklander 927*3d3b0591SJens Wiklander return( mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx, 928*3d3b0591SJens Wiklander tag ) ); 929*3d3b0591SJens Wiklander } 930*3d3b0591SJens Wiklander #endif 931817466cbSJens Wiklander 932817466cbSJens Wiklander return( 0 ); 933817466cbSJens Wiklander } 934817466cbSJens Wiklander 935817466cbSJens Wiklander int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, 936817466cbSJens Wiklander const unsigned char *tag, size_t tag_len ) 937817466cbSJens Wiklander { 938*3d3b0591SJens Wiklander unsigned char check_tag[16]; 939817466cbSJens Wiklander int ret; 940817466cbSJens Wiklander 941*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 942*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); 943*3d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 944*3d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 945*3d3b0591SJens Wiklander 946*3d3b0591SJens Wiklander if( MBEDTLS_DECRYPT != ctx->operation ) 947817466cbSJens Wiklander { 948817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 949817466cbSJens Wiklander } 950817466cbSJens Wiklander 951*3d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) 952817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 953817466cbSJens Wiklander { 954817466cbSJens Wiklander if( tag_len > sizeof( check_tag ) ) 955817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 956817466cbSJens Wiklander 957817466cbSJens Wiklander if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, 958817466cbSJens Wiklander check_tag, tag_len ) ) ) 959817466cbSJens Wiklander { 960817466cbSJens Wiklander return( ret ); 961817466cbSJens Wiklander } 962817466cbSJens Wiklander 963817466cbSJens Wiklander /* Check the tag in "constant-time" */ 964*3d3b0591SJens Wiklander if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) 965817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); 966817466cbSJens Wiklander 967817466cbSJens Wiklander return( 0 ); 968817466cbSJens Wiklander } 969*3d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C */ 970*3d3b0591SJens Wiklander 971*3d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 972*3d3b0591SJens Wiklander if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) 973*3d3b0591SJens Wiklander { 974*3d3b0591SJens Wiklander /* Don't allow truncated MAC for Poly1305 */ 975*3d3b0591SJens Wiklander if ( tag_len != sizeof( check_tag ) ) 976*3d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 977*3d3b0591SJens Wiklander 978*3d3b0591SJens Wiklander ret = mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx, 979*3d3b0591SJens Wiklander check_tag ); 980*3d3b0591SJens Wiklander if ( ret != 0 ) 981*3d3b0591SJens Wiklander { 982*3d3b0591SJens Wiklander return( ret ); 983*3d3b0591SJens Wiklander } 984*3d3b0591SJens Wiklander 985*3d3b0591SJens Wiklander /* Check the tag in "constant-time" */ 986*3d3b0591SJens Wiklander if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) 987*3d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); 988817466cbSJens Wiklander 989817466cbSJens Wiklander return( 0 ); 990817466cbSJens Wiklander } 991*3d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */ 992*3d3b0591SJens Wiklander 993*3d3b0591SJens Wiklander return( 0 ); 994*3d3b0591SJens Wiklander } 995*3d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ 996817466cbSJens Wiklander 997817466cbSJens Wiklander /* 998817466cbSJens Wiklander * Packet-oriented wrapper for non-AEAD modes 999817466cbSJens Wiklander */ 1000817466cbSJens Wiklander int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, 1001817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 1002817466cbSJens Wiklander const unsigned char *input, size_t ilen, 1003817466cbSJens Wiklander unsigned char *output, size_t *olen ) 1004817466cbSJens Wiklander { 1005817466cbSJens Wiklander int ret; 1006817466cbSJens Wiklander size_t finish_olen; 1007817466cbSJens Wiklander 1008*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 1009*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL ); 1010*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); 1011*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( output != NULL ); 1012*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( olen != NULL ); 1013*3d3b0591SJens Wiklander 1014817466cbSJens Wiklander if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 ) 1015817466cbSJens Wiklander return( ret ); 1016817466cbSJens Wiklander 1017817466cbSJens Wiklander if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 ) 1018817466cbSJens Wiklander return( ret ); 1019817466cbSJens Wiklander 1020817466cbSJens Wiklander if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 ) 1021817466cbSJens Wiklander return( ret ); 1022817466cbSJens Wiklander 1023817466cbSJens Wiklander if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 ) 1024817466cbSJens Wiklander return( ret ); 1025817466cbSJens Wiklander 1026817466cbSJens Wiklander *olen += finish_olen; 1027817466cbSJens Wiklander 1028817466cbSJens Wiklander return( 0 ); 1029817466cbSJens Wiklander } 1030817466cbSJens Wiklander 1031817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_AEAD) 1032817466cbSJens Wiklander /* 1033817466cbSJens Wiklander * Packet-oriented encryption for AEAD modes 1034817466cbSJens Wiklander */ 1035817466cbSJens Wiklander int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, 1036817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 1037817466cbSJens Wiklander const unsigned char *ad, size_t ad_len, 1038817466cbSJens Wiklander const unsigned char *input, size_t ilen, 1039817466cbSJens Wiklander unsigned char *output, size_t *olen, 1040817466cbSJens Wiklander unsigned char *tag, size_t tag_len ) 1041817466cbSJens Wiklander { 1042*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 1043*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( iv != NULL ); 1044*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); 1045*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); 1046*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( output != NULL ); 1047*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( olen != NULL ); 1048*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); 1049*3d3b0591SJens Wiklander 1050817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 1051817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 1052817466cbSJens Wiklander { 1053817466cbSJens Wiklander *olen = ilen; 1054817466cbSJens Wiklander return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen, 1055817466cbSJens Wiklander iv, iv_len, ad, ad_len, input, output, 1056817466cbSJens Wiklander tag_len, tag ) ); 1057817466cbSJens Wiklander } 1058817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */ 1059817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C) 1060817466cbSJens Wiklander if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) 1061817466cbSJens Wiklander { 1062817466cbSJens Wiklander *olen = ilen; 1063817466cbSJens Wiklander return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen, 1064817466cbSJens Wiklander iv, iv_len, ad, ad_len, input, output, 1065817466cbSJens Wiklander tag, tag_len ) ); 1066817466cbSJens Wiklander } 1067817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */ 1068*3d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 1069*3d3b0591SJens Wiklander if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) 1070*3d3b0591SJens Wiklander { 1071*3d3b0591SJens Wiklander /* ChachaPoly has fixed length nonce and MAC (tag) */ 1072*3d3b0591SJens Wiklander if ( ( iv_len != ctx->cipher_info->iv_size ) || 1073*3d3b0591SJens Wiklander ( tag_len != 16U ) ) 1074*3d3b0591SJens Wiklander { 1075*3d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 1076*3d3b0591SJens Wiklander } 1077*3d3b0591SJens Wiklander 1078*3d3b0591SJens Wiklander *olen = ilen; 1079*3d3b0591SJens Wiklander return( mbedtls_chachapoly_encrypt_and_tag( ctx->cipher_ctx, 1080*3d3b0591SJens Wiklander ilen, iv, ad, ad_len, input, output, tag ) ); 1081*3d3b0591SJens Wiklander } 1082*3d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */ 1083817466cbSJens Wiklander 1084817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 1085817466cbSJens Wiklander } 1086817466cbSJens Wiklander 1087817466cbSJens Wiklander /* 1088817466cbSJens Wiklander * Packet-oriented decryption for AEAD modes 1089817466cbSJens Wiklander */ 1090817466cbSJens Wiklander int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, 1091817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 1092817466cbSJens Wiklander const unsigned char *ad, size_t ad_len, 1093817466cbSJens Wiklander const unsigned char *input, size_t ilen, 1094817466cbSJens Wiklander unsigned char *output, size_t *olen, 1095817466cbSJens Wiklander const unsigned char *tag, size_t tag_len ) 1096817466cbSJens Wiklander { 1097*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 1098*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( iv != NULL ); 1099*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); 1100*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); 1101*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( output != NULL ); 1102*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( olen != NULL ); 1103*3d3b0591SJens Wiklander CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); 1104*3d3b0591SJens Wiklander 1105817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 1106817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 1107817466cbSJens Wiklander { 1108817466cbSJens Wiklander int ret; 1109817466cbSJens Wiklander 1110817466cbSJens Wiklander *olen = ilen; 1111817466cbSJens Wiklander ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen, 1112817466cbSJens Wiklander iv, iv_len, ad, ad_len, 1113817466cbSJens Wiklander tag, tag_len, input, output ); 1114817466cbSJens Wiklander 1115817466cbSJens Wiklander if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED ) 1116817466cbSJens Wiklander ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; 1117817466cbSJens Wiklander 1118817466cbSJens Wiklander return( ret ); 1119817466cbSJens Wiklander } 1120817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */ 1121817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C) 1122817466cbSJens Wiklander if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) 1123817466cbSJens Wiklander { 1124817466cbSJens Wiklander int ret; 1125817466cbSJens Wiklander 1126817466cbSJens Wiklander *olen = ilen; 1127817466cbSJens Wiklander ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen, 1128817466cbSJens Wiklander iv, iv_len, ad, ad_len, 1129817466cbSJens Wiklander input, output, tag, tag_len ); 1130817466cbSJens Wiklander 1131817466cbSJens Wiklander if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED ) 1132817466cbSJens Wiklander ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; 1133817466cbSJens Wiklander 1134817466cbSJens Wiklander return( ret ); 1135817466cbSJens Wiklander } 1136817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */ 1137*3d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 1138*3d3b0591SJens Wiklander if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) 1139*3d3b0591SJens Wiklander { 1140*3d3b0591SJens Wiklander int ret; 1141*3d3b0591SJens Wiklander 1142*3d3b0591SJens Wiklander /* ChachaPoly has fixed length nonce and MAC (tag) */ 1143*3d3b0591SJens Wiklander if ( ( iv_len != ctx->cipher_info->iv_size ) || 1144*3d3b0591SJens Wiklander ( tag_len != 16U ) ) 1145*3d3b0591SJens Wiklander { 1146*3d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 1147*3d3b0591SJens Wiklander } 1148*3d3b0591SJens Wiklander 1149*3d3b0591SJens Wiklander *olen = ilen; 1150*3d3b0591SJens Wiklander ret = mbedtls_chachapoly_auth_decrypt( ctx->cipher_ctx, ilen, 1151*3d3b0591SJens Wiklander iv, ad, ad_len, tag, input, output ); 1152*3d3b0591SJens Wiklander 1153*3d3b0591SJens Wiklander if( ret == MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED ) 1154*3d3b0591SJens Wiklander ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; 1155*3d3b0591SJens Wiklander 1156*3d3b0591SJens Wiklander return( ret ); 1157*3d3b0591SJens Wiklander } 1158*3d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */ 1159817466cbSJens Wiklander 1160817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 1161817466cbSJens Wiklander } 1162817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_AEAD */ 1163817466cbSJens Wiklander 1164817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_C */ 1165