5a7be10419
Without this parameter, it would be hard for callers to know how many bytes of output the function wrote into the output buffer. It would be possible, since the cumulated output must have the same length as the cumulated input, but it would be cumbersome for the caller to keep track. Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
1183 lines
38 KiB
C
1183 lines
38 KiB
C
/*
|
|
* NIST SP800-38D compliant GCM implementation
|
|
*
|
|
* Copyright The Mbed TLS Contributors
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
* not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
* http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
|
|
*
|
|
* See also:
|
|
* [MGV] http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
|
|
*
|
|
* We use the algorithm described as Shoup's method with 4-bit tables in
|
|
* [MGV] 4.1, pp. 12-13, to enhance speed without using too much memory.
|
|
*/
|
|
|
|
#include "common.h"
|
|
|
|
#if defined(MBEDTLS_GCM_C)
|
|
|
|
#include "mbedtls/gcm.h"
|
|
#include "mbedtls/platform_util.h"
|
|
#include "mbedtls/error.h"
|
|
|
|
#include <string.h>
|
|
|
|
#if defined(MBEDTLS_AESNI_C)
|
|
#include "aesni.h"
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
|
|
#include "mbedtls/aes.h"
|
|
#include "mbedtls/platform.h"
|
|
#if !defined(MBEDTLS_PLATFORM_C)
|
|
#include <stdio.h>
|
|
#define mbedtls_printf printf
|
|
#endif /* MBEDTLS_PLATFORM_C */
|
|
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
|
|
|
|
#if !defined(MBEDTLS_GCM_ALT)
|
|
|
|
/* Parameter validation macros */
|
|
#define GCM_VALIDATE_RET( cond ) \
|
|
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_GCM_BAD_INPUT )
|
|
#define GCM_VALIDATE( cond ) \
|
|
MBEDTLS_INTERNAL_VALIDATE( cond )
|
|
|
|
/*
|
|
* 32-bit integer manipulation macros (big endian)
|
|
*/
|
|
#ifndef GET_UINT32_BE
|
|
#define GET_UINT32_BE(n,b,i) \
|
|
{ \
|
|
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
|
|
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
|
|
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
|
|
| ( (uint32_t) (b)[(i) + 3] ); \
|
|
}
|
|
#endif
|
|
|
|
#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
|
|
|
|
/*
|
|
* Initialize a context
|
|
*/
|
|
void mbedtls_gcm_init( mbedtls_gcm_context *ctx )
|
|
{
|
|
GCM_VALIDATE( ctx != NULL );
|
|
memset( ctx, 0, sizeof( mbedtls_gcm_context ) );
|
|
}
|
|
|
|
/*
|
|
* Precompute small multiples of H, that is set
|
|
* HH[i] || HL[i] = H times i,
|
|
* where i is seen as a field element as in [MGV], ie high-order bits
|
|
* correspond to low powers of P. The result is stored in the same way, that
|
|
* is the high-order bit of HH corresponds to P^0 and the low-order bit of HL
|
|
* corresponds to P^127.
|
|
*/
|
|
static int gcm_gen_table( mbedtls_gcm_context *ctx )
|
|
{
|
|
int ret, i, j;
|
|
uint64_t hi, lo;
|
|
uint64_t vl, vh;
|
|
unsigned char h[16];
|
|
size_t olen = 0;
|
|
|
|
memset( h, 0, 16 );
|
|
if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, h, 16, h, &olen ) ) != 0 )
|
|
return( ret );
|
|
|
|
/* pack h as two 64-bits ints, big-endian */
|
|
GET_UINT32_BE( hi, h, 0 );
|
|
GET_UINT32_BE( lo, h, 4 );
|
|
vh = (uint64_t) hi << 32 | lo;
|
|
|
|
GET_UINT32_BE( hi, h, 8 );
|
|
GET_UINT32_BE( lo, h, 12 );
|
|
vl = (uint64_t) hi << 32 | lo;
|
|
|
|
/* 8 = 1000 corresponds to 1 in GF(2^128) */
|
|
ctx->HL[8] = vl;
|
|
ctx->HH[8] = vh;
|
|
|
|
#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
|
|
/* With CLMUL support, we need only h, not the rest of the table */
|
|
if( mbedtls_aesni_has_support( MBEDTLS_AESNI_CLMUL ) )
|
|
return( 0 );
|
|
#endif
|
|
|
|
/* 0 corresponds to 0 in GF(2^128) */
|
|
ctx->HH[0] = 0;
|
|
ctx->HL[0] = 0;
|
|
|
|
for( i = 4; i > 0; i >>= 1 )
|
|
{
|
|
uint32_t T = ( vl & 1 ) * 0xe1000000U;
|
|
vl = ( vh << 63 ) | ( vl >> 1 );
|
|
vh = ( vh >> 1 ) ^ ( (uint64_t) T << 32);
|
|
|
|
ctx->HL[i] = vl;
|
|
ctx->HH[i] = vh;
|
|
}
|
|
|
|
for( i = 2; i <= 8; i *= 2 )
|
|
{
|
|
uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i;
|
|
vh = *HiH;
|
|
vl = *HiL;
|
|
for( j = 1; j < i; j++ )
|
|
{
|
|
HiH[j] = vh ^ ctx->HH[j];
|
|
HiL[j] = vl ^ ctx->HL[j];
|
|
}
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx,
|
|
mbedtls_cipher_id_t cipher,
|
|
const unsigned char *key,
|
|
unsigned int keybits )
|
|
{
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
const mbedtls_cipher_info_t *cipher_info;
|
|
|
|
GCM_VALIDATE_RET( ctx != NULL );
|
|
GCM_VALIDATE_RET( key != NULL );
|
|
GCM_VALIDATE_RET( keybits == 128 || keybits == 192 || keybits == 256 );
|
|
|
|
cipher_info = mbedtls_cipher_info_from_values( cipher, keybits,
|
|
MBEDTLS_MODE_ECB );
|
|
if( cipher_info == NULL )
|
|
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
|
|
|
if( cipher_info->block_size != 16 )
|
|
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
|
|
|
mbedtls_cipher_free( &ctx->cipher_ctx );
|
|
|
|
if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
|
|
return( ret );
|
|
|
|
if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
|
|
MBEDTLS_ENCRYPT ) ) != 0 )
|
|
{
|
|
return( ret );
|
|
}
|
|
|
|
if( ( ret = gcm_gen_table( ctx ) ) != 0 )
|
|
return( ret );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/*
|
|
* Shoup's method for multiplication use this table with
|
|
* last4[x] = x times P^128
|
|
* where x and last4[x] are seen as elements of GF(2^128) as in [MGV]
|
|
*/
|
|
static const uint64_t last4[16] =
|
|
{
|
|
0x0000, 0x1c20, 0x3840, 0x2460,
|
|
0x7080, 0x6ca0, 0x48c0, 0x54e0,
|
|
0xe100, 0xfd20, 0xd940, 0xc560,
|
|
0x9180, 0x8da0, 0xa9c0, 0xb5e0
|
|
};
|
|
|
|
/*
|
|
* Sets output to x times H using the precomputed tables.
|
|
* x and output are seen as elements of GF(2^128) as in [MGV].
|
|
*/
|
|
static void gcm_mult( mbedtls_gcm_context *ctx, const unsigned char x[16],
|
|
unsigned char output[16] )
|
|
{
|
|
int i = 0;
|
|
unsigned char lo, hi, rem;
|
|
uint64_t zh, zl;
|
|
|
|
#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
|
|
if( mbedtls_aesni_has_support( MBEDTLS_AESNI_CLMUL ) ) {
|
|
unsigned char h[16];
|
|
|
|
PUT_UINT32_BE( ctx->HH[8] >> 32, h, 0 );
|
|
PUT_UINT32_BE( ctx->HH[8], h, 4 );
|
|
PUT_UINT32_BE( ctx->HL[8] >> 32, h, 8 );
|
|
PUT_UINT32_BE( ctx->HL[8], h, 12 );
|
|
|
|
mbedtls_aesni_gcm_mult( output, x, h );
|
|
return;
|
|
}
|
|
#endif /* MBEDTLS_AESNI_C && MBEDTLS_HAVE_X86_64 */
|
|
|
|
lo = x[15] & 0xf;
|
|
|
|
zh = ctx->HH[lo];
|
|
zl = ctx->HL[lo];
|
|
|
|
for( i = 15; i >= 0; i-- )
|
|
{
|
|
lo = x[i] & 0xf;
|
|
hi = ( x[i] >> 4 ) & 0xf;
|
|
|
|
if( i != 15 )
|
|
{
|
|
rem = (unsigned char) zl & 0xf;
|
|
zl = ( zh << 60 ) | ( zl >> 4 );
|
|
zh = ( zh >> 4 );
|
|
zh ^= (uint64_t) last4[rem] << 48;
|
|
zh ^= ctx->HH[lo];
|
|
zl ^= ctx->HL[lo];
|
|
|
|
}
|
|
|
|
rem = (unsigned char) zl & 0xf;
|
|
zl = ( zh << 60 ) | ( zl >> 4 );
|
|
zh = ( zh >> 4 );
|
|
zh ^= (uint64_t) last4[rem] << 48;
|
|
zh ^= ctx->HH[hi];
|
|
zl ^= ctx->HL[hi];
|
|
}
|
|
|
|
PUT_UINT32_BE( zh >> 32, output, 0 );
|
|
PUT_UINT32_BE( zh, output, 4 );
|
|
PUT_UINT32_BE( zl >> 32, output, 8 );
|
|
PUT_UINT32_BE( zl, output, 12 );
|
|
}
|
|
|
|
int mbedtls_gcm_starts( mbedtls_gcm_context *ctx,
|
|
int mode,
|
|
const unsigned char *iv, size_t iv_len )
|
|
{
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
unsigned char work_buf[16];
|
|
size_t i;
|
|
const unsigned char *p;
|
|
size_t use_len, olen = 0;
|
|
|
|
GCM_VALIDATE_RET( ctx != NULL );
|
|
GCM_VALIDATE_RET( iv != NULL );
|
|
|
|
/* IV is limited to 2^64 bits, so 2^61 bytes */
|
|
/* IV is not allowed to be zero length */
|
|
if( iv_len == 0 || (uint64_t) iv_len >> 61 != 0 )
|
|
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
|
|
|
memset( ctx->y, 0x00, sizeof(ctx->y) );
|
|
memset( ctx->buf, 0x00, sizeof(ctx->buf) );
|
|
|
|
ctx->mode = mode;
|
|
ctx->len = 0;
|
|
ctx->add_len = 0;
|
|
|
|
if( iv_len == 12 )
|
|
{
|
|
memcpy( ctx->y, iv, iv_len );
|
|
ctx->y[15] = 1;
|
|
}
|
|
else
|
|
{
|
|
memset( work_buf, 0x00, 16 );
|
|
PUT_UINT32_BE( iv_len * 8, work_buf, 12 );
|
|
|
|
p = iv;
|
|
while( iv_len > 0 )
|
|
{
|
|
use_len = ( iv_len < 16 ) ? iv_len : 16;
|
|
|
|
for( i = 0; i < use_len; i++ )
|
|
ctx->y[i] ^= p[i];
|
|
|
|
gcm_mult( ctx, ctx->y, ctx->y );
|
|
|
|
iv_len -= use_len;
|
|
p += use_len;
|
|
}
|
|
|
|
for( i = 0; i < 16; i++ )
|
|
ctx->y[i] ^= work_buf[i];
|
|
|
|
gcm_mult( ctx, ctx->y, ctx->y );
|
|
}
|
|
|
|
if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16,
|
|
ctx->base_ectr, &olen ) ) != 0 )
|
|
{
|
|
return( ret );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/**
|
|
* mbedtls_gcm_context::buf contains the partial state of the computation of
|
|
* the authentication tag.
|
|
* mbedtls_gcm_context::add_len and mbedtls_gcm_context::len indicate
|
|
* different stages of the computation:
|
|
* * len == 0 && add_len == 0: initial state
|
|
* * len == 0 && add_len % 16 != 0: the first `add_len % 16` bytes have
|
|
* a partial block of AD that has been
|
|
* xored in but not yet multiplied in.
|
|
* * len == 0 && add_len % 16 == 0: the authentication tag is correct if
|
|
* the data ends now.
|
|
* * len % 16 != 0: the first `len % 16` bytes have
|
|
* a partial block of ciphertext that has
|
|
* been xored in but not yet multiplied in.
|
|
* * len > 0 && len % 16 == 0: the authentication tag is correct if
|
|
* the data ends now.
|
|
*/
|
|
int mbedtls_gcm_update_ad( mbedtls_gcm_context *ctx,
|
|
const unsigned char *add, size_t add_len )
|
|
{
|
|
const unsigned char *p;
|
|
size_t use_len, i, offset;
|
|
|
|
GCM_VALIDATE_RET( add_len == 0 || add != NULL );
|
|
|
|
/* IV is limited to 2^64 bits, so 2^61 bytes */
|
|
if( (uint64_t) add_len >> 61 != 0 )
|
|
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
|
|
|
offset = ctx->add_len % 16;
|
|
p = add;
|
|
|
|
if( offset != 0 )
|
|
{
|
|
use_len = 16 - offset;
|
|
if( use_len > add_len )
|
|
use_len = add_len;
|
|
|
|
for( i = 0; i < use_len; i++ )
|
|
ctx->buf[i+offset] ^= p[i];
|
|
|
|
if( offset + use_len == 16 )
|
|
gcm_mult( ctx, ctx->buf, ctx->buf );
|
|
|
|
ctx->add_len += use_len;
|
|
add_len -= use_len;
|
|
p += use_len;
|
|
}
|
|
|
|
ctx->add_len += add_len;
|
|
|
|
while( add_len >= 16 )
|
|
{
|
|
for( i = 0; i < 16; i++ )
|
|
ctx->buf[i] ^= p[i];
|
|
|
|
gcm_mult( ctx, ctx->buf, ctx->buf );
|
|
|
|
add_len -= 16;
|
|
p += 16;
|
|
}
|
|
|
|
if( add_len > 0 )
|
|
{
|
|
for( i = 0; i < add_len; i++ )
|
|
ctx->buf[i] ^= p[i];
|
|
}
|
|
|
|
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,
|
|
const unsigned char *input, size_t input_length,
|
|
unsigned char *output, size_t output_size,
|
|
size_t *output_length )
|
|
{
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
const unsigned char *p = input;
|
|
unsigned char *out_p = output;
|
|
size_t offset;
|
|
unsigned char ectr[16];
|
|
|
|
if( output_size < input_length )
|
|
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
|
GCM_VALIDATE_RET( output_length != NULL );
|
|
*output_length = input_length;
|
|
|
|
/* Exit early if input_length==0 so that we don't do any pointer arithmetic
|
|
* on a potentially null pointer.
|
|
* Returning early also means that the last partial block of AD remains
|
|
* untouched for mbedtls_gcm_finish */
|
|
if( input_length == 0 )
|
|
return( 0 );
|
|
|
|
GCM_VALIDATE_RET( ctx != NULL );
|
|
GCM_VALIDATE_RET( input != NULL );
|
|
GCM_VALIDATE_RET( output != NULL );
|
|
|
|
if( output > input && (size_t) ( output - input ) < input_length )
|
|
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
|
|
|
/* Total length is restricted to 2^39 - 256 bits, ie 2^36 - 2^5 bytes
|
|
* Also check for possible overflow */
|
|
if( ctx->len + input_length < ctx->len ||
|
|
(uint64_t) ctx->len + input_length > 0xFFFFFFFE0ull )
|
|
{
|
|
return( MBEDTLS_ERR_GCM_BAD_INPUT );
|
|
}
|
|
|
|
if( ctx->len == 0 && ctx->add_len % 16 != 0 )
|
|
{
|
|
gcm_mult( ctx, ctx->buf, ctx->buf );
|
|
}
|
|
|
|
offset = ctx->len % 16;
|
|
if( offset != 0 )
|
|
{
|
|
size_t use_len = 16 - offset;
|
|
if( use_len > input_length )
|
|
use_len = input_length;
|
|
|
|
if( ( ret = gcm_mask( ctx, ectr, offset, use_len, p, out_p ) ) != 0 )
|
|
return( ret );
|
|
|
|
if( offset + use_len == 16 )
|
|
gcm_mult( ctx, ctx->buf, ctx->buf );
|
|
|
|
ctx->len += use_len;
|
|
input_length -= use_len;
|
|
p += use_len;
|
|
out_p += use_len;
|
|
}
|
|
|
|
ctx->len += input_length;
|
|
|
|
while( input_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 );
|
|
|
|
input_length -= 16;
|
|
p += 16;
|
|
out_p += 16;
|
|
}
|
|
|
|
if( input_length > 0 )
|
|
{
|
|
gcm_incr( ctx->y );
|
|
if( ( ret = gcm_mask( ctx, ectr, 0, input_length, p, out_p ) ) != 0 )
|
|
return( ret );
|
|
}
|
|
|
|
mbedtls_platform_zeroize( ectr, sizeof( ectr ) );
|
|
return( 0 );
|
|
}
|
|
|
|
int mbedtls_gcm_finish( mbedtls_gcm_context *ctx,
|
|
unsigned char *output, size_t output_size,
|
|
size_t *output_length,
|
|
unsigned char *tag, size_t tag_len )
|
|
{
|
|
unsigned char work_buf[16];
|
|
size_t i;
|
|
uint64_t orig_len;
|
|
uint64_t orig_add_len;
|
|
|
|
GCM_VALIDATE_RET( ctx != NULL );
|
|
GCM_VALIDATE_RET( tag != NULL );
|
|
|
|
/* We never pass any output in finish(). The output parameter exists only
|
|
* for the sake of alternative implementations. */
|
|
(void) output;
|
|
(void) output_size;
|
|
*output_length = 0;
|
|
|
|
orig_len = ctx->len * 8;
|
|
orig_add_len = ctx->add_len * 8;
|
|
|
|
if( ctx->len == 0 && ctx->add_len % 16 != 0 )
|
|
{
|
|
gcm_mult( ctx, ctx->buf, ctx->buf );
|
|
}
|
|
|
|
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 )
|
|
{
|
|
memset( work_buf, 0x00, 16 );
|
|
|
|
PUT_UINT32_BE( ( orig_add_len >> 32 ), work_buf, 0 );
|
|
PUT_UINT32_BE( ( orig_add_len ), work_buf, 4 );
|
|
PUT_UINT32_BE( ( orig_len >> 32 ), work_buf, 8 );
|
|
PUT_UINT32_BE( ( orig_len ), work_buf, 12 );
|
|
|
|
for( i = 0; i < 16; i++ )
|
|
ctx->buf[i] ^= work_buf[i];
|
|
|
|
gcm_mult( ctx, ctx->buf, ctx->buf );
|
|
|
|
for( i = 0; i < tag_len; i++ )
|
|
tag[i] ^= ctx->buf[i];
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx,
|
|
int mode,
|
|
size_t length,
|
|
const unsigned char *iv,
|
|
size_t iv_len,
|
|
const unsigned char *add,
|
|
size_t add_len,
|
|
const unsigned char *input,
|
|
unsigned char *output,
|
|
size_t tag_len,
|
|
unsigned char *tag )
|
|
{
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
size_t olen;
|
|
|
|
GCM_VALIDATE_RET( ctx != NULL );
|
|
GCM_VALIDATE_RET( iv != NULL );
|
|
GCM_VALIDATE_RET( add_len == 0 || add != NULL );
|
|
GCM_VALIDATE_RET( length == 0 || input != NULL );
|
|
GCM_VALIDATE_RET( length == 0 || output != NULL );
|
|
GCM_VALIDATE_RET( tag != NULL );
|
|
|
|
if( ( ret = mbedtls_gcm_starts( ctx, mode, iv, iv_len ) ) != 0 )
|
|
return( ret );
|
|
|
|
if( ( ret = mbedtls_gcm_update_ad( ctx, add, add_len ) ) != 0 )
|
|
return( ret );
|
|
|
|
if( ( ret = mbedtls_gcm_update( ctx, input, length,
|
|
output, length, &olen ) ) != 0 )
|
|
return( ret );
|
|
|
|
if( ( ret = mbedtls_gcm_finish( ctx, NULL, 0, &olen, tag, tag_len ) ) != 0 )
|
|
return( ret );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx,
|
|
size_t length,
|
|
const unsigned char *iv,
|
|
size_t iv_len,
|
|
const unsigned char *add,
|
|
size_t add_len,
|
|
const unsigned char *tag,
|
|
size_t tag_len,
|
|
const unsigned char *input,
|
|
unsigned char *output )
|
|
{
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
unsigned char check_tag[16];
|
|
size_t i;
|
|
int diff;
|
|
|
|
GCM_VALIDATE_RET( ctx != NULL );
|
|
GCM_VALIDATE_RET( iv != NULL );
|
|
GCM_VALIDATE_RET( add_len == 0 || add != NULL );
|
|
GCM_VALIDATE_RET( tag != NULL );
|
|
GCM_VALIDATE_RET( length == 0 || input != NULL );
|
|
GCM_VALIDATE_RET( length == 0 || output != NULL );
|
|
|
|
if( ( ret = mbedtls_gcm_crypt_and_tag( ctx, MBEDTLS_GCM_DECRYPT, length,
|
|
iv, iv_len, add, add_len,
|
|
input, output, tag_len, check_tag ) ) != 0 )
|
|
{
|
|
return( ret );
|
|
}
|
|
|
|
/* Check tag in "constant-time" */
|
|
for( diff = 0, i = 0; i < tag_len; i++ )
|
|
diff |= tag[i] ^ check_tag[i];
|
|
|
|
if( diff != 0 )
|
|
{
|
|
mbedtls_platform_zeroize( output, length );
|
|
return( MBEDTLS_ERR_GCM_AUTH_FAILED );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
void mbedtls_gcm_free( mbedtls_gcm_context *ctx )
|
|
{
|
|
if( ctx == NULL )
|
|
return;
|
|
mbedtls_cipher_free( &ctx->cipher_ctx );
|
|
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_gcm_context ) );
|
|
}
|
|
|
|
#endif /* !MBEDTLS_GCM_ALT */
|
|
|
|
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
|
|
/*
|
|
* AES-GCM test vectors from:
|
|
*
|
|
* http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip
|
|
*/
|
|
#define MAX_TESTS 6
|
|
|
|
static const int key_index_test_data[MAX_TESTS] =
|
|
{ 0, 0, 1, 1, 1, 1 };
|
|
|
|
static const unsigned char key_test_data[MAX_TESTS][32] =
|
|
{
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
{ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
|
|
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
|
|
0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
|
|
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
|
|
};
|
|
|
|
static const size_t iv_len_test_data[MAX_TESTS] =
|
|
{ 12, 12, 12, 12, 8, 60 };
|
|
|
|
static const int iv_index_test_data[MAX_TESTS] =
|
|
{ 0, 0, 1, 1, 1, 2 };
|
|
|
|
static const unsigned char iv_test_data[MAX_TESTS][64] =
|
|
{
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00 },
|
|
{ 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
|
|
0xde, 0xca, 0xf8, 0x88 },
|
|
{ 0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5,
|
|
0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa,
|
|
0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1,
|
|
0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28,
|
|
0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39,
|
|
0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54,
|
|
0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
|
|
0xa6, 0x37, 0xb3, 0x9b },
|
|
};
|
|
|
|
static const size_t add_len_test_data[MAX_TESTS] =
|
|
{ 0, 0, 0, 20, 20, 20 };
|
|
|
|
static const int add_index_test_data[MAX_TESTS] =
|
|
{ 0, 0, 0, 1, 1, 1 };
|
|
|
|
static const unsigned char additional_test_data[MAX_TESTS][64] =
|
|
{
|
|
{ 0x00 },
|
|
{ 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
|
|
0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
|
|
0xab, 0xad, 0xda, 0xd2 },
|
|
};
|
|
|
|
static const size_t pt_len_test_data[MAX_TESTS] =
|
|
{ 0, 16, 64, 60, 60, 60 };
|
|
|
|
static const int pt_index_test_data[MAX_TESTS] =
|
|
{ 0, 0, 1, 1, 1, 1 };
|
|
|
|
static const unsigned char pt_test_data[MAX_TESTS][64] =
|
|
{
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
{ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
|
|
0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
|
|
0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
|
|
0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
|
|
0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
|
|
0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
|
|
0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
|
|
0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 },
|
|
};
|
|
|
|
static const unsigned char ct_test_data[MAX_TESTS * 3][64] =
|
|
{
|
|
{ 0x00 },
|
|
{ 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
|
|
0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78 },
|
|
{ 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
|
|
0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
|
|
0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
|
|
0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
|
|
0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
|
|
0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
|
|
0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
|
|
0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 },
|
|
{ 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
|
|
0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
|
|
0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
|
|
0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
|
|
0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
|
|
0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
|
|
0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
|
|
0x3d, 0x58, 0xe0, 0x91 },
|
|
{ 0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a,
|
|
0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55,
|
|
0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8,
|
|
0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23,
|
|
0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2,
|
|
0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42,
|
|
0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07,
|
|
0xc2, 0x3f, 0x45, 0x98 },
|
|
{ 0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6,
|
|
0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94,
|
|
0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8,
|
|
0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7,
|
|
0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90,
|
|
0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f,
|
|
0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03,
|
|
0x4c, 0x34, 0xae, 0xe5 },
|
|
{ 0x00 },
|
|
{ 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41,
|
|
0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00 },
|
|
{ 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
|
|
0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
|
|
0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
|
|
0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
|
|
0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
|
|
0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
|
|
0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
|
|
0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56 },
|
|
{ 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
|
|
0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
|
|
0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
|
|
0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
|
|
0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
|
|
0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
|
|
0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
|
|
0xcc, 0xda, 0x27, 0x10 },
|
|
{ 0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54,
|
|
0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32, 0x4d, 0xb8,
|
|
0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f,
|
|
0x83, 0x47, 0x28, 0x0f, 0xc4, 0x50, 0x70, 0x57,
|
|
0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75,
|
|
0xc6, 0x65, 0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9,
|
|
0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f,
|
|
0xa0, 0xf0, 0x62, 0xf7 },
|
|
{ 0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c,
|
|
0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc, 0xf9, 0xff,
|
|
0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef,
|
|
0x6e, 0xf7, 0xb7, 0x98, 0x28, 0x66, 0x6e, 0x45,
|
|
0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9,
|
|
0xe2, 0xf0, 0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3,
|
|
0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7,
|
|
0xe9, 0xb7, 0x37, 0x3b },
|
|
{ 0x00 },
|
|
{ 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e,
|
|
0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18 },
|
|
{ 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
|
|
0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
|
|
0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
|
|
0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
|
|
0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
|
|
0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
|
|
0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
|
|
0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad },
|
|
{ 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
|
|
0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
|
|
0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
|
|
0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
|
|
0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
|
|
0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
|
|
0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
|
|
0xbc, 0xc9, 0xf6, 0x62 },
|
|
{ 0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32,
|
|
0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98, 0x44, 0xcb,
|
|
0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa,
|
|
0xc5, 0x2f, 0xf7, 0xd7, 0x9b, 0xba, 0x9d, 0xe0,
|
|
0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0,
|
|
0x95, 0x4c, 0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78,
|
|
0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99,
|
|
0xf4, 0x7c, 0x9b, 0x1f },
|
|
{ 0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1,
|
|
0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e, 0x2a, 0x20,
|
|
0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19,
|
|
0xa0, 0x58, 0xab, 0x4f, 0x6f, 0x74, 0x6b, 0xf4,
|
|
0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45,
|
|
0x2d, 0xa3, 0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde,
|
|
0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e,
|
|
0x44, 0xae, 0x7e, 0x3f },
|
|
};
|
|
|
|
static const unsigned char tag_test_data[MAX_TESTS * 3][16] =
|
|
{
|
|
{ 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61,
|
|
0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a },
|
|
{ 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd,
|
|
0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf },
|
|
{ 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
|
|
0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 },
|
|
{ 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb,
|
|
0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 },
|
|
{ 0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85,
|
|
0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb },
|
|
{ 0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa,
|
|
0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50 },
|
|
{ 0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b,
|
|
0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35 },
|
|
{ 0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab,
|
|
0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb },
|
|
{ 0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf,
|
|
0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14 },
|
|
{ 0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f,
|
|
0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c },
|
|
{ 0x65, 0xdc, 0xc5, 0x7f, 0xcf, 0x62, 0x3a, 0x24,
|
|
0x09, 0x4f, 0xcc, 0xa4, 0x0d, 0x35, 0x33, 0xf8 },
|
|
{ 0xdc, 0xf5, 0x66, 0xff, 0x29, 0x1c, 0x25, 0xbb,
|
|
0xb8, 0x56, 0x8f, 0xc3, 0xd3, 0x76, 0xa6, 0xd9 },
|
|
{ 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9,
|
|
0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b },
|
|
{ 0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0,
|
|
0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19 },
|
|
{ 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd,
|
|
0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c },
|
|
{ 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
|
|
0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b },
|
|
{ 0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4,
|
|
0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e, 0xa8, 0xf2 },
|
|
{ 0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0,
|
|
0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9, 0xf1, 0x9a },
|
|
};
|
|
|
|
int mbedtls_gcm_self_test( int verbose )
|
|
{
|
|
mbedtls_gcm_context ctx;
|
|
unsigned char buf[64];
|
|
unsigned char tag_buf[16];
|
|
int i, j, ret;
|
|
mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES;
|
|
size_t olen;
|
|
|
|
for( j = 0; j < 3; j++ )
|
|
{
|
|
int key_len = 128 + 64 * j;
|
|
|
|
for( i = 0; i < MAX_TESTS; i++ )
|
|
{
|
|
mbedtls_gcm_init( &ctx );
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( " AES-GCM-%3d #%d (%s): ",
|
|
key_len, i, "enc" );
|
|
|
|
ret = mbedtls_gcm_setkey( &ctx, cipher,
|
|
key_test_data[key_index_test_data[i]],
|
|
key_len );
|
|
/*
|
|
* AES-192 is an optional feature that may be unavailable when
|
|
* there is an alternative underlying implementation i.e. when
|
|
* MBEDTLS_AES_ALT is defined.
|
|
*/
|
|
if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && key_len == 192 )
|
|
{
|
|
mbedtls_printf( "skipped\n" );
|
|
break;
|
|
}
|
|
else if( ret != 0 )
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_ENCRYPT,
|
|
pt_len_test_data[i],
|
|
iv_test_data[iv_index_test_data[i]],
|
|
iv_len_test_data[i],
|
|
additional_test_data[add_index_test_data[i]],
|
|
add_len_test_data[i],
|
|
pt_test_data[pt_index_test_data[i]],
|
|
buf, 16, tag_buf );
|
|
#if defined(MBEDTLS_GCM_ALT)
|
|
/* Allow alternative implementations to only support 12-byte nonces. */
|
|
if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED &&
|
|
iv_len_test_data[i] != 12 )
|
|
{
|
|
mbedtls_printf( "skipped\n" );
|
|
break;
|
|
}
|
|
#endif /* defined(MBEDTLS_GCM_ALT) */
|
|
if( ret != 0 )
|
|
goto exit;
|
|
|
|
if ( memcmp( buf, ct_test_data[j * 6 + i],
|
|
pt_len_test_data[i] ) != 0 ||
|
|
memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
|
|
{
|
|
ret = 1;
|
|
goto exit;
|
|
}
|
|
|
|
mbedtls_gcm_free( &ctx );
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "passed\n" );
|
|
|
|
mbedtls_gcm_init( &ctx );
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( " AES-GCM-%3d #%d (%s): ",
|
|
key_len, i, "dec" );
|
|
|
|
ret = mbedtls_gcm_setkey( &ctx, cipher,
|
|
key_test_data[key_index_test_data[i]],
|
|
key_len );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
|
|
ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_DECRYPT,
|
|
pt_len_test_data[i],
|
|
iv_test_data[iv_index_test_data[i]],
|
|
iv_len_test_data[i],
|
|
additional_test_data[add_index_test_data[i]],
|
|
add_len_test_data[i],
|
|
ct_test_data[j * 6 + i], buf, 16, tag_buf );
|
|
|
|
if( ret != 0 )
|
|
goto exit;
|
|
|
|
if( memcmp( buf, pt_test_data[pt_index_test_data[i]],
|
|
pt_len_test_data[i] ) != 0 ||
|
|
memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
|
|
{
|
|
ret = 1;
|
|
goto exit;
|
|
}
|
|
|
|
mbedtls_gcm_free( &ctx );
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "passed\n" );
|
|
|
|
mbedtls_gcm_init( &ctx );
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( " AES-GCM-%3d #%d split (%s): ",
|
|
key_len, i, "enc" );
|
|
|
|
ret = mbedtls_gcm_setkey( &ctx, cipher,
|
|
key_test_data[key_index_test_data[i]],
|
|
key_len );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
|
|
ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_ENCRYPT,
|
|
iv_test_data[iv_index_test_data[i]],
|
|
iv_len_test_data[i] );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
|
|
ret = mbedtls_gcm_update_ad( &ctx,
|
|
additional_test_data[add_index_test_data[i]],
|
|
add_len_test_data[i] );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
|
|
if( pt_len_test_data[i] > 32 )
|
|
{
|
|
size_t rest_len = pt_len_test_data[i] - 32;
|
|
ret = mbedtls_gcm_update( &ctx,
|
|
pt_test_data[pt_index_test_data[i]],
|
|
32,
|
|
buf, sizeof( buf ), &olen );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
if( olen != 32 )
|
|
goto exit;
|
|
|
|
ret = mbedtls_gcm_update( &ctx,
|
|
pt_test_data[pt_index_test_data[i]] + 32,
|
|
rest_len,
|
|
buf + 32, sizeof( buf ) - 32, &olen );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
if( olen != rest_len )
|
|
goto exit;
|
|
}
|
|
else
|
|
{
|
|
ret = mbedtls_gcm_update( &ctx,
|
|
pt_test_data[pt_index_test_data[i]],
|
|
pt_len_test_data[i],
|
|
buf, sizeof( buf ), &olen );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
if( olen != pt_len_test_data[i] )
|
|
goto exit;
|
|
}
|
|
|
|
ret = mbedtls_gcm_finish( &ctx, NULL, 0, &olen, tag_buf, 16 );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
|
|
if( memcmp( buf, ct_test_data[j * 6 + i],
|
|
pt_len_test_data[i] ) != 0 ||
|
|
memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
|
|
{
|
|
ret = 1;
|
|
goto exit;
|
|
}
|
|
|
|
mbedtls_gcm_free( &ctx );
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "passed\n" );
|
|
|
|
mbedtls_gcm_init( &ctx );
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( " AES-GCM-%3d #%d split (%s): ",
|
|
key_len, i, "dec" );
|
|
|
|
ret = mbedtls_gcm_setkey( &ctx, cipher,
|
|
key_test_data[key_index_test_data[i]],
|
|
key_len );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
|
|
ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_DECRYPT,
|
|
iv_test_data[iv_index_test_data[i]],
|
|
iv_len_test_data[i] );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
ret = mbedtls_gcm_update_ad( &ctx,
|
|
additional_test_data[add_index_test_data[i]],
|
|
add_len_test_data[i] );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
|
|
if( pt_len_test_data[i] > 32 )
|
|
{
|
|
size_t rest_len = pt_len_test_data[i] - 32;
|
|
ret = mbedtls_gcm_update( &ctx,
|
|
ct_test_data[j * 6 + i], 32,
|
|
buf, sizeof( buf ), &olen );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
if( olen != 32 )
|
|
goto exit;
|
|
|
|
ret = mbedtls_gcm_update( &ctx,
|
|
ct_test_data[j * 6 + i] + 32,
|
|
rest_len,
|
|
buf + 32, sizeof( buf ) - 32, &olen );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
if( olen != rest_len )
|
|
goto exit;
|
|
}
|
|
else
|
|
{
|
|
ret = mbedtls_gcm_update( &ctx,
|
|
ct_test_data[j * 6 + i],
|
|
pt_len_test_data[i],
|
|
buf, sizeof( buf ), &olen );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
if( olen != pt_len_test_data[i] )
|
|
goto exit;
|
|
}
|
|
|
|
ret = mbedtls_gcm_finish( &ctx, NULL, 0, &olen, tag_buf, 16 );
|
|
if( ret != 0 )
|
|
goto exit;
|
|
|
|
if( memcmp( buf, pt_test_data[pt_index_test_data[i]],
|
|
pt_len_test_data[i] ) != 0 ||
|
|
memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
|
|
{
|
|
ret = 1;
|
|
goto exit;
|
|
}
|
|
|
|
mbedtls_gcm_free( &ctx );
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "passed\n" );
|
|
}
|
|
}
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "\n" );
|
|
|
|
ret = 0;
|
|
|
|
exit:
|
|
if( ret != 0 )
|
|
{
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "failed\n" );
|
|
mbedtls_gcm_free( &ctx );
|
|
}
|
|
|
|
return( ret );
|
|
}
|
|
|
|
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
|
|
|
|
#endif /* MBEDTLS_GCM_C */
|