From 625ec431eb5a743ee62deb308235ab1b7a891fb1 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 21 Apr 2021 23:59:14 -0500 Subject: [PATCH] Improve AES-CBC code in preparation for audio encryption --- src/ControlStream.c | 4 +-- src/InputStream.c | 4 +-- src/PlatformCrypto.c | 77 +++++++++++++++++++++++++++----------------- src/PlatformCrypto.h | 7 ++-- 4 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/ControlStream.c b/src/ControlStream.c index 7941b03..b4422b8 100644 --- a/src/ControlStream.c +++ b/src/ControlStream.c @@ -426,7 +426,7 @@ static bool encryptControlMessage(PNVCTL_ENCRYPTED_PACKET_HEADER encPacket, PNVC memset(iv, 0, sizeof(iv)); iv[0] = (unsigned char)encPacket->seq; - return PltEncryptMessage(encryptionCtx, ALGORITHM_AES_GCM, + return PltEncryptMessage(encryptionCtx, ALGORITHM_AES_GCM, 0, (unsigned char*)StreamConfig.remoteInputAesKey, sizeof(StreamConfig.remoteInputAesKey), iv, sizeof(iv), (unsigned char*)(encPacket + 1), AES_GCM_TAG_LENGTH, // Write tag into the space after the encrypted header @@ -459,7 +459,7 @@ static bool decryptControlMessageToV1(PNVCTL_ENCRYPTED_PACKET_HEADER encPacket, return false; } - if (!PltDecryptMessage(decryptionCtx, ALGORITHM_AES_GCM, + if (!PltDecryptMessage(decryptionCtx, ALGORITHM_AES_GCM, 0, (unsigned char*)StreamConfig.remoteInputAesKey, sizeof(StreamConfig.remoteInputAesKey), iv, sizeof(iv), (unsigned char*)(encPacket + 1), AES_GCM_TAG_LENGTH, // The tag is located right after the header diff --git a/src/InputStream.c b/src/InputStream.c index bba41db..cec07a0 100644 --- a/src/InputStream.c +++ b/src/InputStream.c @@ -63,7 +63,7 @@ static int encryptData(unsigned char* plaintext, int plaintextLen, unsigned char* ciphertext, int* ciphertextLen) { // Starting in Gen 7, AES GCM is used for encryption if (AppVersionQuad[0] >= 7) { - if (!PltEncryptMessage(cryptoContext, ALGORITHM_AES_GCM, + if (!PltEncryptMessage(cryptoContext, ALGORITHM_AES_GCM, 0, (unsigned char*)StreamConfig.remoteInputAesKey, sizeof(StreamConfig.remoteInputAesKey), currentAesIv, sizeof(currentAesIv), ciphertext, 16, @@ -84,7 +84,7 @@ static int encryptData(unsigned char* plaintext, int plaintextLen, memcpy(paddedData, plaintext, plaintextLen); // Prior to Gen 7, 128-bit AES CBC is used for encryption - return PltEncryptMessage(cryptoContext, ALGORITHM_AES_CBC, + return PltEncryptMessage(cryptoContext, ALGORITHM_AES_CBC, 0, (unsigned char*)StreamConfig.remoteInputAesKey, sizeof(StreamConfig.remoteInputAesKey), currentAesIv, sizeof(currentAesIv), NULL, 0, diff --git a/src/PlatformCrypto.c b/src/PlatformCrypto.c index c8bbebe..870f14b 100644 --- a/src/PlatformCrypto.c +++ b/src/PlatformCrypto.c @@ -26,7 +26,7 @@ static int addPkcs7PaddingInPlace(unsigned char* plaintext, int plaintextLen) { #endif // For CBC modes, inputData buffer must be allocated with length rounded up to next multiple of 16 and inputData buffer may be modified! -bool PltEncryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, +bool PltEncryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, int flags, unsigned char* key, int keyLength, unsigned char* iv, int ivLength, unsigned char* tag, int tagLength, @@ -38,6 +38,8 @@ bool PltEncryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, switch (algorithm) { case ALGORITHM_AES_CBC: + LC_ASSERT(flags & CIPHER_FLAG_RESET_IV); + LC_ASSERT(flags & CIPHER_FLAG_FINISH); LC_ASSERT(tag == NULL); LC_ASSERT(tagLength == 0); cipherMode = MBEDTLS_MODE_CBC; @@ -80,7 +82,6 @@ bool PltEncryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, *outputDataLength = outLength; return true; #else - bool ret = false; const EVP_CIPHER* cipher; switch (algorithm) { @@ -102,22 +103,26 @@ bool PltEncryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, } if (algorithm == ALGORITHM_AES_GCM) { + EVP_CIPHER_CTX_reset(ctx->ctx); + if (EVP_EncryptInit_ex(ctx->ctx, cipher, NULL, NULL, NULL) != 1) { - goto cleanup; + return false; } if (EVP_CIPHER_CTX_ctrl(ctx->ctx, EVP_CTRL_GCM_SET_IVLEN, ivLength, NULL) != 1) { - goto cleanup; + return false; } if (EVP_EncryptInit_ex(ctx->ctx, NULL, NULL, key, iv) != 1) { - goto cleanup; + return false; } } else { - if (!ctx->initialized) { + if (!ctx->initialized || (flags & CIPHER_FLAG_RESET_IV)) { + EVP_CIPHER_CTX_reset(ctx->ctx); + if (EVP_EncryptInit_ex(ctx->ctx, cipher, NULL, key, iv) != 1) { - goto cleanup; + return false; } ctx->initialized = true; @@ -127,7 +132,7 @@ bool PltEncryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, } if (EVP_EncryptUpdate(ctx->ctx, outputData, outputDataLength, inputData, inputDataLength) != 1) { - goto cleanup; + return false; } if (algorithm == ALGORITHM_AES_GCM) { @@ -135,26 +140,30 @@ bool PltEncryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, // GCM encryption won't ever fill ciphertext here but we have to call it anyway if (EVP_EncryptFinal_ex(ctx->ctx, outputData, &len) != 1) { - goto cleanup; + return false; } LC_ASSERT(len == 0); if (EVP_CIPHER_CTX_ctrl(ctx->ctx, EVP_CTRL_GCM_GET_TAG, tagLength, tag) != 1) { - goto cleanup; + return false; } } + else if (flags & CIPHER_FLAG_FINISH) { + int len; - ret = true; + if (EVP_EncryptFinal_ex(ctx->ctx, &outputData[*outputDataLength], &len) != 1) { + return false; + } -cleanup: - if (algorithm == ALGORITHM_AES_GCM) { - EVP_CIPHER_CTX_reset(ctx->ctx); + *outputDataLength += len; } - return ret; + + return true; #endif } -bool PltDecryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, +// For CBC modes, outputData buffer must be allocated with length rounded up to next multiple of 16! +bool PltDecryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, int flags, unsigned char* key, int keyLength, unsigned char* iv, int ivLength, unsigned char* tag, int tagLength, @@ -166,6 +175,8 @@ bool PltDecryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, switch (algorithm) { case ALGORITHM_AES_CBC: + LC_ASSERT(flags & CIPHER_FLAG_RESET_IV); + LC_ASSERT(flags & CIPHER_FLAG_FINISH); LC_ASSERT(tag == NULL); LC_ASSERT(tagLength == 0); cipherMode = MBEDTLS_MODE_CBC; @@ -208,7 +219,6 @@ bool PltDecryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, *outputDataLength = outLength; return true; #else - bool ret = false; const EVP_CIPHER* cipher; switch (algorithm) { @@ -230,22 +240,26 @@ bool PltDecryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, } if (algorithm == ALGORITHM_AES_GCM) { + EVP_CIPHER_CTX_reset(ctx->ctx); + if (EVP_DecryptInit_ex(ctx->ctx, cipher, NULL, NULL, NULL) != 1) { - goto cleanup; + return false; } if (EVP_CIPHER_CTX_ctrl(ctx->ctx, EVP_CTRL_GCM_SET_IVLEN, ivLength, NULL) != 1) { - goto cleanup; + return false; } if (EVP_DecryptInit_ex(ctx->ctx, NULL, NULL, key, iv) != 1) { - goto cleanup; + return false; } } else { - if (!ctx->initialized) { + if (!ctx->initialized || (flags & CIPHER_FLAG_RESET_IV)) { + EVP_CIPHER_CTX_reset(ctx->ctx); + if (EVP_DecryptInit_ex(ctx->ctx, cipher, NULL, key, iv) != 1) { - goto cleanup; + return false; } ctx->initialized = true; @@ -253,7 +267,7 @@ bool PltDecryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, } if (EVP_DecryptUpdate(ctx->ctx, outputData, outputDataLength, inputData, inputDataLength) != 1) { - goto cleanup; + return false; } if (algorithm == ALGORITHM_AES_GCM) { @@ -261,24 +275,27 @@ bool PltDecryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, // Set the GCM tag before calling EVP_DecryptFinal_ex() if (EVP_CIPHER_CTX_ctrl(ctx->ctx, EVP_CTRL_GCM_SET_TAG, tagLength, tag) != 1) { - goto cleanup; + return false; } // GCM will never have additional plaintext here, but we need to call it to // ensure that the GCM authentication tag is correct for this data. if (EVP_DecryptFinal_ex(ctx->ctx, outputData, &len) != 1) { - goto cleanup; + return false; } LC_ASSERT(len == 0); } + else if (flags & CIPHER_FLAG_FINISH) { + int len; - ret = true; + if (EVP_DecryptFinal_ex(ctx->ctx, &outputData[*outputDataLength], &len) != 1) { + return false; + } -cleanup: - if (algorithm == ALGORITHM_AES_GCM) { - EVP_CIPHER_CTX_reset(ctx->ctx); + *outputDataLength += len; } - return ret; + + return true; #endif } diff --git a/src/PlatformCrypto.h b/src/PlatformCrypto.h index f39ac95..3f65833 100644 --- a/src/PlatformCrypto.h +++ b/src/PlatformCrypto.h @@ -27,14 +27,17 @@ void PltDestroyCryptoContext(PPLT_CRYPTO_CONTEXT ctx); #define ALGORITHM_AES_CBC 1 #define ALGORITHM_AES_GCM 2 -bool PltEncryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, +#define CIPHER_FLAG_RESET_IV 0x01 +#define CIPHER_FLAG_FINISH 0x02 + +bool PltEncryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, int flags, unsigned char* key, int keyLength, unsigned char* iv, int ivLength, unsigned char* tag, int tagLength, unsigned char* inputData, int inputDataLength, unsigned char* outputData, int* outputDataLength); -bool PltDecryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, +bool PltDecryptMessage(PPLT_CRYPTO_CONTEXT ctx, int algorithm, int flags, unsigned char* key, int keyLength, unsigned char* iv, int ivLength, unsigned char* tag, int tagLength,