aes-gcm: modified to use sequence number rather that a random explicit IV

This commit is contained in:
John Safranek 2012-07-31 09:32:29 -07:00
parent 3cd231bdfc
commit 9b8c5fb40e
6 changed files with 86 additions and 48 deletions

View File

@ -186,8 +186,8 @@ void bench_aesgcm()
double start, total, persec;
int i;
AesGcmSetKey(&enc, key, 16);
AesSetIV(&enc, iv);
AesGcmSetKey(&enc, key, 16, iv);
AesGcmSetExpIV(&enc, iv+4);
start = current_time();
for(i = 0; i < megs; i++)

View File

@ -1407,6 +1407,25 @@ void AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
#ifdef HAVE_AESGCM
/*
* The IV for AES GCM, stored in struct Aes's member reg, is comprised of
* three parts in order:
* 1. The implicit IV. This is generated from the PRF using the shared
* secrets between endpoints. It is 4 bytes long.
* 2. The explicit IV. This is set by the user of the AES. It needs to be
* unique for each call to encrypt. The explicit IV is shared with the
* other end of the transaction in the clear.
* 3. The counter. Each block of data is encrypted with its own sequence
* number counter.
*/
enum {
IMPLICIT_IV_SZ = 4,
EXPLICIT_IV_SZ = 8,
CTR_SZ = 4
};
static INLINE void InitGcmCounter(byte* inOutCtr)
{
inOutCtr[AES_BLOCK_SIZE - 4] = 0;
@ -1421,13 +1440,43 @@ static INLINE void IncrementGcmCounter(byte* inOutCtr)
int i;
/* in network byte order so start at end and work back */
for (i = AES_BLOCK_SIZE - 1; i >= AES_BLOCK_SIZE - 4; i--) {
for (i = AES_BLOCK_SIZE - 1; i >= AES_BLOCK_SIZE - CTR_SZ; i--) {
if (++inOutCtr[i]) /* we're done unless we overflow */
return;
}
}
/*
* The explicit IV is set by the caller. A common practice is to treat it as
* a sequence number seeded with a random number. The caller manages
* incrementing the explicit IV when appropriate.
*/
void AesGcmSetExpIV(Aes* aes, const byte* iv)
{
XMEMCPY((byte*)aes->reg + IMPLICIT_IV_SZ, iv, EXPLICIT_IV_SZ);
}
void AesGcmGetExpIV(Aes* aes, byte* iv)
{
XMEMCPY(iv, (byte*)aes->reg + IMPLICIT_IV_SZ, EXPLICIT_IV_SZ);
}
void AesGcmIncExpIV(Aes* aes)
{
int i;
byte* iv = (byte*)aes->reg + IMPLICIT_IV_SZ;
for (i = EXPLICIT_IV_SZ - 1; i >= 0; i--) {
if (++iv[i])
return;
}
}
#if defined(GCM_SMALL) || defined(GCM_TABLE)
static INLINE void FlattenSzInBits(byte* buf, word32 sz)
@ -1493,13 +1542,17 @@ static void GenerateM0(Aes* aes)
#endif /* GCM_TABLE */
void AesGcmSetKey(Aes* aes, const byte* key, word32 len)
void AesGcmSetKey(Aes* aes, const byte* key, word32 len,
const byte* implicitIV)
{
byte iv[AES_BLOCK_SIZE];
byte fullIV[AES_BLOCK_SIZE];
XMEMSET(iv, 0, AES_BLOCK_SIZE);
AesSetKey(aes, key, len, iv, AES_ENCRYPTION);
AesEncrypt(aes, iv, aes->H);
XMEMSET(fullIV, 0, AES_BLOCK_SIZE);
XMEMCPY(fullIV, implicitIV, IMPLICIT_IV_SZ);
AesSetKey(aes, key, len, fullIV, AES_ENCRYPTION);
XMEMSET(fullIV, 0, AES_BLOCK_SIZE);
AesEncrypt(aes, fullIV, aes->H);
#ifdef GCM_TABLE
GenerateM0(aes);
#endif /* GCM_TABLE */

View File

@ -1226,8 +1226,8 @@ int aesgcm_test()
memset(c2, 0, 60);
memset(p2, 0, 60);
AesGcmSetKey(&enc, k, sizeof(k));
AesSetIV(&enc, iv);
AesGcmSetKey(&enc, k, sizeof(k), iv);
AesGcmSetExpIV(&enc, iv + /*AES_GCM_IMP_IV_SZ*/ 4);
/* AES-GCM encrypt and decrypt both use AES encrypt internally */
AesGcmEncrypt(&enc, c2, p, sizeof(c2), t2, sizeof(t2), a, sizeof(a));
if (memcmp(c, c2, sizeof(c2)))

View File

@ -89,7 +89,11 @@ CYASSL_API void AesEncryptDirect(Aes* aes, byte* out, const byte* in);
CYASSL_API void AesDecryptDirect(Aes* aes, byte* out, const byte* in);
#ifdef HAVE_AESGCM
CYASSL_API void AesGcmSetKey(Aes* aes, const byte* key, word32 len);
CYASSL_API void AesGcmSetKey(Aes* aes, const byte* key, word32 len,
const byte* implicitIV);
CYASSL_API void AesGcmSetExpIV(Aes* aes, const byte* iv);
CYASSL_API void AesGcmGetExpIV(Aes* aes, byte* iv);
CYASSL_API void AesGcmIncExpIV(Aes* aes);
CYASSL_API void AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz,
byte* authTag, word32 authTagSz,
const byte* authIn, word32 authInSz);

View File

@ -2223,22 +2223,6 @@ static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz)
case aes_gcm:
{
byte additional[AES_BLOCK_SIZE];
byte nonce[AES_BLOCK_SIZE];
/* use this side's IV */
if (ssl->options.side == SERVER_END) {
XMEMCPY(nonce, ssl->keys.server_write_IV,
AES_GCM_IMP_IV_SZ);
}
else {
XMEMCPY(nonce, ssl->keys.client_write_IV,
AES_GCM_IMP_IV_SZ);
}
XMEMCPY(nonce + AES_GCM_IMP_IV_SZ,
input, AES_GCM_EXP_IV_SZ);
XMEMSET(nonce + AES_GCM_IMP_IV_SZ + AES_GCM_EXP_IV_SZ,
0, AES_GCM_CTR_IV_SZ);
AesSetIV(&ssl->encrypt.aes, nonce);
XMEMSET(additional, 0, AES_BLOCK_SIZE);
@ -2259,6 +2243,7 @@ static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz)
sz - AES_GCM_EXP_IV_SZ - AEAD_AUTH_TAG_SZ,
out + sz - AEAD_AUTH_TAG_SZ, AEAD_AUTH_TAG_SZ,
additional, AEAD_AUTH_DATA_SZ);
AesGcmIncExpIV(&ssl->encrypt.aes);
}
break;
#endif
@ -2307,23 +2292,8 @@ static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input,
case aes_gcm:
{
byte additional[AES_BLOCK_SIZE];
byte nonce[AES_BLOCK_SIZE];
/* use the other side's IV */
if (ssl->options.side == SERVER_END) {
XMEMCPY(nonce, ssl->keys.client_write_IV,
AES_GCM_IMP_IV_SZ);
}
else {
XMEMCPY(nonce, ssl->keys.server_write_IV,
AES_GCM_IMP_IV_SZ);
}
XMEMCPY(nonce + AES_GCM_IMP_IV_SZ,
input, AES_GCM_EXP_IV_SZ);
XMEMSET(nonce + AES_GCM_IMP_IV_SZ + AES_GCM_EXP_IV_SZ,
0, AES_GCM_CTR_IV_SZ);
AesSetIV(&ssl->decrypt.aes, nonce);
AesGcmSetExpIV(&ssl->decrypt.aes, input);
XMEMSET(additional, 0, AES_BLOCK_SIZE);
/* sequence number field is 64-bits, we only use 32-bits */
@ -3035,7 +3005,7 @@ static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz,
if (ssl->specs.cipher_type == aead) {
ivSz = AES_GCM_EXP_IV_SZ;
sz += (ivSz + 16 - digestSz);
RNG_GenerateBlock(&ssl->rng, iv, ivSz);
AesGcmGetExpIV(&ssl->encrypt.aes, iv);
}
size = (word16)(sz - headerSz); /* include mac and digest */
AddRecordHeader(output, size, (byte)type, ssl);

View File

@ -1009,12 +1009,16 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs,
#ifdef BUILD_AESGCM
if (specs->bulk_cipher_algorithm == aes_gcm) {
if (side == CLIENT_END) {
AesGcmSetKey(&enc->aes, keys->client_write_key, specs->key_size);
AesGcmSetKey(&dec->aes, keys->server_write_key, specs->key_size);
AesGcmSetKey(&enc->aes, keys->client_write_key, specs->key_size,
keys->client_write_IV);
AesGcmSetKey(&dec->aes, keys->server_write_key, specs->key_size,
keys->server_write_IV);
}
else {
AesGcmSetKey(&enc->aes, keys->server_write_key, specs->key_size);
AesGcmSetKey(&dec->aes, keys->client_write_key, specs->key_size);
AesGcmSetKey(&enc->aes, keys->server_write_key, specs->key_size,
keys->server_write_IV);
AesGcmSetKey(&dec->aes, keys->client_write_key, specs->key_size,
keys->client_write_IV);
}
}
#endif
@ -1039,6 +1043,13 @@ int StoreKeys(CYASSL* ssl, const byte* keyData)
XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz);
i += sz;
}
else if (ssl->specs.bulk_cipher_algorithm == aes_gcm) {
byte iv[AES_GCM_EXP_IV_SZ];
/* Initialize the AES-GCM explicit IV to a random number. */
RNG_GenerateBlock(&ssl->rng, iv, sizeof(iv));
AesGcmSetExpIV(&ssl->encrypt.aes, iv);
}
sz = ssl->specs.key_size;
XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz);