added random generator and ecdsa test

This commit is contained in:
merlokk 2018-11-02 19:41:34 +02:00
commit 17d042747b
5 changed files with 1225 additions and 0 deletions

View file

@ -6,6 +6,7 @@ mbedtls_SOURCES = \
asn1write.c \
base64.c \
bignum.c \
ctr_drbg.c \
ecp.c \
ecp_curves.c \
certs.c \

652
common/mbedtls/ctr_drbg.c Normal file
View file

@ -0,0 +1,652 @@
/*
* CTR_DRBG implementation based on AES-256 (NIST SP 800-90)
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: GPL-2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The NIST SP 800-90 DRBGs are described in the following publication.
*
* http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_CTR_DRBG_C)
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/platform_util.h"
#include <string.h>
#if defined(MBEDTLS_FS_IO)
#include <stdio.h>
#endif
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
/*
* CTR_DRBG context initialization
*/
void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) );
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_init( &ctx->mutex );
#endif
}
/*
* Non-public function wrapped by mbedtls_ctr_drbg_seed(). Necessary to allow
* NIST tests to succeed (which require known length fixed entropy)
*/
int mbedtls_ctr_drbg_seed_entropy_len(
mbedtls_ctr_drbg_context *ctx,
int (*f_entropy)(void *, unsigned char *, size_t),
void *p_entropy,
const unsigned char *custom,
size_t len,
size_t entropy_len )
{
int ret;
unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
mbedtls_aes_init( &ctx->aes_ctx );
ctx->f_entropy = f_entropy;
ctx->p_entropy = p_entropy;
ctx->entropy_len = entropy_len;
ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
/*
* Initialize with an empty key
*/
if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
{
return( ret );
}
if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 )
{
return( ret );
}
return( 0 );
}
int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
int (*f_entropy)(void *, unsigned char *, size_t),
void *p_entropy,
const unsigned char *custom,
size_t len )
{
return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy, custom, len,
MBEDTLS_CTR_DRBG_ENTROPY_LEN ) );
}
void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
{
if( ctx == NULL )
return;
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_free( &ctx->mutex );
#endif
mbedtls_aes_free( &ctx->aes_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) );
}
void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, int resistance )
{
ctx->prediction_resistance = resistance;
}
void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, size_t len )
{
ctx->entropy_len = len;
}
void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, int interval )
{
ctx->reseed_interval = interval;
}
static int block_cipher_df( unsigned char *output,
const unsigned char *data, size_t data_len )
{
unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16];
unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE];
unsigned char *p, *iv;
mbedtls_aes_context aes_ctx;
int ret = 0;
int i, j;
size_t buf_len, use_len;
if( data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
memset( buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16 );
mbedtls_aes_init( &aes_ctx );
/*
* Construct IV (16 bytes) and S in buffer
* IV = Counter (in 32-bits) padded to 16 with zeroes
* S = Length input string (in 32-bits) || Length of output (in 32-bits) ||
* data || 0x80
* (Total is padded to a multiple of 16-bytes with zeroes)
*/
p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE;
*p++ = ( data_len >> 24 ) & 0xff;
*p++ = ( data_len >> 16 ) & 0xff;
*p++ = ( data_len >> 8 ) & 0xff;
*p++ = ( data_len ) & 0xff;
p += 3;
*p++ = MBEDTLS_CTR_DRBG_SEEDLEN;
memcpy( p, data, data_len );
p[data_len] = 0x80;
buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1;
for( i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++ )
key[i] = i;
if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
{
goto exit;
}
/*
* Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data
*/
for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
{
p = buf;
memset( chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE );
use_len = buf_len;
while( use_len > 0 )
{
for( i = 0; i < MBEDTLS_CTR_DRBG_BLOCKSIZE; i++ )
chain[i] ^= p[i];
p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
use_len -= ( use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE ) ?
MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len;
if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, chain, chain ) ) != 0 )
{
goto exit;
}
}
memcpy( tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE );
/*
* Update IV
*/
buf[3]++;
}
/*
* Do final encryption with reduced data
*/
if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
{
goto exit;
}
iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE;
p = output;
for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
{
if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, iv, iv ) ) != 0 )
{
goto exit;
}
memcpy( p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE );
p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
}
exit:
mbedtls_aes_free( &aes_ctx );
/*
* tidy up the stack
*/
mbedtls_platform_zeroize( buf, sizeof( buf ) );
mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
mbedtls_platform_zeroize( key, sizeof( key ) );
mbedtls_platform_zeroize( chain, sizeof( chain ) );
if( 0 != ret )
{
/*
* wipe partial seed from memory
*/
mbedtls_platform_zeroize( output, MBEDTLS_CTR_DRBG_SEEDLEN );
}
return( ret );
}
static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx,
const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] )
{
unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
unsigned char *p = tmp;
int i, j;
int ret = 0;
memset( tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN );
for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
{
/*
* Increase counter
*/
for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- )
if( ++ctx->counter[i - 1] != 0 )
break;
/*
* Crypt counter block
*/
if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, p ) ) != 0 )
{
return( ret );
}
p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
}
for( i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++ )
tmp[i] ^= data[i];
/*
* Update key and counter
*/
if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
{
return( ret );
}
memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, MBEDTLS_CTR_DRBG_BLOCKSIZE );
return( 0 );
}
void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional, size_t add_len )
{
unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
if( add_len > 0 )
{
/* MAX_INPUT would be more logical here, but we have to match
* block_cipher_df()'s limits since we can't propagate errors */
if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT;
block_cipher_df( add_input, additional, add_len );
ctr_drbg_update_internal( ctx, add_input );
}
}
int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional, size_t len )
{
unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
size_t seedlen = 0;
int ret;
if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ||
len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT );
/*
* Gather entropy_len bytes of entropy to seed state
*/
if( 0 != ctx->f_entropy( ctx->p_entropy, seed,
ctx->entropy_len ) )
{
return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
}
seedlen += ctx->entropy_len;
/*
* Add additional data
*/
if( additional && len )
{
memcpy( seed + seedlen, additional, len );
seedlen += len;
}
/*
* Reduce to 384 bits
*/
if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 )
{
return( ret );
}
/*
* Update state
*/
if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 )
{
return( ret );
}
ctx->reseed_counter = 1;
return( 0 );
}
int mbedtls_ctr_drbg_random_with_add( void *p_rng,
unsigned char *output, size_t output_len,
const unsigned char *additional, size_t add_len )
{
int ret = 0;
mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
unsigned char *p = output;
unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE];
int i;
size_t use_len;
if( output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST )
return( MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG );
if( add_len > MBEDTLS_CTR_DRBG_MAX_INPUT )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
memset( add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN );
if( ctx->reseed_counter > ctx->reseed_interval ||
ctx->prediction_resistance )
{
if( ( ret = mbedtls_ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 )
{
return( ret );
}
add_len = 0;
}
if( add_len > 0 )
{
if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 )
{
return( ret );
}
if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
{
return( ret );
}
}
while( output_len > 0 )
{
/*
* Increase counter
*/
for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- )
if( ++ctx->counter[i - 1] != 0 )
break;
/*
* Crypt counter block
*/
if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, tmp ) ) != 0 )
{
return( ret );
}
use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? MBEDTLS_CTR_DRBG_BLOCKSIZE :
output_len;
/*
* Copy random block to destination
*/
memcpy( p, tmp, use_len );
p += use_len;
output_len -= use_len;
}
if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
{
return( ret );
}
ctx->reseed_counter++;
return( 0 );
}
int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len )
{
int ret;
mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
#if defined(MBEDTLS_THREADING_C)
if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
return( ret );
#endif
ret = mbedtls_ctr_drbg_random_with_add( ctx, output, output_len, NULL, 0 );
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif
return( ret );
}
#if defined(MBEDTLS_FS_IO)
int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path )
{
int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
FILE *f;
unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ];
if( ( f = fopen( path, "wb" ) ) == NULL )
return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR );
if( ( ret = mbedtls_ctr_drbg_random( ctx, buf, MBEDTLS_CTR_DRBG_MAX_INPUT ) ) != 0 )
goto exit;
if( fwrite( buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f ) != MBEDTLS_CTR_DRBG_MAX_INPUT )
ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
else
ret = 0;
exit:
mbedtls_platform_zeroize( buf, sizeof( buf ) );
fclose( f );
return( ret );
}
int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path )
{
int ret = 0;
FILE *f;
size_t n;
unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ];
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR );
fseek( f, 0, SEEK_END );
n = (size_t) ftell( f );
fseek( f, 0, SEEK_SET );
if( n > MBEDTLS_CTR_DRBG_MAX_INPUT )
{
fclose( f );
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
}
if( fread( buf, 1, n, f ) != n )
ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
else
mbedtls_ctr_drbg_update( ctx, buf, n );
fclose( f );
mbedtls_platform_zeroize( buf, sizeof( buf ) );
if( ret != 0 )
return( ret );
return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) );
}
#endif /* MBEDTLS_FS_IO */
#if defined(MBEDTLS_SELF_TEST)
static const unsigned char entropy_source_pr[96] =
{ 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16,
0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02,
0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b,
0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb,
0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9,
0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95,
0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63,
0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3,
0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31,
0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4,
0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56,
0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 };
static const unsigned char entropy_source_nopr[64] =
{ 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14,
0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe,
0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d,
0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20,
0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9,
0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46,
0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e,
0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e };
static const unsigned char nonce_pers_pr[16] =
{ 0xd2, 0x54, 0xfc, 0xff, 0x02, 0x1e, 0x69, 0xd2,
0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c };
static const unsigned char nonce_pers_nopr[16] =
{ 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5,
0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f };
static const unsigned char result_pr[16] =
{ 0x34, 0x01, 0x16, 0x56, 0xb4, 0x29, 0x00, 0x8f,
0x35, 0x63, 0xec, 0xb5, 0xf2, 0x59, 0x07, 0x23 };
static const unsigned char result_nopr[16] =
{ 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88,
0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f };
static size_t test_offset;
static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf,
size_t len )
{
const unsigned char *p = data;
memcpy( buf, p + test_offset, len );
test_offset += len;
return( 0 );
}
#define CHK( c ) if( (c) != 0 ) \
{ \
if( verbose != 0 ) \
mbedtls_printf( "failed\n" ); \
return( 1 ); \
}
/*
* Checkup routine
*/
int mbedtls_ctr_drbg_self_test( int verbose )
{
mbedtls_ctr_drbg_context ctx;
unsigned char buf[16];
mbedtls_ctr_drbg_init( &ctx );
/*
* Based on a NIST CTR_DRBG test vector (PR = True)
*/
if( verbose != 0 )
mbedtls_printf( " CTR_DRBG (PR = TRUE) : " );
test_offset = 0;
CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
(void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) );
mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
CHK( memcmp( buf, result_pr, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
mbedtls_ctr_drbg_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
/*
* Based on a NIST CTR_DRBG test vector (PR = FALSE)
*/
if( verbose != 0 )
mbedtls_printf( " CTR_DRBG (PR = FALSE): " );
mbedtls_ctr_drbg_init( &ctx );
test_offset = 0;
CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
(void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
CHK( memcmp( buf, result_nopr, 16 ) );
mbedtls_ctr_drbg_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_CTR_DRBG_C */

332
common/mbedtls/ctr_drbg.h Normal file
View file

@ -0,0 +1,332 @@
/**
* \file ctr_drbg.h
*
* \brief This file contains CTR_DRBG definitions and functions.
*
* CTR_DRBG is a standardized way of building a PRNG from a block-cipher
* in counter mode operation, as defined in <em>NIST SP 800-90A:
* Recommendation for Random Number Generation Using Deterministic Random
* Bit Generators</em>.
*
* The Mbed TLS implementation of CTR_DRBG uses AES-256 as the underlying
* block cipher.
*/
/*
* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved
* SPDX-License-Identifier: GPL-2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_CTR_DRBG_H
#define MBEDTLS_CTR_DRBG_H
#include "aes.h"
#if defined(MBEDTLS_THREADING_C)
#include "threading.h"
#endif
#define MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED -0x0034 /**< The entropy source failed. */
#define MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 /**< The requested random buffer length is too big. */
#define MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /**< The input (entropy + additional data) is too large. */
#define MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read or write error in file. */
#define MBEDTLS_CTR_DRBG_BLOCKSIZE 16 /**< The block size used by the cipher. */
#define MBEDTLS_CTR_DRBG_KEYSIZE 32 /**< The key size used by the cipher. */
#define MBEDTLS_CTR_DRBG_KEYBITS ( MBEDTLS_CTR_DRBG_KEYSIZE * 8 ) /**< The key size for the DRBG operation, in bits. */
#define MBEDTLS_CTR_DRBG_SEEDLEN ( MBEDTLS_CTR_DRBG_KEYSIZE + MBEDTLS_CTR_DRBG_BLOCKSIZE ) /**< The seed length, calculated as (counter + AES key). */
/**
* \name SECTION: Module settings
*
* The configuration options you can set for this module are in this section.
* Either change them in config.h or define them using the compiler command
* line.
* \{
*/
#if !defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN)
#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256)
#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48
/**< The amount of entropy used per seed by default:
* <ul><li>48 with SHA-512.</li>
* <li>32 with SHA-256.</li></ul>
*/
#else
#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 32
/**< Amount of entropy used per seed by default:
* <ul><li>48 with SHA-512.</li>
* <li>32 with SHA-256.</li></ul>
*/
#endif
#endif
#if !defined(MBEDTLS_CTR_DRBG_RESEED_INTERVAL)
#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000
/**< The interval before reseed is performed by default. */
#endif
#if !defined(MBEDTLS_CTR_DRBG_MAX_INPUT)
#define MBEDTLS_CTR_DRBG_MAX_INPUT 256
/**< The maximum number of additional input Bytes. */
#endif
#if !defined(MBEDTLS_CTR_DRBG_MAX_REQUEST)
#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024
/**< The maximum number of requested Bytes per call. */
#endif
#if !defined(MBEDTLS_CTR_DRBG_MAX_SEED_INPUT)
#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384
/**< The maximum size of seed or reseed buffer. */
#endif
/* \} name SECTION: Module settings */
#define MBEDTLS_CTR_DRBG_PR_OFF 0
/**< Prediction resistance is disabled. */
#define MBEDTLS_CTR_DRBG_PR_ON 1
/**< Prediction resistance is enabled. */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief The CTR_DRBG context structure.
*/
typedef struct mbedtls_ctr_drbg_context
{
unsigned char counter[16]; /*!< The counter (V). */
int reseed_counter; /*!< The reseed counter. */
int prediction_resistance; /*!< This determines whether prediction
resistance is enabled, that is
whether to systematically reseed before
each random generation. */
size_t entropy_len; /*!< The amount of entropy grabbed on each
seed or reseed operation. */
int reseed_interval; /*!< The reseed interval. */
mbedtls_aes_context aes_ctx; /*!< The AES context. */
/*
* Callbacks (Entropy)
*/
int (*f_entropy)(void *, unsigned char *, size_t);
/*!< The entropy callback function. */
void *p_entropy; /*!< The context for the entropy function. */
#if defined(MBEDTLS_THREADING_C)
mbedtls_threading_mutex_t mutex;
#endif
}
mbedtls_ctr_drbg_context;
/**
* \brief This function initializes the CTR_DRBG context,
* and prepares it for mbedtls_ctr_drbg_seed()
* or mbedtls_ctr_drbg_free().
*
* \param ctx The CTR_DRBG context to initialize.
*/
void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );
/**
* \brief This function seeds and sets up the CTR_DRBG
* entropy source for future reseeds.
*
* \note Personalization data can be provided in addition to the more generic
* entropy source, to make this instantiation as unique as possible.
*
* \param ctx The CTR_DRBG context to seed.
* \param f_entropy The entropy callback, taking as arguments the
* \p p_entropy context, the buffer to fill, and the
length of the buffer.
* \param p_entropy The entropy context.
* \param custom Personalization data, that is device-specific
identifiers. Can be NULL.
* \param len The length of the personalization data.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure.
*/
int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
int (*f_entropy)(void *, unsigned char *, size_t),
void *p_entropy,
const unsigned char *custom,
size_t len );
/**
* \brief This function clears CTR_CRBG context data.
*
* \param ctx The CTR_DRBG context to clear.
*/
void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx );
/**
* \brief This function turns prediction resistance on or off.
* The default value is off.
*
* \note If enabled, entropy is gathered at the beginning of
* every call to mbedtls_ctr_drbg_random_with_add().
* Only use this if your entropy source has sufficient
* throughput.
*
* \param ctx The CTR_DRBG context.
* \param resistance #MBEDTLS_CTR_DRBG_PR_ON or #MBEDTLS_CTR_DRBG_PR_OFF.
*/
void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx,
int resistance );
/**
* \brief This function sets the amount of entropy grabbed on each
* seed or reseed. The default value is
* #MBEDTLS_CTR_DRBG_ENTROPY_LEN.
*
* \param ctx The CTR_DRBG context.
* \param len The amount of entropy to grab.
*/
void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx,
size_t len );
/**
* \brief This function sets the reseed interval.
* The default value is #MBEDTLS_CTR_DRBG_RESEED_INTERVAL.
*
* \param ctx The CTR_DRBG context.
* \param interval The reseed interval.
*/
void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx,
int interval );
/**
* \brief This function reseeds the CTR_DRBG context, that is
* extracts data from the entropy source.
*
* \param ctx The CTR_DRBG context.
* \param additional Additional data to add to the state. Can be NULL.
* \param len The length of the additional data.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure.
*/
int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional, size_t len );
/**
* \brief This function updates the state of the CTR_DRBG context.
*
* \note If \p add_len is greater than
* #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, only the first
* #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT Bytes are used.
* The remaining Bytes are silently discarded.
*
* \param ctx The CTR_DRBG context.
* \param additional The data to update the state with.
* \param add_len Length of \p additional data.
*
*/
void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional, size_t add_len );
/**
* \brief This function updates a CTR_DRBG instance with additional
* data and uses it to generate random data.
*
* \note The function automatically reseeds if the reseed counter is exceeded.
*
* \param p_rng The CTR_DRBG context. This must be a pointer to a
* #mbedtls_ctr_drbg_context structure.
* \param output The buffer to fill.
* \param output_len The length of the buffer.
* \param additional Additional data to update. Can be NULL.
* \param add_len The length of the additional data.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or
* #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure.
*/
int mbedtls_ctr_drbg_random_with_add( void *p_rng,
unsigned char *output, size_t output_len,
const unsigned char *additional, size_t add_len );
/**
* \brief This function uses CTR_DRBG to generate random data.
*
* \note The function automatically reseeds if the reseed counter is exceeded.
*
* \param p_rng The CTR_DRBG context. This must be a pointer to a
* #mbedtls_ctr_drbg_context structure.
* \param output The buffer to fill.
* \param output_len The length of the buffer.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or
* #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure.
*/
int mbedtls_ctr_drbg_random( void *p_rng,
unsigned char *output, size_t output_len );
#if defined(MBEDTLS_FS_IO)
/**
* \brief This function writes a seed file.
*
* \param ctx The CTR_DRBG context.
* \param path The name of the file.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error.
* \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on
* failure.
*/
int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path );
/**
* \brief This function reads and updates a seed file. The seed
* is added to this instance.
*
* \param ctx The CTR_DRBG context.
* \param path The name of the file.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error.
* \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or
* #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG on failure.
*/
int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path );
#endif /* MBEDTLS_FS_IO */
/**
* \brief The CTR_DRBG checkup routine.
*
* \return \c 0 on success.
* \return \c 1 on failure.
*/
int mbedtls_ctr_drbg_self_test( int verbose );
/* Internal functions (do not call directly) */
int mbedtls_ctr_drbg_seed_entropy_len( mbedtls_ctr_drbg_context *,
int (*)(void *, unsigned char *, size_t), void *,
const unsigned char *, size_t, size_t );
#ifdef __cplusplus
}
#endif
#endif /* ctr_drbg.h */

