mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-03-29 04:20:12 +00:00
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:
parent
36dd93e745
commit
58fc272af9
113
library/gcm.c
113
library/gcm.c
@ -355,21 +355,64 @@ int mbedtls_gcm_starts( mbedtls_gcm_context *ctx,
|
|||||||
return( 0 );
|
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,
|
int mbedtls_gcm_update( mbedtls_gcm_context *ctx,
|
||||||
size_t length,
|
size_t length,
|
||||||
const unsigned char *input,
|
const unsigned char *input,
|
||||||
unsigned char *output )
|
unsigned char *output )
|
||||||
{
|
{
|
||||||
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||||
unsigned char ectr[16];
|
const unsigned char *p = input;
|
||||||
size_t i;
|
|
||||||
const unsigned char *p;
|
|
||||||
unsigned char *out_p = output;
|
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( ctx != NULL );
|
||||||
GCM_VALIDATE_RET( length == 0 || input != NULL );
|
GCM_VALIDATE_RET( input != NULL );
|
||||||
GCM_VALIDATE_RET( length == 0 || output != NULL );
|
GCM_VALIDATE_RET( output != NULL );
|
||||||
|
|
||||||
if( output > input && (size_t) ( output - input ) < length )
|
if( output > input && (size_t) ( output - input ) < length )
|
||||||
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
||||||
@ -382,39 +425,48 @@ int mbedtls_gcm_update( mbedtls_gcm_context *ctx,
|
|||||||
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->len += length;
|
offset = ctx->len % 16;
|
||||||
|
if( offset != 0 )
|
||||||
p = input;
|
|
||||||
while( length > 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( ( ret = gcm_mask( ctx, ectr, offset, use_len, p, out_p ) ) != 0 )
|
||||||
if( ++ctx->y[i - 1] != 0 )
|
|
||||||
break;
|
|
||||||
|
|
||||||
if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ectr,
|
|
||||||
&olen ) ) != 0 )
|
|
||||||
{
|
|
||||||
return( ret );
|
return( ret );
|
||||||
}
|
|
||||||
|
|
||||||
for( i = 0; i < use_len; i++ )
|
if( offset + use_len == 16 )
|
||||||
{
|
gcm_mult( ctx, ctx->buf, ctx->buf );
|
||||||
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 );
|
|
||||||
|
|
||||||
|
ctx->len += use_len;
|
||||||
length -= use_len;
|
length -= use_len;
|
||||||
p += use_len;
|
p += use_len;
|
||||||
out_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 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,6 +488,9 @@ int mbedtls_gcm_finish( mbedtls_gcm_context *ctx,
|
|||||||
if( tag_len > 16 || tag_len < 4 )
|
if( tag_len > 16 || tag_len < 4 )
|
||||||
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
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 );
|
memcpy( tag, ctx->base_ectr, tag_len );
|
||||||
|
|
||||||
if( orig_len || orig_add_len )
|
if( orig_len || orig_add_len )
|
||||||
|
@ -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( output, src_str->len, dst->x, dst->len );
|
||||||
ASSERT_COMPARE( tag_output, tag_len, tag->x, tag->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 );
|
mbedtls_test_set_step( n1 );
|
||||||
if( !check_multipart( &ctx, MBEDTLS_GCM_ENCRYPT,
|
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 );
|
TEST_ASSERT( ret == 0 );
|
||||||
ASSERT_COMPARE( output, src_str->len, pt_result->x, pt_result->len );
|
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 );
|
mbedtls_test_set_step( n1 );
|
||||||
if( !check_multipart( &ctx, MBEDTLS_GCM_DECRYPT,
|
if( !check_multipart( &ctx, MBEDTLS_GCM_DECRYPT,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user