* This file is part of the openHiTLS project.
*
* openHiTLS is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "hitls_build.h"
#ifdef HITLS_TLS_SUITE_CIPHER_CBC
#include <string.h>
#include "hitls_error.h"
#include "bsl_err_internal.h"
#include "bsl_log_internal.h"
#include "tls_binlog_id.h"
#include "bsl_bytes.h"
#include "crypt.h"
#include "rec_alert.h"
#include "rec_conn.h"
#include "record.h"
#include "rec_crypto_cbc.h"
#define CBC_PADDING_LEN_TAG_SIZE 1u
#define HMAC_MAX_BLEN 144
uint8_t RecConnGetCbcPaddingLen(uint8_t blockLen, uint32_t plaintextLen)
{
if (blockLen == 0) {
return 0;
}
uint8_t remainder = (plaintextLen + CBC_PADDING_LEN_TAG_SIZE) % blockLen;
if (remainder == 0) {
return 0;
}
return blockLen - remainder;
}
static uint32_t CbcCalCiphertextLen(const TLS_Ctx *ctx, RecConnSuitInfo *suiteInfo, uint32_t plantextLen, bool isRead)
{
uint32_t ciphertextLen = plantextLen;
ciphertextLen += suiteInfo->recordIvLength;
bool isEncryptThenMac = isRead ?
ctx->negotiatedInfo.isEncryptThenMacRead : ctx->negotiatedInfo.isEncryptThenMacWrite;
if (isEncryptThenMac) {
ciphertextLen += RecConnGetCbcPaddingLen(suiteInfo->blockLength, ciphertextLen) + CBC_PADDING_LEN_TAG_SIZE;
ciphertextLen += suiteInfo->macLen;
} else {
ciphertextLen += suiteInfo->macLen;
ciphertextLen += RecConnGetCbcPaddingLen(suiteInfo->blockLength, ciphertextLen) + CBC_PADDING_LEN_TAG_SIZE;
}
return ciphertextLen;
}
static int32_t CbcCalPlantextBufLen(TLS_Ctx *ctx, RecConnSuitInfo *suiteInfo,
uint32_t ciphertextLen, uint32_t *offset, uint32_t *plainLen)
{
uint32_t plantextLen = ciphertextLen;
*offset = suiteInfo->recordIvLength;
plantextLen -= *offset;
if (ctx->negotiatedInfo.isEncryptThenMacRead) {
plantextLen -= suiteInfo->macLen;
}
if (plantextLen > ciphertextLen) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID17242, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"plantextLen err", 0, 0, 0, 0);
return HITLS_INVALID_INPUT;
}
*plainLen = plantextLen;
return HITLS_SUCCESS;
}
static void RecConnInitCipherParam(HITLS_CipherParameters *cipherParam, const RecConnState *state)
{
cipherParam->ctx = &state->suiteInfo->ctx;
cipherParam->type = state->suiteInfo->cipherType;
cipherParam->algo = state->suiteInfo->cipherAlg;
cipherParam->key = state->suiteInfo->key;
cipherParam->keyLen = state->suiteInfo->encKeyLen;
cipherParam->iv = state->suiteInfo->iv;
cipherParam->ivLen = state->suiteInfo->fixedIvLength;
}
static int32_t RecConnCbcCheckCryptMsg(TLS_Ctx *ctx, const RecConnState *state, const REC_TextInput *cryptMsg,
bool isEncryptThenMac)
{
uint8_t offset = 0;
if (isEncryptThenMac) {
offset = state->suiteInfo->macLen;
}
if ((state->suiteInfo->blockLength == 0) || ((cryptMsg->textLen - offset) % state->suiteInfo->blockLength != 0)) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15397, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"record cbc mode decrypt error: block length = %u, cipher text length = %u.",
state->suiteInfo->blockLength, cryptMsg->textLen, 0, 0);
return RecordSendAlertMsg(ctx, ALERT_LEVEL_FATAL, ALERT_BAD_RECORD_MAC);
}
return HITLS_SUCCESS;
}
static int32_t RecConnCbcDecCheckPaddingEtM(TLS_Ctx *ctx, const REC_TextInput *cryptMsg, uint8_t *plain,
uint32_t plainLen, uint32_t offset)
{
#ifdef HITLS_BSL_LOG
const RecConnState *state = ctx->recCtx->readStates.currentState;
#else
(void)offset;
#endif
uint8_t padLen = plain[plainLen - 1];
if (cryptMsg->isEncryptThenMac && (plainLen < padLen + CBC_PADDING_LEN_TAG_SIZE)) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15399, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"record cbc mode decrypt error: ciphertext len = %u, plaintext len = %u, mac len = %u, padding len = %u.",
cryptMsg->textLen - offset - state->suiteInfo->macLen, plainLen, state->suiteInfo->macLen, padLen);
return RecordSendAlertMsg(ctx, ALERT_LEVEL_FATAL, ALERT_BAD_RECORD_MAC);
}
uint32_t good = Uint32ConstTimeGe(plainLen, padLen + 1);
for (uint32_t i = 1; i <= 255; i++) {
uint32_t mask = good & Uint32ConstTimeLe(i, padLen);
good &= Uint32ConstTimeEqual(plain[plainLen - 1 - (i & mask)], padLen);
}
if (good == 0) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15400, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"record cbc mode decrypt error: padding len = %u, padding check failed.",
padLen, 0, 0, 0);
return RecordSendAlertMsg(ctx, ALERT_LEVEL_FATAL, ALERT_BAD_RECORD_MAC);
}
return HITLS_SUCCESS;
}
static uint32_t GetHmacBLen(HITLS_MacAlgo macAlgo)
{
switch (macAlgo) {
case HITLS_MAC_1:
case HITLS_MAC_224:
case HITLS_MAC_256:
case HITLS_MAC_SM3:
return 64;
case HITLS_MAC_384:
case HITLS_MAC_512:
return 128;
default:
return 0;
}
}
static inline uintptr_t UintPtrConstTimeSelect(uint32_t mask, uintptr_t a, uintptr_t b)
{
uintptr_t wideMask = (uintptr_t)0 - (uintptr_t)((mask >> 31) & 0x1u);
return (wideMask & a) | (~wideMask & b);
}
* a constant-time implemenation of HMAC to prevent side-channel attacks
* reference: https://datatracker.ietf.org/doc/html/rfc2104#autoid-2
*/
static int32_t ConstTimeHmac(RecConnSuitInfo *suiteInfo, HITLS_HASH_Ctx **hashCtx, uint32_t good,
const REC_TextInput *cryptMsg, uint8_t *data, uint32_t dataLen, uint8_t *mac, uint32_t *macLen)
{
HITLS_HASH_Ctx *obCtx = hashCtx[2];
uint32_t padLen = data[dataLen - 1];
padLen = Uint32ConstTimeSelect(good, padLen, 0);
uint32_t plainLen = dataLen - (suiteInfo->macLen + padLen + 1);
plainLen = Uint32ConstTimeSelect(good, plainLen, 0);
uint32_t blen = GetHmacBLen(suiteInfo->macAlg);
uint8_t ipad[HMAC_MAX_BLEN] = {0};
uint8_t opad[HMAC_MAX_BLEN * 2] = {0};
uint8_t key[HMAC_MAX_BLEN] = {0};
uint8_t ihash[MAX_DIGEST_SIZE] = {0};
uint32_t ihashLen = sizeof(ihash);
memcpy(key, suiteInfo->macKey, suiteInfo->macKeyLen);
for (uint32_t i = 0; i < blen; i++) {
ipad[i] = key[i] ^ 0x36;
opad[i] = key[i] ^ 0x5c;
}
(void)SAL_CRYPT_DigestUpdate(hashCtx[0], ipad, blen);
(void)SAL_CRYPT_DigestUpdate(obCtx, ipad, blen);
* constant-time update plaintext to resist lucky13
* ref: https://www.isg.rhul.ac.uk/tls/TLStiming.pdf
*/
uint8_t header[13] = {0};
uint32_t pos = 0;
memcpy(header, cryptMsg->seq, REC_CONN_SEQ_SIZE);
pos += REC_CONN_SEQ_SIZE;
header[pos++] = cryptMsg->type;
BSL_Uint16ToByte(cryptMsg->version, header + pos);
pos += sizeof(uint16_t);
BSL_Uint16ToByte((uint16_t)plainLen, header + pos);
(void)SAL_CRYPT_DigestUpdate(hashCtx[0], header, sizeof(header));
(void)SAL_CRYPT_DigestUpdate(obCtx, header, sizeof(header));
uint32_t maxLen = dataLen - (suiteInfo->macLen + 1);
maxLen = Uint32ConstTimeSelect(good, maxLen, dataLen);
uint32_t flag = Uint32ConstTimeGt(maxLen, 256);
uint32_t minLen = Uint32ConstTimeSelect(flag, maxLen - 256, 0);
(void)SAL_CRYPT_DigestUpdate(hashCtx[0], data, minLen);
(void)SAL_CRYPT_DigestUpdate(obCtx, data, minLen);
for (uint32_t i = minLen; i < maxLen; i++) {
uint32_t usePlainCtx = Uint32ConstTimeLt(i, plainLen);
HITLS_HASH_Ctx *dstCtx =
(HITLS_HASH_Ctx *)(uintptr_t)UintPtrConstTimeSelect(usePlainCtx, (uintptr_t)hashCtx[0], (uintptr_t)obCtx);
(void)SAL_CRYPT_DigestUpdate(dstCtx, data + i, 1);
}
(void)SAL_CRYPT_DigestFinal(hashCtx[0], ihash, &ihashLen);
memcpy(opad + blen, ihash, ihashLen);
(void)SAL_CRYPT_DigestUpdate(hashCtx[1], opad, blen + ihashLen);
(void)SAL_CRYPT_DigestFinal(hashCtx[1], mac, macLen);
BSL_SAL_CleanseData(ipad, sizeof(ipad));
BSL_SAL_CleanseData(opad, sizeof(opad));
BSL_SAL_CleanseData(key, sizeof(key));
return HITLS_SUCCESS;
}
static inline uint32_t ConstTimeSelectMemcmp(uint32_t good, uint8_t *a, uint8_t *b, uint32_t l)
{
uint8_t *t = (uint8_t *)(uintptr_t)UintPtrConstTimeSelect(good, (uintptr_t)a, (uintptr_t)b);
return ConstTimeMemcmp(t, b, l);
}
static int32_t RecConnCbcDecMtECheckMacTls(TLS_Ctx *ctx, const REC_TextInput *cryptMsg,
uint8_t *plain, uint32_t plainLen)
{
uint32_t tempPlainLen = plainLen;
const RecConnState *state = ctx->recCtx->readStates.currentState;
uint32_t hashAlg = RecGetHashAlgoFromMacAlgo(state->suiteInfo->macAlg);
if (hashAlg == HITLS_HASH_BUTT) {
return HITLS_CRYPT_ERR_HMAC;
}
HITLS_HASH_Ctx *ihashCtx = NULL;
HITLS_HASH_Ctx *ohashCtx = NULL;
HITLS_HASH_Ctx *obscureHashCtx = NULL;
ihashCtx = SAL_CRYPT_DigestInit(LIBCTX_FROM_CTX(ctx), ATTRIBUTE_FROM_CTX(ctx), hashAlg);
ohashCtx = SAL_CRYPT_DigestCopy(ihashCtx);
obscureHashCtx = SAL_CRYPT_DigestCopy(ihashCtx);
if (ihashCtx == NULL || ohashCtx == NULL || obscureHashCtx == NULL) {
SAL_CRYPT_DigestFree(ihashCtx);
SAL_CRYPT_DigestFree(ohashCtx);
SAL_CRYPT_DigestFree(obscureHashCtx);
return HITLS_REC_ERR_GENERATE_MAC;
}
uint8_t mac[MAX_DIGEST_SIZE] = {0};
uint32_t macLen = sizeof(mac);
uint8_t padLen = plain[tempPlainLen - 1];
uint32_t good = Uint32ConstTimeGe(tempPlainLen, state->suiteInfo->macLen + padLen + 1);
for (uint32_t i = 1; i <= 255; i++) {
uint32_t mask = good & Uint32ConstTimeLe(i, padLen);
good &= Uint32ConstTimeEqual(plain[tempPlainLen - 1 - (i & mask)], padLen);
}
HITLS_HASH_Ctx *hashCtxs[3] = {ihashCtx, ohashCtx, obscureHashCtx};
ConstTimeHmac(state->suiteInfo, hashCtxs, good, cryptMsg, plain, tempPlainLen, mac, &macLen);
uint32_t retLen = Uint32ConstTimeSelect(good, padLen, 0);
tempPlainLen -= state->suiteInfo->macLen + retLen + 1;
good &= ConstTimeSelectMemcmp(good, &plain[tempPlainLen], mac, macLen);
SAL_CRYPT_DigestFree(ihashCtx);
SAL_CRYPT_DigestFree(ohashCtx);
SAL_CRYPT_DigestFree(obscureHashCtx);
return ~good;
}
static int32_t RecConnCbcDecryptByMacThenEncrypt(TLS_Ctx *ctx, const RecConnState *state, const REC_TextInput *cryptMsg,
uint8_t *data, uint32_t *dataLen)
{
int32_t ret = RecConnCbcCheckCryptMsg(ctx, state, cryptMsg, false);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID17243, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"RecConnCbcCheckCryptMsg fail", 0, 0, 0, 0);
return ret;
}
uint32_t offset = 0;
uint32_t plaintextLen = *dataLen;
HITLS_CipherParameters cipherParam = {0};
RecConnInitCipherParam(&cipherParam, state);
* ciphertext block does not need to be decrypted */
cipherParam.iv = cryptMsg->text;
offset = state->suiteInfo->fixedIvLength;
ret = SAL_CRYPT_Decrypt(LIBCTX_FROM_CTX(ctx), ATTRIBUTE_FROM_CTX(ctx),
&cipherParam, &cryptMsg->text[offset], cryptMsg->textLen - offset, data, &plaintextLen);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15398, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"record cbc mode decrypt error.", 0, 0, 0, 0);
return RecordSendAlertMsg(ctx, ALERT_LEVEL_FATAL, ALERT_BAD_RECORD_MAC);
}
ret = RecConnCbcDecMtECheckMacTls(ctx, cryptMsg, data, plaintextLen);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID17244, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"RecConnCbcDecMtECheckMacTls fail", 0, 0, 0, 0);
return RecordSendAlertMsg(ctx, ALERT_LEVEL_FATAL, ALERT_BAD_RECORD_MAC);
}
*dataLen = plaintextLen - (state->suiteInfo->macLen + data[plaintextLen - 1] + CBC_PADDING_LEN_TAG_SIZE);
return ret;
}
static int32_t RecConnCbcDecryptByEncryptThenMac(TLS_Ctx *ctx, const RecConnState *state, const REC_TextInput *cryptMsg,
uint8_t *data, uint32_t *dataLen)
{
* Encrypt-then-MAC mode: Verify MAC first, then decrypt.
* The MAC is computed over the ciphertext (including explicit IV),
* so timing does not leak plaintext information.
*/
int32_t ret = RecConnCheckMac(ctx, state->suiteInfo, cryptMsg, cryptMsg->text, cryptMsg->textLen);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID17245, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN, "check mac fail", 0, 0, 0, 0);
return ret;
}
ret = RecConnCbcCheckCryptMsg(ctx, state, cryptMsg, true);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID17246, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"RecConnCbcCheckCryptMsg fail", 0, 0, 0, 0);
return ret;
}
uint32_t offset = 0;
uint32_t plaintextLen = *dataLen;
uint8_t macLen = state->suiteInfo->macLen;
HITLS_CipherParameters cipherParam = {0};
RecConnInitCipherParam(&cipherParam, state);
cipherParam.iv = cryptMsg->text;
offset = state->suiteInfo->fixedIvLength;
ret = SAL_CRYPT_Decrypt(LIBCTX_FROM_CTX(ctx), ATTRIBUTE_FROM_CTX(ctx),
&cipherParam, &cryptMsg->text[offset],
cryptMsg->textLen - offset - macLen, data, &plaintextLen);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15915, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"record cbc mode decrypt error.", 0, 0, 0, 0);
return RecordSendAlertMsg(ctx, ALERT_LEVEL_FATAL, ALERT_BAD_RECORD_MAC);
}
uint8_t paddingLen = data[plaintextLen - 1];
ret = RecConnCbcDecCheckPaddingEtM(ctx, cryptMsg, data, plaintextLen, offset);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID17247, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"RecConnCbcDecCheckPaddingEtM fail", 0, 0, 0, 0);
return ret;
}
*dataLen = plaintextLen - paddingLen - CBC_PADDING_LEN_TAG_SIZE;
return HITLS_SUCCESS;
}
static int32_t CbcDecrypt(TLS_Ctx *ctx, RecConnState *state, const REC_TextInput *cryptMsg,
uint8_t *data, uint32_t *dataLen)
{
uint8_t *decryptData = data;
uint32_t decryptDataLen = *dataLen;
int32_t ret;
if (ctx->negotiatedInfo.isEncryptThenMacRead) {
ret = RecConnCbcDecryptByEncryptThenMac(ctx, state, cryptMsg, decryptData, &decryptDataLen);
} else {
ret = RecConnCbcDecryptByMacThenEncrypt(ctx, state, cryptMsg, decryptData, &decryptDataLen);
}
if (ret != HITLS_SUCCESS) {
return ret;
}
*dataLen = decryptDataLen;
return HITLS_SUCCESS;
}
static int32_t RecConnCopyIV(TLS_Ctx *ctx, const RecConnState *state, uint8_t *cipherText, uint32_t cipherTextLen)
{
if (!state->suiteInfo->isExportIV) {
int32_t ret = SAL_CRYPT_Rand(LIBCTX_FROM_CTX(ctx), state->suiteInfo->iv, state->suiteInfo->fixedIvLength);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15847, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"Record CBC encrypt error: generate iv fail.", 0, 0, 0, 0);
return ret;
}
}
state->suiteInfo->isExportIV = 0;
if (state->suiteInfo->fixedIvLength > cipherTextLen) {
BSL_ERR_PUSH_ERROR(HITLS_MEMCPY_FAIL);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15847, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"Record CBC encrypt error: copy iv fail.", 0, 0, 0, 0);
return HITLS_MEMCPY_FAIL;
}
memcpy(cipherText, state->suiteInfo->iv, state->suiteInfo->fixedIvLength);
return HITLS_SUCCESS;
}
static int32_t GenerateCbcPlainTextBeforeMac(const RecConnState *state, const REC_TextInput *plainMsg,
uint32_t cipherTextLen, uint8_t *plainText, uint32_t *textLen)
{
if (plainMsg->textLen > cipherTextLen) {
BSL_ERR_PUSH_ERROR(HITLS_MEMCPY_FAIL);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15392, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"Record CBC encrypt error: memcpy plainMsg fail.", 0, 0, 0, 0);
return HITLS_MEMCPY_FAIL;
}
memcpy(plainText, plainMsg->text, plainMsg->textLen);
uint32_t plainTextLen = plainMsg->textLen;
uint8_t paddingLen = RecConnGetCbcPaddingLen(state->suiteInfo->blockLength, plainTextLen);
uint32_t count = paddingLen + CBC_PADDING_LEN_TAG_SIZE;
if (count > cipherTextLen - plainTextLen) {
BSL_ERR_PUSH_ERROR(HITLS_REC_ERR_ENCRYPT);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15904, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"Record CBC encrypt error: memset padding fail.", 0, 0, 0, 0);
return HITLS_REC_ERR_ENCRYPT;
}
memset(&plainText[plainTextLen], paddingLen, count);
plainTextLen += count;
*textLen = plainTextLen;
return HITLS_SUCCESS;
}
static int32_t PreparePlainText(const RecConnState *state, const REC_TextInput *plainMsg, uint32_t cipherTextLen,
uint8_t **plainText, uint32_t *plainTextLen)
{
*plainText = BSL_SAL_Calloc(1u, cipherTextLen);
if (*plainText == NULL) {
BSL_ERR_PUSH_ERROR(HITLS_MEMALLOC_FAIL);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15927, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"Record CBC encrypt error: out of memory.", 0, 0, 0, 0);
return HITLS_MEMALLOC_FAIL;
}
int32_t ret = GenerateCbcPlainTextBeforeMac(state, plainMsg, cipherTextLen, *plainText, plainTextLen);
if (ret != HITLS_SUCCESS) {
BSL_SAL_FREE(*plainText);
}
return ret;
}
static int32_t GenerateCbcPlainTextAfterMac(HITLS_Lib_Ctx *libCtx, const char *attrName,
const RecConnState *state, const REC_TextInput *plainMsg,
uint32_t cipherTextLen, uint8_t *plainText, uint32_t *textLen)
{
if (plainMsg->textLen > cipherTextLen) {
BSL_ERR_PUSH_ERROR(HITLS_MEMCPY_FAIL);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15898, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"Record CBC encrypt error: memcpy plainMsg fail.", 0, 0, 0, 0);
return HITLS_MEMCPY_FAIL;
}
memcpy(plainText, plainMsg->text, plainMsg->textLen);
uint32_t plainTextLen = plainMsg->textLen;
uint32_t macLen = state->suiteInfo->macLen;
REC_TextInput input = {0};
RecConnInitGenerateMacInput(plainMsg, plainMsg->text, plainMsg->textLen, &input);
int32_t ret = RecConnGenerateMac(libCtx, attrName, state->suiteInfo,
&input, &plainText[plainTextLen], &macLen);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID17248, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"RecConnGenerateMac fail.", 0, 0, 0, 0);
return ret;
}
plainTextLen += macLen;
uint8_t paddingLen = RecConnGetCbcPaddingLen(state->suiteInfo->blockLength, plainTextLen);
uint32_t count = paddingLen + CBC_PADDING_LEN_TAG_SIZE;
if (count > cipherTextLen - plainTextLen) {
BSL_ERR_PUSH_ERROR(HITLS_REC_ERR_ENCRYPT);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15393, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"Record CBC encrypt error: memset padding fail.", 0, 0, 0, 0);
return HITLS_REC_ERR_ENCRYPT;
}
memset(&plainText[plainTextLen], paddingLen, count);
plainTextLen += count;
*textLen = plainTextLen;
return HITLS_SUCCESS;
}
static int32_t RecConnCbcEncryptThenMac(
TLS_Ctx *ctx, const RecConnState *state, const REC_TextInput *plainMsg, uint8_t *cipherText, uint32_t cipherTextLen)
{
uint32_t offset = 0;
uint8_t *plainText = NULL;
uint32_t plainTextLen = 0;
int32_t ret = PreparePlainText(state, plainMsg, cipherTextLen, &plainText, &plainTextLen);
if (ret != HITLS_SUCCESS) {
return ret;
}
ret = RecConnCopyIV(ctx, state, cipherText, cipherTextLen);
if (ret != HITLS_SUCCESS) {
BSL_SAL_ClearFree(plainText, plainTextLen);
return ret;
}
offset += state->suiteInfo->fixedIvLength;
uint32_t macLen = state->suiteInfo->macLen;
uint32_t encLen = cipherTextLen - offset - macLen;
HITLS_CipherParameters cipherParam = {0};
RecConnInitCipherParam(&cipherParam, state);
ret = SAL_CRYPT_Encrypt(LIBCTX_FROM_CTX(ctx), ATTRIBUTE_FROM_CTX(ctx),
&cipherParam, plainText, plainTextLen, &cipherText[offset], &encLen);
BSL_SAL_ClearFree(plainText, plainTextLen);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15848, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"CBC encrypt record error.", 0, 0, 0, 0);
return ret;
}
if (encLen != (cipherTextLen - offset - macLen)) {
BSL_ERR_PUSH_ERROR(HITLS_REC_ERR_ENCRYPT);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15903, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"encrypt record (length) error.", 0, 0, 0, 0);
return HITLS_REC_ERR_ENCRYPT;
}
REC_TextInput input = {0};
RecConnInitGenerateMacInput(plainMsg, cipherText, cipherTextLen - macLen, &input);
return RecConnGenerateMac(LIBCTX_FROM_CTX(ctx), ATTRIBUTE_FROM_CTX(ctx),
state->suiteInfo, &input, &cipherText[offset + encLen], &macLen);
}
int32_t RecConnCbcMacThenEncrypt(
TLS_Ctx *ctx, const RecConnState *state, const REC_TextInput *plainMsg, uint8_t *cipherText, uint32_t cipherTextLen)
{
uint32_t plainTextLen = 0;
uint8_t *plainText = BSL_SAL_Calloc(1u, cipherTextLen);
if (plainText == NULL) {
BSL_ERR_PUSH_ERROR(HITLS_MEMALLOC_FAIL);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15390, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"Record CBC encrypt error: out of memory.", 0, 0, 0, 0);
return HITLS_MEMALLOC_FAIL;
}
int32_t ret = GenerateCbcPlainTextAfterMac(LIBCTX_FROM_CTX(ctx), ATTRIBUTE_FROM_CTX(ctx),
state, plainMsg, cipherTextLen, plainText, &plainTextLen);
if (ret != HITLS_SUCCESS) {
BSL_SAL_FREE(plainText);
return ret;
}
uint32_t offset = 0;
ret = RecConnCopyIV(ctx, state, cipherText, cipherTextLen);
if (ret != HITLS_SUCCESS) {
BSL_SAL_FREE(plainText);
return ret;
}
offset += state->suiteInfo->fixedIvLength;
uint32_t encLen = cipherTextLen - offset;
HITLS_CipherParameters cipherParam = {0};
RecConnInitCipherParam(&cipherParam, state);
ret = SAL_CRYPT_Encrypt(LIBCTX_FROM_CTX(ctx), ATTRIBUTE_FROM_CTX(ctx),
&cipherParam, plainText, plainTextLen, &cipherText[offset], &encLen);
BSL_SAL_FREE(plainText);
if (ret != HITLS_SUCCESS) {
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15391, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"CBC encrypt record error.", 0, 0, 0, 0);
return ret;
}
if (encLen != (cipherTextLen - offset)) {
BSL_ERR_PUSH_ERROR(HITLS_REC_ERR_ENCRYPT);
BSL_LOG_BINLOG_FIXLEN(BINLOG_ID15922, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
"encrypt record (length) error.", 0, 0, 0, 0);
return HITLS_REC_ERR_ENCRYPT;
}
return HITLS_SUCCESS;
}
static int32_t CbcEncrypt(TLS_Ctx *ctx, RecConnState *state, const REC_TextInput *plainMsg, uint8_t *cipherText,
uint32_t cipherTextLen)
{
if (plainMsg->isEncryptThenMac) {
return RecConnCbcEncryptThenMac(ctx, state, plainMsg, cipherText, cipherTextLen);
}
return RecConnCbcMacThenEncrypt(ctx, state, plainMsg, cipherText, cipherTextLen);
}
const RecCryptoFunc *RecGetCbcCryptoFuncs(DecryptPostProcess decryptPostProcess, EncryptPreProcess encryptPreProcess)
{
static RecCryptoFunc cryptoFuncCbc = {
.calCiphertextLen = CbcCalCiphertextLen,
.calPlantextBufLen = CbcCalPlantextBufLen,
.decrypt = CbcDecrypt,
.encryt = CbcEncrypt,
};
cryptoFuncCbc.decryptPostProcess = decryptPostProcess;
cryptoFuncCbc.encryptPreProcess = encryptPreProcess;
return &cryptoFuncCbc;
}
#endif