From 2eb678f5e822ac7160479ad7c35eee00360d2d04 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Mon, 13 Jan 2020 16:44:13 +0200 Subject: [PATCH 1/5] Update AES SCA countermeasures -Add dummy rounds to the start and/or end of the AES calculation rounds. --- library/aes.c | 259 +++++++++++++++++++++++++++++--------------------- 1 file changed, 152 insertions(+), 107 deletions(-) diff --git a/library/aes.c b/library/aes.c index c96f29e31..ece7a82d2 100644 --- a/library/aes.c +++ b/library/aes.c @@ -95,7 +95,7 @@ typedef struct { #if defined(MBEDTLS_AES_SCA_COUNTERMEASURES) /* Number of additional AES calculation rounds added for SCA CM */ -#define AES_SCA_CM_ROUNDS 3 +#define AES_SCA_CM_ROUNDS 4 #else /* MBEDTLS_AES_SCA_COUNTERMEASURES */ #define AES_SCA_CM_ROUNDS 0 #endif /* MBEDTLS_AES_SCA_COUNTERMEASURES */ @@ -513,97 +513,99 @@ static void aes_gen_tables( void ) #endif /* MBEDTLS_AES_ROM_TABLES */ /** - * Randomize positions when to use AES SCA countermeasures. - * Each byte indicates one AES round as follows: - * first ( tbl_len - 4 ) bytes are reserved for middle AES rounds: - * -4 high bit = table to use 0x10 for SCA CM data, 0 otherwise - * -4 low bits = offset based on order, 4 for even position, 0 otherwise - * Last 4 bytes for first(2) and final(2) round calculation - * -4 high bit = table to use, 0x10 for SCA CM data, otherwise real data - * -4 low bits = not used + * Randomize positions for AES SCA countermeasures if AES countermeasures are + * enabled. If countermeasures are not enabled then fill given table with real + * data values. + * + * Dummy rounds are added as follows: + * 1. One dummy round added to the initial round key addition (executed in + * random order). + * 2. Random number of dummy rounds added as first and/or last AES calculation + * round. Total number of dummy rounds is AES_SCA_CM_ROUNDS. + * + * Description of the bytes in the table are as follows: + * - 2 bytes for initial round key addition + * - remaining bytes for AES calculation with real or dummy data + * + * Each byte indicates one AES calculation round: + * -4 high bit = table to use 0x10 for dummy data, 0x00 real data + * -bit 2 = offset for even/odd rounds + * -bit 0-1: stop mark (0x03) to indicate calculation end * * Return Number of additional AES rounds * * Example of the control bytes: - * Control data when only real data (R) is used: - * | R | R | R | R | R | R | R | R | Start | Final | - * |0x04|0x00|0x00|0x04|0x00|0x04|0x00|0x04|0x00|0x00|0x00|0x00| + * 1. No countermeasures enabled and AES-128, only real data (R) used: + * | Ri | R | R | R | R | R | R | R | R | R | R | + * |0x03|0x04|0x00|0x04|0x00|0x04|0x00|0x04|0x00|0x07|0x03| * - * Control data with 5 (F) dummy rounds and randomized start and final round: - * | R | F | R | F | F | R | R | R | R | R | R | START RF| FINAL FR| - * |0x04|0x10|0x04|0x10|0x10|0x00|0x04|0x00|0x04|0x00|0x04|0x00|0x10|0x10|0x00| + * 2. Countermeasures enabled, 3 (F) dummy rounds in start and 1 at end: + * | Fi | Ri | F | F | F | R | R | ... | R | R | R | R | F | + * |0x10|0x03 |0x10|0x10|0x10|0x04|0x00| ... |0x04|0x00|0x04|0x03|0x07| */ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) { - int i, is_even_pos; + int i = 0, j = 0, is_even_pos; #if AES_SCA_CM_ROUNDS != 0 - int is_unique_number; int num; #endif mbedtls_platform_memset( tbl, 0, tbl_len ); #if AES_SCA_CM_ROUNDS != 0 - // Randomize SCA CM positions to tbl - for( i = 0; i < AES_SCA_CM_ROUNDS; i++ ) + num = mbedtls_platform_random_in_range( 0x1f ); + + // Randomize execution order of initial round key addition + if ( ( num & 0x10 ) == 0 ) { - is_unique_number = 0; - do - { - is_unique_number++; - num = mbedtls_platform_random_in_range( tbl_len - 4 ); - - if( is_unique_number > 10 ) - { - // prevent forever loop if random returns constant - is_unique_number = 0; - tbl[i] = 0x10; // fake data - } - - if( tbl[num] == 0 ) - { - is_unique_number = 0; - tbl[num] = 0x10; // fake data - } - } while( is_unique_number != 0 ); + tbl[i++] = 0x10; // dummy data + tbl[i++] = 0x00 | 0x03; // real data + stop marker + } else { + tbl[i++] = 0x00; // real data + tbl[i++] = 0x10 | 0x03; // dummy data + stop marker } - // randomize control data for start and final round - for( i = 1; i <= 2; i++ ) + // Randomize AES rounds + num = num % ( AES_SCA_CM_ROUNDS + 1 ); + + // add dummy rounds to the start (if needed) + for ( ; i < num + 2; i++ ) { - num = mbedtls_platform_random_in_range( 0xff ); - if( ( num % 2 ) == 0 ) - { - tbl[tbl_len - ( i * 2 - 0 )] = 0x10; // fake data - tbl[tbl_len - ( i * 2 - 1 )] = 0x00; // real data - } - else - { - tbl[tbl_len - ( i * 2 - 0 )] = 0x00; // real data - tbl[tbl_len - ( i * 2 - 1 )] = 0x10; // fake data - } + tbl[i] = 0x10; // dummy data } + + // add dummy rounds to the last, (AES_SCA_CM_ROUNDS - num) rounds if needed + for ( j = tbl_len - AES_SCA_CM_ROUNDS + num; j < tbl_len; j++ ) + { + tbl[j] = 0x10; // dummy data + } +#else /* AES_SCA_CM_ROUNDS != 0 */ + tbl[i++] = 0x03; // real data + stop marker for the round key addition #endif /* AES_SCA_CM_ROUNDS != 0 */ - // Fill real AES round data to the remaining places + // Fill real AES data to the remaining places is_even_pos = 1; - for( i = 0; i < tbl_len - 4; i++ ) + for( ; i < tbl_len; i++ ) { if( tbl[i] == 0 ) { if( is_even_pos == 1 ) { - tbl[i] = 0x04; // real data, offset 4 + tbl[i] = 0x04; // real data, offset for rounds 1,3,5, etc... is_even_pos = 0; } else { - tbl[i] = 0x00; // real data, offset 0 + tbl[i] = 0x00; // real data, offset for rounds 2,4,6,... is_even_pos = 1; } + j = i; // remember the final round position in table } } + tbl[( tbl_len - 1)] |= 0x03; // Stop marker for the last item in tbl + tbl[( j - 1 )] |= 0x03; // stop marker for final - 1 real data + return( AES_SCA_CM_ROUNDS ); } @@ -1051,30 +1053,31 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) { - int i, j, offset, start_fin_loops = 1; + int i, tindex, offset, stop_mark; aes_r_data_t aes_data_real; // real data #if AES_SCA_CM_ROUNDS != 0 aes_r_data_t aes_data_fake; // fake data #endif /* AES_SCA_CM_ROUNDS != 0 */ - aes_r_data_t *aes_data_ptr; // pointer to aes_data_real or aes_data_fake + aes_r_data_t *aes_data_ptr; // pointer to real or fake data aes_r_data_t *aes_data_table[2]; // pointers to real and fake data - int round_ctrl_table_len = ctx->nr - 1 + AES_SCA_CM_ROUNDS + 2 + 2; + int round_ctrl_table_len = ctx->nr + 1; volatile int flow_control; - // control bytes for AES rounds, reserve based on max ctx->nr - uint8_t round_ctrl_table[ 14 - 1 + AES_SCA_CM_ROUNDS + 2 + 2]; + // control bytes for AES calculation rounds, + // reserve based on max rounds + dummy rounds + 2 (for initial key addition) + uint8_t round_ctrl_table[( 14 + AES_SCA_CM_ROUNDS + 2 )]; aes_data_real.rk_ptr = ctx->rk; aes_data_table[0] = &aes_data_real; #if AES_SCA_CM_ROUNDS != 0 + round_ctrl_table_len += ( AES_SCA_CM_ROUNDS + 1 ); aes_data_table[1] = &aes_data_fake; aes_data_fake.rk_ptr = ctx->rk; - start_fin_loops = 2; for( i = 0; i < 4; i++ ) aes_data_fake.xy_values[i] = mbedtls_platform_random_in_range( 0xffffffff ); #endif - // Get randomized AES calculation control bytes + // Get AES calculation control bytes flow_control = aes_sca_cm_data_randomize( round_ctrl_table, round_ctrl_table_len ); @@ -1091,22 +1094,29 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, GET_UINT32_LE( aes_data_real.xy_values[i], input, ( i * 4 ) ); } - for( i = 0; i < 4; i++ ) + tindex = 0; + do { - for( j = 0; j < start_fin_loops; j++ ) - { - aes_data_ptr = - aes_data_table[round_ctrl_table[ round_ctrl_table_len - 2 + j ] >> 4]; - aes_data_ptr->xy_values[i] ^= *aes_data_ptr->rk_ptr++; - flow_control++; - } - } + // Get pointer to the real or fake data + aes_data_ptr = aes_data_table[round_ctrl_table[tindex] >> 4]; + stop_mark = round_ctrl_table[tindex] & 0x03; - for( i = 0; i < ( ctx->nr - 1 + AES_SCA_CM_ROUNDS ); i++ ) + // initial round key addition + for( i = 0; i < 4; i++ ) + { + aes_data_ptr->xy_values[i] ^= *aes_data_ptr->rk_ptr++; + } + tindex++; + flow_control++; + } while( stop_mark == 0 ); + + // Calculate AES rounds (9, 11 or 13 rounds) + dummy rounds + do { - // Read AES control data - aes_data_ptr = aes_data_table[round_ctrl_table[i] >> 4]; - offset = round_ctrl_table[i] & 0x0f; + // Get pointer to the real or fake data + aes_data_ptr = aes_data_table[round_ctrl_table[tindex] >> 4]; + offset = round_ctrl_table[tindex] & 0x04; + stop_mark = round_ctrl_table[tindex] & 0x03; aes_data_ptr->rk_ptr = aes_fround( aes_data_ptr->rk_ptr, &aes_data_ptr->xy_values[0 + offset], @@ -1117,12 +1127,15 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, aes_data_ptr->xy_values[5 - offset], aes_data_ptr->xy_values[6 - offset], aes_data_ptr->xy_values[7 - offset] ); + tindex++; flow_control++; - } + } while( stop_mark == 0 ); - for( j = 0; j < start_fin_loops; j++ ) + // Calculate final AES round + dummy rounds + do { - aes_data_ptr = aes_data_table[round_ctrl_table[ i + j ] >> 4]; + aes_data_ptr = aes_data_table[round_ctrl_table[tindex] >> 4]; + stop_mark = round_ctrl_table[tindex] & 0x03; aes_fround_final( aes_data_ptr->rk_ptr, &aes_data_ptr->xy_values[0], &aes_data_ptr->xy_values[1], @@ -1133,7 +1146,8 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, aes_data_ptr->xy_values[6], aes_data_ptr->xy_values[7] ); flow_control++; - } + tindex++; + } while( stop_mark == 0 ); mbedtls_platform_memset( output, 0, 16 ); offset = mbedtls_platform_random_in_range( 4 ); @@ -1150,8 +1164,7 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, flow_control++; } - if( flow_control == ( AES_SCA_CM_ROUNDS + ( 4 * start_fin_loops ) + - ctx->nr - 1 + AES_SCA_CM_ROUNDS + start_fin_loops + 4 ) ) + if( flow_control == round_ctrl_table_len + AES_SCA_CM_ROUNDS + 4 ) { /* Validate control path due possible fault injection */ return 0; @@ -1232,50 +1245,70 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) { - int i, j, offset, start_fin_loops = 1; + int i, tindex, offset, stop_mark; aes_r_data_t aes_data_real; // real data #if AES_SCA_CM_ROUNDS != 0 aes_r_data_t aes_data_fake; // fake data #endif /* AES_SCA_CM_ROUNDS != 0 */ - aes_r_data_t *aes_data_ptr; // pointer to aes_data_real or aes_data_fake + aes_r_data_t *aes_data_ptr; // pointer to real or fake data aes_r_data_t *aes_data_table[2]; // pointers to real and fake data - int round_ctrl_table_len = ctx->nr - 1 + AES_SCA_CM_ROUNDS + 2 + 2; - // control bytes for AES rounds, reserve based on max ctx->nr + int round_ctrl_table_len = ctx->nr + 1; volatile int flow_control; - uint8_t round_ctrl_table[ 14 - 1 + AES_SCA_CM_ROUNDS + 2 + 2 ]; + // control bytes for AES calculation rounds, + // reserve based on max rounds + dummy rounds + 2 (for initial key addition) + uint8_t round_ctrl_table[( 14 + AES_SCA_CM_ROUNDS + 2 )]; aes_data_real.rk_ptr = ctx->rk; aes_data_table[0] = &aes_data_real; #if AES_SCA_CM_ROUNDS != 0 + round_ctrl_table_len += ( AES_SCA_CM_ROUNDS + 1 ); aes_data_table[1] = &aes_data_fake; aes_data_fake.rk_ptr = ctx->rk; - start_fin_loops = 2; for( i = 0; i < 4; i++ ) aes_data_fake.xy_values[i] = mbedtls_platform_random_in_range( 0xffffffff ); #endif - // Get randomized AES calculation control bytes + // Get AES calculation control bytes flow_control = aes_sca_cm_data_randomize( round_ctrl_table, round_ctrl_table_len ); - for( i = 0; i < 4; i++ ) + mbedtls_platform_memset( aes_data_real.xy_values, 0, 16 ); + offset = mbedtls_platform_random_in_range( 4 ); + + for( i = offset; i < 4; i++ ) { GET_UINT32_LE( aes_data_real.xy_values[i], input, ( i * 4 ) ); - for( j = 0; j < start_fin_loops; j++ ) - { - aes_data_ptr = - aes_data_table[round_ctrl_table[ round_ctrl_table_len - 4 + j ] >> 4]; - aes_data_ptr->xy_values[i] ^= *aes_data_ptr->rk_ptr++; - flow_control++; - } } - for( i = 0; i < ( ctx->nr - 1 + AES_SCA_CM_ROUNDS ); i++ ) + for( i = 0; i < offset; i++ ) { - // Read AES control data - aes_data_ptr = aes_data_table[round_ctrl_table[i] >> 4]; - offset = round_ctrl_table[i] & 0x0f; + GET_UINT32_LE( aes_data_real.xy_values[i], input, ( i * 4 ) ); + } + + tindex = 0; + do + { + // Get pointer to the real or fake data + aes_data_ptr = aes_data_table[round_ctrl_table[tindex] >> 4]; + stop_mark = round_ctrl_table[tindex] & 0x03; + + // initial round key addition + for( i = 0; i < 4; i++ ) + { + aes_data_ptr->xy_values[i] ^= *aes_data_ptr->rk_ptr++; + } + tindex++; + flow_control++; + } while( stop_mark == 0 ); + + // Calculate AES rounds (9, 11 or 13 rounds) + dummy rounds + do + { + // Get pointer to the real or fake data + aes_data_ptr = aes_data_table[round_ctrl_table[tindex] >> 4]; + offset = round_ctrl_table[tindex] & 0x04; + stop_mark = round_ctrl_table[tindex] & 0x03; aes_data_ptr->rk_ptr = aes_rround( aes_data_ptr->rk_ptr, &aes_data_ptr->xy_values[0 + offset], @@ -1286,12 +1319,15 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, aes_data_ptr->xy_values[5 - offset], aes_data_ptr->xy_values[6 - offset], aes_data_ptr->xy_values[7 - offset] ); + tindex++; flow_control++; - } + } while( stop_mark == 0 ); - for( j = 0; j < start_fin_loops; j++ ) + // Calculate final AES round + dummy rounds + do { - aes_data_ptr = aes_data_table[round_ctrl_table[ i + j ] >> 4]; + aes_data_ptr = aes_data_table[round_ctrl_table[tindex] >> 4]; + stop_mark = round_ctrl_table[tindex] & 0x03; aes_rround_final( aes_data_ptr->rk_ptr, &aes_data_ptr->xy_values[0], &aes_data_ptr->xy_values[1], @@ -1302,16 +1338,25 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, aes_data_ptr->xy_values[6], aes_data_ptr->xy_values[7] ); flow_control++; - } + tindex++; + } while( stop_mark == 0 ); - for( i = 0; i < 4; i++ ) + mbedtls_platform_memset( output, 0, 16 ); + offset = mbedtls_platform_random_in_range( 4 ); + + for( i = offset; i < 4; i++ ) { PUT_UINT32_LE( aes_data_real.xy_values[i], output, ( i * 4 ) ); flow_control++; } - if( flow_control == ( AES_SCA_CM_ROUNDS + ( 4 * start_fin_loops ) + - ctx->nr - 1 + AES_SCA_CM_ROUNDS + start_fin_loops + 4 ) ) + for( i = 0; i < offset; i++ ) + { + PUT_UINT32_LE( aes_data_real.xy_values[i], output, ( i * 4 ) ); + flow_control++; + } + + if( flow_control == round_ctrl_table_len + AES_SCA_CM_ROUNDS + 4 ) { /* Validate control path due possible fault injection */ return 0; From 98c93af1ef5ed8cf15f2ae994ac466f87fca8583 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Tue, 14 Jan 2020 13:31:03 +0200 Subject: [PATCH 2/5] Randomize number of AES dummy calculation rounds Use either 4 or 5 dummy rounds in AES encryption/decryption. --- library/aes.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/library/aes.c b/library/aes.c index ece7a82d2..cbedabc24 100644 --- a/library/aes.c +++ b/library/aes.c @@ -95,7 +95,7 @@ typedef struct { #if defined(MBEDTLS_AES_SCA_COUNTERMEASURES) /* Number of additional AES calculation rounds added for SCA CM */ -#define AES_SCA_CM_ROUNDS 4 +#define AES_SCA_CM_ROUNDS 5 #else /* MBEDTLS_AES_SCA_COUNTERMEASURES */ #define AES_SCA_CM_ROUNDS 0 #endif /* MBEDTLS_AES_SCA_COUNTERMEASURES */ @@ -545,7 +545,7 @@ static void aes_gen_tables( void ) */ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) { - int i = 0, j = 0, is_even_pos; + int i = 0, j = 0, is_even_pos, dummy_rounds; #if AES_SCA_CM_ROUNDS != 0 int num; #endif @@ -566,7 +566,9 @@ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) } // Randomize AES rounds - num = num % ( AES_SCA_CM_ROUNDS + 1 ); + dummy_rounds = AES_SCA_CM_ROUNDS - ( num & 0x01 ); + tbl_len = tbl_len - (AES_SCA_CM_ROUNDS - dummy_rounds); + num = num % ( dummy_rounds + 1 ); // add dummy rounds to the start (if needed) for ( ; i < num + 2; i++ ) @@ -575,11 +577,12 @@ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) } // add dummy rounds to the last, (AES_SCA_CM_ROUNDS - num) rounds if needed - for ( j = tbl_len - AES_SCA_CM_ROUNDS + num; j < tbl_len; j++ ) + for ( j = tbl_len - dummy_rounds + num; j < tbl_len; j++ ) { tbl[j] = 0x10; // dummy data } #else /* AES_SCA_CM_ROUNDS != 0 */ + dummy_rounds = 0; tbl[i++] = 0x03; // real data + stop marker for the round key addition #endif /* AES_SCA_CM_ROUNDS != 0 */ @@ -606,7 +609,7 @@ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) tbl[( tbl_len - 1)] |= 0x03; // Stop marker for the last item in tbl tbl[( j - 1 )] |= 0x03; // stop marker for final - 1 real data - return( AES_SCA_CM_ROUNDS ); + return( dummy_rounds ); } #if defined(MBEDTLS_AES_FEWER_TABLES) @@ -1053,7 +1056,7 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) { - int i, tindex, offset, stop_mark; + int i, tindex, offset, stop_mark, dummy_rounds; aes_r_data_t aes_data_real; // real data #if AES_SCA_CM_ROUNDS != 0 aes_r_data_t aes_data_fake; // fake data @@ -1078,8 +1081,8 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, #endif // Get AES calculation control bytes - flow_control = aes_sca_cm_data_randomize( round_ctrl_table, - round_ctrl_table_len ); + dummy_rounds = aes_sca_cm_data_randomize( round_ctrl_table, round_ctrl_table_len ); + flow_control = dummy_rounds; mbedtls_platform_memset( aes_data_real.xy_values, 0, 16 ); offset = mbedtls_platform_random_in_range( 4 ); @@ -1164,7 +1167,7 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, flow_control++; } - if( flow_control == round_ctrl_table_len + AES_SCA_CM_ROUNDS + 4 ) + if( flow_control == tindex + dummy_rounds + 4 ) { /* Validate control path due possible fault injection */ return 0; @@ -1245,7 +1248,7 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) { - int i, tindex, offset, stop_mark; + int i, tindex, offset, stop_mark, dummy_rounds; aes_r_data_t aes_data_real; // real data #if AES_SCA_CM_ROUNDS != 0 aes_r_data_t aes_data_fake; // fake data @@ -1270,9 +1273,11 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, #endif // Get AES calculation control bytes - flow_control = aes_sca_cm_data_randomize( round_ctrl_table, + dummy_rounds = aes_sca_cm_data_randomize( round_ctrl_table, round_ctrl_table_len ); + flow_control = dummy_rounds; + mbedtls_platform_memset( aes_data_real.xy_values, 0, 16 ); offset = mbedtls_platform_random_in_range( 4 ); @@ -1356,7 +1361,7 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, flow_control++; } - if( flow_control == round_ctrl_table_len + AES_SCA_CM_ROUNDS + 4 ) + if( flow_control == tindex + dummy_rounds + 4 ) { /* Validate control path due possible fault injection */ return 0; From 2b24f4280ff259203ee7124f63f79ac65a85abff Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Thu, 16 Jan 2020 15:04:11 +0200 Subject: [PATCH 3/5] AES review corrections -Do not reuse any part of randomized number, use separate byte for each purpose. -Combine some separate loops together to get rid of gap between them -Extend usage of flow_control --- library/aes.c | 79 +++++++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 46 deletions(-) diff --git a/library/aes.c b/library/aes.c index cbedabc24..a6e0d75dc 100644 --- a/library/aes.c +++ b/library/aes.c @@ -545,18 +545,17 @@ static void aes_gen_tables( void ) */ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) { - int i = 0, j = 0, is_even_pos, dummy_rounds; + int i = 0, j, is_even_pos, dummy_rounds; + #if AES_SCA_CM_ROUNDS != 0 int num; -#endif mbedtls_platform_memset( tbl, 0, tbl_len ); - -#if AES_SCA_CM_ROUNDS != 0 - num = mbedtls_platform_random_in_range( 0x1f ); + // get random from 0xfff (each byte will be used separately) + num = mbedtls_platform_random_in_range( 0x1000 ); // Randomize execution order of initial round key addition - if ( ( num & 0x10 ) == 0 ) + if ( ( num & 0x0100 ) == 0 ) { tbl[i++] = 0x10; // dummy data tbl[i++] = 0x00 | 0x03; // real data + stop marker @@ -565,24 +564,28 @@ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) tbl[i++] = 0x10 | 0x03; // dummy data + stop marker } - // Randomize AES rounds - dummy_rounds = AES_SCA_CM_ROUNDS - ( num & 0x01 ); + // Randomize number of dummy AES rounds + dummy_rounds = AES_SCA_CM_ROUNDS - ( ( num >> 8 ) & 0x01 ); tbl_len = tbl_len - (AES_SCA_CM_ROUNDS - dummy_rounds); - num = num % ( dummy_rounds + 1 ); - // add dummy rounds to the start (if needed) + // randomize positions for the dummy rounds + num = ( num & 0x00f ) % ( dummy_rounds + 1 ); + + // add dummy rounds after initial round key addition (if needed) for ( ; i < num + 2; i++ ) { tbl[i] = 0x10; // dummy data } - // add dummy rounds to the last, (AES_SCA_CM_ROUNDS - num) rounds if needed + // add dummy rounds to the end, (AES_SCA_CM_ROUNDS - num) rounds if needed for ( j = tbl_len - dummy_rounds + num; j < tbl_len; j++ ) { tbl[j] = 0x10; // dummy data } #else /* AES_SCA_CM_ROUNDS != 0 */ + mbedtls_platform_memset( tbl, 0, tbl_len ); dummy_rounds = 0; + j = 0; tbl[i++] = 0x03; // real data + stop marker for the round key addition #endif /* AES_SCA_CM_ROUNDS != 0 */ @@ -1081,21 +1084,19 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, #endif // Get AES calculation control bytes - dummy_rounds = aes_sca_cm_data_randomize( round_ctrl_table, round_ctrl_table_len ); + dummy_rounds = aes_sca_cm_data_randomize( round_ctrl_table, + round_ctrl_table_len ); flow_control = dummy_rounds; mbedtls_platform_memset( aes_data_real.xy_values, 0, 16 ); offset = mbedtls_platform_random_in_range( 4 ); - for( i = offset; i < 4; i++ ) + i = offset; + do { GET_UINT32_LE( aes_data_real.xy_values[i], input, ( i * 4 ) ); - } - - for( i = 0; i < offset; i++ ) - { - GET_UINT32_LE( aes_data_real.xy_values[i], input, ( i * 4 ) ); - } + flow_control++; + } while( ( i = ( i + 1 ) % 4 ) != offset ); tindex = 0; do @@ -1155,19 +1156,14 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, mbedtls_platform_memset( output, 0, 16 ); offset = mbedtls_platform_random_in_range( 4 ); - for( i = offset; i < 4; i++ ) + i = offset; + do { PUT_UINT32_LE( aes_data_real.xy_values[i], output, ( i * 4 ) ); flow_control++; - } + } while( ( i = ( i + 1 ) % 4 ) != offset ); - for( i = 0; i < offset; i++ ) - { - PUT_UINT32_LE( aes_data_real.xy_values[i], output, ( i * 4 ) ); - flow_control++; - } - - if( flow_control == tindex + dummy_rounds + 4 ) + if( flow_control == tindex + dummy_rounds + 8 ) { /* Validate control path due possible fault injection */ return 0; @@ -1274,22 +1270,18 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, // Get AES calculation control bytes dummy_rounds = aes_sca_cm_data_randomize( round_ctrl_table, - round_ctrl_table_len ); - + round_ctrl_table_len ); flow_control = dummy_rounds; mbedtls_platform_memset( aes_data_real.xy_values, 0, 16 ); offset = mbedtls_platform_random_in_range( 4 ); - for( i = offset; i < 4; i++ ) + i = offset; + do { GET_UINT32_LE( aes_data_real.xy_values[i], input, ( i * 4 ) ); - } - - for( i = 0; i < offset; i++ ) - { - GET_UINT32_LE( aes_data_real.xy_values[i], input, ( i * 4 ) ); - } + flow_control++; + } while( ( i = ( i + 1 ) % 4 ) != offset ); tindex = 0; do @@ -1349,19 +1341,14 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, mbedtls_platform_memset( output, 0, 16 ); offset = mbedtls_platform_random_in_range( 4 ); - for( i = offset; i < 4; i++ ) + i = offset; + do { PUT_UINT32_LE( aes_data_real.xy_values[i], output, ( i * 4 ) ); flow_control++; - } + } while( ( i = ( i + 1 ) % 4 ) != offset ); - for( i = 0; i < offset; i++ ) - { - PUT_UINT32_LE( aes_data_real.xy_values[i], output, ( i * 4 ) ); - flow_control++; - } - - if( flow_control == tindex + dummy_rounds + 4 ) + if( flow_control == tindex + dummy_rounds + 8 ) { /* Validate control path due possible fault injection */ return 0; From 311ab594d71136b222b3fc69b7ce549906f01058 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Thu, 16 Jan 2020 17:20:51 +0200 Subject: [PATCH 4/5] Flag SCA_CM encrypt/decrypt functions There is a 50% performance drop in the SCA_CM enabled encrypt and decrypt functions. Therefore use the older version of encrypt/decypt functions when SCA_CM is disabled. --- include/mbedtls/config.h | 9 +- library/aes.c | 210 ++++++++++++++++++++++++++++++++------- 2 files changed, 182 insertions(+), 37 deletions(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 0f651339c..e5e9a8866 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -640,10 +640,13 @@ * Add countermeasures against possible side-channel-attack to AES calculation. * * Uncommenting this macro adds additional calculation rounds to AES - * calculation. Additional rounds are using random data and can occur in any - * AES calculation round. + * calculation. Additional rounds are using random data for calculation. The + * additional rounds are added to: + * -initial key addition phase + * -before the first AES calculation round + * -after the last AES calculation round * - * Tradeoff: Uncommenting this increases ROM footprint by ~100 bytes. + * Tradeoff: Uncommenting this macro does not increases ROM footprint. * The performance loss is ~50% with 128 bit AES. * * This option is dependent of \c MBEDTLS_ENTROPY_HARDWARE_ALT. diff --git a/library/aes.c b/library/aes.c index a6e0d75dc..171215759 100644 --- a/library/aes.c +++ b/library/aes.c @@ -96,8 +96,6 @@ typedef struct { #if defined(MBEDTLS_AES_SCA_COUNTERMEASURES) /* Number of additional AES calculation rounds added for SCA CM */ #define AES_SCA_CM_ROUNDS 5 -#else /* MBEDTLS_AES_SCA_COUNTERMEASURES */ -#define AES_SCA_CM_ROUNDS 0 #endif /* MBEDTLS_AES_SCA_COUNTERMEASURES */ #if defined(MBEDTLS_PADLOCK_C) && \ @@ -543,12 +541,10 @@ static void aes_gen_tables( void ) * | Fi | Ri | F | F | F | R | R | ... | R | R | R | R | F | * |0x10|0x03 |0x10|0x10|0x10|0x04|0x00| ... |0x04|0x00|0x04|0x03|0x07| */ +#if defined(MBEDTLS_AES_SCA_COUNTERMEASURES) static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) { - int i = 0, j, is_even_pos, dummy_rounds; - -#if AES_SCA_CM_ROUNDS != 0 - int num; + int i = 0, j, is_even_pos, dummy_rounds, num; mbedtls_platform_memset( tbl, 0, tbl_len ); // get random from 0xfff (each byte will be used separately) @@ -582,12 +578,6 @@ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) { tbl[j] = 0x10; // dummy data } -#else /* AES_SCA_CM_ROUNDS != 0 */ - mbedtls_platform_memset( tbl, 0, tbl_len ); - dummy_rounds = 0; - j = 0; - tbl[i++] = 0x03; // real data + stop marker for the round key addition -#endif /* AES_SCA_CM_ROUNDS != 0 */ // Fill real AES data to the remaining places is_even_pos = 1; @@ -614,6 +604,7 @@ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) return( dummy_rounds ); } +#endif /*MBEDTLS_AES_SCA_COUNTERMEASURES */ #if defined(MBEDTLS_AES_FEWER_TABLES) @@ -1003,6 +994,7 @@ int mbedtls_aes_xts_setkey_dec( mbedtls_aes_xts_context *ctx, */ #if !defined(MBEDTLS_AES_ENCRYPT_ALT) +#if defined(MBEDTLS_AES_SCA_COUNTERMEASURES) static uint32_t *aes_fround( uint32_t *R, uint32_t *X0, uint32_t *X1, uint32_t *X2, uint32_t *X3, uint32_t Y0, uint32_t Y1, uint32_t Y2, uint32_t Y3 ) @@ -1061,27 +1053,19 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, { int i, tindex, offset, stop_mark, dummy_rounds; aes_r_data_t aes_data_real; // real data -#if AES_SCA_CM_ROUNDS != 0 aes_r_data_t aes_data_fake; // fake data -#endif /* AES_SCA_CM_ROUNDS != 0 */ aes_r_data_t *aes_data_ptr; // pointer to real or fake data aes_r_data_t *aes_data_table[2]; // pointers to real and fake data - int round_ctrl_table_len = ctx->nr + 1; + int round_ctrl_table_len = ctx->nr + 2 + AES_SCA_CM_ROUNDS; volatile int flow_control; // control bytes for AES calculation rounds, // reserve based on max rounds + dummy rounds + 2 (for initial key addition) uint8_t round_ctrl_table[( 14 + AES_SCA_CM_ROUNDS + 2 )]; aes_data_real.rk_ptr = ctx->rk; - aes_data_table[0] = &aes_data_real; - -#if AES_SCA_CM_ROUNDS != 0 - round_ctrl_table_len += ( AES_SCA_CM_ROUNDS + 1 ); - aes_data_table[1] = &aes_data_fake; aes_data_fake.rk_ptr = ctx->rk; - for( i = 0; i < 4; i++ ) - aes_data_fake.xy_values[i] = mbedtls_platform_random_in_range( 0xffffffff ); -#endif + aes_data_table[0] = &aes_data_real; + aes_data_table[1] = &aes_data_fake; // Get AES calculation control bytes dummy_rounds = aes_sca_cm_data_randomize( round_ctrl_table, @@ -1095,6 +1079,7 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, do { GET_UINT32_LE( aes_data_real.xy_values[i], input, ( i * 4 ) ); + aes_data_fake.xy_values[i] = mbedtls_platform_random_in_range( 0xffffffff ); flow_control++; } while( ( i = ( i + 1 ) % 4 ) != offset ); @@ -1171,6 +1156,87 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, return( MBEDTLS_ERR_PLATFORM_FAULT_DETECTED ); } + +#else /* MBEDTLS_AES_SCA_COUNTERMEASURES */ + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ + do \ + { \ + (X0) = *RK++ ^ AES_FT0( ( (Y0) ) & 0xFF ) ^ \ + AES_FT1( ( (Y1) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y2) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y3) >> 24 ) & 0xFF ); \ + \ + (X1) = *RK++ ^ AES_FT0( ( (Y1) ) & 0xFF ) ^ \ + AES_FT1( ( (Y2) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y3) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y0) >> 24 ) & 0xFF ); \ + \ + (X2) = *RK++ ^ AES_FT0( ( (Y2) ) & 0xFF ) ^ \ + AES_FT1( ( (Y3) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y0) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y1) >> 24 ) & 0xFF ); \ + \ + (X3) = *RK++ ^ AES_FT0( ( (Y3) ) & 0xFF ) ^ \ + AES_FT1( ( (Y0) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y1) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y2) >> 24 ) & 0xFF ); \ + } while( 0 ) + +int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; + GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; + GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; + GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; + + for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) + { + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y0 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y1 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y2 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y3 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + + PUT_UINT32_LE( X0, output, 0 ); + PUT_UINT32_LE( X1, output, 4 ); + PUT_UINT32_LE( X2, output, 8 ); + PUT_UINT32_LE( X3, output, 12 ); + + return( 0 ); +} +#endif /* MBEDTLS_AES_SCA_COUNTERMEASURES */ #endif /* !MBEDTLS_AES_ENCRYPT_ALT */ #if !defined(MBEDTLS_DEPRECATED_REMOVED) @@ -1189,6 +1255,7 @@ void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, #if !defined(MBEDTLS_AES_DECRYPT_ALT) #if !defined(MBEDTLS_AES_ONLY_ENCRYPT) +#if defined(MBEDTLS_AES_SCA_COUNTERMEASURES) static uint32_t *aes_rround( uint32_t *R, uint32_t *X0, uint32_t *X1, uint32_t *X2, uint32_t *X3, uint32_t Y0, uint32_t Y1, uint32_t Y2, uint32_t Y3 ) @@ -1246,27 +1313,19 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, { int i, tindex, offset, stop_mark, dummy_rounds; aes_r_data_t aes_data_real; // real data -#if AES_SCA_CM_ROUNDS != 0 aes_r_data_t aes_data_fake; // fake data -#endif /* AES_SCA_CM_ROUNDS != 0 */ aes_r_data_t *aes_data_ptr; // pointer to real or fake data aes_r_data_t *aes_data_table[2]; // pointers to real and fake data - int round_ctrl_table_len = ctx->nr + 1; + int round_ctrl_table_len = ctx->nr + 2 + AES_SCA_CM_ROUNDS; volatile int flow_control; // control bytes for AES calculation rounds, // reserve based on max rounds + dummy rounds + 2 (for initial key addition) uint8_t round_ctrl_table[( 14 + AES_SCA_CM_ROUNDS + 2 )]; aes_data_real.rk_ptr = ctx->rk; - aes_data_table[0] = &aes_data_real; - -#if AES_SCA_CM_ROUNDS != 0 - round_ctrl_table_len += ( AES_SCA_CM_ROUNDS + 1 ); - aes_data_table[1] = &aes_data_fake; aes_data_fake.rk_ptr = ctx->rk; - for( i = 0; i < 4; i++ ) - aes_data_fake.xy_values[i] = mbedtls_platform_random_in_range( 0xffffffff ); -#endif + aes_data_table[0] = &aes_data_real; + aes_data_table[1] = &aes_data_fake; // Get AES calculation control bytes dummy_rounds = aes_sca_cm_data_randomize( round_ctrl_table, @@ -1280,6 +1339,7 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, do { GET_UINT32_LE( aes_data_real.xy_values[i], input, ( i * 4 ) ); + aes_data_fake.xy_values[i] = mbedtls_platform_random_in_range( 0xffffffff ); flow_control++; } while( ( i = ( i + 1 ) % 4 ) != offset ); @@ -1356,6 +1416,88 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, return( MBEDTLS_ERR_PLATFORM_FAULT_DETECTED ); } + +#else /* MBEDTLS_AES_SCA_COUNTERMEASURES */ + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ + do \ + { \ + (X0) = *RK++ ^ AES_RT0( ( (Y0) ) & 0xFF ) ^ \ + AES_RT1( ( (Y3) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y2) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y1) >> 24 ) & 0xFF ); \ + \ + (X1) = *RK++ ^ AES_RT0( ( (Y1) ) & 0xFF ) ^ \ + AES_RT1( ( (Y0) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y3) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y2) >> 24 ) & 0xFF ); \ + \ + (X2) = *RK++ ^ AES_RT0( ( (Y2) ) & 0xFF ) ^ \ + AES_RT1( ( (Y1) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y0) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y3) >> 24 ) & 0xFF ); \ + \ + (X3) = *RK++ ^ AES_RT0( ( (Y3) ) & 0xFF ) ^ \ + AES_RT1( ( (Y2) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y1) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y0) >> 24 ) & 0xFF ); \ + } while( 0 ) + +int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; + GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; + GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; + GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; + + for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) + { + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y0 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y1 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y2 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y3 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + + PUT_UINT32_LE( X0, output, 0 ); + PUT_UINT32_LE( X1, output, 4 ); + PUT_UINT32_LE( X2, output, 8 ); + PUT_UINT32_LE( X3, output, 12 ); + + return( 0 ); +} +#endif /* MBEDTLS_AES_SCA_COUNTERMEASURES */ + #endif /* !MBEDTLS_AES_ONLY_ENCRYPT */ #endif /* !MBEDTLS_AES_DECRYPT_ALT */ From 17540ab74c46a7cb20ba52808e5eab982affb6bb Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Mon, 20 Jan 2020 11:46:34 +0200 Subject: [PATCH 5/5] Fix usage of randomized number in AES -Fix usage of randomized bits (do not reuse the bits) -Update comments --- include/mbedtls/config.h | 2 +- library/aes.c | 45 ++++++++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index e5e9a8866..347a8fa81 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -646,7 +646,7 @@ * -before the first AES calculation round * -after the last AES calculation round * - * Tradeoff: Uncommenting this macro does not increases ROM footprint. + * Tradeoff: Uncommenting this macro does not increase codesize. * The performance loss is ~50% with 128 bit AES. * * This option is dependent of \c MBEDTLS_ENTROPY_HARDWARE_ALT. diff --git a/library/aes.c b/library/aes.c index 171215759..9098d4795 100644 --- a/library/aes.c +++ b/library/aes.c @@ -94,7 +94,7 @@ typedef struct { } aes_r_data_t; #if defined(MBEDTLS_AES_SCA_COUNTERMEASURES) -/* Number of additional AES calculation rounds added for SCA CM */ +/* Number of additional AES dummy rounds added for SCA countermeasures */ #define AES_SCA_CM_ROUNDS 5 #endif /* MBEDTLS_AES_SCA_COUNTERMEASURES */ @@ -512,8 +512,8 @@ static void aes_gen_tables( void ) /** * Randomize positions for AES SCA countermeasures if AES countermeasures are - * enabled. If countermeasures are not enabled then fill given table with real - * data values. + * enabled. If the countermeasures are not enabled then we fill the given table + * with only real AES rounds to be executed. * * Dummy rounds are added as follows: * 1. One dummy round added to the initial round key addition (executed in @@ -533,13 +533,18 @@ static void aes_gen_tables( void ) * Return Number of additional AES rounds * * Example of the control bytes: + * R = real data in actual AES calculation round + * Ri = Real data in initial round key addition phase + * F = fake data in actual AES calculation round + * Fi = fake data in initial round key addition phase + * * 1. No countermeasures enabled and AES-128, only real data (R) used: * | Ri | R | R | R | R | R | R | R | R | R | R | * |0x03|0x04|0x00|0x04|0x00|0x04|0x00|0x04|0x00|0x07|0x03| * * 2. Countermeasures enabled, 3 (F) dummy rounds in start and 1 at end: - * | Fi | Ri | F | F | F | R | R | ... | R | R | R | R | F | - * |0x10|0x03 |0x10|0x10|0x10|0x04|0x00| ... |0x04|0x00|0x04|0x03|0x07| + * | Fi | Ri | F | F | F | R | R | ... | R | R | R | R | F | + * |0x10|0x03|0x10|0x10|0x10|0x04|0x00| ... |0x04|0x00|0x04|0x03|0x07| */ #if defined(MBEDTLS_AES_SCA_COUNTERMEASURES) static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) @@ -547,7 +552,7 @@ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) int i = 0, j, is_even_pos, dummy_rounds, num; mbedtls_platform_memset( tbl, 0, tbl_len ); - // get random from 0xfff (each byte will be used separately) + // get random from 0x0fff (each f will be used separately) num = mbedtls_platform_random_in_range( 0x1000 ); // Randomize execution order of initial round key addition @@ -561,11 +566,11 @@ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) } // Randomize number of dummy AES rounds - dummy_rounds = AES_SCA_CM_ROUNDS - ( ( num >> 8 ) & 0x01 ); + dummy_rounds = AES_SCA_CM_ROUNDS - ( ( num & 0x0010 ) >> 4 ); tbl_len = tbl_len - (AES_SCA_CM_ROUNDS - dummy_rounds); // randomize positions for the dummy rounds - num = ( num & 0x00f ) % ( dummy_rounds + 1 ); + num = ( num & 0x000f ) % ( dummy_rounds + 1 ); // add dummy rounds after initial round key addition (if needed) for ( ; i < num + 2; i++ ) @@ -604,7 +609,7 @@ static int aes_sca_cm_data_randomize( uint8_t *tbl, uint8_t tbl_len ) return( dummy_rounds ); } -#endif /*MBEDTLS_AES_SCA_COUNTERMEASURES */ +#endif /* MBEDTLS_AES_SCA_COUNTERMEASURES */ #if defined(MBEDTLS_AES_FEWER_TABLES) @@ -1072,9 +1077,13 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, round_ctrl_table_len ); flow_control = dummy_rounds; + // SCA countermeasure, safely clear the aes_data_real.xy_values mbedtls_platform_memset( aes_data_real.xy_values, 0, 16 ); - offset = mbedtls_platform_random_in_range( 4 ); + // SCA countermeasure, randomize secret data location by initializing it in + // a random order and writing randomized fake data between the real data + // writes. + offset = mbedtls_platform_random_in_range( 4 ); i = offset; do { @@ -1138,9 +1147,12 @@ int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, tindex++; } while( stop_mark == 0 ); + // SCA countermeasure, safely clear the output mbedtls_platform_memset( output, 0, 16 ); - offset = mbedtls_platform_random_in_range( 4 ); + // SCA countermeasure, randomize secret data location by writing to it in + // a random order. + offset = mbedtls_platform_random_in_range( 4 ); i = offset; do { @@ -1332,9 +1344,13 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, round_ctrl_table_len ); flow_control = dummy_rounds; + // SCA countermeasure, safely clear the aes_data_real.xy_values mbedtls_platform_memset( aes_data_real.xy_values, 0, 16 ); - offset = mbedtls_platform_random_in_range( 4 ); + // SCA countermeasure, randomize secret data location by initializing it in + // a random order and writing randomized fake data between the real data + // writes. + offset = mbedtls_platform_random_in_range( 4 ); i = offset; do { @@ -1398,9 +1414,12 @@ int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, tindex++; } while( stop_mark == 0 ); + // SCA countermeasure, safely clear the output mbedtls_platform_memset( output, 0, 16 ); - offset = mbedtls_platform_random_in_range( 4 ); + // SCA countermeasure, randomize secret data location by writing to it in + // a random order. + offset = mbedtls_platform_random_in_range( 4 ); i = offset; do {