AES-GCM: fixed the encryption/decryption bug

This commit is contained in:
John Safranek
2012-06-26 15:51:40 -07:00
parent 3a9a195683
commit 4e3d7f494b
3 changed files with 140 additions and 141 deletions

View File

@@ -1551,7 +1551,7 @@ void AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz,
byte* c = out; byte* c = out;
byte h[AES_BLOCK_SIZE]; byte h[AES_BLOCK_SIZE];
byte ctr[AES_BLOCK_SIZE]; byte ctr[AES_BLOCK_SIZE];
byte scratch[AES_BLOCK_SIZE]; byte scratch[AES_BLOCK_SIZE];
CYASSL_ENTER("AesGcmEncrypt"); CYASSL_ENTER("AesGcmEncrypt");
@@ -1568,7 +1568,7 @@ void AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz,
IncrementGcmCounter(ctr); IncrementGcmCounter(ctr);
AesEncrypt(aes, ctr, scratch); AesEncrypt(aes, ctr, scratch);
xorbuf(scratch, p, AES_BLOCK_SIZE); xorbuf(scratch, p, AES_BLOCK_SIZE);
XMEMCPY(c, scratch, AES_BLOCK_SIZE); XMEMCPY(c, scratch, AES_BLOCK_SIZE);
p += AES_BLOCK_SIZE; p += AES_BLOCK_SIZE;
c += AES_BLOCK_SIZE; c += AES_BLOCK_SIZE;
@@ -1576,7 +1576,7 @@ void AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz,
if (partial != 0) { if (partial != 0) {
IncrementGcmCounter(ctr); IncrementGcmCounter(ctr);
AesEncrypt(aes, ctr, scratch); AesEncrypt(aes, ctr, scratch);
xorbuf(scratch, p, partial); xorbuf(scratch, p, partial);
XMEMCPY(c, scratch, partial); XMEMCPY(c, scratch, partial);
} }
GHASH(h, authIn, authInSz, out, sz, authTag, authTagSz); GHASH(h, authIn, authInSz, out, sz, authTag, authTagSz);
@@ -1596,7 +1596,7 @@ int AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz,
byte* p = out; byte* p = out;
byte h[AES_BLOCK_SIZE]; byte h[AES_BLOCK_SIZE];
byte ctr[AES_BLOCK_SIZE]; byte ctr[AES_BLOCK_SIZE];
byte scratch[AES_BLOCK_SIZE]; byte scratch[AES_BLOCK_SIZE];
CYASSL_ENTER("AesGcmDecrypt"); CYASSL_ENTER("AesGcmDecrypt");
@@ -1627,7 +1627,7 @@ int AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz,
IncrementGcmCounter(ctr); IncrementGcmCounter(ctr);
AesEncrypt(aes, ctr, scratch); AesEncrypt(aes, ctr, scratch);
xorbuf(scratch, c, AES_BLOCK_SIZE); xorbuf(scratch, c, AES_BLOCK_SIZE);
XMEMCPY(p, scratch, AES_BLOCK_SIZE); XMEMCPY(p, scratch, AES_BLOCK_SIZE);
p += AES_BLOCK_SIZE; p += AES_BLOCK_SIZE;
c += AES_BLOCK_SIZE; c += AES_BLOCK_SIZE;

View File

