| /** @file | |
| AEAD (AES-GCM) Wrapper Implementation over OpenSSL. | |
| RFC 5116 - An Interface and Algorithms for Authenticated Encryption | |
| NIST SP800-38d - Cipher Modes of Operation: Galois / Counter Mode(GCM) and GMAC | |
| Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "InternalCryptLib.h" | |
| #include <openssl/aes.h> | |
| #include <openssl/evp.h> | |
| /** | |
| Performs AEAD AES-GCM authenticated encryption on a data buffer and additional authenticated data (AAD). | |
| IvSize must be 12, otherwise FALSE is returned. | |
| KeySize must be 16, 24 or 32, otherwise FALSE is returned. | |
| TagSize must be 12, 13, 14, 15, 16, otherwise FALSE is returned. | |
| @param[in] Key Pointer to the encryption key. | |
| @param[in] KeySize Size of the encryption key in bytes. | |
| @param[in] Iv Pointer to the IV value. | |
| @param[in] IvSize Size of the IV value in bytes. | |
| @param[in] AData Pointer to the additional authenticated data (AAD). | |
| @param[in] ADataSize Size of the additional authenticated data (AAD) in bytes. | |
| @param[in] DataIn Pointer to the input data buffer to be encrypted. | |
| @param[in] DataInSize Size of the input data buffer in bytes. | |
| @param[out] TagOut Pointer to a buffer that receives the authentication tag output. | |
| @param[in] TagSize Size of the authentication tag in bytes. | |
| @param[out] DataOut Pointer to a buffer that receives the encryption output. | |
| @param[out] DataOutSize Size of the output data buffer in bytes. | |
| @retval TRUE AEAD AES-GCM authenticated encryption succeeded. | |
| @retval FALSE AEAD AES-GCM authenticated encryption failed. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| AeadAesGcmEncrypt ( | |
| IN CONST UINT8 *Key, | |
| IN UINTN KeySize, | |
| IN CONST UINT8 *Iv, | |
| IN UINTN IvSize, | |
| IN CONST UINT8 *AData, | |
| IN UINTN ADataSize, | |
| IN CONST UINT8 *DataIn, | |
| IN UINTN DataInSize, | |
| OUT UINT8 *TagOut, | |
| IN UINTN TagSize, | |
| OUT UINT8 *DataOut, | |
| OUT UINTN *DataOutSize | |
| ) | |
| { | |
| EVP_CIPHER_CTX *Ctx; | |
| CONST EVP_CIPHER *Cipher; | |
| UINTN TempOutSize; | |
| BOOLEAN RetValue; | |
| if (DataInSize > INT_MAX) { | |
| return FALSE; | |
| } | |
| if (ADataSize > INT_MAX) { | |
| return FALSE; | |
| } | |
| if (IvSize != 12) { | |
| return FALSE; | |
| } | |
| switch (KeySize) { | |
| case 16: | |
| Cipher = EVP_aes_128_gcm (); | |
| break; | |
| case 24: | |
| Cipher = EVP_aes_192_gcm (); | |
| break; | |
| case 32: | |
| Cipher = EVP_aes_256_gcm (); | |
| break; | |
| default: | |
| return FALSE; | |
| } | |
| if ((TagSize != 12) && (TagSize != 13) && (TagSize != 14) && (TagSize != 15) && (TagSize != 16)) { | |
| return FALSE; | |
| } | |
| if (DataOutSize != NULL) { | |
| if ((*DataOutSize > INT_MAX) || (*DataOutSize < DataInSize)) { | |
| return FALSE; | |
| } | |
| } | |
| Ctx = EVP_CIPHER_CTX_new (); | |
| if (Ctx == NULL) { | |
| return FALSE; | |
| } | |
| RetValue = (BOOLEAN)EVP_EncryptInit_ex (Ctx, Cipher, NULL, NULL, NULL); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_CIPHER_CTX_ctrl (Ctx, EVP_CTRL_GCM_SET_IVLEN, (INT32)IvSize, NULL); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_EncryptInit_ex (Ctx, NULL, NULL, Key, Iv); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_EncryptUpdate (Ctx, NULL, (INT32 *)&TempOutSize, AData, (INT32)ADataSize); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_EncryptUpdate (Ctx, DataOut, (INT32 *)&TempOutSize, DataIn, (INT32)DataInSize); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_EncryptFinal_ex (Ctx, DataOut, (INT32 *)&TempOutSize); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_CIPHER_CTX_ctrl (Ctx, EVP_CTRL_GCM_GET_TAG, (INT32)TagSize, (VOID *)TagOut); | |
| Done: | |
| EVP_CIPHER_CTX_free (Ctx); | |
| if (!RetValue) { | |
| return RetValue; | |
| } | |
| if (DataOutSize != NULL) { | |
| *DataOutSize = DataInSize; | |
| } | |
| return RetValue; | |
| } | |
| /** | |
| Performs AEAD AES-GCM authenticated decryption on a data buffer and additional authenticated data (AAD). | |
| IvSize must be 12, otherwise FALSE is returned. | |
| KeySize must be 16, 24 or 32, otherwise FALSE is returned. | |
| TagSize must be 12, 13, 14, 15, 16, otherwise FALSE is returned. | |
| If additional authenticated data verification fails, FALSE is returned. | |
| @param[in] Key Pointer to the encryption key. | |
| @param[in] KeySize Size of the encryption key in bytes. | |
| @param[in] Iv Pointer to the IV value. | |
| @param[in] IvSize Size of the IV value in bytes. | |
| @param[in] AData Pointer to the additional authenticated data (AAD). | |
| @param[in] ADataSize Size of the additional authenticated data (AAD) in bytes. | |
| @param[in] DataIn Pointer to the input data buffer to be decrypted. | |
| @param[in] DataInSize Size of the input data buffer in bytes. | |
| @param[in] Tag Pointer to a buffer that contains the authentication tag. | |
| @param[in] TagSize Size of the authentication tag in bytes. | |
| @param[out] DataOut Pointer to a buffer that receives the decryption output. | |
| @param[out] DataOutSize Size of the output data buffer in bytes. | |
| @retval TRUE AEAD AES-GCM authenticated decryption succeeded. | |
| @retval FALSE AEAD AES-GCM authenticated decryption failed. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| AeadAesGcmDecrypt ( | |
| IN CONST UINT8 *Key, | |
| IN UINTN KeySize, | |
| IN CONST UINT8 *Iv, | |
| IN UINTN IvSize, | |
| IN CONST UINT8 *AData, | |
| IN UINTN ADataSize, | |
| IN CONST UINT8 *DataIn, | |
| IN UINTN DataInSize, | |
| IN CONST UINT8 *Tag, | |
| IN UINTN TagSize, | |
| OUT UINT8 *DataOut, | |
| OUT UINTN *DataOutSize | |
| ) | |
| { | |
| EVP_CIPHER_CTX *Ctx; | |
| CONST EVP_CIPHER *Cipher; | |
| UINTN TempOutSize; | |
| BOOLEAN RetValue; | |
| if (DataInSize > INT_MAX) { | |
| return FALSE; | |
| } | |
| if (ADataSize > INT_MAX) { | |
| return FALSE; | |
| } | |
| if (IvSize != 12) { | |
| return FALSE; | |
| } | |
| switch (KeySize) { | |
| case 16: | |
| Cipher = EVP_aes_128_gcm (); | |
| break; | |
| case 24: | |
| Cipher = EVP_aes_192_gcm (); | |
| break; | |
| case 32: | |
| Cipher = EVP_aes_256_gcm (); | |
| break; | |
| default: | |
| return FALSE; | |
| } | |
| if ((TagSize != 12) && (TagSize != 13) && (TagSize != 14) && (TagSize != 15) && (TagSize != 16)) { | |
| return FALSE; | |
| } | |
| if (DataOutSize != NULL) { | |
| if ((*DataOutSize > INT_MAX) || (*DataOutSize < DataInSize)) { | |
| return FALSE; | |
| } | |
| } | |
| Ctx = EVP_CIPHER_CTX_new (); | |
| if (Ctx == NULL) { | |
| return FALSE; | |
| } | |
| RetValue = (BOOLEAN)EVP_DecryptInit_ex (Ctx, Cipher, NULL, NULL, NULL); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_CIPHER_CTX_ctrl (Ctx, EVP_CTRL_GCM_SET_IVLEN, (INT32)IvSize, NULL); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_DecryptInit_ex (Ctx, NULL, NULL, Key, Iv); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_DecryptUpdate (Ctx, NULL, (INT32 *)&TempOutSize, AData, (INT32)ADataSize); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_DecryptUpdate (Ctx, DataOut, (INT32 *)&TempOutSize, DataIn, (INT32)DataInSize); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_CIPHER_CTX_ctrl (Ctx, EVP_CTRL_GCM_SET_TAG, (INT32)TagSize, (VOID *)Tag); | |
| if (!RetValue) { | |
| goto Done; | |
| } | |
| RetValue = (BOOLEAN)EVP_DecryptFinal_ex (Ctx, DataOut, (INT32 *)&TempOutSize); | |
| Done: | |
| EVP_CIPHER_CTX_free (Ctx); | |
| if (!RetValue) { | |
| return RetValue; | |
| } | |
| if (DataOutSize != NULL) { | |
| *DataOutSize = DataInSize; | |
| } | |
| return RetValue; | |
| } |