Remove alignment requirement for mbedtls_gcm_update: implementation

mbedtls_gcm_update now accepts inputs of arbitrary size. There is no
longer a requirement that all calls except the last one pass a
multiple of 16 bytes.

This commit updates the library code and adjusts the GCM tests to
exercise arbitrarily aligned input sizes.

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
This commit is contained in:
Gilles Peskine 2021-04-13 15:58:27 +02:00
parent 36dd93e745
commit 58fc272af9
2 changed files with 86 additions and 31 deletions

View File

@ -355,21 +355,64 @@ int mbedtls_gcm_starts( mbedtls_gcm_context *ctx,
return( 0 );
}
/* Increment the counter. */
static void gcm_incr( unsigned char y[16] )
{
size_t i;
for( i = 16; i > 12; i-- )
if( ++y[i - 1] != 0 )
break;
}
/* Calculate and apply the encryption mask. Process use_len bytes of data,
* starting at position offset in the mask block. */
static int gcm_mask( mbedtls_gcm_context *ctx,
unsigned char ectr[16],
size_t offset, size_t use_len,
const unsigned char *input,
unsigned char *output )
{
size_t i;
size_t olen = 0;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ectr,
&olen ) ) != 0 )
{
mbedtls_platform_zeroize( ectr, 16 );
return( ret );
}
for( i = 0; i < use_len; i++ )
{
if( ctx->mode == MBEDTLS_GCM_DECRYPT )
ctx->buf[offset + i] ^= input[i];
output[i] = ectr[offset + i] ^ input[i];
if( ctx->mode == MBEDTLS_GCM_ENCRYPT )
ctx->buf[offset + i] ^= output[i];
}
return( 0 );
}
int mbedtls_gcm_update( mbedtls_gcm_context *ctx,
size_t length,
const unsigned char *input,
unsigned char *output )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char ectr[16];
size_t i;
const unsigned char *p;
const unsigned char *p = input;
unsigned char *out_p = output;
size_t use_len, olen = 0;
size_t offset;
unsigned char ectr[16];
/* Exit early if length==0 so that we don't do any pointer arithmetic on
* a potentially null pointer. */
if( length == 0 )
return( 0 );
GCM_VALIDATE_RET( ctx != NULL );
GCM_VALIDATE_RET( length == 0 || input != NULL );
GCM_VALIDATE_RET( length == 0 || output != NULL );
GCM_VALIDATE_RET( input != NULL );
GCM_VALIDATE_RET( output != NULL );
if( output > input && (size_t) ( output - input ) < length )
return( MBEDTLS_ERR_GCM_BAD_INPUT );
@ -382,39 +425,48 @@ int mbedtls_gcm_update( mbedtls_gcm_context *ctx,
return( MBEDTLS_ERR_GCM_BAD_INPUT );
}
ctx->len += length;
p = input;
while( length > 0 )
offset = ctx->len % 16;
if( offset != 0 )
{
use_len = ( length < 16 ) ? length : 16;
size_t use_len = 16 - offset;
if( use_len > length )
use_len = length;
for( i = 16; i > 12; i-- )
if( ++ctx->y[i - 1] != 0 )
break;
if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ectr,
&olen ) ) != 0 )
{
if( ( ret = gcm_mask( ctx, ectr, offset, use_len, p, out_p ) ) != 0 )
return( ret );
}
for( i = 0; i < use_len; i++ )
{
if( ctx->mode == MBEDTLS_GCM_DECRYPT )
ctx->buf[i] ^= p[i];
out_p[i] = ectr[i] ^ p[i];
if( ctx->mode == MBEDTLS_GCM_ENCRYPT )
ctx->buf[i] ^= out_p[i];
}
gcm_mult( ctx, ctx->buf, ctx->buf );
if( offset + use_len == 16 )
gcm_mult( ctx, ctx->buf, ctx->buf );
ctx->len += use_len;
length -= use_len;
p += use_len;
out_p += use_len;
}
ctx->len += length;
while( length >= 16 )
{
gcm_incr( ctx->y );
if( ( ret = gcm_mask( ctx, ectr, 0, 16, p, out_p ) ) != 0 )
return( ret );
gcm_mult( ctx, ctx->buf, ctx->buf );
length -= 16;
p += 16;
out_p += 16;
}
if( length > 0 )
{
gcm_incr( ctx->y );
if( ( ret = gcm_mask( ctx, ectr, 0, length, p, out_p ) ) != 0 )
return( ret );
}
mbedtls_platform_zeroize( ectr, sizeof( ectr ) );
return( 0 );
}
@ -436,6 +488,9 @@ int mbedtls_gcm_finish( mbedtls_gcm_context *ctx,
if( tag_len > 16 || tag_len < 4 )
return( MBEDTLS_ERR_GCM_BAD_INPUT );
if( ctx->len % 16 != 0 )
gcm_mult( ctx, ctx->buf, ctx->buf );
memcpy( tag, ctx->base_ectr, tag_len );
if( orig_len || orig_add_len )

View File

@ -111,7 +111,7 @@ void gcm_encrypt_and_tag( int cipher_id, data_t * key_str,
ASSERT_COMPARE( output, src_str->len, dst->x, dst->len );
ASSERT_COMPARE( tag_output, tag_len, tag->x, tag->len );
for( n1 = 16; n1 < src_str->len; n1 += 16 )
for( n1 = 0; n1 <= src_str->len; n1 += 1 )
{
mbedtls_test_set_step( n1 );
if( !check_multipart( &ctx, MBEDTLS_GCM_ENCRYPT,
@ -159,7 +159,7 @@ void gcm_decrypt_and_verify( int cipher_id, data_t * key_str,
TEST_ASSERT( ret == 0 );
ASSERT_COMPARE( output, src_str->len, pt_result->x, pt_result->len );
for( n1 = 16; n1 < src_str->len; n1 += 16 )
for( n1 = 0; n1 <= src_str->len; n1 += 1 )
{
mbedtls_test_set_step( n1 );
if( !check_multipart( &ctx, MBEDTLS_GCM_DECRYPT,