View file

@ -10,9 +10,16 @@
//-----------------------------------------------------------------------------
#include "polarssl/libpcrypto.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <mbedtls/aes.h>
#include <mbedtls/cmac.h>
#include <mbedtls/ecdsa.h>
#include <mbedtls/sha256.h>
#include "mbedtls/ctr_drbg.h"
//test!!!
#include <util.h>
// NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001.
int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){
@ -69,3 +76,234 @@ int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int lengt
return 0;
}
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
/**
* This function just returns data from rand().
* Although predictable and often similar on multiple
* runs, this does not result in identical random on
* each run. So do not use this if the results of a
* test depend on the random data that is generated.
*
* rng_state shall be NULL.
*/
static int rnd_std_rand( void *rng_state, unsigned char *output, size_t len )
{
#if !defined(__OpenBSD__)
size_t i;
if( rng_state != NULL )
rng_state = NULL;
for( i = 0; i < len; ++i )
output[i] = rand();
#else
if( rng_state != NULL )
rng_state = NULL;
arc4random_buf( output, len );
#endif /* !OpenBSD */
return( 0 );
}
/**
* This function only returns zeros
*
* rng_state shall be NULL.
*/
static int rnd_zero_rand( void *rng_state, unsigned char *output, size_t len )
{
if( rng_state != NULL )
rng_state = NULL;
memset( output, 0, len );
return( 0 );
}
typedef struct
{
unsigned char *buf;
size_t length;
} rnd_buf_info;
/**
* This function returns random based on a buffer it receives.
*
* rng_state shall be a pointer to a rnd_buf_info structure.
*
* The number of bytes released from the buffer on each call to
* the random function is specified by per_call. (Can be between
* 1 and 4)
*
* After the buffer is empty it will return rand();
*/
static int rnd_buffer_rand( void *rng_state, unsigned char *output, size_t len )
{
rnd_buf_info *info = (rnd_buf_info *) rng_state;
size_t use_len;
if( rng_state == NULL )
return( rnd_std_rand( NULL, output, len ) );
use_len = len;
if( len > info->length )
use_len = info->length;
if( use_len )
{
memcpy( output, info->buf, use_len );
info->buf += use_len;
info->length -= use_len;
}
if( len - use_len > 0 )
return( rnd_std_rand( NULL, output + use_len, len - use_len ) );
printf("rnd[%d] %s\n", len, sprint_hex_inrow(output, len));
return( 0 );
}
/**
* Info structure for the pseudo random function
*
* Key should be set at the start to a test-unique value.
* Do not forget endianness!
* State( v0, v1 ) should be set to zero.
*/
typedef struct
{
uint32_t key[16];
uint32_t v0, v1;
} rnd_pseudo_info;
/**
* This function returns random based on a pseudo random function.
* This means the results should be identical on all systems.
* Pseudo random is based on the XTEA encryption algorithm to
* generate pseudorandom.
*
* rng_state shall be a pointer to a rnd_pseudo_info structure.
*/
static int rnd_pseudo_rand( void *rng_state, unsigned char *output, size_t len )
{
rnd_pseudo_info *info = (rnd_pseudo_info *) rng_state;
uint32_t i, *k, sum, delta=0x9E3779B9;
unsigned char result[4], *out = output;
if( rng_state == NULL )
return( rnd_std_rand( NULL, output, len ) );
k = info->key;
while( len > 0 )
{
size_t use_len = ( len > 4 ) ? 4 : len;
sum = 0;
for( i = 0; i < 32; i++ )
{
info->v0 += ( ( ( info->v1 << 4 ) ^ ( info->v1 >> 5 ) )
+ info->v1 ) ^ ( sum + k[sum & 3] );
sum += delta;
info->v1 += ( ( ( info->v0 << 4 ) ^ ( info->v0 >> 5 ) )
+ info->v0 ) ^ ( sum + k[( sum>>11 ) & 3] );
}
PUT_UINT32_BE( info->v0, result, 0 );
memcpy( out, result, use_len );
len -= use_len;
out += 4;
}
return( 0 );
}
#define T_PRIVATE_KEY "C477F9F65C22CCE20657FAA5B2D1D8122336F851A508A1ED04E479C34985BF96"
#define T_Q_X "B7E08AFDFE94BAD3F1DC8C734798BA1C62B3A0AD1E9EA2A38201CD0889BC7A19"
#define T_Q_Y "3603F747959DBF7A4BB226E41928729063ADC7AE43529E61B563BBC606CC5E09"
#define T_K "7A1A7E52797FC8CAAA435D2A4DACE39158504BF204FBE19F14DBB427FAEE50AE"
#define T_R "2B42F576D07F4165FF65D1F3B1500F81E44C316F1F0B3EF57325B69ACA46104F"
#define T_S "DC42C2122D6392CD3E3A993A89502A8198C1886FE69D262C4B329BDB6B63FAF1"
static int fixed_rand( void *rng_state, unsigned char *output, size_t len ) {
memset(output, 0x00, len);
if (len <= 32) {
uint8_t rnd[33] = {0};
int rndlen = 0;
param_gethex_to_eol(T_K, 0, rnd, sizeof(rnd), &rndlen);
memcpy(output, rnd, len);
}
return 0;
}
int ecdsa_signature_verify(uint8_t *key_xy, uint8_t *input, uint8_t *mac, int length) {
int ret;
uint8_t shahash[32] = {0}; // SHA-256
mbedtls_sha256_context sctx;
mbedtls_sha256_init(&sctx);
mbedtls_sha256_starts(&sctx, 0); // SHA-256, not 224
mbedtls_sha256_update(&sctx, input, length);
mbedtls_sha256_finish(&sctx, shahash);
mbedtls_sha256_free(&sctx);
printf("hash: %s\n", sprint_hex(shahash, sizeof(shahash)));
int res;
mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx);
// secp256r1
mbedtls_ecp_group_load(&ctx.grp, MBEDTLS_ECP_DP_SECP256R1);
mbedtls_mpi_read_string(&ctx.d, 16, T_PRIVATE_KEY);
mbedtls_ecp_point_read_string(&ctx.Q, 16, T_Q_X, T_Q_Y);
// mbedtls_ctr_drbg_context ctr_drbg;
// mbedtls_ctr_drbg_init(&ctr_drbg);
// init keys
uint8_t buf[257] = {0};
size_t buflen = 0;
mbedtls_mpi_write_string(&ctx.d, 16, (char *)buf, sizeof(buf), &buflen);
printf("prvkey[%d]: %s\n", buflen, buf);
mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED,
&buflen, buf, sizeof(buf));
printf("pubkey[%d]: %s\n", buflen, sprint_hex_inrow(buf, buflen));
// make signature
uint8_t signature[300] = {0};
size_t siglen = 0;
res = mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, shahash, sizeof(shahash), signature, &siglen, fixed_rand, NULL);
printf("res: %x signature[%x]: %s\n", (res<0)?-res:res, siglen, sprint_hex(signature, siglen));
// check vectors
// verify signature
res = mbedtls_ecdsa_read_signature(&ctx, shahash, sizeof(shahash), signature, siglen);
printf("signature check res: %x\n", (res<0)?-res:res);
// verify wrong signature
shahash[0] ^= 0xFF;
res = mbedtls_ecdsa_read_signature(&ctx, shahash, sizeof(shahash), signature, siglen);
printf("wrong signature check res: %x\n", (res<0)?-res:res);
ret = 1;
goto exit;
exit:
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_ecdsa_free(&ctx);
return ret;
}

View file

@ -19,4 +19,6 @@ extern int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output
extern int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length);
extern int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length);
extern int ecdsa_signature_verify(uint8_t *key_xy, uint8_t *input, uint8_t *mac, int length);
#endif /* libpcrypto.h */