@@ -1187,7 +1187,7 @@ static void HashOutput(CYASSL* ssl, const byte* output, int sz, int ivSz)
#ifdef CYASSL_SHA384 #ifdef CYASSL_SHA384
Sha384Update(&ssl->hashSha384, adj, sz); Sha384Update(&ssl->hashSha384, adj, sz);
#endif #endif
} }
} }
@@ -1213,7 +1213,7 @@ static void HashInput(CYASSL* ssl, const byte* input, int sz)
#ifdef CYASSL_SHA384 #ifdef CYASSL_SHA384
Sha384Update(&ssl->hashSha384, adj, sz); Sha384Update(&ssl->hashSha384, adj, sz);
#endif #endif
} }
} }
@@ -1636,8 +1636,8 @@ static void BuildFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
sha256 = ssl->hashSha256; sha256 = ssl->hashSha256;
#endif #endif
#if CYASSL_SHA384 #if CYASSL_SHA384
Sha384 sha384; Sha384 sha384;
InitSha384(&sha384); InitSha384(&sha384);
if (IsAtLeastTLSv1_2(ssl)) if (IsAtLeastTLSv1_2(ssl))
sha384 = ssl->hashSha384; sha384 = ssl->hashSha384;
#endif #endif
@@ -2038,30 +2038,30 @@ int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx, int sniff)
} }
} }
if (ssl->specs.cipher_type != aead) { if (ssl->specs.cipher_type != aead) {
ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz, ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz,
handshake, 1); handshake, 1);
idx += finishedSz; idx += finishedSz;
/* read mac and fill */ /* read mac and fill */
mac = input + idx; mac = input + idx;
idx += ssl->specs.hash_size; idx += ssl->specs.hash_size;
if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
padSz -= ssl->specs.block_size; padSz -= ssl->specs.block_size;
idx += padSz; idx += padSz;
/* verify mac */ /* verify mac */
if (XMEMCMP(mac, verifyMAC, ssl->specs.hash_size)) { if (XMEMCMP(mac, verifyMAC, ssl->specs.hash_size)) {
CYASSL_MSG("Verify finished error on mac"); CYASSL_MSG("Verify finished error on mac");
return VERIFY_MAC_ERROR; return VERIFY_MAC_ERROR;
} }
} }
else { else {
idx = idx + finishedSz + 16; idx = idx + finishedSz + 16;
/* XXX the 16 should be from specs */ /* XXX the 16 should be from specs */
} }
if (ssl->options.side == CLIENT_END) { if (ssl->options.side == CLIENT_END) {
ssl->options.serverState = SERVER_FINISHED_COMPLETE; ssl->options.serverState = SERVER_FINISHED_COMPLETE;
@@ -2222,34 +2222,35 @@ static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz)
break; break;
#endif #endif
#ifdef BUILD_AESGCM #ifdef BUILD_AESGCM
case aes_gcm: case aes_gcm:
{ {
byte additional[AES_BLOCK_SIZE]; byte additional[AES_BLOCK_SIZE];
byte nonce[AES_BLOCK_SIZE]; byte nonce[AES_BLOCK_SIZE];
if (ssl->options.side == SERVER_END) { if (ssl->options.side == SERVER_END) {
XMEMCPY(nonce, ssl->keys.server_write_IV, XMEMCPY(nonce, ssl->keys.server_write_IV,
AES_GCM_IMPLICIT_IV_SIZE); AES_GCM_IMPLICIT_IV_SIZE);
} }
else { else {
XMEMCPY(nonce, ssl->keys.client_write_IV, XMEMCPY(nonce, ssl->keys.client_write_IV,
AES_GCM_IMPLICIT_IV_SIZE); AES_GCM_IMPLICIT_IV_SIZE);
} }
XMEMCPY(nonce + AES_GCM_IMPLICIT_IV_SIZE, XMEMCPY(nonce + AES_GCM_IMPLICIT_IV_SIZE,
input, AES_GCM_EXPLICIT_IV_SIZE); input, AES_GCM_EXPLICIT_IV_SIZE);
XMEMSET(nonce + AES_GCM_IMPLICIT_IV_SIZE + XMEMSET(nonce + AES_GCM_IMPLICIT_IV_SIZE +
AES_GCM_EXPLICIT_IV_SIZE, 0, 4); AES_GCM_EXPLICIT_IV_SIZE, 0, 4);
AesSetIV(&ssl->encrypt.aes, nonce); AesSetIV(&ssl->encrypt.aes, nonce);
XMEMSET(additional, 0, 16); XMEMSET(additional, 0, 16);
c32toa(GetSEQIncrement(ssl, 0), additional + 4); c32toa(GetSEQIncrement(ssl, 0), additional + 4);
XMEMCPY(additional+8, input - 5, 5); XMEMCPY(additional+8, input - 5, 5);
AesGcmEncrypt(&ssl->encrypt.aes, out+8, input+8, sz-24, c16toa(sz - 24, additional+11);
out + 8 + (sz - 24), 16, additional, 13); AesGcmEncrypt(&ssl->encrypt.aes, out+8, input+8, sz-24,
} out + sz - 16, 16, additional, 13);
break; }
#endif break;
#endif
#ifdef HAVE_HC128 #ifdef HAVE_HC128
case hc128: case hc128:
@@ -2293,37 +2294,37 @@ static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input,
#ifdef BUILD_AESGCM #ifdef BUILD_AESGCM
case aes_gcm: case aes_gcm:
{ {
byte additional[16]; byte additional[16];
byte nonce[16]; byte nonce[16];
/* use the other side's IV */ /* use the other side's IV */
if (ssl->options.side == SERVER_END) { if (ssl->options.side == SERVER_END) {
XMEMCPY(nonce, ssl->keys.client_write_IV, XMEMCPY(nonce, ssl->keys.client_write_IV,
AES_GCM_IMPLICIT_IV_SIZE); AES_GCM_IMPLICIT_IV_SIZE);
} }
else { else {
XMEMCPY(nonce, ssl->keys.server_write_IV, XMEMCPY(nonce, ssl->keys.server_write_IV,
AES_GCM_IMPLICIT_IV_SIZE); AES_GCM_IMPLICIT_IV_SIZE);
} }
XMEMCPY(nonce + AES_GCM_IMPLICIT_IV_SIZE, XMEMCPY(nonce + AES_GCM_IMPLICIT_IV_SIZE,
input, AES_GCM_EXPLICIT_IV_SIZE); input, AES_GCM_EXPLICIT_IV_SIZE);
XMEMSET(nonce + AES_GCM_IMPLICIT_IV_SIZE + XMEMSET(nonce + AES_GCM_IMPLICIT_IV_SIZE +
AES_GCM_EXPLICIT_IV_SIZE, 0, 4); AES_GCM_EXPLICIT_IV_SIZE, 0, 4);
AesSetIV(&ssl->decrypt.aes, nonce); AesSetIV(&ssl->decrypt.aes, nonce);
XMEMSET(additional, 0, 4); XMEMSET(additional, 0, 4);
c32toa(GetSEQIncrement(ssl, 1), additional + 4); c32toa(GetSEQIncrement(ssl, 1), additional + 4);
additional[8] = ssl->curRL.type; additional[8] = ssl->curRL.type;
additional[9] = ssl->curRL.version.major; additional[9] = ssl->curRL.version.major;
additional[10] = ssl->curRL.version.minor; additional[10] = ssl->curRL.version.minor;
c16toa(sz, additional + 11); c16toa(sz-24, additional + 11);
if (AesGcmDecrypt(&ssl->decrypt.aes, plain+8, input+8, sz-24, if (AesGcmDecrypt(&ssl->decrypt.aes, plain+8, input+8, sz-24,
input + 8 + (sz - 24), 16, additional, 13) < 0) { input + 8 + (sz - 24), 16, additional, 13) < 0) {
SendAlert(ssl, alert_fatal, bad_record_mac); SendAlert(ssl, alert_fatal, bad_record_mac);
return VERIFY_MAC_ERROR; return VERIFY_MAC_ERROR;
} }
break; break;
} }
#endif #endif
#ifdef HAVE_HC128 #ifdef HAVE_HC128
@@ -2341,23 +2342,23 @@ static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input,
default: default:
CYASSL_MSG("CyaSSL Decrypt programming error"); CYASSL_MSG("CyaSSL Decrypt programming error");
} }
return 0; return 0;
} }
/* decrypt input message in place */ /* decrypt input message in place */
static int DecryptMessage(CYASSL* ssl, byte* input, word32 sz, word32* idx) static int DecryptMessage(CYASSL* ssl, byte* input, word32 sz, word32* idx)
{ {
int decryptResult = Decrypt(ssl, input, input, sz); int decryptResult = Decrypt(ssl, input, input, sz);
if (decryptResult == 0) if (decryptResult == 0)
{ {
ssl->keys.encryptSz = sz; ssl->keys.encryptSz = sz;
if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
*idx += ssl->specs.block_size; /* go past TLSv1.1 IV */ *idx += ssl->specs.block_size; /* go past TLSv1.1 IV */
if (ssl->specs.cipher_type == aead) if (ssl->specs.cipher_type == aead)
*idx += AES_GCM_EXPLICIT_IV_SIZE; *idx += AES_GCM_EXPLICIT_IV_SIZE;
} }
return decryptResult; return decryptResult;
} }
@@ -2386,10 +2387,10 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx)
pad = *(input + idx + msgSz - ivExtra - 1); pad = *(input + idx + msgSz - ivExtra - 1);
padByte = 1; padByte = 1;
} }
if (ssl->specs.cipher_type == aead) { if (ssl->specs.cipher_type == aead) {
ivExtra = 8; ivExtra = 8;
digestSz = 16; digestSz = 16;
} }
dataSz = msgSz - ivExtra - digestSz - pad - padByte; dataSz = msgSz - ivExtra - digestSz - pad - padByte;
if (dataSz < 0) { if (dataSz < 0) {
@@ -2401,8 +2402,8 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx)
if (dataSz) { if (dataSz) {
int rawSz = dataSz; /* keep raw size for hmac */ int rawSz = dataSz; /* keep raw size for hmac */
if (ssl->specs.cipher_type != aead) if (ssl->specs.cipher_type != aead)
ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1); ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1);
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
if (ssl->options.usingCompression) { if (ssl->options.usingCompression) {
@@ -2435,7 +2436,7 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx)
/* verify */ /* verify */
if (dataSz) { if (dataSz) {
if (ssl->specs.cipher_type != aead && XMEMCMP(mac, verify, digestSz)) { if (ssl->specs.cipher_type != aead && XMEMCMP(mac, verify, digestSz)) {
CYASSL_MSG("App data verify mac error"); CYASSL_MSG("App data verify mac error");
return VERIFY_MAC_ERROR; return VERIFY_MAC_ERROR;
} }
@@ -2471,30 +2472,30 @@ static int DoAlert(CYASSL* ssl, byte* input, word32* inOutIdx, int* type)
} }
CYASSL_ERROR(*type); CYASSL_ERROR(*type);
if (ssl->keys.encryptionOn) { if (ssl->keys.encryptionOn) {
if (ssl->specs.cipher_type != aead) { if (ssl->specs.cipher_type != aead) {
int aSz = ALERT_SIZE; int aSz = ALERT_SIZE;
const byte* mac; const byte* mac;
byte verify[SHA256_DIGEST_SIZE]; byte verify[SHA256_DIGEST_SIZE];
int padSz = ssl->keys.encryptSz - aSz - ssl->specs.hash_size; int padSz = ssl->keys.encryptSz - aSz - ssl->specs.hash_size;
ssl->hmac(ssl, verify, input + *inOutIdx - aSz, aSz, alert, 1); ssl->hmac(ssl, verify, input + *inOutIdx - aSz, aSz, alert, 1);
/* read mac and fill */ /* read mac and fill */
mac = input + *inOutIdx; mac = input + *inOutIdx;
*inOutIdx += (ssl->specs.hash_size + padSz); *inOutIdx += (ssl->specs.hash_size + padSz);
/* verify */ /* verify */
if (XMEMCMP(mac, verify, ssl->specs.hash_size)) { if (XMEMCMP(mac, verify, ssl->specs.hash_size)) {
CYASSL_MSG(" alert verify mac error"); CYASSL_MSG(" alert verify mac error");
return VERIFY_MAC_ERROR; return VERIFY_MAC_ERROR;
} }
} }
else { else {
*inOutIdx += 16; *inOutIdx += 16;
/* XXX this should be a value out of the cipher specs */ /* XXX this should be a value out of the cipher specs */
} }
} }
return level; return level;
} }
@@ -3010,11 +3011,11 @@ static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz,
sz += pad; sz += pad;
} }
if (ssl->specs.cipher_type == aead) { if (ssl->specs.cipher_type == aead) {
ivSz = AES_GCM_EXPLICIT_IV_SIZE; ivSz = AES_GCM_EXPLICIT_IV_SIZE;
sz = sz + ivSz + 16 - digestSz; sz = sz + ivSz + 16 - digestSz;
RNG_GenerateBlock(&ssl->rng, iv, ivSz); RNG_GenerateBlock(&ssl->rng, iv, ivSz);
} }
size = (word16)(sz - headerSz); /* include mac and digest */ size = (word16)(sz - headerSz); /* include mac and digest */
AddRecordHeader(output, size, (byte)type, ssl); AddRecordHeader(output, size, (byte)type, ssl);
@@ -3028,10 +3029,10 @@ static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz,
if (type == handshake) if (type == handshake)
HashOutput(ssl, output, headerSz + inSz, ivSz); HashOutput(ssl, output, headerSz + inSz, ivSz);
if (ssl->specs.cipher_type != aead) { if (ssl->specs.cipher_type != aead) {
ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0); ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0);
idx += digestSz; idx += digestSz;
} }
if (ssl->specs.cipher_type == block) if (ssl->specs.cipher_type == block)
for (i = 0; i <= pad; i++) for (i = 0; i <= pad; i++)

View File

@@ -1002,17 +1002,15 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs,
/* TLS can call too */ /* TLS can call too */
int StoreKeys(CYASSL* ssl, const byte* keyData) int StoreKeys(CYASSL* ssl, const byte* keyData)
{ {
int sz = ssl->specs.hash_size, i; int sz, i = 0;
if (ssl->specs.cipher_type != aead) { if (ssl->specs.cipher_type != aead) {
XMEMCPY(ssl->keys.client_write_MAC_secret, keyData, sz); sz = ssl->specs.hash_size;
i = sz; XMEMCPY(ssl->keys.client_write_MAC_secret,&keyData[i], sz);
XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz); i += sz;
i += sz; XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz);
} i += sz;
else { }
sz = 0;
}
sz = ssl->specs.key_size; sz = ssl->specs.key_size;
XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz); XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz);