Improve AES-CBC code in preparation for audio encryption

This commit is contained in:
Cameron Gutman 2021-04-21 23:59:14 -05:00
parent 3abd3af4b2
commit 625ec431eb
4 changed files with 56 additions and 36 deletions

View File

@ -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

View File

@ -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,

View File

@ -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
}

View File

@ -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,