/* * W-1 function as defined in RFC 3394 section 2.2.2 * This function assumes the following: * 1. Output buffer is at least of size ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH. * 2. The input buffer is of size semiblocks * KW_SEMIBLOCK_LENGTH. * 3. Minimal number of semiblocks is 3. * 4. A is a buffer to hold the first semiblock of the input buffer. */ static int unwrap( mbedtls_nist_kw_context *ctx, const unsigned char *input, size_t semiblocks, unsigned char A[KW_SEMIBLOCK_LENGTH], unsigned char *output, size_t* out_len ) { int ret = 0; const size_t s = 6 * ( semiblocks - 1 ); size_t olen; uint64_t t = 0; unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2]; unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2]; unsigned char *R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH; *out_len = 0; if( semiblocks < MIN_SEMIBLOCKS_COUNT ) { return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } memcpy( A, input, KW_SEMIBLOCK_LENGTH ); memmove( output, input + KW_SEMIBLOCK_LENGTH, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH ); /* Calculate intermediate values */ for( t = s; t >= 1; t-- ) { calc_a_xor_t( A, t ); memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH ); memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH ); ret = mbedtls_cipher_update( &ctx->cipher_ctx, inbuff, 16, outbuff, &olen ); if( ret != 0 ) goto cleanup; memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH ); /* Set R as LSB64 of outbuff */ memcpy( R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH ); if( R == output ) R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH; else R -= KW_SEMIBLOCK_LENGTH; } *out_len = ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH; cleanup: if( ret != 0) memset( output, 0, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH ); mbedtls_platform_zeroize( inbuff, sizeof( inbuff ) ); mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) ); return( ret ); }
void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ) { if( ctx == NULL ) return; mbedtls_platform_zeroize( ctx, sizeof( mbedtls_blowfish_context ) ); }
int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) { int ret = 0; FILE *f = NULL; size_t n; unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; unsigned char c; if( ( f = fopen( path, "rb" ) ) == NULL ) return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); n = fread( buf, 1, sizeof( buf ), f ); if( fread( &c, 1, 1, f ) != 0 ) { ret = MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG; goto exit; } if( n == 0 || ferror( f ) ) { ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; goto exit; } fclose( f ); f = NULL; ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n ); exit: mbedtls_platform_zeroize( buf, sizeof( buf ) ); if( f != NULL ) fclose( f ); if( ret != 0 ) return( ret ); return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) ); }
int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) { int ret; FILE *f; unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; if( ( f = fopen( path, "wb" ) ) == NULL ) return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); if( ( ret = mbedtls_hmac_drbg_random( ctx, buf, sizeof( buf ) ) ) != 0 ) goto exit; if( fwrite( buf, 1, sizeof( buf ), f ) != sizeof( buf ) ) { ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; goto exit; } ret = 0; exit: fclose( f ); mbedtls_platform_zeroize( buf, sizeof( buf ) ); return( ret ); }
void mbedtls_havege_free( mbedtls_havege_state *hs ) { if( hs == NULL ) return; mbedtls_platform_zeroize( hs, sizeof( mbedtls_havege_state ) ); }
void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ) { if( ctx == NULL ) return; #if defined(MBEDTLS_CMAC_C) if( ctx->cmac_ctx ) { mbedtls_platform_zeroize( ctx->cmac_ctx, sizeof( mbedtls_cmac_context_t ) ); mbedtls_free( ctx->cmac_ctx ); } #endif if( ctx->cipher_ctx ) ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx ); mbedtls_platform_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); }
/* * Free an HMAC_DRBG context */ void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ) { if( ctx == NULL ) return; #if defined(MBEDTLS_THREADING_C) mbedtls_mutex_free( &ctx->mutex ); #endif mbedtls_md_free( &ctx->md_ctx ); mbedtls_platform_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) ); }
/* Default implementations for the platform independent seed functions use * standard libc file functions to read from and write to a pre-defined filename */ int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len ) { FILE *file; size_t n; if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "rb" ) ) == NULL ) return( -1 ); if( ( n = fread( buf, 1, buf_len, file ) ) != buf_len ) { fclose( file ); mbedtls_platform_zeroize( buf, buf_len ); return( -1 ); } fclose( file ); return( (int)n ); }
/* * HMAC_DRBG update, using optional additional data (10.1.2.2) */ int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx, const unsigned char *additional, size_t add_len ) { size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info ); unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1; unsigned char sep[1]; unsigned char K[MBEDTLS_MD_MAX_SIZE]; int ret; for( sep[0] = 0; sep[0] < rounds; sep[0]++ ) { /* Step 1 or 4 */ if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 ) goto exit; if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ) ) != 0 ) goto exit; if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, sep, 1 ) ) != 0 ) goto exit; if( rounds == 2 ) { if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, additional, add_len ) ) != 0 ) goto exit; } if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, K ) ) != 0 ) goto exit; /* Step 2 or 5 */ if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ) ) != 0 ) goto exit; if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ) ) != 0 ) goto exit; if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 ) goto exit; } exit: mbedtls_platform_zeroize( K, sizeof( K ) ); return( ret ); }
/* * HMAC_DRBG reseeding: 10.1.2.4 (arabic) + 9.2 (Roman) */ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, const unsigned char *additional, size_t len ) { unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT]; size_t seedlen; int ret; /* III. Check input length */ if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT || ctx->entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ) { return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); } memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ); /* IV. Gather entropy_len bytes of entropy for the seed */ if( ( ret = ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) ) != 0 ) return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED ); seedlen = ctx->entropy_len; /* 1. Concatenate entropy and additional data if any */ if( additional != NULL && len != 0 ) { memcpy( seed + seedlen, additional, len ); seedlen += len; } /* 2. Update state */ if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, seed, seedlen ) ) != 0 ) goto exit; /* 3. Reset reseed_counter */ ctx->reseed_counter = 1; exit: /* 4. Done */ mbedtls_platform_zeroize( seed, seedlen ); return( ret ); }
static void pk_opaque_free_wrap( void *ctx ) { mbedtls_platform_zeroize( ctx, sizeof( psa_key_slot_t ) ); mbedtls_free( ctx ); }
static void rsa_alt_free_wrap( void *ctx ) { mbedtls_platform_zeroize( ctx, sizeof( mbedtls_rsa_alt_context ) ); mbedtls_free( ctx ); }
/* * KW-AD as defined in SP 800-38F section 6.2 * KWP-AD as defined in SP 800-38F section 6.3 */ int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx, mbedtls_nist_kw_mode_t mode, const unsigned char *input, size_t in_len, unsigned char *output, size_t *out_len, size_t out_size ) { int ret = 0; size_t i, olen; unsigned char A[KW_SEMIBLOCK_LENGTH]; unsigned char diff, bad_padding = 0; *out_len = 0; if( out_size < in_len - KW_SEMIBLOCK_LENGTH ) { return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } if( mode == MBEDTLS_KW_MODE_KW ) { /* * According to SP 800-38F Table 1, the ciphertext length for KW * must be between 3 to 2^54 semiblocks inclusive. */ if( in_len < 24 || #if SIZE_MAX > 0x200000000000000 in_len > 0x200000000000000 || #endif in_len % KW_SEMIBLOCK_LENGTH != 0 ) { return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH, A, output, out_len ); if( ret != 0 ) goto cleanup; /* Check ICV in "constant-time" */ diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH ); if( diff != 0 ) { ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; goto cleanup; } } else if( mode == MBEDTLS_KW_MODE_KWP ) { size_t padlen = 0; uint32_t Plen; /* * According to SP 800-38F Table 1, the ciphertext length for KWP * must be between 2 to 2^29 semiblocks inclusive. */ if( in_len < KW_SEMIBLOCK_LENGTH * 2 || #if SIZE_MAX > 0x100000000 in_len > 0x100000000 || #endif in_len % KW_SEMIBLOCK_LENGTH != 0 ) { return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } if( in_len == KW_SEMIBLOCK_LENGTH * 2 ) { unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2]; ret = mbedtls_cipher_update( &ctx->cipher_ctx, input, 16, outbuff, &olen ); if( ret != 0 ) goto cleanup; memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH ); memcpy( output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH ); mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) ); *out_len = KW_SEMIBLOCK_LENGTH; } else { /* in_len >= KW_SEMIBLOCK_LENGTH * 3 */ ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH, A, output, out_len ); if( ret != 0 ) goto cleanup; } /* Check ICV in "constant-time" */ diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 ); if( diff != 0 ) { ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; } GET_UINT32_BE( Plen, A, KW_SEMIBLOCK_LENGTH / 2 ); /* * Plen is the length of the plaintext, when the input is valid. * If Plen is larger than the plaintext and padding, padlen will be * larger than 8, because of the type wrap around. */ padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen; if ( padlen > 7 ) { padlen &= 7; ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; } /* Check padding in "constant-time" */ for( diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++ ) { if( i >= KW_SEMIBLOCK_LENGTH - padlen ) diff |= output[*out_len - KW_SEMIBLOCK_LENGTH + i]; else bad_padding |= output[*out_len - KW_SEMIBLOCK_LENGTH + i]; } if( diff != 0 ) { ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; } if( ret != 0 ) { goto cleanup; } memset( output + Plen, 0, padlen ); *out_len = Plen; } else { ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; goto cleanup; } cleanup: if( ret != 0 ) { memset( output, 0, *out_len ); *out_len = 0; } mbedtls_platform_zeroize( &bad_padding, sizeof( bad_padding) ); mbedtls_platform_zeroize( &diff, sizeof( diff ) ); mbedtls_platform_zeroize( A, sizeof( A ) ); return( ret ); }
/* * KW-AE as defined in SP 800-38F section 6.2 * KWP-AE as defined in SP 800-38F section 6.3 */ int mbedtls_nist_kw_wrap( mbedtls_nist_kw_context *ctx, mbedtls_nist_kw_mode_t mode, const unsigned char *input, size_t in_len, unsigned char *output, size_t *out_len, size_t out_size ) { int ret = 0; size_t semiblocks = 0; size_t s; size_t olen, padlen = 0; uint64_t t = 0; unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2]; unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2]; unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH; unsigned char *A = output; *out_len = 0; /* * Generate the String to work on */ if( mode == MBEDTLS_KW_MODE_KW ) { if( out_size < in_len + KW_SEMIBLOCK_LENGTH ) { return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } /* * According to SP 800-38F Table 1, the plaintext length for KW * must be between 2 to 2^54-1 semiblocks inclusive. */ if( in_len < 16 || #if SIZE_MAX > 0x1FFFFFFFFFFFFF8 in_len > 0x1FFFFFFFFFFFFF8 || #endif in_len % KW_SEMIBLOCK_LENGTH != 0 ) { return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } memcpy( output, NIST_KW_ICV1, KW_SEMIBLOCK_LENGTH ); memmove( output + KW_SEMIBLOCK_LENGTH, input, in_len ); } else { if( in_len % 8 != 0 ) { padlen = ( 8 - ( in_len % 8 ) ); } if( out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen ) { return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } /* * According to SP 800-38F Table 1, the plaintext length for KWP * must be between 1 and 2^32-1 octets inclusive. */ if( in_len < 1 #if SIZE_MAX > 0xFFFFFFFF || in_len > 0xFFFFFFFF #endif ) { return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); } memcpy( output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2 ); PUT_UINT32_BE( ( in_len & 0xffffffff ), output, KW_SEMIBLOCK_LENGTH / 2 ); memcpy( output + KW_SEMIBLOCK_LENGTH, input, in_len ); memset( output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen ); } semiblocks = ( ( in_len + padlen ) / KW_SEMIBLOCK_LENGTH ) + 1; s = 6 * ( semiblocks - 1 ); if( mode == MBEDTLS_KW_MODE_KWP && in_len <= KW_SEMIBLOCK_LENGTH ) { memcpy( inbuff, output, 16 ); ret = mbedtls_cipher_update( &ctx->cipher_ctx, inbuff, 16, output, &olen ); if( ret != 0 ) goto cleanup; } else { /* * Do the wrapping function W, as defined in RFC 3394 section 2.2.1 */ if( semiblocks < MIN_SEMIBLOCKS_COUNT ) { ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; goto cleanup; } /* Calculate intermediate values */ for( t = 1; t <= s; t++ ) { memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH ); memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH ); ret = mbedtls_cipher_update( &ctx->cipher_ctx, inbuff, 16, outbuff, &olen ); if( ret != 0 ) goto cleanup; memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH ); calc_a_xor_t( A, t ); memcpy( R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH ); R2 += KW_SEMIBLOCK_LENGTH; if( R2 >= output + ( semiblocks * KW_SEMIBLOCK_LENGTH ) ) R2 = output + KW_SEMIBLOCK_LENGTH; } } *out_len = semiblocks * KW_SEMIBLOCK_LENGTH; cleanup: if( ret != 0) { memset( output, 0, semiblocks * KW_SEMIBLOCK_LENGTH ); } mbedtls_platform_zeroize( inbuff, KW_SEMIBLOCK_LENGTH * 2 ); mbedtls_platform_zeroize( outbuff, KW_SEMIBLOCK_LENGTH * 2 ); return( ret ); }
/* * Free context */ void mbedtls_nist_kw_free( mbedtls_nist_kw_context *ctx ) { mbedtls_cipher_free( &ctx->cipher_ctx ); mbedtls_platform_zeroize( ctx, sizeof( mbedtls_nist_kw_context ) ); }