Merge pull request #5170 from haydenroche5/evp_cipher_aes_gcm

Fix EVP_CTRL_GCM_IV_GEN with AES-GCM.
This commit is contained in:
Sean Parkinson 2022-06-01 08:20:33 +10:00 committed by GitHub
commit 81cd1e652e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 609 additions and 245 deletions

View File

@ -45185,27 +45185,279 @@ static void test_wolfSSL_EVP_BytesToKey(void)
printf(resultFmt, passed);
#endif
}
static void test_IncCtr(void)
static void test_evp_cipher_aes_gcm(void)
{
#if defined(HAVE_AESGCM) && !defined(HAVE_FIPS)
byte key[AES_128_KEY_SIZE] = {0};
byte iv[GCM_NONCE_MID_SZ] = {0};
int type = EVP_CTRL_GCM_IV_GEN;
int arg = 0;
void *ptr = NULL;
#if defined(HAVE_AESGCM) && ((!defined(HAVE_FIPS) && \
!defined(HAVE_SELFTEST)) || (defined(HAVE_FIPS_VERSION) && \
(HAVE_FIPS_VERSION >= 2)))
/*
* This test checks data at various points in the encrypt/decrypt process
* against known values produced using the same test with OpenSSL. This
* interop testing is critical for verifying the correctness of our
* EVP_Cipher implementation with AES-GCM. Specifically, this test exercises
* a flow supported by OpenSSL that uses the control command
* EVP_CTRL_GCM_IV_GEN to increment the IV between cipher operations without
* the need to call EVP_CipherInit. OpenSSH uses this flow, for example. We
* had a bug with OpenSSH where wolfSSL OpenSSH servers could only talk to
* wolfSSL OpenSSH clients because there was a bug in this flow that
* happened to "cancel out" if both sides of the connection had the bug.
*/
enum {
NUM_ENCRYPTIONS = 3,
AAD_SIZE = 4
};
byte plainText1[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
};
byte plainText2[] = {
0x42, 0x49, 0x3b, 0x27, 0x03, 0x35, 0x59, 0x14, 0x41, 0x47, 0x37, 0x14,
0x0e, 0x34, 0x0d, 0x28, 0x63, 0x09, 0x0a, 0x5b, 0x22, 0x57, 0x42, 0x22,
0x0f, 0x5c, 0x1e, 0x53, 0x45, 0x15, 0x62, 0x08, 0x60, 0x43, 0x50, 0x2c
};
byte plainText3[] = {
0x36, 0x0d, 0x2b, 0x09, 0x4a, 0x56, 0x3b, 0x4c, 0x21, 0x22, 0x58, 0x0e,
0x5b, 0x57, 0x10
};
byte* plainTexts[NUM_ENCRYPTIONS] = {
plainText1,
plainText2,
plainText3
};
const int plainTextSzs[NUM_ENCRYPTIONS] = {
sizeof(plainText1),
sizeof(plainText2),
sizeof(plainText3)
};
byte aad1[AAD_SIZE] = {
0x00, 0x00, 0x00, 0x01
};
byte aad2[AAD_SIZE] = {
0x00, 0x00, 0x00, 0x10
};
byte aad3[AAD_SIZE] = {
0x00, 0x00, 0x01, 0x00
};
byte* aads[NUM_ENCRYPTIONS] = {
aad1,
aad2,
aad3
};
const byte iv[GCM_NONCE_MID_SZ] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF
};
byte currentIv[GCM_NONCE_MID_SZ];
const byte key[] = {
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
};
const byte expIvs[NUM_ENCRYPTIONS][GCM_NONCE_MID_SZ] = {
{
0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE,
0xEF
},
{
0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE,
0xF0
},
{
0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE,
0xF1
}
};
const byte expTags[NUM_ENCRYPTIONS][AES_BLOCK_SIZE] = {
{
0x65, 0x4F, 0xF7, 0xA0, 0xBB, 0x7B, 0x90, 0xB7, 0x9C, 0xC8, 0x14,
0x3D, 0x32, 0x18, 0x34, 0xA9
},
{
0x50, 0x3A, 0x13, 0x8D, 0x91, 0x1D, 0xEC, 0xBB, 0xBA, 0x5B, 0x57,
0xA2, 0xFD, 0x2D, 0x6B, 0x7F
},
{
0x3B, 0xED, 0x18, 0x9C, 0xB3, 0xE3, 0x61, 0x1E, 0x11, 0xEB, 0x13,
0x5B, 0xEC, 0x52, 0x49, 0x32,
}
};
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
const EVP_CIPHER *init = EVP_aes_128_gcm();
const byte expCipherText1[] = {
0xCB, 0x93, 0x4F, 0xC8, 0x22, 0xE2, 0xC0, 0x35, 0xAA, 0x6B, 0x41, 0x15,
0x17, 0x30, 0x2F, 0x97, 0x20, 0x74, 0x39, 0x28, 0xF8, 0xEB, 0xC5, 0x51,
0x7B, 0xD9, 0x8A, 0x36, 0xB8, 0xDA, 0x24, 0x80, 0xE7, 0x9E, 0x09, 0xDE
};
const byte expCipherText2[] = {
0xF9, 0x32, 0xE1, 0x87, 0x37, 0x0F, 0x04, 0xC1, 0xB5, 0x59, 0xF0, 0x45,
0x3A, 0x0D, 0xA0, 0x26, 0xFF, 0xA6, 0x8D, 0x38, 0xFE, 0xB8, 0xE5, 0xC2,
0x2A, 0x98, 0x4A, 0x54, 0x8F, 0x1F, 0xD6, 0x13, 0x03, 0xB2, 0x1B, 0xC0
};
const byte expCipherText3[] = {
0xD0, 0x37, 0x59, 0x1C, 0x2F, 0x85, 0x39, 0x4D, 0xED, 0xC2, 0x32, 0x5B,
0x80, 0x5E, 0x6B,
};
const byte* expCipherTexts[NUM_ENCRYPTIONS] = {
expCipherText1,
expCipherText2,
expCipherText3
};
byte* cipherText;
byte* calcPlainText;
byte tag[AES_BLOCK_SIZE];
EVP_CIPHER_CTX* encCtx = NULL;
EVP_CIPHER_CTX* decCtx = NULL;
int i, j, outl;
printf(testingFmt, "IncCtr");
printf(testingFmt, "test_evp_cipher_aes_gcm");
AssertNotNull(ctx);
wolfSSL_EVP_CIPHER_CTX_init(ctx);
AssertIntEQ(EVP_CipherInit(ctx, init, key, iv, 1), WOLFSSL_SUCCESS);
/****************************************************/
for (i = 0; i < 3; ++i) {
AssertNotNull(encCtx = EVP_CIPHER_CTX_new());
AssertNotNull(decCtx = EVP_CIPHER_CTX_new());
AssertIntEQ(wolfSSL_EVP_CIPHER_CTX_ctrl(ctx, type, arg, ptr), WOLFSSL_SUCCESS);
/* First iteration, set key before IV. */
if (i == 0) {
AssertIntEQ(EVP_CipherInit(encCtx, EVP_aes_256_gcm(), key, NULL, 1),
SSL_SUCCESS);
AssertIntEQ(EVP_CipherInit(encCtx, NULL, NULL, iv, 1),
SSL_SUCCESS);
AssertIntEQ(EVP_CipherInit(decCtx, EVP_aes_256_gcm(), key, NULL, 0),
SSL_SUCCESS);
AssertIntEQ(EVP_CipherInit(decCtx, NULL, NULL, iv, 0),
SSL_SUCCESS);
}
/* Second iteration, IV before key. */
else {
AssertIntEQ(EVP_CipherInit(encCtx, EVP_aes_256_gcm(), NULL, iv, 1),
SSL_SUCCESS);
AssertIntEQ(EVP_CipherInit(encCtx, NULL, key, NULL, 1),
SSL_SUCCESS);
AssertIntEQ(EVP_CipherInit(decCtx, EVP_aes_256_gcm(), NULL, iv, 0),
SSL_SUCCESS);
AssertIntEQ(EVP_CipherInit(decCtx, NULL, key, NULL, 0),
SSL_SUCCESS);
}
EVP_CIPHER_CTX_free(ctx);
/*
* EVP_CTRL_GCM_IV_GEN should fail if EVP_CTRL_GCM_SET_IV_FIXED hasn't
* been issued first.
*/
AssertIntEQ(EVP_CIPHER_CTX_ctrl(encCtx, EVP_CTRL_GCM_IV_GEN, -1,
currentIv), SSL_FAILURE);
AssertIntEQ(EVP_CIPHER_CTX_ctrl(encCtx, EVP_CTRL_GCM_SET_IV_FIXED, -1,
(void*)iv), SSL_SUCCESS);
AssertIntEQ(EVP_CIPHER_CTX_ctrl(decCtx, EVP_CTRL_GCM_SET_IV_FIXED, -1,
(void*)iv), SSL_SUCCESS);
for (j = 0; j < NUM_ENCRYPTIONS; ++j) {
/*************** Encrypt ***************/
AssertIntEQ(EVP_CIPHER_CTX_ctrl(encCtx, EVP_CTRL_GCM_IV_GEN, -1,
currentIv), SSL_SUCCESS);
/* Check current IV against expected. */
AssertIntEQ(XMEMCMP(currentIv, expIvs[j], GCM_NONCE_MID_SZ), 0);
/* Add AAD. */
if (i == 2) {
/* Test streaming API. */
AssertIntEQ(EVP_CipherUpdate(encCtx, NULL, &outl, aads[j],
AAD_SIZE), SSL_SUCCESS);
}
else {
AssertIntEQ(EVP_Cipher(encCtx, NULL, aads[j], AAD_SIZE),
AAD_SIZE);
}
AssertNotNull(cipherText = (byte*)XMALLOC(plainTextSzs[j], NULL,
DYNAMIC_TYPE_TMP_BUFFER));
/* Encrypt plaintext. */
if (i == 2){
AssertIntEQ(EVP_CipherUpdate(encCtx, cipherText, &outl,
plainTexts[j], plainTextSzs[j]),
SSL_SUCCESS);
}
else {
AssertIntEQ(EVP_Cipher(encCtx, cipherText, plainTexts[j],
plainTextSzs[j]), plainTextSzs[j]);
}
if (i == 2) {
AssertIntEQ(EVP_CipherFinal(encCtx, cipherText, &outl),
SSL_SUCCESS);
}
else {
/*
* Calling EVP_Cipher with NULL input and output for AES-GCM is
* akin to calling EVP_CipherFinal.
*/
AssertIntGE(EVP_Cipher(encCtx, NULL, NULL, 0), 0);
}
/* Check ciphertext against expected. */
AssertIntEQ(XMEMCMP(cipherText, expCipherTexts[j], plainTextSzs[j]),
0);
/* Get and check tag against expected. */
AssertIntEQ(EVP_CIPHER_CTX_ctrl(encCtx, EVP_CTRL_GCM_GET_TAG,
sizeof(tag), tag), SSL_SUCCESS);
AssertIntEQ(XMEMCMP(tag, expTags[j], sizeof(tag)), 0);
/*************** Decrypt ***************/
AssertIntEQ(EVP_CIPHER_CTX_ctrl(decCtx, EVP_CTRL_GCM_IV_GEN, -1,
currentIv), SSL_SUCCESS);
/* Check current IV against expected. */
AssertIntEQ(XMEMCMP(currentIv, expIvs[j], GCM_NONCE_MID_SZ), 0);
/* Add AAD. */
if (i == 2) {
/* Test streaming API. */
AssertIntEQ(EVP_CipherUpdate(decCtx, NULL, &outl, aads[j],
AAD_SIZE), SSL_SUCCESS);
}
else {
AssertIntEQ(EVP_Cipher(decCtx, NULL, aads[j], AAD_SIZE),
AAD_SIZE);
}
/* Set expected tag. */
AssertIntEQ(EVP_CIPHER_CTX_ctrl(decCtx, EVP_CTRL_GCM_SET_TAG,
sizeof(tag), tag), SSL_SUCCESS);
/* Decrypt ciphertext. */
AssertNotNull(calcPlainText = (byte*)XMALLOC(plainTextSzs[j], NULL,
DYNAMIC_TYPE_TMP_BUFFER));
if (i == 2){
AssertIntEQ(EVP_CipherUpdate(decCtx, calcPlainText, &outl,
cipherText, plainTextSzs[j]),
SSL_SUCCESS);
}
else {
/* This first EVP_Cipher call will check the tag, too. */
AssertIntEQ(EVP_Cipher(decCtx, calcPlainText, cipherText,
plainTextSzs[j]), plainTextSzs[j]);
}
if (i == 2) {
AssertIntEQ(EVP_CipherFinal(decCtx, calcPlainText, &outl),
SSL_SUCCESS);
}
else {
AssertIntGE(EVP_Cipher(decCtx, NULL, NULL, 0), 0);
}
/* Check plaintext against expected. */
AssertIntEQ(XMEMCMP(calcPlainText, plainTexts[j], plainTextSzs[j]),
0);
XFREE(cipherText, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(calcPlainText, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
EVP_CIPHER_CTX_free(encCtx);
EVP_CIPHER_CTX_free(decCtx);
}
printf(resultFmt, passed);
#endif
}
@ -54485,7 +54737,7 @@ void ApiTest(void)
test_wolfSSL_EVP_BytesToKey();
test_wolfSSL_EVP_PKEY_param_check();
test_wolfSSL_QT_EVP_PKEY_CTX_free();
test_IncCtr();
test_evp_cipher_aes_gcm();
test_wolfSSL_OBJ_ln();
test_wolfSSL_OBJ_sn();
test_wolfSSL_TXT_DB();

View File

@ -824,17 +824,36 @@ static int checkPad(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *buff)
return ctx->block_size - n;
}
int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx,
unsigned char *out, int *outl)
#if defined(HAVE_AESGCM) && ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) \
|| FIPS_VERSION_GE(2,0))
static WC_INLINE void IncCtr(byte* ctr, word32 ctrSz)
{
int i;
for (i = ctrSz-1; i >= 0; i--) {
if (++ctr[i])
break;
}
}
#endif /* HAVE_AESGCM && ((!HAVE_FIPS && !HAVE_SELFTEST) ||
* HAVE_FIPS_VERSION >= 2 */
int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out,
int *outl)
{
int fl;
int ret = WOLFSSL_SUCCESS;
#if defined(HAVE_AESGCM) && ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) \
|| FIPS_VERSION_GE(2,0))
byte tmp = 0;
#endif
if (!ctx || !outl)
return WOLFSSL_FAILURE;
WOLFSSL_ENTER("wolfSSL_EVP_CipherFinal");
switch (ctx->cipherType) {
#if !defined(NO_AES) && defined(HAVE_AESGCM)
#if defined(HAVE_AESGCM) && ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) \
|| FIPS_VERSION_GE(2,0))
case AES_128_GCM_TYPE:
case AES_192_GCM_TYPE:
case AES_256_GCM_TYPE:
@ -864,6 +883,12 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx,
XFREE(ctx->gcmBuffer, NULL, DYNAMIC_TYPE_OPENSSL);
ctx->gcmBuffer = NULL;
ctx->gcmBufferLen = 0;
if (ctx->gcmIncIv) {
IncCtr((byte*)ctx->cipher.aes.reg,
ctx->cipher.aes.nonceSz);
ctx->gcmIncIv = 0;
}
}
else {
*outl = 0;
@ -878,18 +903,41 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx,
else {
ret = wc_AesGcmDecryptFinal(&ctx->cipher.aes, ctx->authTag,
ctx->authTagSz);
if (ctx->gcmIncIv) {
IncCtr((byte*)ctx->cipher.aes.reg, ctx->cipher.aes.nonceSz);
}
}
if (ret == 0) {
ret = WOLFSSL_SUCCESS;
/* Reinitialize for subsequent wolfSSL_EVP_Cipher calls. */
if (wc_AesGcmInit(&ctx->cipher.aes, NULL, 0,
(byte*)ctx->cipher.aes.reg,
ctx->ivSz) != 0) {
WOLFSSL_MSG("wc_AesGcmInit failed");
ret = WOLFSSL_FAILURE;
}
else {
ret = WOLFSSL_SUCCESS;
}
}
else {
ret = WOLFSSL_FAILURE;
}
#endif /* WOLFSSL_AESGCM_STREAM */
/* Clear IV, since IV reuse is not recommended for AES GCM. */
XMEMSET(ctx->iv, 0, AES_BLOCK_SIZE);
if (ret == WOLFSSL_SUCCESS) {
if (ctx->gcmIncIv) {
ctx->gcmIncIv = 0;
}
else {
/* Clear IV, since IV reuse is not recommended for AES GCM. */
XMEMSET(ctx->iv, 0, AES_BLOCK_SIZE);
}
if (wolfSSL_StoreExternalIV(ctx) != WOLFSSL_SUCCESS) {
ret = WOLFSSL_FAILURE;
}
}
break;
#endif /* !NO_AES && HAVE_AESGCM */
#endif /* HAVE_AESGCM && ((!HAVE_FIPS && !HAVE_SELFTEST) ||
* HAVE_FIPS_VERSION >= 2 */
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
case CHACHA20_POLY1305_TYPE:
if (wc_ChaCha20Poly1305_Final(&ctx->cipher.chachaPoly,
@ -962,9 +1010,33 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx,
}
if (ret == WOLFSSL_SUCCESS) {
#if defined(HAVE_AESGCM) && ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) \
|| FIPS_VERSION_GE(2,0))
/*
* This flag needs to retain its value between wolfSSL_EVP_CipherFinal
* calls. wolfSSL_EVP_CipherInit will clear it, so we save and restore
* it here.
*/
if (ctx->cipherType == AES_128_GCM_TYPE ||
ctx->cipherType == AES_192_GCM_TYPE ||
ctx->cipherType == AES_256_GCM_TYPE) {
tmp = ctx->gcmIvGenEnable;
}
#endif
/* reset cipher state after final */
ret = wolfSSL_EVP_CipherInit(ctx, NULL, NULL, NULL, -1);
#if defined(HAVE_AESGCM) && ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) \
|| FIPS_VERSION_GE(2,0))
if (ctx->cipherType == AES_128_GCM_TYPE ||
ctx->cipherType == AES_192_GCM_TYPE ||
ctx->cipherType == AES_256_GCM_TYPE) {
ctx->gcmIvGenEnable = tmp;
}
#endif
}
return ret;
}
@ -5287,17 +5359,6 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
}
}
#if defined(HAVE_AESGCM) && !defined(HAVE_SELFTEST)
static WC_INLINE void IncCtr(byte* ctr, word32 ctrSz)
{
int i;
for (i = ctrSz-1; i >= 0; i--) {
if (++ctr[i])
break;
}
}
#endif
/* This function allows cipher specific parameters to be
determined and set. */
int wolfSSL_EVP_CIPHER_CTX_ctrl(WOLFSSL_EVP_CIPHER_CTX *ctx, int type, \
@ -5381,35 +5442,58 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
break;
}
}
#ifdef HAVE_AESGCM
if (ret == WOLFSSL_SUCCESS) {
/*
* OpenSSL requires that a EVP_CTRL_AEAD_SET_IV_FIXED
* command be issued before a EVP_CTRL_GCM_IV_GEN command.
* This flag is used to enforce that.
*/
ctx->gcmIvGenEnable = 1;
}
#endif
#endif /* !WC_NO_RNG */
break;
#if defined(HAVE_AESGCM) && !defined(_WIN32) && !defined(HAVE_SELFTEST) && \
(!defined(HAVE_FIPS) || FIPS_VERSION_GE(2,0))
/*
* Using EVP_CTRL_GCM_IV_GEN is a way to do AES-GCM encrypt/decrypt
* multiple times with EVP_Cipher without having to call
* EVP_CipherInit between each iteration. The IV is incremented for
* each subsequent EVP_Cipher call to prevent IV reuse.
*/
case EVP_CTRL_GCM_IV_GEN:
if ((ctx->flags & WOLFSSL_EVP_CIPH_FLAG_AEAD_CIPHER) == 0)
break;
if (!ctx->gcmIvGenEnable) {
WOLFSSL_MSG("Must use EVP_CTRL_AEAD_SET_IV_FIXED before "
"EVP_CTRL_GCM_IV_GEN");
break;
}
if (ctx->cipher.aes.keylen == 0 || ctx->ivSz == 0) {
WOLFSSL_MSG("Key or IV not set");
break;
}
if (wc_AesGcmSetExtIV(&ctx->cipher.aes, ctx->iv,
ctx->ivSz) != 0) {
WOLFSSL_MSG("wc_AesGcmSetIV failed");
if (ptr == NULL) {
WOLFSSL_MSG("Destination buffer for IV bytes NULL.");
break;
}
#ifdef WOLFSSL_AESGCM_STREAM
/* Initialize using IV cached in Aes object. */
if (wc_AesGcmInit(&ctx->cipher.aes, NULL, 0, NULL, 0) != 0) {
WOLFSSL_MSG("wc_AesGcmInit failed");
break;
if (arg <= 0 || arg > ctx->ivSz) {
XMEMCPY(ptr, ctx->iv, ctx->ivSz);
}
#endif /* WOLFSSL_AESGCM_STREAM */
/* OpenSSL increments the IV. Not sure why */
IncCtr(ctx->iv, ctx->ivSz);
/* Clear any leftover AAD. */
if (ctx->gcmAuthIn != NULL)
XMEMSET(ctx->gcmAuthIn, 0, ctx->gcmAuthInSz);
ctx->gcmAuthInSz = 0;
else {
/*
* Copy the last "arg" bytes of ctx->iv into the buffer at
* "ptr." Not sure why OpenSSL does this, but it does.
*/
XMEMCPY(ptr, ctx->iv + ctx->ivSz - arg, arg);
}
/*
* The gcmIncIV flag indicates that the IV should be incremented
* after the next cipher operation.
*/
ctx->gcmIncIv = 1;
ret = WOLFSSL_SUCCESS;
break;
#endif /* HAVE_AESGCM && !_WIN32 && !HAVE_SELFTEST && (!HAVE_FIPS ||
@ -5498,6 +5582,8 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
ctx->gcmAuthIn = NULL;
}
ctx->gcmAuthInSz = 0;
ctx->gcmIvGenEnable = 0;
ctx->gcmIncIv = 0;
#endif
}
@ -5608,8 +5694,190 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
#endif /* AES_ANY_SIZE && AES_SET_KEY */
#endif /* NO_AES */
#if defined(HAVE_AESGCM) && ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) \
|| FIPS_VERSION_GE(2,0))
static int EvpCipherInitAesGCM(WOLFSSL_EVP_CIPHER_CTX* ctx,
const WOLFSSL_EVP_CIPHER* type,
const byte* key, const byte* iv, int enc)
{
int ret = WOLFSSL_SUCCESS;
ctx->block_size = AES_BLOCK_SIZE;
ctx->authTagSz = AES_BLOCK_SIZE;
if (ctx->ivSz == 0) {
ctx->ivSz = GCM_NONCE_MID_SZ;
}
ctx->flags &= ~WOLFSSL_EVP_CIPH_MODE;
ctx->flags |= WOLFSSL_EVP_CIPH_GCM_MODE |
WOLFSSL_EVP_CIPH_FLAG_AEAD_CIPHER;
if (enc == 0 || enc == 1) {
ctx->enc = enc ? 1 : 0;
}
#ifdef WOLFSSL_AES_128
if (ctx->cipherType == AES_128_GCM_TYPE ||
(type && EVP_CIPHER_TYPE_MATCHES(type, EVP_AES_128_GCM))) {
WOLFSSL_MSG("EVP_AES_128_GCM");
ctx->cipherType = AES_128_GCM_TYPE;
ctx->keyLen = AES_128_KEY_SIZE;
}
#endif
#ifdef WOLFSSL_AES_192
if (ctx->cipherType == AES_192_GCM_TYPE ||
(type && EVP_CIPHER_TYPE_MATCHES(type, EVP_AES_192_GCM))) {
WOLFSSL_MSG("EVP_AES_192_GCM");
ctx->cipherType = AES_192_GCM_TYPE;
ctx->keyLen = AES_192_KEY_SIZE;
}
#endif
#ifdef WOLFSSL_AES_256
if (ctx->cipherType == AES_256_GCM_TYPE ||
(type && EVP_CIPHER_TYPE_MATCHES(type, EVP_AES_256_GCM))) {
WOLFSSL_MSG("EVP_AES_256_GCM");
ctx->cipherType = AES_256_GCM_TYPE;
ctx->keyLen = AES_256_KEY_SIZE;
}
#endif
#ifndef WOLFSSL_AESGCM_STREAM
if (ret == WOLFSSL_SUCCESS && key &&
wc_AesGcmSetKey(&ctx->cipher.aes, key, ctx->keyLen)) {
WOLFSSL_MSG("wc_AesGcmSetKey() failed");
ret = WOLFSSL_FAILURE;
}
#endif /* !WOLFSSL_AESGCM_STREAM */
if (ret == WOLFSSL_SUCCESS && iv &&
wc_AesGcmSetExtIV(&ctx->cipher.aes, iv, ctx->ivSz)) {
WOLFSSL_MSG("wc_AesGcmSetExtIV() failed");
ret = WOLFSSL_FAILURE;
}
#ifdef WOLFSSL_AESGCM_STREAM
/*
* Initialize with key and IV if available. wc_AesGcmInit will fail
* if called with IV only and no key has been set.
*/
if (ret == WOLFSSL_SUCCESS &&
(key || (iv && ctx->cipher.aes.gcmKeySet)) &&
wc_AesGcmInit(&ctx->cipher.aes, key,
(key == NULL) ? 0 : ctx->keyLen, iv,
(iv == NULL) ? 0 : ctx->ivSz) != 0) {
WOLFSSL_MSG("wc_AesGcmInit() failed");
ret = WOLFSSL_FAILURE;
}
#endif /* WOLFSSL_AESGCM_STREAM */
return ret;
}
static int EvpCipherAesGCM(WOLFSSL_EVP_CIPHER_CTX* ctx, byte* dst,
byte* src, word32 len)
{
int ret = WOLFSSL_FAILURE;
#ifndef WOLFSSL_AESGCM_STREAM
/* No destination means only AAD. */
if (src != NULL && dst == NULL) {
ret = wolfSSL_EVP_CipherUpdate_GCM_AAD(ctx, src, len);
}
else if (src != NULL && dst != NULL) {
if (ctx->enc) {
ret = wc_AesGcmEncrypt(&ctx->cipher.aes, dst, src,
len, ctx->iv, ctx->ivSz, ctx->authTag,
ctx->authTagSz, ctx->gcmAuthIn,
ctx->gcmAuthInSz);
}
else {
ret = wc_AesGcmDecrypt(&ctx->cipher.aes, dst, src,
len, ctx->iv, ctx->ivSz, ctx->authTag,
ctx->authTagSz, ctx->gcmAuthIn,
ctx->gcmAuthInSz);
}
if (ctx->gcmIncIv) {
IncCtr((byte*)ctx->cipher.aes.reg,
ctx->cipher.aes.nonceSz);
ctx->gcmIncIv = 0;
}
}
#else
/*
* No need to call wc_AesGcmInit. Should have been called by
* wolfSSL_EVP_CipherInit.
*/
/* NULL dst and non-NULL src means only AAD. */
if (src != NULL && dst == NULL) {
if (ctx->enc) {
ret = wc_AesGcmEncryptUpdate(&ctx->cipher.aes, NULL,
NULL, 0, src, len);
}
else {
ret = wc_AesGcmDecryptUpdate(&ctx->cipher.aes, NULL,
NULL, 0, src, len);
}
}
/* Only plain/cipher text. */
else if (src != NULL && dst != NULL) {
if (ctx->enc) {
ret = wc_AesGcmEncryptUpdate(&ctx->cipher.aes, dst, src,
len, NULL, 0);
}
else {
ret = wc_AesGcmDecryptUpdate(&ctx->cipher.aes, dst, src,
len, NULL, 0);
}
}
/*
* src == NULL is analogous to other "final"-type functions
* (e.g. EVP_CipherFinal). Calculates tag on encrypt
* and checks tag on decrypt.
*/
else {
if (ctx->enc) {
/* Calculate authentication tag. */
ret = wc_AesGcmEncryptFinal(&ctx->cipher.aes,
ctx->authTag, ctx->authTagSz);
/*
* wc_AesGcmEncryptFinal increments the IV in
* ctx->cipher.aes.reg, so we don't call IncCtr here.
*/
}
else {
/* Calculate authentication tag and compare. */
ret = wc_AesGcmDecryptFinal(&ctx->cipher.aes,
ctx->authTag, ctx->authTagSz);
if (ctx->gcmIncIv) {
IncCtr((byte*)ctx->cipher.aes.reg,
ctx->cipher.aes.nonceSz);
}
}
/* Reinitialize for subsequent wolfSSL_EVP_Cipher calls. */
if (wc_AesGcmInit(&ctx->cipher.aes, NULL, 0,
(byte*)ctx->cipher.aes.reg,
ctx->ivSz) != 0) {
WOLFSSL_MSG("wc_AesGcmInit failed");
return WOLFSSL_FATAL_ERROR;
}
ctx->gcmIncIv = 0;
}
#endif /* WOLFSSL_AESGCM_STREAM */
if (src == NULL) {
/*
* Clear any leftover AAD on final (final is when src is
* NULL).
*/
XMEMSET(ctx->gcmAuthIn, 0, ctx->gcmAuthInSz);
ctx->gcmAuthInSz = 0;
}
if (ret == 0) {
ret = len;
}
return ret;
}
#endif /* HAVE_AESGCM && ((!HAVE_FIPS && !HAVE_SELFTEST) ||
* HAVE_FIPS_VERSION >= 2 */
/* return WOLFSSL_SUCCESS on ok, 0 on failure to match API compatibility */
int wolfSSL_EVP_CipherInit(WOLFSSL_EVP_CIPHER_CTX* ctx,
int wolfSSL_EVP_CipherInit(WOLFSSL_EVP_CIPHER_CTX* ctx,
const WOLFSSL_EVP_CIPHER* type, const byte* key,
const byte* iv, int enc)
{
@ -5648,6 +5916,8 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
ctx->gcmAuthIn = NULL;
}
ctx->gcmAuthInSz = 0;
ctx->gcmIvGenEnable = 0;
ctx->gcmIncIv = 0;
#endif
#ifndef NO_AES
@ -5732,125 +6002,29 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
}
#endif /* WOLFSSL_AES_256 */
#endif /* HAVE_AES_CBC || WOLFSSL_AES_DIRECT */
#if (!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) || \
(defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))
#ifdef HAVE_AESGCM
#if defined(HAVE_AESGCM) && ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) \
|| FIPS_VERSION_GE(2,0))
if (
#ifdef WOLFSSL_AES_128
if (ctx->cipherType == AES_128_GCM_TYPE ||
(type && EVP_CIPHER_TYPE_MATCHES(type, EVP_AES_128_GCM))) {
WOLFSSL_MSG("EVP_AES_128_GCM");
ctx->cipherType = AES_128_GCM_TYPE;
ctx->flags &= ~WOLFSSL_EVP_CIPH_MODE;
ctx->flags |= WOLFSSL_EVP_CIPH_GCM_MODE |
WOLFSSL_EVP_CIPH_FLAG_AEAD_CIPHER;
ctx->keyLen = 16;
ctx->block_size = AES_BLOCK_SIZE;
ctx->authTagSz = AES_BLOCK_SIZE;
if (ctx->ivSz == 0) {
ctx->ivSz = GCM_NONCE_MID_SZ;
}
#ifndef WOLFSSL_AESGCM_STREAM
if (key && wc_AesGcmSetKey(&ctx->cipher.aes, key, ctx->keyLen)) {
WOLFSSL_MSG("wc_AesGcmSetKey() failed");
return WOLFSSL_FAILURE;
}
#endif /* !WOLFSSL_AESGCM_STREAM */
if (iv && wc_AesGcmSetExtIV(&ctx->cipher.aes, iv, ctx->ivSz)) {
WOLFSSL_MSG("wc_AesGcmSetExtIV() failed");
return WOLFSSL_FAILURE;
}
#ifdef WOLFSSL_AESGCM_STREAM
/* Initialize with key and IV if available. */
if (wc_AesGcmInit(&ctx->cipher.aes, key,
(key == NULL) ? 0 : ctx->keyLen, iv,
(iv == NULL) ? 0 : ctx->ivSz) != 0) {
WOLFSSL_MSG("wc_AesGcmInit() failed");
return WOLFSSL_FAILURE;
}
#endif /* WOLFSSL_AESGCM_STREAM */
if (enc == 0 || enc == 1)
ctx->enc = enc ? 1 : 0;
}
#endif /* WOLFSSL_AES_128 */
ctx->cipherType == AES_128_GCM_TYPE ||
(type && EVP_CIPHER_TYPE_MATCHES(type, EVP_AES_128_GCM))
#endif
#ifdef WOLFSSL_AES_192
if (ctx->cipherType == AES_192_GCM_TYPE ||
(type && EVP_CIPHER_TYPE_MATCHES(type, EVP_AES_192_GCM))) {
WOLFSSL_MSG("EVP_AES_192_GCM");
ctx->cipherType = AES_192_GCM_TYPE;
ctx->flags &= ~WOLFSSL_EVP_CIPH_MODE;
ctx->flags |= WOLFSSL_EVP_CIPH_GCM_MODE |
WOLFSSL_EVP_CIPH_FLAG_AEAD_CIPHER;
ctx->keyLen = 24;
ctx->block_size = AES_BLOCK_SIZE;
ctx->authTagSz = AES_BLOCK_SIZE;
if (ctx->ivSz == 0) {
ctx->ivSz = GCM_NONCE_MID_SZ;
}
#ifndef WOLFSSL_AESGCM_STREAM
if (key && wc_AesGcmSetKey(&ctx->cipher.aes, key, ctx->keyLen)) {
WOLFSSL_MSG("wc_AesGcmSetKey() failed");
return WOLFSSL_FAILURE;
}
#endif /* !WOLFSSL_AESGCM_STREAM */
if (iv && wc_AesGcmSetExtIV(&ctx->cipher.aes, iv, ctx->ivSz)) {
WOLFSSL_MSG("wc_AesGcmSetExtIV() failed");
return WOLFSSL_FAILURE;
}
#ifdef WOLFSSL_AESGCM_STREAM
/* Initialize with key and IV if available. */
if (wc_AesGcmInit(&ctx->cipher.aes, key,
(key == NULL) ? 0 : ctx->keyLen, iv,
(iv == NULL) ? 0 : ctx->ivSz) != 0) {
WOLFSSL_MSG("wc_AesGcmInit() failed");
return WOLFSSL_FAILURE;
}
#endif /* WOLFSSL_AESGCM_STREAM */
if (enc == 0 || enc == 1)
ctx->enc = enc ? 1 : 0;
}
#endif /* WOLFSSL_AES_192 */
|| ctx->cipherType == AES_192_GCM_TYPE ||
(type && EVP_CIPHER_TYPE_MATCHES(type, EVP_AES_192_GCM))
#endif
#ifdef WOLFSSL_AES_256
if (ctx->cipherType == AES_256_GCM_TYPE ||
(type && EVP_CIPHER_TYPE_MATCHES(type, EVP_AES_256_GCM))) {
WOLFSSL_MSG("EVP_AES_256_GCM");
ctx->cipherType = AES_256_GCM_TYPE;
ctx->flags &= ~WOLFSSL_EVP_CIPH_MODE;
ctx->flags |= WOLFSSL_EVP_CIPH_GCM_MODE |
WOLFSSL_EVP_CIPH_FLAG_AEAD_CIPHER;
ctx->keyLen = 32;
ctx->block_size = AES_BLOCK_SIZE;
ctx->authTagSz = AES_BLOCK_SIZE;
if (ctx->ivSz == 0) {
ctx->ivSz = GCM_NONCE_MID_SZ;
}
#ifndef WOLFSSL_AESGCM_STREAM
if (key && wc_AesGcmSetKey(&ctx->cipher.aes, key, ctx->keyLen)) {
WOLFSSL_MSG("wc_AesGcmSetKey() failed");
|| ctx->cipherType == AES_256_GCM_TYPE ||
(type && EVP_CIPHER_TYPE_MATCHES(type, EVP_AES_256_GCM))
#endif
) {
if (EvpCipherInitAesGCM(ctx, type, key, iv, enc)
!= WOLFSSL_SUCCESS) {
return WOLFSSL_FAILURE;
}
#endif /* !WOLFSSL_AESGCM_STREAM */
if (iv && wc_AesGcmSetExtIV(&ctx->cipher.aes, iv, ctx->ivSz)) {
WOLFSSL_MSG("wc_AesGcmSetExtIV() failed");
return WOLFSSL_FAILURE;
}
#ifdef WOLFSSL_AESGCM_STREAM
/* Initialize with key and IV if available. */
if (wc_AesGcmInit(&ctx->cipher.aes,
key, (key == NULL) ? 0 : ctx->keyLen,
iv, (iv == NULL) ? 0 : ctx->ivSz) != 0) {
WOLFSSL_MSG("wc_AesGcmInit() failed");
return WOLFSSL_FAILURE;
}
#endif /* WOLFSSL_AESGCM_STREAM */
if (enc == 0 || enc == 1)
ctx->enc = enc ? 1 : 0;
}
#endif /* WOLFSSL_AES_256 */
#endif /* HAVE_AESGCM */
#endif /* (!HAVE_FIPS && !HAVE_SELFTEST) || HAVE_FIPS_VERSION >= 2 */
#endif /* HAVE_AESGCM && ((!HAVE_FIPS && !HAVE_SELFTEST) ||
* HAVE_FIPS_VERSION >= 2 */
#ifdef WOLFSSL_AES_COUNTER
#ifdef WOLFSSL_AES_128
if (ctx->cipherType == AES_128_CTR_TYPE ||
@ -6596,31 +6770,23 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
/* Return length on ok */
int wolfSSL_EVP_Cipher(WOLFSSL_EVP_CIPHER_CTX* ctx, byte* dst, byte* src,
word32 len)
word32 len)
{
int ret = 0;
int ret = WOLFSSL_FAILURE;
WOLFSSL_ENTER("wolfSSL_EVP_Cipher");
if (ctx == NULL) {
WOLFSSL_MSG("Bad function argument");
if (ctx == NULL || ((src == NULL || dst == NULL) &&
(ctx->cipherType != AES_128_GCM_TYPE &&
ctx->cipherType != AES_192_GCM_TYPE &&
ctx->cipherType != AES_256_GCM_TYPE))) {
WOLFSSL_MSG("Bad argument.");
return WOLFSSL_FATAL_ERROR;
}
if (src == NULL || dst == NULL) {
if (src != NULL && dst == NULL &&
(ctx->cipherType == AES_128_GCM_TYPE ||
ctx->cipherType == AES_192_GCM_TYPE ||
ctx->cipherType == AES_256_GCM_TYPE)) {
WOLFSSL_MSG("Setting GCM AAD.");
}
else {
WOLFSSL_MSG("Bad function argument");
return WOLFSSL_FATAL_ERROR;
}
}
if (ctx->cipherType == 0xff) {
WOLFSSL_MSG("no init");
if (ctx->cipherType == WOLFSSL_EVP_CIPH_TYPE_INIT) {
WOLFSSL_MSG("Cipher operation not initialized. Call "
"wolfSSL_EVP_CipherInit.");
return WOLFSSL_FATAL_ERROR;
}
@ -6706,74 +6872,16 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
break;
#endif /* WOLFSSL_AES_XTS */
#ifdef HAVE_AESGCM
#if defined(HAVE_AESGCM) && ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) \
|| FIPS_VERSION_GE(2,0))
case AES_128_GCM_TYPE :
case AES_192_GCM_TYPE :
case AES_256_GCM_TYPE :
WOLFSSL_MSG("AES GCM");
#ifndef WOLFSSL_AESGCM_STREAM
/* No destination means only AAD. */
if (!dst) {
ret = wolfSSL_EVP_CipherUpdate_GCM_AAD(ctx, src, len);
}
else {
if (ctx->enc)
ret = wc_AesGcmEncrypt(&ctx->cipher.aes, dst, src,
len, ctx->iv, ctx->ivSz, ctx->authTag,
ctx->authTagSz, ctx->gcmAuthIn, ctx->gcmAuthInSz);
else
ret = wc_AesGcmDecrypt(&ctx->cipher.aes, dst, src,
len, ctx->iv, ctx->ivSz, ctx->authTag,
ctx->authTagSz, ctx->gcmAuthIn, ctx->gcmAuthInSz);
}
#else
/* Do one shot operation with streaming API as other
* initialization set up for streaming. */
ret = wc_AesGcmInit(&ctx->cipher.aes, NULL, 0, ctx->iv,
ctx->ivSz);
/* No destination means only AAD. */
if ((ret == 0) && (dst == NULL)) {
if (ctx->enc) {
ret = wc_AesGcmEncryptUpdate(&ctx->cipher.aes, NULL,
NULL, 0, src, len);
}
else {
ret = wc_AesGcmDecryptUpdate(&ctx->cipher.aes, NULL,
NULL, 0, src, len);
}
}
/* Only plaintext/cipher text. */
else if (ret == 0) {
if (ctx->enc) {
ret = wc_AesGcmEncryptUpdate(&ctx->cipher.aes, dst, src,
len, NULL, 0);
}
else {
ret = wc_AesGcmDecryptUpdate(&ctx->cipher.aes, dst, src,
len, NULL, 0);
if (ret == 0) {
ret = wc_AesGcmDecryptFinal(&ctx->cipher.aes,
ctx->authTag, ctx->authTagSz);
}
}
}
if (ret == 0) {
if (ctx->enc) {
/* Calculate authentication tag. */
ret = wc_AesGcmEncryptFinal(&ctx->cipher.aes,
ctx->authTag, ctx->authTagSz);
}
else {
/* Calculate authentication tag and compare. */
ret = wc_AesGcmDecryptFinal(&ctx->cipher.aes,
ctx->authTag, ctx->authTagSz);
}
}
#endif /* WOLFSSL_AESGCM_STREAM */
if (ret == 0)
ret = len;
ret = EvpCipherAesGCM(ctx, dst, src, len);
break;
#endif /* HAVE_AESGCM */
#endif /* HAVE_AESGCM && ((!HAVE_FIPS && !HAVE_SELFTEST) ||
* HAVE_FIPS_VERSION >= 2 */
#ifdef HAVE_AES_ECB
case AES_128_ECB_TYPE :
case AES_192_ECB_TYPE :

View File

@ -438,6 +438,10 @@ struct WOLFSSL_EVP_CIPHER_CTX {
#endif
int authTagSz;
#endif
#ifdef HAVE_AESGCM
byte gcmIvGenEnable:1;
byte gcmIncIv:1;
#endif
#endif
};