diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Runtime/common/crypto/cipher-openssl.cpp | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Runtime/common/crypto/cipher-openssl.cpp')
-rw-r--r-- | src/VBox/Runtime/common/crypto/cipher-openssl.cpp | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/crypto/cipher-openssl.cpp b/src/VBox/Runtime/common/crypto/cipher-openssl.cpp new file mode 100644 index 00000000..079af227 --- /dev/null +++ b/src/VBox/Runtime/common/crypto/cipher-openssl.cpp @@ -0,0 +1,596 @@ +/* $Id: cipher-openssl.cpp $ */ +/** @file + * IPRT - Crypto - Symmetric Cipher using OpenSSL. + */ + +/* + * Copyright (C) 2018-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#ifdef IPRT_WITH_OPENSSL +# include "internal/iprt.h" +# include <iprt/crypto/cipher.h> + +# include <iprt/asm.h> +# include <iprt/assert.h> +# include <iprt/err.h> +# include <iprt/mem.h> +# include <iprt/string.h> + +# include "internal/iprt-openssl.h" +# include "internal/openssl-pre.h" +# include <openssl/evp.h> +# include "internal/openssl-post.h" + +# include "internal/magics.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#if defined(EVP_CTRL_AEAD_GET_TAG) +# define MY_EVP_CTRL_AEAD_GET_TAG EVP_CTRL_AEAD_GET_TAG +#else +# define MY_EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG +#endif + +#if defined(EVP_CTRL_AEAD_SET_TAG) +# define MY_EVP_CTRL_AEAD_SET_TAG EVP_CTRL_AEAD_SET_TAG +#else +# define MY_EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG +#endif + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** + * OpenSSL cipher instance data. + */ +typedef struct RTCRCIPHERINT +{ + /** Magic value (RTCRCIPHERINT_MAGIC). */ + uint32_t u32Magic; + /** Reference count. */ + uint32_t volatile cRefs; + /** The cihper. */ + const EVP_CIPHER *pCipher; + /** The IPRT cipher type, if we know it. */ + RTCRCIPHERTYPE enmType; +} RTCRCIPHERINT; + + +/** + * OpenSSL cipher context data + */ +typedef struct RTCRCIPHERCTXINT +{ + /** Pointer to cipher instance data */ + RTCRCIPHERINT *phCipher; + /** Pointer to cipher context */ + EVP_CIPHER_CTX *pCipherCtx; + /** Is decryption */ + bool fDecryption; +} RTCRCIPHERCTXINT; + + +RTDECL(int) RTCrCipherOpenByType(PRTCRCIPHER phCipher, RTCRCIPHERTYPE enmType, uint32_t fFlags) +{ + AssertPtrReturn(phCipher, VERR_INVALID_POINTER); + *phCipher = NIL_RTCRCIPHER; + AssertReturn(!fFlags, VERR_INVALID_FLAGS); + + /* + * Translate the IPRT cipher type to EVP cipher. + */ + const EVP_CIPHER *pCipher = NULL; + switch (enmType) + { + case RTCRCIPHERTYPE_XTS_AES_128: + pCipher = EVP_aes_128_xts(); + break; + case RTCRCIPHERTYPE_XTS_AES_256: + pCipher = EVP_aes_256_xts(); + break; + case RTCRCIPHERTYPE_GCM_AES_128: + pCipher = EVP_aes_128_gcm(); + break; + case RTCRCIPHERTYPE_GCM_AES_256: + pCipher = EVP_aes_256_gcm(); + break; + case RTCRCIPHERTYPE_CTR_AES_128: + pCipher = EVP_aes_128_ctr(); + break; + case RTCRCIPHERTYPE_CTR_AES_256: + pCipher = EVP_aes_256_ctr(); + break; + + /* no default! */ + case RTCRCIPHERTYPE_INVALID: + case RTCRCIPHERTYPE_END: + case RTCRCIPHERTYPE_32BIT_HACK: + AssertFailedReturn(VERR_INVALID_PARAMETER); + } + AssertReturn(pCipher, VERR_CR_CIPHER_NOT_SUPPORTED); + + /* + * Create the instance. + */ + RTCRCIPHERINT *pThis = (RTCRCIPHERINT *)RTMemAllocZ(sizeof(*pThis)); + if (pThis) + { + pThis->u32Magic = RTCRCIPHERINT_MAGIC; + pThis->cRefs = 1; + pThis->pCipher = pCipher; + pThis->enmType = enmType; + *phCipher = pThis; + return VINF_SUCCESS; + } + return VERR_NO_MEMORY; +} + + +RTDECL(uint32_t) RTCrCipherRetain(RTCRCIPHER hCipher) +{ + RTCRCIPHERINT *pThis = hCipher; + AssertPtrReturn(pThis, UINT32_MAX); + AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, UINT32_MAX); + + uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs); + Assert(cRefs > 1 && cRefs < 1024); + return cRefs; +} + + +/** + * Destroys the cipher instance. + */ +static uint32_t rtCrCipherDestroy(RTCRCIPHER pThis) +{ + pThis->u32Magic= ~RTCRCIPHERINT_MAGIC; + pThis->pCipher = NULL; + RTMemFree(pThis); + return 0; +} + + +RTDECL(uint32_t) RTCrCipherRelease(RTCRCIPHER hCipher) +{ + RTCRCIPHERINT *pThis = hCipher; + if (pThis == NIL_RTCRCIPHER) + return 0; + AssertPtrReturn(pThis, UINT32_MAX); + AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, UINT32_MAX); + + uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs); + Assert(cRefs < 1024); + if (cRefs == 0) + return rtCrCipherDestroy(pThis); + return cRefs; +} + + +RTDECL(uint32_t) RTCrCipherGetKeyLength(RTCRCIPHER hCipher) +{ + RTCRCIPHERINT *pThis = hCipher; + AssertPtrReturn(pThis, 0); + AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, 0); + + return EVP_CIPHER_key_length(pThis->pCipher); +} + + +RTDECL(uint32_t) RTCrCipherGetInitializationVectorLength(RTCRCIPHER hCipher) +{ + RTCRCIPHERINT *pThis = hCipher; + AssertPtrReturn(pThis, 0); + AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, 0); + + return EVP_CIPHER_iv_length(pThis->pCipher); +} + + +RTDECL(uint32_t) RTCrCipherGetBlockSize(RTCRCIPHER hCipher) +{ + RTCRCIPHERINT *pThis = hCipher; + AssertPtrReturn(pThis, 0); + AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, 0); + + return EVP_CIPHER_block_size(pThis->pCipher); +} + + +RTDECL(int) RTCrCipherCtxFree(RTCRCIPHERCTX hCipherCtx) +{ + AssertReturn(hCipherCtx, VERR_INVALID_PARAMETER); + RTCRCIPHERCTXINT *pCtx = hCipherCtx; + +# if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER) + EVP_CIPHER_CTX_free(pCtx->pCipherCtx); +# else + EVP_CIPHER_CTX_cleanup(pCtx->pCipherCtx); + RTMemFree(pCtx->pCipherCtx); +# endif + RTMemFree(pCtx); + + return VINF_SUCCESS; +} + + +RTDECL(int) RTCrCipherCtxEncryptInit(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + PRTCRCIPHERCTX phCipherCtx) +{ + /* + * Validate input. + */ + RTCRCIPHERINT *pThis = hCipher; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, VERR_INVALID_HANDLE); + AssertMsgReturn((ssize_t)cbKey == EVP_CIPHER_key_length(pThis->pCipher), + ("%zu, expected %d\n", cbKey, EVP_CIPHER_key_length(pThis->pCipher)), + VERR_CR_CIPHER_INVALID_KEY_LENGTH); + AssertMsgReturn((ssize_t)cbInitVector == EVP_CIPHER_iv_length(pThis->pCipher), + ("%zu, expected %d\n", cbInitVector, EVP_CIPHER_iv_length(pThis->pCipher)), + VERR_CR_CIPHER_INVALID_INITIALIZATION_VECTOR_LENGTH); + + Assert(EVP_CIPHER_block_size(pThis->pCipher) <= 1); /** @todo more complicated ciphers later */ + + /* + * Allocate and initialize the cipher context. + */ + int rc = VERR_NO_MEMORY; + /* + * Create the instance. + */ + RTCRCIPHERCTXINT *pCtx = (RTCRCIPHERCTXINT *)RTMemAlloc(sizeof(RTCRCIPHERCTXINT)); + if (pCtx) + { + pCtx->phCipher = hCipher; + pCtx->fDecryption = false; +# if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER) + pCtx->pCipherCtx = EVP_CIPHER_CTX_new(); + if (pCtx->pCipherCtx) +# else + pCtx->pCipherCtx = (EVP_CIPHER_CTX *)RTMemAllocZ(sizeof(EVP_CIPHER_CTX)); +# endif + { + if (EVP_EncryptInit(pCtx->pCipherCtx, pCtx->phCipher->pCipher, (unsigned char const *)pvKey, + (unsigned char const *)pvInitVector)) + { + if (pvAuthData && cbAuthData) + { + /* Add auth data. */ + int cbEncryptedAuth = 0; + rc = EVP_EncryptUpdate(pCtx->pCipherCtx, NULL, &cbEncryptedAuth, + (unsigned char const *)pvAuthData, (int)cbAuthData) ? VINF_SUCCESS + : VERR_CR_CIPHER_OSSL_ENCRYPT_UPDATE_FAILED; + } + else + rc = VINF_SUCCESS; + } + else + rc = VERR_CR_CIPHER_OSSL_ENCRYPT_INIT_FAILED; + } + } + + if (RT_SUCCESS(rc)) + *phCipherCtx = pCtx; + else + RTCrCipherCtxFree(pCtx); + return rc; +} + + +RTDECL(int) RTCrCipherCtxEncryptProcess(RTCRCIPHERCTX hCipherCtx, void const *pvPlainText, size_t cbPlainText, + void *pvEncrypted, size_t cbEncrypted, size_t *pcbEncrypted) +{ + AssertReturn(hCipherCtx, VERR_INVALID_PARAMETER); + AssertReturn(cbPlainText > 0, VERR_NO_DATA); + AssertReturn((size_t)(int)cbPlainText == cbPlainText && (int)cbPlainText > 0, VERR_OUT_OF_RANGE); + AssertReturn(cbEncrypted >= cbPlainText, VERR_BUFFER_OVERFLOW); + + RTCRCIPHERCTXINT *pCtx = hCipherCtx; + AssertReturn(!pCtx->fDecryption, VERR_INVALID_STATE); + int cbEncrypted1 = 0; + int rc = VERR_CR_CIPHER_OSSL_ENCRYPT_UPDATE_FAILED; + if (EVP_EncryptUpdate(pCtx->pCipherCtx, (unsigned char *)pvEncrypted, &cbEncrypted1, + (unsigned char const *)pvPlainText, (int)cbPlainText)) + { + *pcbEncrypted = cbEncrypted1; + rc = VINF_SUCCESS; + } + return rc; +} + + +RTDECL(int) RTCrCipherCtxEncryptFinish(RTCRCIPHERCTX hCipherCtx, + void *pvEncrypted, size_t *pcbEncrypted, + void *pvTag, size_t cbTag, size_t *pcbTag) +{ + AssertReturn(hCipherCtx, VERR_INVALID_PARAMETER); + RTCRCIPHERCTXINT *pCtx = hCipherCtx; + AssertReturn(!pCtx->fDecryption, VERR_INVALID_STATE); + AssertReturn(!pvTag || (pvTag && cbTag == 16), VERR_CR_CIPHER_INVALID_TAG_LENGTH); + int cbEncrypted2 = 0; + int rc = VERR_CR_CIPHER_OSSL_ENCRYPT_FINAL_FAILED; + if (EVP_EncryptFinal(pCtx->pCipherCtx, (uint8_t *)pvEncrypted, &cbEncrypted2)) + { + if (pvTag && cbTag) + { + if (EVP_CIPHER_CTX_ctrl(pCtx->pCipherCtx, MY_EVP_CTRL_AEAD_GET_TAG, (int)cbTag, pvTag)) + { + *pcbTag = cbTag; + rc = VINF_SUCCESS; + } + else + rc = VERR_CR_CIPHER_OSSL_GET_TAG_FAILED; + } + else + rc = VINF_SUCCESS; + + if (RT_SUCCESS(rc) && pcbEncrypted) + *pcbEncrypted = cbEncrypted2; + } + + return rc; +} + + +RTDECL(int) RTCrCipherCtxDecryptInit(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + void *pvTag, size_t cbTag, PRTCRCIPHERCTX phCipherCtx) +{ + /* + * Validate input. + */ + RTCRCIPHERINT *pThis = hCipher; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, VERR_INVALID_HANDLE); + AssertMsgReturn((ssize_t)cbKey == EVP_CIPHER_key_length(pThis->pCipher), + ("%zu, expected %d\n", cbKey, EVP_CIPHER_key_length(pThis->pCipher)), + VERR_CR_CIPHER_INVALID_KEY_LENGTH); + AssertMsgReturn((ssize_t)cbInitVector == EVP_CIPHER_iv_length(pThis->pCipher), + ("%zu, expected %d\n", cbInitVector, EVP_CIPHER_iv_length(pThis->pCipher)), + VERR_CR_CIPHER_INVALID_INITIALIZATION_VECTOR_LENGTH); + AssertReturn(!pvTag || (pvTag && cbTag == 16), VERR_CR_CIPHER_INVALID_TAG_LENGTH); + + Assert(EVP_CIPHER_block_size(pThis->pCipher) <= 1); /** @todo more complicated ciphers later */ + + /* + * Allocate and initialize the cipher context. + */ + int rc = VERR_NO_MEMORY; + /* + * Create the instance. + */ + RTCRCIPHERCTXINT *pCtx = (RTCRCIPHERCTXINT *)RTMemAlloc(sizeof(RTCRCIPHERCTXINT)); + if (pCtx) + { + pCtx->phCipher = hCipher; + pCtx->fDecryption = true; +# if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER) + pCtx->pCipherCtx = EVP_CIPHER_CTX_new(); +# else + pCtx->pCipherCtx = (EVP_CIPHER_CTX *)RTMemAllocZ(sizeof(EVP_CIPHER_CTX)); +# endif + + if (EVP_DecryptInit(pCtx->pCipherCtx, pThis->pCipher, (unsigned char const *)pvKey, + (unsigned char const *)pvInitVector)) + { + rc = VINF_SUCCESS; + if (pvTag && cbTag && !EVP_CIPHER_CTX_ctrl(pCtx->pCipherCtx, MY_EVP_CTRL_AEAD_SET_TAG, (int)cbTag, pvTag)) + rc = VERR_CR_CIPHER_OSSL_SET_TAG_FAILED; + + if (RT_SUCCESS(rc) && pvAuthData && cbAuthData) + { + /* Add auth data. */ + int cbDecryptedAuth = 0; + if (!EVP_DecryptUpdate(pCtx->pCipherCtx, NULL, &cbDecryptedAuth, + (unsigned char const *)pvAuthData, (int)cbAuthData)) + rc = VERR_CR_CIPHER_OSSL_DECRYPT_UPDATE_FAILED; + } + } + else + rc = VERR_CR_CIPHER_OSSL_DECRYPT_INIT_FAILED; + } + + if (RT_SUCCESS(rc)) + *phCipherCtx = pCtx; + else + RTCrCipherCtxFree(pCtx); + + return rc; +} + + +RTDECL(int) RTCrCipherCtxDecryptProcess(RTCRCIPHERCTX hCipherCtx, + void const *pvEncrypted, size_t cbEncrypted, + void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText) +{ + AssertReturn(hCipherCtx, VERR_INVALID_PARAMETER); + AssertReturn(cbEncrypted > 0, VERR_NO_DATA); + AssertReturn((size_t)(int)cbEncrypted == cbEncrypted && (int)cbEncrypted > 0, VERR_OUT_OF_RANGE); + AssertReturn(cbPlainText >= cbEncrypted, VERR_BUFFER_OVERFLOW); + + RTCRCIPHERCTXINT *pCtx = hCipherCtx; + AssertReturn(pCtx->fDecryption, VERR_INVALID_STATE); + int rc = VERR_CR_CIPHER_OSSL_DECRYPT_UPDATE_FAILED; + int cbDecrypted1 = 0; + if (EVP_DecryptUpdate(pCtx->pCipherCtx, (unsigned char *)pvPlainText, &cbDecrypted1, + (unsigned char const *)pvEncrypted, (int)cbEncrypted)) + { + *pcbPlainText = cbDecrypted1; + rc = VINF_SUCCESS; + } + return rc; +} + + +RTDECL(int) RTCrCipherCtxDecryptFinish(RTCRCIPHERCTX hCipherCtx, + void *pvPlainText, size_t *pcbPlainText) +{ + AssertReturn(hCipherCtx, VERR_INVALID_PARAMETER); + RTCRCIPHERCTXINT *pCtx = hCipherCtx; + AssertReturn(pCtx->fDecryption, VERR_INVALID_STATE); + int cbDecrypted2 = 0; + int rc = VERR_CR_CIPHER_OSSL_ENCRYPT_FINAL_FAILED; + if (EVP_DecryptFinal(pCtx->pCipherCtx, (uint8_t *)pvPlainText, &cbDecrypted2)) + { + rc = VINF_SUCCESS; + if (pcbPlainText) + *pcbPlainText = cbDecrypted2; + } + + return rc; +} + + +RTDECL(int) RTCrCipherEncrypt(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvPlainText, size_t cbPlainText, + void *pvEncrypted, size_t cbEncrypted, size_t *pcbEncrypted) +{ + return RTCrCipherEncryptEx(hCipher, pvKey, cbKey, pvInitVector, cbInitVector, + NULL, 0, pvPlainText, cbPlainText, pvEncrypted, cbEncrypted, + pcbEncrypted, NULL, 0, NULL); +} + + +RTDECL(int) RTCrCipherDecrypt(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvEncrypted, size_t cbEncrypted, + void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText) +{ + return RTCrCipherDecryptEx(hCipher, pvKey, cbKey, pvInitVector, cbInitVector, + NULL, 0, NULL, 0, pvEncrypted, cbEncrypted, + pvPlainText, cbPlainText, pcbPlainText); +} + + +RTDECL(int) RTCrCipherEncryptEx(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + void const *pvPlainText, size_t cbPlainText, + void *pvEncrypted, size_t cbEncrypted, size_t *pcbEncrypted, + void *pvTag, size_t cbTag, size_t *pcbTag) +{ + size_t const cbNeeded = cbPlainText; + if (pcbEncrypted) + { + *pcbEncrypted = cbNeeded; + AssertReturn(cbEncrypted >= cbNeeded, VERR_BUFFER_OVERFLOW); + } + else + AssertReturn(cbEncrypted == cbNeeded, VERR_INVALID_PARAMETER); + AssertReturn((size_t)(int)cbPlainText == cbPlainText && (int)cbPlainText > 0, VERR_OUT_OF_RANGE); + + RTCRCIPHERCTXINT *pCtx = NIL_RTCRCIPHERCTX; + + int rc = RTCrCipherCtxEncryptInit(hCipher, pvKey, cbKey, pvInitVector, cbInitVector, + pvAuthData, cbAuthData, &pCtx); + if (RT_SUCCESS(rc)) + { + size_t cbEncrypted1 = 0; + rc = RTCrCipherCtxEncryptProcess(pCtx, pvPlainText, cbPlainText, pvEncrypted, cbEncrypted, &cbEncrypted1); + if (RT_SUCCESS(rc)) + { + size_t cbEncrypted2 = 0; + rc = RTCrCipherCtxEncryptFinish(pCtx, (unsigned char *)pvEncrypted + cbEncrypted1, + &cbEncrypted2, pvTag, cbTag, pcbTag); + if (RT_SUCCESS(rc)) + { + Assert(cbEncrypted1 + cbEncrypted2 == cbNeeded); + if (pcbEncrypted) + *pcbEncrypted = cbEncrypted1 + cbEncrypted2; + } + } + } + + if (pCtx != NIL_RTCRCIPHERCTX) + RTCrCipherCtxFree(pCtx); + + return rc; +} + + +RTDECL(int) RTCrCipherDecryptEx(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey, + void const *pvInitVector, size_t cbInitVector, + void const *pvAuthData, size_t cbAuthData, + void *pvTag, size_t cbTag, + void const *pvEncrypted, size_t cbEncrypted, + void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText) +{ + size_t const cbNeeded = cbEncrypted; + if (pcbPlainText) + { + *pcbPlainText = cbNeeded; + AssertReturn(cbPlainText >= cbNeeded, VERR_BUFFER_OVERFLOW); + } + else + AssertReturn(cbPlainText == cbNeeded, VERR_INVALID_PARAMETER); + AssertReturn((size_t)(int)cbEncrypted == cbEncrypted && (int)cbEncrypted > 0, VERR_OUT_OF_RANGE); + + RTCRCIPHERCTXINT *pCtx = NIL_RTCRCIPHERCTX; + + int rc = RTCrCipherCtxDecryptInit(hCipher, pvKey, cbKey, pvInitVector, cbInitVector, + pvAuthData, cbAuthData, pvTag, cbTag, &pCtx); + if (RT_SUCCESS(rc)) + { + size_t cbDecrypted1 = 0; + rc = RTCrCipherCtxDecryptProcess(pCtx, pvEncrypted, cbEncrypted, pvPlainText, cbPlainText, &cbDecrypted1); + if (RT_SUCCESS(rc)) + { + size_t cbDecrypted2 = 0; + rc = RTCrCipherCtxDecryptFinish(pCtx, (unsigned char *)pvPlainText + cbDecrypted1, + &cbDecrypted2); + if (RT_SUCCESS(rc)) + { + Assert(cbDecrypted1 + cbDecrypted2 == cbNeeded); + if (pcbPlainText) + *pcbPlainText = cbDecrypted1 + cbDecrypted2; + } + } + } + + if (pCtx != NIL_RTCRCIPHERCTX) + RTCrCipherCtxFree(pCtx); + + return rc; +} + +#endif /* IPRT_WITH_OPENSSL */ + |