1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /** 3817466cbSJens Wiklander * \file cipher.c 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * \brief Generic cipher wrapper for mbed TLS 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * \author Adriaan de Jong <dejong@fox-it.com> 8817466cbSJens Wiklander * 9817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 12817466cbSJens Wiklander * not use this file except in compliance with the License. 13817466cbSJens Wiklander * You may obtain a copy of the License at 14817466cbSJens Wiklander * 15817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 16817466cbSJens Wiklander * 17817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 18817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 19817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20817466cbSJens Wiklander * See the License for the specific language governing permissions and 21817466cbSJens Wiklander * limitations under the License. 22817466cbSJens Wiklander * 23817466cbSJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 24817466cbSJens Wiklander */ 25817466cbSJens Wiklander 26817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 27817466cbSJens Wiklander #include "mbedtls/config.h" 28817466cbSJens Wiklander #else 29817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 30817466cbSJens Wiklander #endif 31817466cbSJens Wiklander 32817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_C) 33817466cbSJens Wiklander 34817466cbSJens Wiklander #include "mbedtls/cipher.h" 35817466cbSJens Wiklander #include "mbedtls/cipher_internal.h" 363d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 37817466cbSJens Wiklander 38817466cbSJens Wiklander #include <stdlib.h> 39817466cbSJens Wiklander #include <string.h> 40817466cbSJens Wiklander 413d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 423d3b0591SJens Wiklander #include "mbedtls/chachapoly.h" 433d3b0591SJens Wiklander #endif 443d3b0591SJens Wiklander 45817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 46817466cbSJens Wiklander #include "mbedtls/gcm.h" 47817466cbSJens Wiklander #endif 48817466cbSJens Wiklander 49817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C) 50817466cbSJens Wiklander #include "mbedtls/ccm.h" 51817466cbSJens Wiklander #endif 52817466cbSJens Wiklander 533d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHA20_C) 543d3b0591SJens Wiklander #include "mbedtls/chacha20.h" 553d3b0591SJens Wiklander #endif 563d3b0591SJens Wiklander 57817466cbSJens Wiklander #if defined(MBEDTLS_CMAC_C) 58817466cbSJens Wiklander #include "mbedtls/cmac.h" 59817466cbSJens Wiklander #endif 60817466cbSJens Wiklander 61817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 62817466cbSJens Wiklander #include "mbedtls/platform.h" 63817466cbSJens Wiklander #else 64817466cbSJens Wiklander #define mbedtls_calloc calloc 65817466cbSJens Wiklander #define mbedtls_free free 66817466cbSJens Wiklander #endif 67817466cbSJens Wiklander 683d3b0591SJens Wiklander #define CIPHER_VALIDATE_RET( cond ) \ 693d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ) 703d3b0591SJens Wiklander #define CIPHER_VALIDATE( cond ) \ 713d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE( cond ) 72817466cbSJens Wiklander 733d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) 743d3b0591SJens Wiklander /* Compare the contents of two buffers in constant time. 753d3b0591SJens Wiklander * Returns 0 if the contents are bitwise identical, otherwise returns 763d3b0591SJens Wiklander * a non-zero value. 773d3b0591SJens Wiklander * This is currently only used by GCM and ChaCha20+Poly1305. 783d3b0591SJens Wiklander */ 793d3b0591SJens Wiklander static int mbedtls_constant_time_memcmp( const void *v1, const void *v2, size_t len ) 803d3b0591SJens Wiklander { 813d3b0591SJens Wiklander const unsigned char *p1 = (const unsigned char*) v1; 823d3b0591SJens Wiklander const unsigned char *p2 = (const unsigned char*) v2; 833d3b0591SJens Wiklander size_t i; 843d3b0591SJens Wiklander unsigned char diff; 853d3b0591SJens Wiklander 863d3b0591SJens Wiklander for( diff = 0, i = 0; i < len; i++ ) 873d3b0591SJens Wiklander diff |= p1[i] ^ p2[i]; 883d3b0591SJens Wiklander 893d3b0591SJens Wiklander return( (int)diff ); 90817466cbSJens Wiklander } 913d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ 92817466cbSJens Wiklander 93817466cbSJens Wiklander static int supported_init = 0; 94817466cbSJens Wiklander 95817466cbSJens Wiklander const int *mbedtls_cipher_list( void ) 96817466cbSJens Wiklander { 97817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 98817466cbSJens Wiklander int *type; 99817466cbSJens Wiklander 100817466cbSJens Wiklander if( ! supported_init ) 101817466cbSJens Wiklander { 102817466cbSJens Wiklander def = mbedtls_cipher_definitions; 103817466cbSJens Wiklander type = mbedtls_cipher_supported; 104817466cbSJens Wiklander 105817466cbSJens Wiklander while( def->type != 0 ) 106817466cbSJens Wiklander *type++ = (*def++).type; 107817466cbSJens Wiklander 108817466cbSJens Wiklander *type = 0; 109817466cbSJens Wiklander 110817466cbSJens Wiklander supported_init = 1; 111817466cbSJens Wiklander } 112817466cbSJens Wiklander 113817466cbSJens Wiklander return( mbedtls_cipher_supported ); 114817466cbSJens Wiklander } 115817466cbSJens Wiklander 116817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ) 117817466cbSJens Wiklander { 118817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 119817466cbSJens Wiklander 120817466cbSJens Wiklander for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) 121817466cbSJens Wiklander if( def->type == cipher_type ) 122817466cbSJens Wiklander return( def->info ); 123817466cbSJens Wiklander 124817466cbSJens Wiklander return( NULL ); 125817466cbSJens Wiklander } 126817466cbSJens Wiklander 127817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ) 128817466cbSJens Wiklander { 129817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 130817466cbSJens Wiklander 131817466cbSJens Wiklander if( NULL == cipher_name ) 132817466cbSJens Wiklander return( NULL ); 133817466cbSJens Wiklander 134817466cbSJens Wiklander for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) 135817466cbSJens Wiklander if( ! strcmp( def->info->name, cipher_name ) ) 136817466cbSJens Wiklander return( def->info ); 137817466cbSJens Wiklander 138817466cbSJens Wiklander return( NULL ); 139817466cbSJens Wiklander } 140817466cbSJens Wiklander 141817466cbSJens Wiklander const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id, 142817466cbSJens Wiklander int key_bitlen, 143817466cbSJens Wiklander const mbedtls_cipher_mode_t mode ) 144817466cbSJens Wiklander { 145817466cbSJens Wiklander const mbedtls_cipher_definition_t *def; 146817466cbSJens Wiklander 147817466cbSJens Wiklander for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) 148817466cbSJens Wiklander if( def->info->base->cipher == cipher_id && 149817466cbSJens Wiklander def->info->key_bitlen == (unsigned) key_bitlen && 150817466cbSJens Wiklander def->info->mode == mode ) 151817466cbSJens Wiklander return( def->info ); 152817466cbSJens Wiklander 153817466cbSJens Wiklander return( NULL ); 154817466cbSJens Wiklander } 155817466cbSJens Wiklander 156817466cbSJens Wiklander void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ) 157817466cbSJens Wiklander { 1583d3b0591SJens Wiklander CIPHER_VALIDATE( ctx != NULL ); 159817466cbSJens Wiklander memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); 160817466cbSJens Wiklander } 161817466cbSJens Wiklander 162817466cbSJens Wiklander void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ) 163817466cbSJens Wiklander { 164817466cbSJens Wiklander if( ctx == NULL ) 165817466cbSJens Wiklander return; 166817466cbSJens Wiklander 167817466cbSJens Wiklander #if defined(MBEDTLS_CMAC_C) 168817466cbSJens Wiklander if( ctx->cmac_ctx ) 169817466cbSJens Wiklander { 1703d3b0591SJens Wiklander mbedtls_platform_zeroize( ctx->cmac_ctx, 1713d3b0591SJens Wiklander sizeof( mbedtls_cmac_context_t ) ); 172817466cbSJens Wiklander mbedtls_free( ctx->cmac_ctx ); 173817466cbSJens Wiklander } 174817466cbSJens Wiklander #endif 175817466cbSJens Wiklander 176817466cbSJens Wiklander if( ctx->cipher_ctx ) 177817466cbSJens Wiklander ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx ); 178817466cbSJens Wiklander 1793d3b0591SJens Wiklander mbedtls_platform_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); 180817466cbSJens Wiklander } 181817466cbSJens Wiklander 18212484fc7SEdison Ai int mbedtls_cipher_clone( mbedtls_cipher_context_t *dst, 18312484fc7SEdison Ai const mbedtls_cipher_context_t *src ) 18412484fc7SEdison Ai { 18512484fc7SEdison Ai if( dst == NULL || dst->cipher_info == NULL || 18612484fc7SEdison Ai src == NULL || src->cipher_info == NULL) 18712484fc7SEdison Ai { 18812484fc7SEdison Ai return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 18912484fc7SEdison Ai } 19012484fc7SEdison Ai 19112484fc7SEdison Ai dst->cipher_info = src->cipher_info; 19212484fc7SEdison Ai dst->key_bitlen = src->key_bitlen; 19312484fc7SEdison Ai dst->operation = src->operation; 19412484fc7SEdison Ai #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) 19512484fc7SEdison Ai dst->add_padding = src->add_padding; 19612484fc7SEdison Ai dst->get_padding = src->get_padding; 19712484fc7SEdison Ai #endif 19812484fc7SEdison Ai memcpy( dst->unprocessed_data, src->unprocessed_data, MBEDTLS_MAX_BLOCK_LENGTH ); 19912484fc7SEdison Ai dst->unprocessed_len = src->unprocessed_len; 20012484fc7SEdison Ai memcpy( dst->iv, src->iv, MBEDTLS_MAX_IV_LENGTH ); 20112484fc7SEdison Ai dst->iv_size = src->iv_size; 20212484fc7SEdison Ai if( dst->cipher_info->base->ctx_clone_func ) 20312484fc7SEdison Ai dst->cipher_info->base->ctx_clone_func( dst->cipher_ctx, src->cipher_ctx ); 20412484fc7SEdison Ai 20512484fc7SEdison Ai #if defined(MBEDTLS_CMAC_C) 20612484fc7SEdison Ai if( dst->cmac_ctx != NULL && src->cmac_ctx != NULL ) 20712484fc7SEdison Ai memcpy( dst->cmac_ctx, src->cmac_ctx, sizeof( mbedtls_cmac_context_t ) ); 20812484fc7SEdison Ai #endif 20912484fc7SEdison Ai return( 0 ); 21012484fc7SEdison Ai } 21112484fc7SEdison Ai 212817466cbSJens Wiklander int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ) 213817466cbSJens Wiklander { 2143d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 2153d3b0591SJens Wiklander if( cipher_info == NULL ) 216817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 217817466cbSJens Wiklander 218817466cbSJens Wiklander memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); 219817466cbSJens Wiklander 220817466cbSJens Wiklander if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) ) 221817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED ); 222817466cbSJens Wiklander 223817466cbSJens Wiklander ctx->cipher_info = cipher_info; 224817466cbSJens Wiklander 225817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) 226817466cbSJens Wiklander /* 227817466cbSJens Wiklander * Ignore possible errors caused by a cipher mode that doesn't use padding 228817466cbSJens Wiklander */ 229817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7) 230817466cbSJens Wiklander (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 ); 231817466cbSJens Wiklander #else 232817466cbSJens Wiklander (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE ); 233817466cbSJens Wiklander #endif 234817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ 235817466cbSJens Wiklander 236817466cbSJens Wiklander return( 0 ); 237817466cbSJens Wiklander } 238817466cbSJens Wiklander 23912484fc7SEdison Ai int mbedtls_cipher_setup_info( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ) 24012484fc7SEdison Ai { 24112484fc7SEdison Ai if( NULL == cipher_info || NULL == ctx ) 24212484fc7SEdison Ai return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 24312484fc7SEdison Ai 24412484fc7SEdison Ai ctx->cipher_info = cipher_info; 24512484fc7SEdison Ai return( 0 ); 24612484fc7SEdison Ai } 24712484fc7SEdison Ai 2483d3b0591SJens Wiklander int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, 2493d3b0591SJens Wiklander const unsigned char *key, 2503d3b0591SJens Wiklander int key_bitlen, 2513d3b0591SJens Wiklander const mbedtls_operation_t operation ) 252817466cbSJens Wiklander { 2533d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 2543d3b0591SJens Wiklander CIPHER_VALIDATE_RET( key != NULL ); 2553d3b0591SJens Wiklander CIPHER_VALIDATE_RET( operation == MBEDTLS_ENCRYPT || 2563d3b0591SJens Wiklander operation == MBEDTLS_DECRYPT ); 2573d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 258817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 259817466cbSJens Wiklander 260817466cbSJens Wiklander if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 && 261817466cbSJens Wiklander (int) ctx->cipher_info->key_bitlen != key_bitlen ) 262817466cbSJens Wiklander { 263817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 264817466cbSJens Wiklander } 265817466cbSJens Wiklander 266817466cbSJens Wiklander ctx->key_bitlen = key_bitlen; 267817466cbSJens Wiklander ctx->operation = operation; 268817466cbSJens Wiklander 269817466cbSJens Wiklander /* 2703d3b0591SJens Wiklander * For OFB, CFB and CTR mode always use the encryption key schedule 271817466cbSJens Wiklander */ 272817466cbSJens Wiklander if( MBEDTLS_ENCRYPT == operation || 273817466cbSJens Wiklander MBEDTLS_MODE_CFB == ctx->cipher_info->mode || 2743d3b0591SJens Wiklander MBEDTLS_MODE_OFB == ctx->cipher_info->mode || 275817466cbSJens Wiklander MBEDTLS_MODE_CTR == ctx->cipher_info->mode ) 276817466cbSJens Wiklander { 2773d3b0591SJens Wiklander return( ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key, 2783d3b0591SJens Wiklander ctx->key_bitlen ) ); 279817466cbSJens Wiklander } 280817466cbSJens Wiklander 281817466cbSJens Wiklander if( MBEDTLS_DECRYPT == operation ) 2823d3b0591SJens Wiklander return( ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key, 2833d3b0591SJens Wiklander ctx->key_bitlen ) ); 284817466cbSJens Wiklander 285817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 286817466cbSJens Wiklander } 287817466cbSJens Wiklander 288817466cbSJens Wiklander int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, 2893d3b0591SJens Wiklander const unsigned char *iv, 2903d3b0591SJens Wiklander size_t iv_len ) 291817466cbSJens Wiklander { 292817466cbSJens Wiklander size_t actual_iv_size; 293817466cbSJens Wiklander 2943d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 2953d3b0591SJens Wiklander CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL ); 2963d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 297817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 298817466cbSJens Wiklander 299817466cbSJens Wiklander /* avoid buffer overflow in ctx->iv */ 300817466cbSJens Wiklander if( iv_len > MBEDTLS_MAX_IV_LENGTH ) 301817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 302817466cbSJens Wiklander 303817466cbSJens Wiklander if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 ) 304817466cbSJens Wiklander actual_iv_size = iv_len; 305817466cbSJens Wiklander else 306817466cbSJens Wiklander { 307817466cbSJens Wiklander actual_iv_size = ctx->cipher_info->iv_size; 308817466cbSJens Wiklander 309817466cbSJens Wiklander /* avoid reading past the end of input buffer */ 310817466cbSJens Wiklander if( actual_iv_size > iv_len ) 311817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 312817466cbSJens Wiklander } 313817466cbSJens Wiklander 3143d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHA20_C) 3153d3b0591SJens Wiklander if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20 ) 3163d3b0591SJens Wiklander { 3173d3b0591SJens Wiklander if ( 0 != mbedtls_chacha20_starts( (mbedtls_chacha20_context*)ctx->cipher_ctx, 3183d3b0591SJens Wiklander iv, 3193d3b0591SJens Wiklander 0U ) ) /* Initial counter value */ 3203d3b0591SJens Wiklander { 3213d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 3223d3b0591SJens Wiklander } 3233d3b0591SJens Wiklander } 3243d3b0591SJens Wiklander #endif 3253d3b0591SJens Wiklander 3263d3b0591SJens Wiklander if ( actual_iv_size != 0 ) 3273d3b0591SJens Wiklander { 328817466cbSJens Wiklander memcpy( ctx->iv, iv, actual_iv_size ); 329817466cbSJens Wiklander ctx->iv_size = actual_iv_size; 3303d3b0591SJens Wiklander } 331817466cbSJens Wiklander 332817466cbSJens Wiklander return( 0 ); 333817466cbSJens Wiklander } 334817466cbSJens Wiklander 335817466cbSJens Wiklander int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ) 336817466cbSJens Wiklander { 3373d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 3383d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 339817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 340817466cbSJens Wiklander 341817466cbSJens Wiklander ctx->unprocessed_len = 0; 342817466cbSJens Wiklander 343817466cbSJens Wiklander return( 0 ); 344817466cbSJens Wiklander } 345817466cbSJens Wiklander 3463d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) 347817466cbSJens Wiklander int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, 348817466cbSJens Wiklander const unsigned char *ad, size_t ad_len ) 349817466cbSJens Wiklander { 3503d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 3513d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); 3523d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 353817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 354817466cbSJens Wiklander 3553d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) 356817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 357817466cbSJens Wiklander { 3583d3b0591SJens Wiklander return( mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation, 3593d3b0591SJens Wiklander ctx->iv, ctx->iv_size, ad, ad_len ) ); 360817466cbSJens Wiklander } 3613d3b0591SJens Wiklander #endif 3623d3b0591SJens Wiklander 3633d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 3643d3b0591SJens Wiklander if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) 3653d3b0591SJens Wiklander { 3663d3b0591SJens Wiklander int result; 3673d3b0591SJens Wiklander mbedtls_chachapoly_mode_t mode; 3683d3b0591SJens Wiklander 3693d3b0591SJens Wiklander mode = ( ctx->operation == MBEDTLS_ENCRYPT ) 3703d3b0591SJens Wiklander ? MBEDTLS_CHACHAPOLY_ENCRYPT 3713d3b0591SJens Wiklander : MBEDTLS_CHACHAPOLY_DECRYPT; 3723d3b0591SJens Wiklander 3733d3b0591SJens Wiklander result = mbedtls_chachapoly_starts( (mbedtls_chachapoly_context*) ctx->cipher_ctx, 3743d3b0591SJens Wiklander ctx->iv, 3753d3b0591SJens Wiklander mode ); 3763d3b0591SJens Wiklander if ( result != 0 ) 3773d3b0591SJens Wiklander return( result ); 3783d3b0591SJens Wiklander 3793d3b0591SJens Wiklander return( mbedtls_chachapoly_update_aad( (mbedtls_chachapoly_context*) ctx->cipher_ctx, 3803d3b0591SJens Wiklander ad, ad_len ) ); 3813d3b0591SJens Wiklander } 3823d3b0591SJens Wiklander #endif 383817466cbSJens Wiklander 384817466cbSJens Wiklander return( 0 ); 385817466cbSJens Wiklander } 3863d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ 387817466cbSJens Wiklander 388817466cbSJens Wiklander int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, 389817466cbSJens Wiklander size_t ilen, unsigned char *output, size_t *olen ) 390817466cbSJens Wiklander { 391817466cbSJens Wiklander int ret; 3923d3b0591SJens Wiklander size_t block_size; 393817466cbSJens Wiklander 3943d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 3953d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); 3963d3b0591SJens Wiklander CIPHER_VALIDATE_RET( output != NULL ); 3973d3b0591SJens Wiklander CIPHER_VALIDATE_RET( olen != NULL ); 3983d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 399817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 400817466cbSJens Wiklander 401817466cbSJens Wiklander *olen = 0; 402817466cbSJens Wiklander block_size = mbedtls_cipher_get_block_size( ctx ); 403*5b25c76aSJerome Forissier if ( 0 == block_size ) 404*5b25c76aSJerome Forissier { 405*5b25c76aSJerome Forissier return( MBEDTLS_ERR_CIPHER_INVALID_CONTEXT ); 406*5b25c76aSJerome Forissier } 407817466cbSJens Wiklander 408817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB ) 409817466cbSJens Wiklander { 410817466cbSJens Wiklander if( ilen != block_size ) 411817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 412817466cbSJens Wiklander 413817466cbSJens Wiklander *olen = ilen; 414817466cbSJens Wiklander 415817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx, 416817466cbSJens Wiklander ctx->operation, input, output ) ) ) 417817466cbSJens Wiklander { 418817466cbSJens Wiklander return( ret ); 419817466cbSJens Wiklander } 420817466cbSJens Wiklander 421817466cbSJens Wiklander return( 0 ); 422817466cbSJens Wiklander } 423817466cbSJens Wiklander 424817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 425817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM ) 426817466cbSJens Wiklander { 427817466cbSJens Wiklander *olen = ilen; 4283d3b0591SJens Wiklander return( mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input, 4293d3b0591SJens Wiklander output ) ); 4303d3b0591SJens Wiklander } 4313d3b0591SJens Wiklander #endif 4323d3b0591SJens Wiklander 4333d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 4343d3b0591SJens Wiklander if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) 4353d3b0591SJens Wiklander { 4363d3b0591SJens Wiklander *olen = ilen; 4373d3b0591SJens Wiklander return( mbedtls_chachapoly_update( (mbedtls_chachapoly_context*) ctx->cipher_ctx, 4383d3b0591SJens Wiklander ilen, input, output ) ); 439817466cbSJens Wiklander } 440817466cbSJens Wiklander #endif 441817466cbSJens Wiklander 442817466cbSJens Wiklander if( input == output && 443817466cbSJens Wiklander ( ctx->unprocessed_len != 0 || ilen % block_size ) ) 444817466cbSJens Wiklander { 445817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 446817466cbSJens Wiklander } 447817466cbSJens Wiklander 448817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CBC) 449817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC ) 450817466cbSJens Wiklander { 451817466cbSJens Wiklander size_t copy_len = 0; 452817466cbSJens Wiklander 453817466cbSJens Wiklander /* 454817466cbSJens Wiklander * If there is not enough data for a full block, cache it. 455817466cbSJens Wiklander */ 4563d3b0591SJens Wiklander if( ( ctx->operation == MBEDTLS_DECRYPT && NULL != ctx->add_padding && 457817466cbSJens Wiklander ilen <= block_size - ctx->unprocessed_len ) || 4583d3b0591SJens Wiklander ( ctx->operation == MBEDTLS_DECRYPT && NULL == ctx->add_padding && 4593d3b0591SJens Wiklander ilen < block_size - ctx->unprocessed_len ) || 460817466cbSJens Wiklander ( ctx->operation == MBEDTLS_ENCRYPT && 461817466cbSJens Wiklander ilen < block_size - ctx->unprocessed_len ) ) 462817466cbSJens Wiklander { 463817466cbSJens Wiklander memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, 464817466cbSJens Wiklander ilen ); 465817466cbSJens Wiklander 466817466cbSJens Wiklander ctx->unprocessed_len += ilen; 467817466cbSJens Wiklander return( 0 ); 468817466cbSJens Wiklander } 469817466cbSJens Wiklander 470817466cbSJens Wiklander /* 471817466cbSJens Wiklander * Process cached data first 472817466cbSJens Wiklander */ 473817466cbSJens Wiklander if( 0 != ctx->unprocessed_len ) 474817466cbSJens Wiklander { 475817466cbSJens Wiklander copy_len = block_size - ctx->unprocessed_len; 476817466cbSJens Wiklander 477817466cbSJens Wiklander memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, 478817466cbSJens Wiklander copy_len ); 479817466cbSJens Wiklander 480817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, 481817466cbSJens Wiklander ctx->operation, block_size, ctx->iv, 482817466cbSJens Wiklander ctx->unprocessed_data, output ) ) ) 483817466cbSJens Wiklander { 484817466cbSJens Wiklander return( ret ); 485817466cbSJens Wiklander } 486817466cbSJens Wiklander 487817466cbSJens Wiklander *olen += block_size; 488817466cbSJens Wiklander output += block_size; 489817466cbSJens Wiklander ctx->unprocessed_len = 0; 490817466cbSJens Wiklander 491817466cbSJens Wiklander input += copy_len; 492817466cbSJens Wiklander ilen -= copy_len; 493817466cbSJens Wiklander } 494817466cbSJens Wiklander 495817466cbSJens Wiklander /* 496817466cbSJens Wiklander * Cache final, incomplete block 497817466cbSJens Wiklander */ 498817466cbSJens Wiklander if( 0 != ilen ) 499817466cbSJens Wiklander { 5003d3b0591SJens Wiklander /* Encryption: only cache partial blocks 5013d3b0591SJens Wiklander * Decryption w/ padding: always keep at least one whole block 5023d3b0591SJens Wiklander * Decryption w/o padding: only cache partial blocks 5033d3b0591SJens Wiklander */ 504817466cbSJens Wiklander copy_len = ilen % block_size; 5053d3b0591SJens Wiklander if( copy_len == 0 && 5063d3b0591SJens Wiklander ctx->operation == MBEDTLS_DECRYPT && 5073d3b0591SJens Wiklander NULL != ctx->add_padding) 5083d3b0591SJens Wiklander { 509817466cbSJens Wiklander copy_len = block_size; 5103d3b0591SJens Wiklander } 511817466cbSJens Wiklander 512817466cbSJens Wiklander memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ), 513817466cbSJens Wiklander copy_len ); 514817466cbSJens Wiklander 515817466cbSJens Wiklander ctx->unprocessed_len += copy_len; 516817466cbSJens Wiklander ilen -= copy_len; 517817466cbSJens Wiklander } 518817466cbSJens Wiklander 519817466cbSJens Wiklander /* 520817466cbSJens Wiklander * Process remaining full blocks 521817466cbSJens Wiklander */ 522817466cbSJens Wiklander if( ilen ) 523817466cbSJens Wiklander { 524817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, 525817466cbSJens Wiklander ctx->operation, ilen, ctx->iv, input, output ) ) ) 526817466cbSJens Wiklander { 527817466cbSJens Wiklander return( ret ); 528817466cbSJens Wiklander } 529817466cbSJens Wiklander 530817466cbSJens Wiklander *olen += ilen; 531817466cbSJens Wiklander } 532817466cbSJens Wiklander 533817466cbSJens Wiklander return( 0 ); 534817466cbSJens Wiklander } 535817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CBC */ 536817466cbSJens Wiklander 537817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CFB) 538817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB ) 539817466cbSJens Wiklander { 540817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx, 541817466cbSJens Wiklander ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv, 542817466cbSJens Wiklander input, output ) ) ) 543817466cbSJens Wiklander { 544817466cbSJens Wiklander return( ret ); 545817466cbSJens Wiklander } 546817466cbSJens Wiklander 547817466cbSJens Wiklander *olen = ilen; 548817466cbSJens Wiklander 549817466cbSJens Wiklander return( 0 ); 550817466cbSJens Wiklander } 551817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CFB */ 552817466cbSJens Wiklander 5533d3b0591SJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_OFB) 5543d3b0591SJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_OFB ) 5553d3b0591SJens Wiklander { 5563d3b0591SJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->ofb_func( ctx->cipher_ctx, 5573d3b0591SJens Wiklander ilen, &ctx->unprocessed_len, ctx->iv, input, output ) ) ) 5583d3b0591SJens Wiklander { 5593d3b0591SJens Wiklander return( ret ); 5603d3b0591SJens Wiklander } 5613d3b0591SJens Wiklander 5623d3b0591SJens Wiklander *olen = ilen; 5633d3b0591SJens Wiklander 5643d3b0591SJens Wiklander return( 0 ); 5653d3b0591SJens Wiklander } 5663d3b0591SJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_OFB */ 5673d3b0591SJens Wiklander 568817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CTR) 569817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR ) 570817466cbSJens Wiklander { 571817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx, 572817466cbSJens Wiklander ilen, &ctx->unprocessed_len, ctx->iv, 573817466cbSJens Wiklander ctx->unprocessed_data, input, output ) ) ) 574817466cbSJens Wiklander { 575817466cbSJens Wiklander return( ret ); 576817466cbSJens Wiklander } 577817466cbSJens Wiklander 578817466cbSJens Wiklander *olen = ilen; 579817466cbSJens Wiklander 580817466cbSJens Wiklander return( 0 ); 581817466cbSJens Wiklander } 582817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CTR */ 583817466cbSJens Wiklander 5843d3b0591SJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_XTS) 5853d3b0591SJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_XTS ) 5863d3b0591SJens Wiklander { 5873d3b0591SJens Wiklander if( ctx->unprocessed_len > 0 ) { 5883d3b0591SJens Wiklander /* We can only process an entire data unit at a time. */ 5893d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 5903d3b0591SJens Wiklander } 5913d3b0591SJens Wiklander 5923d3b0591SJens Wiklander ret = ctx->cipher_info->base->xts_func( ctx->cipher_ctx, 5933d3b0591SJens Wiklander ctx->operation, ilen, ctx->iv, input, output ); 5943d3b0591SJens Wiklander if( ret != 0 ) 5953d3b0591SJens Wiklander { 5963d3b0591SJens Wiklander return( ret ); 5973d3b0591SJens Wiklander } 5983d3b0591SJens Wiklander 5993d3b0591SJens Wiklander *olen = ilen; 6003d3b0591SJens Wiklander 6013d3b0591SJens Wiklander return( 0 ); 6023d3b0591SJens Wiklander } 6033d3b0591SJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_XTS */ 6043d3b0591SJens Wiklander 605817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_STREAM) 606817466cbSJens Wiklander if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM ) 607817466cbSJens Wiklander { 608817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx, 609817466cbSJens Wiklander ilen, input, output ) ) ) 610817466cbSJens Wiklander { 611817466cbSJens Wiklander return( ret ); 612817466cbSJens Wiklander } 613817466cbSJens Wiklander 614817466cbSJens Wiklander *olen = ilen; 615817466cbSJens Wiklander 616817466cbSJens Wiklander return( 0 ); 617817466cbSJens Wiklander } 618817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_STREAM */ 619817466cbSJens Wiklander 620817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 621817466cbSJens Wiklander } 622817466cbSJens Wiklander 623817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) 624817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7) 625817466cbSJens Wiklander /* 626817466cbSJens Wiklander * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len 627817466cbSJens Wiklander */ 628817466cbSJens Wiklander static void add_pkcs_padding( unsigned char *output, size_t output_len, 629817466cbSJens Wiklander size_t data_len ) 630817466cbSJens Wiklander { 631817466cbSJens Wiklander size_t padding_len = output_len - data_len; 632817466cbSJens Wiklander unsigned char i; 633817466cbSJens Wiklander 634817466cbSJens Wiklander for( i = 0; i < padding_len; i++ ) 635817466cbSJens Wiklander output[data_len + i] = (unsigned char) padding_len; 636817466cbSJens Wiklander } 637817466cbSJens Wiklander 638817466cbSJens Wiklander static int get_pkcs_padding( unsigned char *input, size_t input_len, 639817466cbSJens Wiklander size_t *data_len ) 640817466cbSJens Wiklander { 641817466cbSJens Wiklander size_t i, pad_idx; 642817466cbSJens Wiklander unsigned char padding_len, bad = 0; 643817466cbSJens Wiklander 644817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 645817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 646817466cbSJens Wiklander 647817466cbSJens Wiklander padding_len = input[input_len - 1]; 648817466cbSJens Wiklander *data_len = input_len - padding_len; 649817466cbSJens Wiklander 650817466cbSJens Wiklander /* Avoid logical || since it results in a branch */ 651817466cbSJens Wiklander bad |= padding_len > input_len; 652817466cbSJens Wiklander bad |= padding_len == 0; 653817466cbSJens Wiklander 654817466cbSJens Wiklander /* The number of bytes checked must be independent of padding_len, 655817466cbSJens Wiklander * so pick input_len, which is usually 8 or 16 (one block) */ 656817466cbSJens Wiklander pad_idx = input_len - padding_len; 657817466cbSJens Wiklander for( i = 0; i < input_len; i++ ) 658817466cbSJens Wiklander bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx ); 659817466cbSJens Wiklander 660817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); 661817466cbSJens Wiklander } 662817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ 663817466cbSJens Wiklander 664817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) 665817466cbSJens Wiklander /* 666817466cbSJens Wiklander * One and zeros padding: fill with 80 00 ... 00 667817466cbSJens Wiklander */ 668817466cbSJens Wiklander static void add_one_and_zeros_padding( unsigned char *output, 669817466cbSJens Wiklander size_t output_len, size_t data_len ) 670817466cbSJens Wiklander { 671817466cbSJens Wiklander size_t padding_len = output_len - data_len; 672817466cbSJens Wiklander unsigned char i = 0; 673817466cbSJens Wiklander 674817466cbSJens Wiklander output[data_len] = 0x80; 675817466cbSJens Wiklander for( i = 1; i < padding_len; i++ ) 676817466cbSJens Wiklander output[data_len + i] = 0x00; 677817466cbSJens Wiklander } 678817466cbSJens Wiklander 679817466cbSJens Wiklander static int get_one_and_zeros_padding( unsigned char *input, size_t input_len, 680817466cbSJens Wiklander size_t *data_len ) 681817466cbSJens Wiklander { 682817466cbSJens Wiklander size_t i; 683817466cbSJens Wiklander unsigned char done = 0, prev_done, bad; 684817466cbSJens Wiklander 685817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 686817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 687817466cbSJens Wiklander 6883d3b0591SJens Wiklander bad = 0x80; 689817466cbSJens Wiklander *data_len = 0; 690817466cbSJens Wiklander for( i = input_len; i > 0; i-- ) 691817466cbSJens Wiklander { 692817466cbSJens Wiklander prev_done = done; 693817466cbSJens Wiklander done |= ( input[i - 1] != 0 ); 694817466cbSJens Wiklander *data_len |= ( i - 1 ) * ( done != prev_done ); 6953d3b0591SJens Wiklander bad ^= input[i - 1] * ( done != prev_done ); 696817466cbSJens Wiklander } 697817466cbSJens Wiklander 698817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); 699817466cbSJens Wiklander 700817466cbSJens Wiklander } 701817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ 702817466cbSJens Wiklander 703817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) 704817466cbSJens Wiklander /* 705817466cbSJens Wiklander * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length 706817466cbSJens Wiklander */ 707817466cbSJens Wiklander static void add_zeros_and_len_padding( unsigned char *output, 708817466cbSJens Wiklander size_t output_len, size_t data_len ) 709817466cbSJens Wiklander { 710817466cbSJens Wiklander size_t padding_len = output_len - data_len; 711817466cbSJens Wiklander unsigned char i = 0; 712817466cbSJens Wiklander 713817466cbSJens Wiklander for( i = 1; i < padding_len; i++ ) 714817466cbSJens Wiklander output[data_len + i - 1] = 0x00; 715817466cbSJens Wiklander output[output_len - 1] = (unsigned char) padding_len; 716817466cbSJens Wiklander } 717817466cbSJens Wiklander 718817466cbSJens Wiklander static int get_zeros_and_len_padding( unsigned char *input, size_t input_len, 719817466cbSJens Wiklander size_t *data_len ) 720817466cbSJens Wiklander { 721817466cbSJens Wiklander size_t i, pad_idx; 722817466cbSJens Wiklander unsigned char padding_len, bad = 0; 723817466cbSJens Wiklander 724817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 725817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 726817466cbSJens Wiklander 727817466cbSJens Wiklander padding_len = input[input_len - 1]; 728817466cbSJens Wiklander *data_len = input_len - padding_len; 729817466cbSJens Wiklander 730817466cbSJens Wiklander /* Avoid logical || since it results in a branch */ 731817466cbSJens Wiklander bad |= padding_len > input_len; 732817466cbSJens Wiklander bad |= padding_len == 0; 733817466cbSJens Wiklander 734817466cbSJens Wiklander /* The number of bytes checked must be independent of padding_len */ 735817466cbSJens Wiklander pad_idx = input_len - padding_len; 736817466cbSJens Wiklander for( i = 0; i < input_len - 1; i++ ) 737817466cbSJens Wiklander bad |= input[i] * ( i >= pad_idx ); 738817466cbSJens Wiklander 739817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); 740817466cbSJens Wiklander } 741817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ 742817466cbSJens Wiklander 743817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS) 744817466cbSJens Wiklander /* 745817466cbSJens Wiklander * Zero padding: fill with 00 ... 00 746817466cbSJens Wiklander */ 747817466cbSJens Wiklander static void add_zeros_padding( unsigned char *output, 748817466cbSJens Wiklander size_t output_len, size_t data_len ) 749817466cbSJens Wiklander { 750817466cbSJens Wiklander size_t i; 751817466cbSJens Wiklander 752817466cbSJens Wiklander for( i = data_len; i < output_len; i++ ) 753817466cbSJens Wiklander output[i] = 0x00; 754817466cbSJens Wiklander } 755817466cbSJens Wiklander 756817466cbSJens Wiklander static int get_zeros_padding( unsigned char *input, size_t input_len, 757817466cbSJens Wiklander size_t *data_len ) 758817466cbSJens Wiklander { 759817466cbSJens Wiklander size_t i; 760817466cbSJens Wiklander unsigned char done = 0, prev_done; 761817466cbSJens Wiklander 762817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 763817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 764817466cbSJens Wiklander 765817466cbSJens Wiklander *data_len = 0; 766817466cbSJens Wiklander for( i = input_len; i > 0; i-- ) 767817466cbSJens Wiklander { 768817466cbSJens Wiklander prev_done = done; 769817466cbSJens Wiklander done |= ( input[i-1] != 0 ); 770817466cbSJens Wiklander *data_len |= i * ( done != prev_done ); 771817466cbSJens Wiklander } 772817466cbSJens Wiklander 773817466cbSJens Wiklander return( 0 ); 774817466cbSJens Wiklander } 775817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ 776817466cbSJens Wiklander 777817466cbSJens Wiklander /* 778817466cbSJens Wiklander * No padding: don't pad :) 779817466cbSJens Wiklander * 780817466cbSJens Wiklander * There is no add_padding function (check for NULL in mbedtls_cipher_finish) 781817466cbSJens Wiklander * but a trivial get_padding function 782817466cbSJens Wiklander */ 783817466cbSJens Wiklander static int get_no_padding( unsigned char *input, size_t input_len, 784817466cbSJens Wiklander size_t *data_len ) 785817466cbSJens Wiklander { 786817466cbSJens Wiklander if( NULL == input || NULL == data_len ) 787817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 788817466cbSJens Wiklander 789817466cbSJens Wiklander *data_len = input_len; 790817466cbSJens Wiklander 791817466cbSJens Wiklander return( 0 ); 792817466cbSJens Wiklander } 793817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ 794817466cbSJens Wiklander 795817466cbSJens Wiklander int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, 796817466cbSJens Wiklander unsigned char *output, size_t *olen ) 797817466cbSJens Wiklander { 7983d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 7993d3b0591SJens Wiklander CIPHER_VALIDATE_RET( output != NULL ); 8003d3b0591SJens Wiklander CIPHER_VALIDATE_RET( olen != NULL ); 8013d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 802817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 803817466cbSJens Wiklander 804817466cbSJens Wiklander *olen = 0; 805817466cbSJens Wiklander 806817466cbSJens Wiklander if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode || 8073d3b0591SJens Wiklander MBEDTLS_MODE_OFB == ctx->cipher_info->mode || 808817466cbSJens Wiklander MBEDTLS_MODE_CTR == ctx->cipher_info->mode || 809817466cbSJens Wiklander MBEDTLS_MODE_GCM == ctx->cipher_info->mode || 8103d3b0591SJens Wiklander MBEDTLS_MODE_XTS == ctx->cipher_info->mode || 811817466cbSJens Wiklander MBEDTLS_MODE_STREAM == ctx->cipher_info->mode ) 812817466cbSJens Wiklander { 813817466cbSJens Wiklander return( 0 ); 814817466cbSJens Wiklander } 815817466cbSJens Wiklander 8163d3b0591SJens Wiklander if ( ( MBEDTLS_CIPHER_CHACHA20 == ctx->cipher_info->type ) || 8173d3b0591SJens Wiklander ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) ) 8183d3b0591SJens Wiklander { 8193d3b0591SJens Wiklander return( 0 ); 8203d3b0591SJens Wiklander } 8213d3b0591SJens Wiklander 822817466cbSJens Wiklander if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode ) 823817466cbSJens Wiklander { 824817466cbSJens Wiklander if( ctx->unprocessed_len != 0 ) 825817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 826817466cbSJens Wiklander 827817466cbSJens Wiklander return( 0 ); 828817466cbSJens Wiklander } 829817466cbSJens Wiklander 830817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_CBC) 831817466cbSJens Wiklander if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode ) 832817466cbSJens Wiklander { 833817466cbSJens Wiklander int ret = 0; 834817466cbSJens Wiklander 835817466cbSJens Wiklander if( MBEDTLS_ENCRYPT == ctx->operation ) 836817466cbSJens Wiklander { 837817466cbSJens Wiklander /* check for 'no padding' mode */ 838817466cbSJens Wiklander if( NULL == ctx->add_padding ) 839817466cbSJens Wiklander { 840817466cbSJens Wiklander if( 0 != ctx->unprocessed_len ) 841817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 842817466cbSJens Wiklander 843817466cbSJens Wiklander return( 0 ); 844817466cbSJens Wiklander } 845817466cbSJens Wiklander 846817466cbSJens Wiklander ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ), 847817466cbSJens Wiklander ctx->unprocessed_len ); 848817466cbSJens Wiklander } 849817466cbSJens Wiklander else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len ) 850817466cbSJens Wiklander { 851817466cbSJens Wiklander /* 852817466cbSJens Wiklander * For decrypt operations, expect a full block, 853817466cbSJens Wiklander * or an empty block if no padding 854817466cbSJens Wiklander */ 855817466cbSJens Wiklander if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len ) 856817466cbSJens Wiklander return( 0 ); 857817466cbSJens Wiklander 858817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); 859817466cbSJens Wiklander } 860817466cbSJens Wiklander 861817466cbSJens Wiklander /* cipher block */ 862817466cbSJens Wiklander if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, 863817466cbSJens Wiklander ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv, 864817466cbSJens Wiklander ctx->unprocessed_data, output ) ) ) 865817466cbSJens Wiklander { 866817466cbSJens Wiklander return( ret ); 867817466cbSJens Wiklander } 868817466cbSJens Wiklander 869817466cbSJens Wiklander /* Set output size for decryption */ 870817466cbSJens Wiklander if( MBEDTLS_DECRYPT == ctx->operation ) 8713d3b0591SJens Wiklander return( ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ), 8723d3b0591SJens Wiklander olen ) ); 873817466cbSJens Wiklander 874817466cbSJens Wiklander /* Set output size for encryption */ 875817466cbSJens Wiklander *olen = mbedtls_cipher_get_block_size( ctx ); 876817466cbSJens Wiklander return( 0 ); 877817466cbSJens Wiklander } 878817466cbSJens Wiklander #else 879817466cbSJens Wiklander ((void) output); 880817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_CBC */ 881817466cbSJens Wiklander 882817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 883817466cbSJens Wiklander } 884817466cbSJens Wiklander 885817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) 8863d3b0591SJens Wiklander int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, 8873d3b0591SJens Wiklander mbedtls_cipher_padding_t mode ) 888817466cbSJens Wiklander { 8893d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 8903d3b0591SJens Wiklander 8913d3b0591SJens Wiklander if( NULL == ctx->cipher_info || MBEDTLS_MODE_CBC != ctx->cipher_info->mode ) 892817466cbSJens Wiklander { 893817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 894817466cbSJens Wiklander } 895817466cbSJens Wiklander 896817466cbSJens Wiklander switch( mode ) 897817466cbSJens Wiklander { 898817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_PKCS7) 899817466cbSJens Wiklander case MBEDTLS_PADDING_PKCS7: 900817466cbSJens Wiklander ctx->add_padding = add_pkcs_padding; 901817466cbSJens Wiklander ctx->get_padding = get_pkcs_padding; 902817466cbSJens Wiklander break; 903817466cbSJens Wiklander #endif 904817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) 905817466cbSJens Wiklander case MBEDTLS_PADDING_ONE_AND_ZEROS: 906817466cbSJens Wiklander ctx->add_padding = add_one_and_zeros_padding; 907817466cbSJens Wiklander ctx->get_padding = get_one_and_zeros_padding; 908817466cbSJens Wiklander break; 909817466cbSJens Wiklander #endif 910817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) 911817466cbSJens Wiklander case MBEDTLS_PADDING_ZEROS_AND_LEN: 912817466cbSJens Wiklander ctx->add_padding = add_zeros_and_len_padding; 913817466cbSJens Wiklander ctx->get_padding = get_zeros_and_len_padding; 914817466cbSJens Wiklander break; 915817466cbSJens Wiklander #endif 916817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_PADDING_ZEROS) 917817466cbSJens Wiklander case MBEDTLS_PADDING_ZEROS: 918817466cbSJens Wiklander ctx->add_padding = add_zeros_padding; 919817466cbSJens Wiklander ctx->get_padding = get_zeros_padding; 920817466cbSJens Wiklander break; 921817466cbSJens Wiklander #endif 922817466cbSJens Wiklander case MBEDTLS_PADDING_NONE: 923817466cbSJens Wiklander ctx->add_padding = NULL; 924817466cbSJens Wiklander ctx->get_padding = get_no_padding; 925817466cbSJens Wiklander break; 926817466cbSJens Wiklander 927817466cbSJens Wiklander default: 928817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 929817466cbSJens Wiklander } 930817466cbSJens Wiklander 931817466cbSJens Wiklander return( 0 ); 932817466cbSJens Wiklander } 933817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ 934817466cbSJens Wiklander 9353d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) 936817466cbSJens Wiklander int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, 937817466cbSJens Wiklander unsigned char *tag, size_t tag_len ) 938817466cbSJens Wiklander { 9393d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 9403d3b0591SJens Wiklander CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); 9413d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 942817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 943817466cbSJens Wiklander 944817466cbSJens Wiklander if( MBEDTLS_ENCRYPT != ctx->operation ) 945817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 946817466cbSJens Wiklander 9473d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) 948817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 9493d3b0591SJens Wiklander return( mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, 9503d3b0591SJens Wiklander tag, tag_len ) ); 9513d3b0591SJens Wiklander #endif 9523d3b0591SJens Wiklander 9533d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 9543d3b0591SJens Wiklander if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) 9553d3b0591SJens Wiklander { 9563d3b0591SJens Wiklander /* Don't allow truncated MAC for Poly1305 */ 9573d3b0591SJens Wiklander if ( tag_len != 16U ) 9583d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 9593d3b0591SJens Wiklander 9603d3b0591SJens Wiklander return( mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx, 9613d3b0591SJens Wiklander tag ) ); 9623d3b0591SJens Wiklander } 9633d3b0591SJens Wiklander #endif 964817466cbSJens Wiklander 965817466cbSJens Wiklander return( 0 ); 966817466cbSJens Wiklander } 967817466cbSJens Wiklander 968817466cbSJens Wiklander int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, 969817466cbSJens Wiklander const unsigned char *tag, size_t tag_len ) 970817466cbSJens Wiklander { 9713d3b0591SJens Wiklander unsigned char check_tag[16]; 972817466cbSJens Wiklander int ret; 973817466cbSJens Wiklander 9743d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 9753d3b0591SJens Wiklander CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); 9763d3b0591SJens Wiklander if( ctx->cipher_info == NULL ) 9773d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 9783d3b0591SJens Wiklander 9793d3b0591SJens Wiklander if( MBEDTLS_DECRYPT != ctx->operation ) 980817466cbSJens Wiklander { 981817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 982817466cbSJens Wiklander } 983817466cbSJens Wiklander 9843d3b0591SJens Wiklander #if defined(MBEDTLS_GCM_C) 985817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 986817466cbSJens Wiklander { 987817466cbSJens Wiklander if( tag_len > sizeof( check_tag ) ) 988817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 989817466cbSJens Wiklander 990817466cbSJens Wiklander if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, 991817466cbSJens Wiklander check_tag, tag_len ) ) ) 992817466cbSJens Wiklander { 993817466cbSJens Wiklander return( ret ); 994817466cbSJens Wiklander } 995817466cbSJens Wiklander 996817466cbSJens Wiklander /* Check the tag in "constant-time" */ 9973d3b0591SJens Wiklander if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) 998817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); 999817466cbSJens Wiklander 1000817466cbSJens Wiklander return( 0 ); 1001817466cbSJens Wiklander } 10023d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C */ 10033d3b0591SJens Wiklander 10043d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 10053d3b0591SJens Wiklander if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) 10063d3b0591SJens Wiklander { 10073d3b0591SJens Wiklander /* Don't allow truncated MAC for Poly1305 */ 10083d3b0591SJens Wiklander if ( tag_len != sizeof( check_tag ) ) 10093d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 10103d3b0591SJens Wiklander 10113d3b0591SJens Wiklander ret = mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx, 10123d3b0591SJens Wiklander check_tag ); 10133d3b0591SJens Wiklander if ( ret != 0 ) 10143d3b0591SJens Wiklander { 10153d3b0591SJens Wiklander return( ret ); 10163d3b0591SJens Wiklander } 10173d3b0591SJens Wiklander 10183d3b0591SJens Wiklander /* Check the tag in "constant-time" */ 10193d3b0591SJens Wiklander if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) 10203d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); 1021817466cbSJens Wiklander 1022817466cbSJens Wiklander return( 0 ); 1023817466cbSJens Wiklander } 10243d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */ 10253d3b0591SJens Wiklander 10263d3b0591SJens Wiklander return( 0 ); 10273d3b0591SJens Wiklander } 10283d3b0591SJens Wiklander #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ 1029817466cbSJens Wiklander 1030817466cbSJens Wiklander /* 1031817466cbSJens Wiklander * Packet-oriented wrapper for non-AEAD modes 1032817466cbSJens Wiklander */ 1033817466cbSJens Wiklander int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, 1034817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 1035817466cbSJens Wiklander const unsigned char *input, size_t ilen, 1036817466cbSJens Wiklander unsigned char *output, size_t *olen ) 1037817466cbSJens Wiklander { 1038817466cbSJens Wiklander int ret; 1039817466cbSJens Wiklander size_t finish_olen; 1040817466cbSJens Wiklander 10413d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 10423d3b0591SJens Wiklander CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL ); 10433d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); 10443d3b0591SJens Wiklander CIPHER_VALIDATE_RET( output != NULL ); 10453d3b0591SJens Wiklander CIPHER_VALIDATE_RET( olen != NULL ); 10463d3b0591SJens Wiklander 1047817466cbSJens Wiklander if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 ) 1048817466cbSJens Wiklander return( ret ); 1049817466cbSJens Wiklander 1050817466cbSJens Wiklander if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 ) 1051817466cbSJens Wiklander return( ret ); 1052817466cbSJens Wiklander 1053817466cbSJens Wiklander if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 ) 1054817466cbSJens Wiklander return( ret ); 1055817466cbSJens Wiklander 1056817466cbSJens Wiklander if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 ) 1057817466cbSJens Wiklander return( ret ); 1058817466cbSJens Wiklander 1059817466cbSJens Wiklander *olen += finish_olen; 1060817466cbSJens Wiklander 1061817466cbSJens Wiklander return( 0 ); 1062817466cbSJens Wiklander } 1063817466cbSJens Wiklander 1064817466cbSJens Wiklander #if defined(MBEDTLS_CIPHER_MODE_AEAD) 1065817466cbSJens Wiklander /* 1066817466cbSJens Wiklander * Packet-oriented encryption for AEAD modes 1067817466cbSJens Wiklander */ 1068817466cbSJens Wiklander int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, 1069817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 1070817466cbSJens Wiklander const unsigned char *ad, size_t ad_len, 1071817466cbSJens Wiklander const unsigned char *input, size_t ilen, 1072817466cbSJens Wiklander unsigned char *output, size_t *olen, 1073817466cbSJens Wiklander unsigned char *tag, size_t tag_len ) 1074817466cbSJens Wiklander { 10753d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 10763d3b0591SJens Wiklander CIPHER_VALIDATE_RET( iv != NULL ); 10773d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); 10783d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); 10793d3b0591SJens Wiklander CIPHER_VALIDATE_RET( output != NULL ); 10803d3b0591SJens Wiklander CIPHER_VALIDATE_RET( olen != NULL ); 10813d3b0591SJens Wiklander CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); 10823d3b0591SJens Wiklander 1083817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 1084817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 1085817466cbSJens Wiklander { 1086817466cbSJens Wiklander *olen = ilen; 1087817466cbSJens Wiklander return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen, 1088817466cbSJens Wiklander iv, iv_len, ad, ad_len, input, output, 1089817466cbSJens Wiklander tag_len, tag ) ); 1090817466cbSJens Wiklander } 1091817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */ 1092817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C) 1093817466cbSJens Wiklander if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) 1094817466cbSJens Wiklander { 1095817466cbSJens Wiklander *olen = ilen; 1096817466cbSJens Wiklander return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen, 1097817466cbSJens Wiklander iv, iv_len, ad, ad_len, input, output, 1098817466cbSJens Wiklander tag, tag_len ) ); 1099817466cbSJens Wiklander } 1100817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */ 11013d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 11023d3b0591SJens Wiklander if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) 11033d3b0591SJens Wiklander { 11043d3b0591SJens Wiklander /* ChachaPoly has fixed length nonce and MAC (tag) */ 11053d3b0591SJens Wiklander if ( ( iv_len != ctx->cipher_info->iv_size ) || 11063d3b0591SJens Wiklander ( tag_len != 16U ) ) 11073d3b0591SJens Wiklander { 11083d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 11093d3b0591SJens Wiklander } 11103d3b0591SJens Wiklander 11113d3b0591SJens Wiklander *olen = ilen; 11123d3b0591SJens Wiklander return( mbedtls_chachapoly_encrypt_and_tag( ctx->cipher_ctx, 11133d3b0591SJens Wiklander ilen, iv, ad, ad_len, input, output, tag ) ); 11143d3b0591SJens Wiklander } 11153d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */ 1116817466cbSJens Wiklander 1117817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 1118817466cbSJens Wiklander } 1119817466cbSJens Wiklander 1120817466cbSJens Wiklander /* 1121817466cbSJens Wiklander * Packet-oriented decryption for AEAD modes 1122817466cbSJens Wiklander */ 1123817466cbSJens Wiklander int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, 1124817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 1125817466cbSJens Wiklander const unsigned char *ad, size_t ad_len, 1126817466cbSJens Wiklander const unsigned char *input, size_t ilen, 1127817466cbSJens Wiklander unsigned char *output, size_t *olen, 1128817466cbSJens Wiklander const unsigned char *tag, size_t tag_len ) 1129817466cbSJens Wiklander { 11303d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ctx != NULL ); 11313d3b0591SJens Wiklander CIPHER_VALIDATE_RET( iv != NULL ); 11323d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); 11333d3b0591SJens Wiklander CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); 11343d3b0591SJens Wiklander CIPHER_VALIDATE_RET( output != NULL ); 11353d3b0591SJens Wiklander CIPHER_VALIDATE_RET( olen != NULL ); 11363d3b0591SJens Wiklander CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); 11373d3b0591SJens Wiklander 1138817466cbSJens Wiklander #if defined(MBEDTLS_GCM_C) 1139817466cbSJens Wiklander if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) 1140817466cbSJens Wiklander { 1141817466cbSJens Wiklander int ret; 1142817466cbSJens Wiklander 1143817466cbSJens Wiklander *olen = ilen; 1144817466cbSJens Wiklander ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen, 1145817466cbSJens Wiklander iv, iv_len, ad, ad_len, 1146817466cbSJens Wiklander tag, tag_len, input, output ); 1147817466cbSJens Wiklander 1148817466cbSJens Wiklander if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED ) 1149817466cbSJens Wiklander ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; 1150817466cbSJens Wiklander 1151817466cbSJens Wiklander return( ret ); 1152817466cbSJens Wiklander } 1153817466cbSJens Wiklander #endif /* MBEDTLS_GCM_C */ 1154817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C) 1155817466cbSJens Wiklander if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) 1156817466cbSJens Wiklander { 1157817466cbSJens Wiklander int ret; 1158817466cbSJens Wiklander 1159817466cbSJens Wiklander *olen = ilen; 1160817466cbSJens Wiklander ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen, 1161817466cbSJens Wiklander iv, iv_len, ad, ad_len, 1162817466cbSJens Wiklander input, output, tag, tag_len ); 1163817466cbSJens Wiklander 1164817466cbSJens Wiklander if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED ) 1165817466cbSJens Wiklander ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; 1166817466cbSJens Wiklander 1167817466cbSJens Wiklander return( ret ); 1168817466cbSJens Wiklander } 1169817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */ 11703d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C) 11713d3b0591SJens Wiklander if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) 11723d3b0591SJens Wiklander { 11733d3b0591SJens Wiklander int ret; 11743d3b0591SJens Wiklander 11753d3b0591SJens Wiklander /* ChachaPoly has fixed length nonce and MAC (tag) */ 11763d3b0591SJens Wiklander if ( ( iv_len != ctx->cipher_info->iv_size ) || 11773d3b0591SJens Wiklander ( tag_len != 16U ) ) 11783d3b0591SJens Wiklander { 11793d3b0591SJens Wiklander return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); 11803d3b0591SJens Wiklander } 11813d3b0591SJens Wiklander 11823d3b0591SJens Wiklander *olen = ilen; 11833d3b0591SJens Wiklander ret = mbedtls_chachapoly_auth_decrypt( ctx->cipher_ctx, ilen, 11843d3b0591SJens Wiklander iv, ad, ad_len, tag, input, output ); 11853d3b0591SJens Wiklander 11863d3b0591SJens Wiklander if( ret == MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED ) 11873d3b0591SJens Wiklander ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; 11883d3b0591SJens Wiklander 11893d3b0591SJens Wiklander return( ret ); 11903d3b0591SJens Wiklander } 11913d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */ 1192817466cbSJens Wiklander 1193817466cbSJens Wiklander return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); 1194817466cbSJens Wiklander } 1195817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_MODE_AEAD */ 1196817466cbSJens Wiklander 1197817466cbSJens Wiklander #endif /* MBEDTLS_CIPHER_C */ 1198