* 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 "app_enc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdbool.h>
#include <termios.h>
#include <unistd.h>
#include <sys/stat.h>
#include "bsl_uio.h"
#include "app_utils.h"
#include "app_errno.h"
#include "app_print.h"
#include "app_list.h"
#include "app_opt.h"
#include "app_provider.h"
#include "app_sm.h"
#include "app_keymgmt.h"
#include "bsl_sal.h"
#include "bsl_ui.h"
#include "bsl_bytes.h"
#include "bsl_errno.h"
#include "crypt_eal_cipher.h"
#include "crypt_eal_rand.h"
#include "crypt_eal_kdf.h"
#include "crypt_algid.h"
#include "crypt_errno.h"
#include "crypt_params_key.h"
#include "bsl_base64.h"
#define HITLS_APP_ENC_MAX_PARAM_NUM 5
#define HITLS_APP_ENC_U32_SIZE ((uint32_t)sizeof(uint32_t))
#define HITLS_APP_ENC_HEADER_U32_FIELDS 4U
#define HITLS_APP_ENC_HEX_CHAR_STEP 2U
#define HITLS_APP_ENC_BLOCK_SIZE 16U
#define HITLS_APP_ENC_SHIFT_24 24U
#define HITLS_APP_ENC_SHIFT_16 16U
#define HITLS_APP_ENC_SHIFT_8 8U
#define HITLS_APP_ENC_U32_IDX_0 0U
#define HITLS_APP_ENC_U32_IDX_1 1U
#define HITLS_APP_ENC_U32_IDX_2 2U
#define HITLS_APP_ENC_U32_IDX_3 3U
#define HITLS_APP_ENC_TAG_DEC 0
#define HITLS_APP_ENC_TAG_ENC 1
#define HITLS_APP_ENC_VERSION 1
typedef enum {
HITLS_APP_OPT_CIPHER_ALG = 2,
HITLS_APP_OPT_IN_FILE,
HITLS_APP_OPT_OUT_FILE,
HITLS_APP_OPT_DEC,
HITLS_APP_OPT_ENC,
HITLS_APP_OPT_HEX,
HITLS_APP_OPT_BASE64,
HITLS_APP_OPT_MD,
HITLS_APP_OPT_PASS,
HITLS_APP_PROV_ENUM,
#ifdef HITLS_APP_SM_MODE
HITLS_SM_OPTIONS_ENUM,
#endif
} HITLS_OptType;
static const HITLS_CmdOption g_encOpts[] = {
{"help", HITLS_APP_OPT_HELP, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "Display this function summary"},
{"cipher", HITLS_APP_OPT_CIPHER_ALG, HITLS_APP_OPT_VALUETYPE_STRING, "Cipher algorthm"},
{"in", HITLS_APP_OPT_IN_FILE, HITLS_APP_OPT_VALUETYPE_IN_FILE, "Input file"},
{"out", HITLS_APP_OPT_OUT_FILE, HITLS_APP_OPT_VALUETYPE_OUT_FILE, "Output file"},
{"dec", HITLS_APP_OPT_DEC, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "Decryption operation"},
{"enc", HITLS_APP_OPT_ENC, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "Encryption operation"},
{"hex", HITLS_APP_OPT_HEX, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "Hex-encoded output/input"},
{"base64", HITLS_APP_OPT_BASE64, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "Base64-encoded output/input"},
{"md", HITLS_APP_OPT_MD, HITLS_APP_OPT_VALUETYPE_STRING, "Specified digest to create a key"},
{"pass", HITLS_APP_OPT_PASS, HITLS_APP_OPT_VALUETYPE_STRING, "Passphrase source, such as stdin ,file etc"},
HITLS_APP_PROV_OPTIONS,
#ifdef HITLS_APP_SM_MODE
HITLS_SM_OPTIONS,
#endif
{NULL, 0, 0, NULL}
};
static const uint32_t CIPHER_IS_BlOCK[] = {
CRYPT_CIPHER_AES128_CBC,
CRYPT_CIPHER_AES192_CBC,
CRYPT_CIPHER_AES256_CBC,
CRYPT_CIPHER_AES128_ECB,
CRYPT_CIPHER_AES192_ECB,
CRYPT_CIPHER_AES256_ECB,
CRYPT_CIPHER_SM4_CBC,
CRYPT_CIPHER_SM4_ECB,
};
static const uint32_t CIPHER_IS_XTS[] = {
CRYPT_CIPHER_AES128_XTS,
CRYPT_CIPHER_AES256_XTS,
CRYPT_CIPHER_SM4_XTS,
};
static const uint32_t CIPHER_IS_AES_WRAP[] = {
CRYPT_CIPHER_AES128_WRAP_NOPAD,
CRYPT_CIPHER_AES128_WRAP_PAD,
CRYPT_CIPHER_AES192_WRAP_NOPAD,
CRYPT_CIPHER_AES192_WRAP_PAD,
CRYPT_CIPHER_AES256_WRAP_NOPAD,
CRYPT_CIPHER_AES256_WRAP_PAD,
};
typedef struct {
char *pass;
uint32_t passLen;
unsigned char *salt;
uint32_t saltLen;
unsigned char *iv;
uint32_t ivLen;
unsigned char *dKey;
uint32_t dKeyLen;
CRYPT_EAL_CipherCtx *ctx;
uint32_t blockSize;
} EncKeyParam;
typedef struct {
BSL_UIO *rUio;
BSL_UIO *wUio;
} EncUio;
typedef struct {
uint32_t version;
char *inFile;
char *outFile;
char *passOptStr;
int32_t cipherId;
int32_t mdId;
int32_t encTag;
int32_t format;
uint32_t iter;
EncKeyParam *keySet;
EncUio *encUio;
AppProvider *provider;
BSL_Base64Ctx *b64EncCtx;
uint8_t *decBuf;
uint32_t decBufLen;
uint8_t *cipherBuf;
uint32_t cipherBufLen;
#ifdef HITLS_APP_SM_MODE
HITLS_APP_SM_Param *smParam;
#endif
} EncCmdOpt;
static void WriteUint32Be(uint8_t *buf, uint32_t value)
{
BSL_Uint32ToByte(value, buf);
}
static uint32_t ReadUint32Be(const uint8_t *buf)
{
return BSL_ByteToUint32(buf);
}
static int32_t AppCopyData(void *dest, uint32_t destLen, const void *src, uint32_t srcLen)
{
uint32_t i;
if (dest == NULL || src == NULL || srcLen > destLen) {
return HITLS_APP_COPY_ARGS_FAILED;
}
for (i = 0; i < srcLen; i++) {
((uint8_t *)dest)[i] = ((const uint8_t *)src)[i];
}
return HITLS_APP_SUCCESS;
}
static int32_t EncWriteBinary(EncCmdOpt *encOpt, uint8_t *buf, uint32_t bufLen)
{
uint32_t writeLen = 0;
if (BSL_UIO_Write(encOpt->encUio->wUio, buf, bufLen, &writeLen) != BSL_SUCCESS || writeLen != bufLen) {
AppPrintError("enc: Failed to write output content.\n");
return HITLS_APP_UIO_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t EncBase64Init(EncCmdOpt *encOpt)
{
if (encOpt->b64EncCtx != NULL) {
return HITLS_APP_SUCCESS;
}
encOpt->b64EncCtx = BSL_BASE64_CtxNew();
if (encOpt->b64EncCtx == NULL) {
return HITLS_APP_MEM_ALLOC_FAIL;
}
(void)BSL_BASE64_SetFlags(encOpt->b64EncCtx, BSL_BASE64_FLAGS_NO_NEWLINE);
if (BSL_BASE64_EncodeInit(encOpt->b64EncCtx) != BSL_SUCCESS) {
return HITLS_APP_ENCODE_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t EncWriteEncoded(EncCmdOpt *encOpt, uint8_t *buf, uint32_t bufLen)
{
if (buf == NULL || bufLen == 0) {
return HITLS_APP_SUCCESS;
}
if (encOpt->format == HITLS_APP_FORMAT_BINARY) {
return EncWriteBinary(encOpt, buf, bufLen);
}
if (encOpt->format == HITLS_APP_FORMAT_HEX) {
return HITLS_APP_OptWriteUio(encOpt->encUio->wUio, (uint8_t *)buf, bufLen, HITLS_APP_FORMAT_HEX);
}
if (encOpt->format == HITLS_APP_FORMAT_BASE64) {
int32_t ret = EncBase64Init(encOpt);
if (ret != HITLS_APP_SUCCESS) {
return ret;
}
uint32_t outBufLen = HITLS_BASE64_ENCODE_LENGTH(bufLen);
char *outBuf = (char *)BSL_SAL_Calloc(outBufLen + 1, 1);
if (outBuf == NULL) {
return HITLS_APP_MEM_ALLOC_FAIL;
}
uint32_t encodeLen = outBufLen;
if (BSL_BASE64_EncodeUpdate(encOpt->b64EncCtx, buf, bufLen, outBuf, &encodeLen) != BSL_SUCCESS) {
BSL_SAL_FREE(outBuf);
return HITLS_APP_ENCODE_FAIL;
}
int32_t writeRet = HITLS_APP_SUCCESS;
if (encodeLen != 0) {
writeRet = EncWriteBinary(encOpt, (uint8_t *)outBuf, encodeLen);
}
BSL_SAL_FREE(outBuf);
return writeRet;
}
return HITLS_APP_INVALID_ARG;
}
static int32_t EncWriteEncodedFinal(EncCmdOpt *encOpt)
{
if (encOpt->format != HITLS_APP_FORMAT_BASE64 || encOpt->b64EncCtx == NULL) {
return HITLS_APP_SUCCESS;
}
uint32_t outBufLen = HITLS_BASE64_ENCODE_LENGTH(0);
char *outBuf = (char *)BSL_SAL_Calloc(outBufLen + 1, 1);
if (outBuf == NULL) {
return HITLS_APP_MEM_ALLOC_FAIL;
}
uint32_t encodeLen = outBufLen;
if (BSL_BASE64_EncodeFinal(encOpt->b64EncCtx, outBuf, &encodeLen) != BSL_SUCCESS) {
BSL_SAL_FREE(outBuf);
return HITLS_APP_ENCODE_FAIL;
}
int32_t writeRet = HITLS_APP_SUCCESS;
if (encodeLen != 0) {
writeRet = EncWriteBinary(encOpt, (uint8_t *)outBuf, encodeLen);
}
BSL_SAL_FREE(outBuf);
return writeRet;
}
static int32_t GetCipherId(const char *name)
{
return HITLS_APP_GetCidByName(name, HITLS_APP_LIST_OPT_CIPHER_ALG);
}
static int32_t GetMacId(const char *name)
{
return HITLS_APP_GetCidByName(name, HITLS_APP_LIST_OPT_MD_TO_MAC_ALG);
}
static bool IsAesWrapCipher(int32_t cipherId)
{
for (uint32_t i = 0; i < sizeof(CIPHER_IS_AES_WRAP) / sizeof(CIPHER_IS_AES_WRAP[0]); ++i) {
if ((uint32_t)cipherId == CIPHER_IS_AES_WRAP[i]) {
return true;
}
}
return false;
}
static int32_t HandleOptItem(EncCmdOpt *encOpt, int32_t encOptType)
{
switch (encOptType) {
case HITLS_APP_OPT_EOF:
return HITLS_APP_SUCCESS;
case HITLS_APP_OPT_ERR:
AppPrintError("enc: Use -help for summary.\n");
return HITLS_APP_OPT_UNKOWN;
case HITLS_APP_OPT_HELP:
HITLS_APP_OptHelpPrint(g_encOpts);
return HITLS_APP_HELP;
case HITLS_APP_OPT_ENC:
encOpt->encTag = HITLS_APP_ENC_TAG_ENC;
return HITLS_APP_SUCCESS;
case HITLS_APP_OPT_DEC:
encOpt->encTag = HITLS_APP_ENC_TAG_DEC;
return HITLS_APP_SUCCESS;
case HITLS_APP_OPT_HEX:
encOpt->format = HITLS_APP_FORMAT_HEX;
return HITLS_APP_SUCCESS;
case HITLS_APP_OPT_BASE64:
encOpt->format = HITLS_APP_FORMAT_BASE64;
return HITLS_APP_SUCCESS;
case HITLS_APP_OPT_IN_FILE:
encOpt->inFile = HITLS_APP_OptGetValueStr();
return HITLS_APP_SUCCESS;
case HITLS_APP_OPT_OUT_FILE:
encOpt->outFile = HITLS_APP_OptGetValueStr();
return HITLS_APP_SUCCESS;
case HITLS_APP_OPT_PASS:
encOpt->passOptStr = HITLS_APP_OptGetValueStr();
return HITLS_APP_SUCCESS;
case HITLS_APP_OPT_MD:
if ((encOpt->mdId = GetMacId(HITLS_APP_OptGetValueStr())) == BSL_CID_UNKNOWN) {
return HITLS_APP_OPT_VALUE_INVALID;
}
return HITLS_APP_SUCCESS;
case HITLS_APP_OPT_CIPHER_ALG:
if ((encOpt->cipherId = GetCipherId(HITLS_APP_OptGetValueStr())) == BSL_CID_UNKNOWN) {
return HITLS_APP_OPT_VALUE_INVALID;
}
return HITLS_APP_SUCCESS;
default:
return HITLS_APP_SUCCESS;
}
}
static int32_t HandleOpt(EncCmdOpt *encOpt)
{
int32_t encOptType;
while ((encOptType = HITLS_APP_OptNext()) != HITLS_APP_OPT_EOF) {
HITLS_APP_PROV_CASES(encOptType, encOpt->provider);
#ifdef HITLS_APP_SM_MODE
HITLS_APP_SM_CASES(encOptType, encOpt->smParam);
#endif
int32_t ret = HandleOptItem(encOpt, encOptType);
if (ret != HITLS_APP_SUCCESS) {
return ret;
}
}
if (HITLS_APP_GetRestOptNum() != 0) {
AppPrintError("enc: Extra arguments given.\n");
AppPrintError("Use -help for summary.\n");
return HITLS_APP_OPT_UNKOWN;
}
return HITLS_APP_SUCCESS;
}
static int32_t CheckSmParam(EncCmdOpt *encOpt)
{
#ifdef HITLS_APP_SM_MODE
if (encOpt->smParam->smTag == 1) {
if (encOpt->smParam->uuid == NULL) {
AppPrintError("enc: The uuid is not specified.\n");
return HITLS_APP_OPT_VALUE_INVALID;
}
if (encOpt->smParam->workPath == NULL) {
AppPrintError("enc: The workpath is not specified.\n");
return HITLS_APP_OPT_VALUE_INVALID;
}
}
#else
(void)encOpt;
#endif
return HITLS_APP_SUCCESS;
}
static int32_t CheckParam(EncCmdOpt *encOpt)
{
int32_t ret = CheckSmParam(encOpt);
if (ret != HITLS_APP_SUCCESS) {
return ret;
}
if (encOpt->cipherId < 0) {
AppPrintError("enc: The cipher algorithm is not specified.\n");
AppPrintError("Use -help for summary.\n");
return HITLS_APP_OPT_VALUE_INVALID;
}
if (IsAesWrapCipher(encOpt->cipherId)) {
AppPrintError("enc: AES-WRAP algorithms are not supported.\n");
return HITLS_APP_OPT_VALUE_INVALID;
}
if (encOpt->encTag != HITLS_APP_ENC_TAG_ENC && encOpt->encTag != HITLS_APP_ENC_TAG_DEC) {
AppPrintError("enc: Need -enc or -dec option.\n");
AppPrintError("Use -help for summary.\n");
return HITLS_APP_OPT_VALUE_INVALID;
}
if (encOpt->iter == 0) {
encOpt->iter = REC_ITERATION_TIMES;
}
if (encOpt->format == HILTS_APP_FORMAT_UNDEF) {
encOpt->format = HITLS_APP_FORMAT_BINARY;
}
if (encOpt->mdId < 0) {
encOpt->mdId = CRYPT_MAC_HMAC_SHA256;
}
if (CRYPT_EAL_CipherGetInfo(encOpt->cipherId, CRYPT_INFO_IV_LEN, &encOpt->keySet->ivLen) != CRYPT_SUCCESS) {
AppPrintError("enc: Failed to get the iv length from cipher ID.\n");
return HITLS_APP_CRYPTO_FAIL;
}
if (encOpt->inFile != NULL && strlen(encOpt->inFile) > REC_MAX_FILENAME_LENGTH) {
AppPrintError("enc: The input file length is invalid.\n");
return HITLS_APP_OPT_VALUE_INVALID;
}
if (encOpt->outFile != NULL && strlen(encOpt->outFile) > REC_MAX_FILENAME_LENGTH) {
AppPrintError("enc: The output file length is invalid.\n");
return HITLS_APP_OPT_VALUE_INVALID;
}
return HITLS_APP_SUCCESS;
}
static int32_t SetOutputFilePermission(const char *outFile)
{
if (outFile == NULL) {
return HITLS_APP_SUCCESS;
}
if (chmod(outFile, S_IRUSR | S_IWUSR) != 0) {
AppPrintError("enc: Failed to set output file permission.\n");
return HITLS_APP_UIO_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t HandleIO(EncCmdOpt *encOpt)
{
encOpt->encUio->rUio = HITLS_APP_UioOpen(encOpt->inFile, 'r', encOpt->inFile != NULL ? 1 : 0);
if (encOpt->encUio->rUio == NULL) {
AppPrintError("enc: Failed to open stdin or input file.\n");
return HITLS_APP_UIO_FAIL;
}
encOpt->encUio->wUio = HITLS_APP_UioOpen(encOpt->outFile, 'w', encOpt->outFile != NULL ? 1 : 0);
if (encOpt->encUio->wUio == NULL) {
BSL_UIO_Free(encOpt->encUio->rUio);
encOpt->encUio->rUio = NULL;
AppPrintError("enc: Failed to create the output pipeline.\n");
return HITLS_APP_UIO_FAIL;
}
if (SetOutputFilePermission(encOpt->outFile) != HITLS_APP_SUCCESS) {
BSL_UIO_Free(encOpt->encUio->rUio);
BSL_UIO_Free(encOpt->encUio->wUio);
encOpt->encUio->rUio = NULL;
encOpt->encUio->wUio = NULL;
return HITLS_APP_UIO_FAIL;
}
return HITLS_APP_SUCCESS;
}
static void FreeEnc(EncCmdOpt *encOpt)
{
if (encOpt->b64EncCtx != NULL) {
BSL_BASE64_CtxFree(encOpt->b64EncCtx);
encOpt->b64EncCtx = NULL;
}
if (encOpt->decBuf != NULL) {
BSL_SAL_FREE(encOpt->decBuf);
encOpt->decBuf = NULL;
}
if (encOpt->keySet->pass != NULL) {
BSL_SAL_ClearFree(encOpt->keySet->pass, encOpt->keySet->passLen);
}
if (encOpt->keySet->dKey != NULL) {
BSL_SAL_ClearFree(encOpt->keySet->dKey, encOpt->keySet->dKeyLen);
}
if (encOpt->keySet->salt != NULL) {
BSL_SAL_ClearFree(encOpt->keySet->salt, encOpt->keySet->saltLen);
}
if (encOpt->keySet->iv != NULL) {
BSL_SAL_ClearFree(encOpt->keySet->iv, encOpt->keySet->ivLen);
}
if (encOpt->keySet->ctx != NULL) {
CRYPT_EAL_CipherFreeCtx(encOpt->keySet->ctx);
}
if (encOpt->encUio->rUio != NULL) {
BSL_UIO_Free(encOpt->encUio->rUio);
}
if (encOpt->encUio->wUio != NULL) {
BSL_UIO_Free(encOpt->encUio->wUio);
}
return;
}
static void ClearEncPass(EncCmdOpt *encOpt)
{
if (encOpt->keySet->pass != NULL) {
BSL_SAL_ClearFree(encOpt->keySet->pass, encOpt->keySet->passLen);
encOpt->keySet->pass = NULL;
encOpt->keySet->passLen = 0;
}
}
static void ClearEncDKey(EncCmdOpt *encOpt)
{
if (encOpt->keySet->dKey != NULL && encOpt->keySet->dKeyLen != 0) {
BSL_SAL_CleanseData(encOpt->keySet->dKey, encOpt->keySet->dKeyLen);
}
}
static int32_t ReadPasswd(EncCmdOpt *encOpt, char **pwd, uint32_t *pwdLen)
{
BSL_UI_ReadPwdParam param = {"password", NULL, true};
if (encOpt->passOptStr == NULL) {
AppPrintError("enc: The password can contain the following characters:\n");
AppPrintError("a~z A~Z 0~9 ! \" # $ %% & ' ( ) * + , - . / : ; < = > ? @ [ \\ ] ^ _ ` { | } ~\n");
AppPrintError("The space is not supported.\n");
if (HITLS_APP_GetPasswd(¶m, pwd, pwdLen) != HITLS_APP_SUCCESS) {
AppPrintError("Failed to read passwd from stdin.\n");
return HITLS_APP_PASSWD_FAIL;
}
return HITLS_APP_SUCCESS;
}
if (HITLS_APP_ParsePasswd(encOpt->passOptStr, pwd) != HITLS_APP_SUCCESS) {
AppPrintError("enc: Failed to read passwd. Enter '-pass file:filePath' or '-pass pass:passwd'.\n");
return HITLS_APP_PASSWD_FAIL;
}
*pwdLen = (uint32_t)strlen(*pwd);
if (*pwdLen < APP_MIN_PASS_LENGTH || *pwdLen > APP_MAX_PASS_LENGTH) {
AppPrintError("enc: Invalid passwd length.\n");
return HITLS_APP_PASSWD_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t ValidatePasswd(const char *pwd, uint32_t pwdLen)
{
if (pwdLen == 0 || pwdLen > APP_MAX_PASS_LENGTH) {
AppPrintError("enc: Invalid passwd length.\n");
return HITLS_APP_PASSWD_FAIL;
}
if (HITLS_APP_CheckPasswd((const uint8_t *)pwd, pwdLen) != HITLS_APP_SUCCESS) {
AppPrintError("enc: Failed to check passwd.\n");
return HITLS_APP_PASSWD_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t CopyPasswd(EncCmdOpt *encOpt, const char *pwd, uint32_t pwdLen)
{
if (AppCopyData(encOpt->keySet->pass, APP_MAX_PASS_LENGTH, pwd, pwdLen) != HITLS_APP_SUCCESS) {
AppPrintError("enc: Invalid passwd length.\n");
return HITLS_APP_PASSWD_FAIL;
}
encOpt->keySet->passLen = pwdLen;
return HITLS_APP_SUCCESS;
}
static int32_t ApplyForSpace(EncCmdOpt *encOpt)
{
if (encOpt == NULL || encOpt->keySet == NULL) {
return HITLS_APP_INVALID_ARG;
}
encOpt->keySet->pass = (char *)BSL_SAL_Calloc(APP_MAX_PASS_LENGTH + 1, 1);
if (encOpt->keySet->pass == NULL) {
return HITLS_APP_MEM_ALLOC_FAIL;
}
encOpt->keySet->salt = (unsigned char *)BSL_SAL_Calloc(REC_SALT_LEN + 1, sizeof(unsigned char));
if (encOpt->keySet->salt == NULL) {
return HITLS_APP_MEM_ALLOC_FAIL;
}
encOpt->keySet->saltLen = REC_SALT_LEN;
encOpt->keySet->iv = (unsigned char *)BSL_SAL_Calloc(REC_MAX_IV_LENGTH + 1, sizeof(unsigned char));
if (encOpt->keySet->iv == NULL) {
return HITLS_APP_MEM_ALLOC_FAIL;
}
encOpt->keySet->dKey = (unsigned char *)BSL_SAL_Calloc(REC_MAX_MAC_KEY_LEN + 1, sizeof(unsigned char));
if (encOpt->keySet->dKey == NULL) {
return HITLS_APP_MEM_ALLOC_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t HandlePasswd(EncCmdOpt *encOpt)
{
#ifdef HITLS_APP_SM_MODE
if (encOpt->smParam->smTag == 1) {
return HITLS_APP_SUCCESS;
}
#endif
int32_t ret = HITLS_APP_PASSWD_FAIL;
char *passBuf = NULL;
uint32_t passLen = 0;
do {
ret = ReadPasswd(encOpt, &passBuf, &passLen);
if (ret != HITLS_APP_SUCCESS) {
break;
}
ret = ValidatePasswd(passBuf, passLen);
if (ret != HITLS_APP_SUCCESS) {
break;
}
ret = CopyPasswd(encOpt, passBuf, passLen);
} while (0);
if (passBuf != NULL) {
if (passLen > 0) {
BSL_SAL_CleanseData(passBuf, passLen);
}
BSL_SAL_Free(passBuf);
}
return ret;
}
static int32_t GenSaltAndIv(EncCmdOpt *encOpt)
{
int32_t ret = CRYPT_EAL_RandbytesEx(APP_GetCurrent_LibCtx(), encOpt->keySet->salt, encOpt->keySet->saltLen);
if (ret != CRYPT_SUCCESS) {
AppPrintError("enc: Failed to generate the salt value, errCode: 0x%x.\n", ret);
return HITLS_APP_CRYPTO_FAIL;
}
if (encOpt->keySet->ivLen > 0) {
ret = CRYPT_EAL_RandbytesEx(APP_GetCurrent_LibCtx(), encOpt->keySet->iv, encOpt->keySet->ivLen);
if (ret != CRYPT_SUCCESS) {
AppPrintError("enc: Failed to generate the iv value, errCode: 0x%x.\n", ret);
return HITLS_APP_CRYPTO_FAIL;
}
}
return HITLS_APP_SUCCESS;
}
static int32_t WriteEncFileHeader(EncCmdOpt *encOpt)
{
uint32_t headerLen = HITLS_APP_ENC_HEADER_U32_FIELDS * HITLS_APP_ENC_U32_SIZE + encOpt->keySet->saltLen +
encOpt->keySet->ivLen;
if (encOpt->keySet->ivLen > 0) {
headerLen += HITLS_APP_ENC_U32_SIZE;
}
uint8_t *header = (uint8_t *)BSL_SAL_Calloc(headerLen, 1);
if (header == NULL) {
return HITLS_APP_MEM_ALLOC_FAIL;
}
uint32_t offset = 0;
WriteUint32Be(header + offset, encOpt->version);
offset += HITLS_APP_ENC_U32_SIZE;
WriteUint32Be(header + offset, (uint32_t)encOpt->cipherId);
offset += HITLS_APP_ENC_U32_SIZE;
WriteUint32Be(header + offset, encOpt->keySet->saltLen);
offset += HITLS_APP_ENC_U32_SIZE;
if (AppCopyData(header + offset, headerLen - offset, encOpt->keySet->salt,
encOpt->keySet->saltLen) != HITLS_APP_SUCCESS) {
BSL_SAL_FREE(header);
return HITLS_APP_COPY_ARGS_FAILED;
}
offset += encOpt->keySet->saltLen;
WriteUint32Be(header + offset, encOpt->iter);
offset += HITLS_APP_ENC_U32_SIZE;
if (encOpt->keySet->ivLen > 0) {
WriteUint32Be(header + offset, encOpt->keySet->ivLen);
offset += HITLS_APP_ENC_U32_SIZE;
if (AppCopyData(header + offset, headerLen - offset, encOpt->keySet->iv,
encOpt->keySet->ivLen) != HITLS_APP_SUCCESS) {
BSL_SAL_FREE(header);
return HITLS_APP_COPY_ARGS_FAILED;
}
offset += encOpt->keySet->ivLen;
}
int32_t ret = EncWriteEncoded(encOpt, header, headerLen);
BSL_SAL_FREE(header);
return ret;
}
static int32_t DecodeHexInput(uint8_t *readBuf, uint64_t readLen, uint8_t **decoded, uint32_t *decodedLen)
{
if ((readLen % HITLS_APP_ENC_HEX_CHAR_STEP) != 0) {
AppPrintError("enc: Invalid hex string length, must be even.\n");
return HITLS_APP_ENCODE_FAIL;
}
uint32_t outLen = (uint32_t)(readLen / HITLS_APP_ENC_HEX_CHAR_STEP);
uint8_t *outBuf = (uint8_t *)BSL_SAL_Calloc(outLen + 1, 1);
if (outBuf == NULL) {
return HITLS_APP_MEM_ALLOC_FAIL;
}
uint32_t tmpLen = outLen;
if (HITLS_APP_HexToBytes((char *)readBuf, outBuf, &tmpLen) != HITLS_APP_SUCCESS) {
BSL_SAL_FREE(outBuf);
AppPrintError("enc: Failed to decode hex input.\n");
return HITLS_APP_ENCODE_FAIL;
}
*decoded = outBuf;
*decodedLen = tmpLen;
return HITLS_APP_SUCCESS;
}
static int32_t DecodeBase64Input(const uint8_t *readBuf, uint64_t readLen, uint8_t **decoded, uint32_t *decodedLen)
{
uint32_t outLen = HITLS_BASE64_DECODE_LENGTH((uint32_t)readLen);
uint8_t *outBuf = (uint8_t *)BSL_SAL_Calloc(outLen + 1, 1);
if (outBuf == NULL) {
return HITLS_APP_MEM_ALLOC_FAIL;
}
uint32_t tmpLen = outLen;
if (BSL_BASE64_Decode((const char *)readBuf, (uint32_t)readLen, outBuf, &tmpLen) != BSL_SUCCESS) {
BSL_SAL_FREE(outBuf);
AppPrintError("enc: Failed to decode base64 input.\n");
return HITLS_APP_ENCODE_FAIL;
}
*decoded = outBuf;
*decodedLen = tmpLen;
return HITLS_APP_SUCCESS;
}
static int32_t DecodeInputForDec(EncCmdOpt *encOpt)
{
uint8_t *readBuf = NULL;
uint64_t readLen = 0;
int32_t ret = HITLS_APP_OptReadUio(encOpt->encUio->rUio, &readBuf, &readLen, UINT64_MAX);
if (ret != HITLS_APP_SUCCESS) {
return ret;
}
if (encOpt->format == HITLS_APP_FORMAT_BINARY) {
encOpt->decBuf = readBuf;
encOpt->decBufLen = (uint32_t)readLen;
return HITLS_APP_SUCCESS;
}
if (encOpt->format == HITLS_APP_FORMAT_HEX) {
uint8_t *decoded = NULL;
uint32_t decodedLen = 0;
ret = DecodeHexInput(readBuf, readLen, &decoded, &decodedLen);
BSL_SAL_FREE(readBuf);
if (ret != HITLS_APP_SUCCESS) {
return ret;
}
encOpt->decBuf = decoded;
encOpt->decBufLen = decodedLen;
return HITLS_APP_SUCCESS;
}
if (encOpt->format == HITLS_APP_FORMAT_BASE64) {
uint8_t *decoded = NULL;
uint32_t decodedLen = 0;
ret = DecodeBase64Input(readBuf, readLen, &decoded, &decodedLen);
BSL_SAL_FREE(readBuf);
if (ret != HITLS_APP_SUCCESS) {
return ret;
}
encOpt->decBuf = decoded;
encOpt->decBufLen = decodedLen;
return HITLS_APP_SUCCESS;
}
BSL_SAL_FREE(readBuf);
return HITLS_APP_INVALID_ARG;
}
static int32_t CheckDecHeaderMinLen(const EncCmdOpt *encOpt)
{
uint32_t minLen = HITLS_APP_ENC_HEADER_U32_FIELDS * HITLS_APP_ENC_U32_SIZE + REC_SALT_LEN;
if (encOpt->keySet->ivLen > 0) {
minLen += HITLS_APP_ENC_U32_SIZE + encOpt->keySet->ivLen;
}
if (encOpt->decBufLen < minLen) {
AppPrintError("enc: Invalid input length.\n");
return HITLS_APP_ENCODE_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t ParseHeaderPrefix(EncCmdOpt *encOpt, uint32_t *offset)
{
uint32_t rVersion = ReadUint32Be(encOpt->decBuf + *offset);
*offset += HITLS_APP_ENC_U32_SIZE;
if (rVersion != encOpt->version) {
AppPrintError("enc: Invalid version %u, the file version is %u.\n", encOpt->version, rVersion);
return HITLS_APP_INFO_CMP_FAIL;
}
int32_t rCipherId = (int32_t)ReadUint32Be(encOpt->decBuf + *offset);
*offset += HITLS_APP_ENC_U32_SIZE;
if (encOpt->cipherId != rCipherId) {
AppPrintError("enc: Cipher ID is %d, cipher ID read from file is %d.\n", encOpt->cipherId, rCipherId);
return HITLS_APP_INFO_CMP_FAIL;
}
encOpt->keySet->saltLen = ReadUint32Be(encOpt->decBuf + *offset);
*offset += HITLS_APP_ENC_U32_SIZE;
if (encOpt->keySet->saltLen != REC_SALT_LEN) {
AppPrintError("enc: Salt length is error, Salt length read from file is %u.\n", encOpt->keySet->saltLen);
return HITLS_APP_INFO_CMP_FAIL;
}
if (*offset + encOpt->keySet->saltLen > encOpt->decBufLen) {
AppPrintError("enc: Invalid salt length.\n");
return HITLS_APP_ENCODE_FAIL;
}
if (AppCopyData(encOpt->keySet->salt, encOpt->keySet->saltLen,
encOpt->decBuf + *offset, encOpt->keySet->saltLen) != HITLS_APP_SUCCESS) {
return HITLS_APP_COPY_ARGS_FAILED;
}
*offset += encOpt->keySet->saltLen;
if (*offset + HITLS_APP_ENC_U32_SIZE > encOpt->decBufLen) {
AppPrintError("enc: Invalid input length.\n");
return HITLS_APP_ENCODE_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t ParseHeaderIterAndIv(EncCmdOpt *encOpt, uint32_t *offset)
{
encOpt->iter = ReadUint32Be(encOpt->decBuf + *offset);
*offset += HITLS_APP_ENC_U32_SIZE;
if (encOpt->keySet->ivLen > 0) {
if (*offset + HITLS_APP_ENC_U32_SIZE > encOpt->decBufLen) {
AppPrintError("enc: Invalid iv length.\n");
return HITLS_APP_ENCODE_FAIL;
}
uint32_t tmpIvLen = ReadUint32Be(encOpt->decBuf + *offset);
*offset += HITLS_APP_ENC_U32_SIZE;
if (tmpIvLen != encOpt->keySet->ivLen) {
AppPrintError("enc: Invalid iv length %u.\n", tmpIvLen);
return HITLS_APP_INFO_CMP_FAIL;
}
if (*offset + encOpt->keySet->ivLen > encOpt->decBufLen) {
AppPrintError("enc: Invalid iv length.\n");
return HITLS_APP_ENCODE_FAIL;
}
if (AppCopyData(encOpt->keySet->iv, encOpt->keySet->ivLen,
encOpt->decBuf + *offset, encOpt->keySet->ivLen) != HITLS_APP_SUCCESS) {
return HITLS_APP_COPY_ARGS_FAILED;
}
*offset += encOpt->keySet->ivLen;
}
if (*offset > encOpt->decBufLen) {
AppPrintError("enc: Invalid input length.\n");
return HITLS_APP_ENCODE_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t HandleDecFileHeader(EncCmdOpt *encOpt)
{
int32_t ret = DecodeInputForDec(encOpt);
if (ret != HITLS_APP_SUCCESS) {
return ret;
}
ret = CheckDecHeaderMinLen(encOpt);
if (ret != HITLS_APP_SUCCESS) {
return ret;
}
uint32_t offset = 0;
ret = ParseHeaderPrefix(encOpt, &offset);
if (ret != HITLS_APP_SUCCESS) {
return ret;
}
ret = ParseHeaderIterAndIv(encOpt, &offset);
if (ret != HITLS_APP_SUCCESS) {
return ret;
}
encOpt->cipherBuf = encOpt->decBuf + offset;
encOpt->cipherBufLen = encOpt->decBufLen - offset;
return HITLS_APP_SUCCESS;
}
#ifdef HITLS_APP_SM_MODE
static int32_t GetKeyFromP12(EncCmdOpt *encOpt)
{
HITLS_APP_KeyInfo keyInfo = {0};
int32_t ret = HITLS_APP_FindKey(encOpt->provider, encOpt->smParam, encOpt->cipherId, &keyInfo);
if (ret != HITLS_APP_SUCCESS) {
AppPrintError("enc: Failed to find key, errCode: 0x%x\n", ret);
return ret;
}
if (encOpt->keySet->dKeyLen != keyInfo.keyLen) {
AppPrintError("enc: Key length is not equal, dKeyLen: %u, keyLen: %u.\n", encOpt->keySet->dKeyLen,
keyInfo.keyLen);
BSL_SAL_CleanseData(keyInfo.key, keyInfo.keyLen);
return HITLS_APP_INVALID_ARG;
}
memcpy(encOpt->keySet->dKey, keyInfo.key, keyInfo.keyLen);
BSL_SAL_CleanseData(keyInfo.key, keyInfo.keyLen);
return HITLS_APP_SUCCESS;
}
#endif
static int32_t GetCipherKey(EncCmdOpt *encOpt)
{
int32_t ret = HITLS_APP_SUCCESS;
if (CRYPT_EAL_CipherGetInfo(encOpt->cipherId, CRYPT_INFO_KEY_LEN, &encOpt->keySet->dKeyLen) != CRYPT_SUCCESS) {
return HITLS_APP_CRYPTO_FAIL;
}
#ifdef HITLS_APP_SM_MODE
if (encOpt->smParam->smTag == 1) {
ret = GetKeyFromP12(encOpt);
ClearEncPass(encOpt);
return ret;
}
#endif
CRYPT_EAL_KdfCtx *ctx = CRYPT_EAL_ProviderKdfNewCtx(APP_GetCurrent_LibCtx(), CRYPT_KDF_PBKDF2,
encOpt->provider->providerAttr);
if (ctx == NULL) {
ClearEncPass(encOpt);
return HITLS_APP_MEM_ALLOC_FAIL;
}
int index = 0;
BSL_Param params[HITLS_APP_ENC_MAX_PARAM_NUM] = {{0}, {0}, {0}, {0}, BSL_PARAM_END};
(void)BSL_PARAM_InitValue(¶ms[index++], CRYPT_PARAM_KDF_MAC_ID, BSL_PARAM_TYPE_UINT32, &encOpt->mdId,
sizeof(encOpt->mdId));
(void)BSL_PARAM_InitValue(¶ms[index++], CRYPT_PARAM_KDF_PASSWORD, BSL_PARAM_TYPE_OCTETS,
encOpt->keySet->pass, encOpt->keySet->passLen);
(void)BSL_PARAM_InitValue(¶ms[index++], CRYPT_PARAM_KDF_SALT, BSL_PARAM_TYPE_OCTETS,
encOpt->keySet->salt, encOpt->keySet->saltLen);
(void)BSL_PARAM_InitValue(¶ms[index++], CRYPT_PARAM_KDF_ITER, BSL_PARAM_TYPE_UINT32,
&encOpt->iter, sizeof(encOpt->iter));
ret = CRYPT_EAL_KdfSetParam(ctx, params);
if (ret != CRYPT_SUCCESS) {
CRYPT_EAL_KdfFreeCtx(ctx);
ClearEncPass(encOpt);
return ret;
}
ret = CRYPT_EAL_KdfDerive(ctx, encOpt->keySet->dKey, encOpt->keySet->dKeyLen);
CRYPT_EAL_KdfFreeCtx(ctx);
ClearEncPass(encOpt);
if (ret != CRYPT_SUCCESS) {
return ret;
}
return BSL_SUCCESS;
}
static bool CipherIdIsValid(uint32_t id, const uint32_t *list, uint32_t num)
{
for (uint32_t i = 0; i < num; i++) {
if (id == list[i]) {
return true;
}
}
return false;
}
static bool IsBlockCipher(CRYPT_CIPHER_AlgId id)
{
if (CipherIdIsValid(id, CIPHER_IS_BlOCK, sizeof(CIPHER_IS_BlOCK) / sizeof(CIPHER_IS_BlOCK[0]))) {
return true;
}
return false;
}
static bool IsXtsCipher(CRYPT_CIPHER_AlgId id)
{
if (CipherIdIsValid(id, CIPHER_IS_XTS, sizeof(CIPHER_IS_XTS) / sizeof(CIPHER_IS_XTS[0]))) {
return true;
}
return false;
}
static int32_t XTSCipherUpdate(EncCmdOpt *encOpt, uint8_t *buf, uint32_t bufLen, uint8_t *res, uint32_t resLen)
{
uint32_t updateLen = bufLen;
if (CRYPT_EAL_CipherUpdate(encOpt->keySet->ctx, buf, bufLen, res, &updateLen) != CRYPT_SUCCESS) {
AppPrintError("enc: Failed to update the cipher.\n");
return HITLS_APP_CRYPTO_FAIL;
}
if (updateLen > resLen) {
return HITLS_APP_CRYPTO_FAIL;
}
if (updateLen != 0 && (EncWriteEncoded(encOpt, res, updateLen) != HITLS_APP_SUCCESS)) {
return HITLS_APP_UIO_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t StreamCipherUpdate(EncCmdOpt *encOpt, uint8_t *readBuf, uint32_t readLen, uint8_t *resBuf,
uint32_t resLen)
{
uint32_t updateLen = 0;
uint32_t hBuffLen = readLen + encOpt->keySet->blockSize;
uint32_t blockNum = readLen / encOpt->keySet->blockSize;
uint32_t remainLen = readLen % encOpt->keySet->blockSize;
for (uint32_t i = 0; i < blockNum; ++i) {
hBuffLen = readLen + encOpt->keySet->blockSize - i * encOpt->keySet->blockSize;
if (CRYPT_EAL_CipherUpdate(encOpt->keySet->ctx, readBuf + (i * encOpt->keySet->blockSize),
encOpt->keySet->blockSize, resBuf + (i * encOpt->keySet->blockSize), &hBuffLen) != CRYPT_SUCCESS) {
AppPrintError("enc: Failed to update the cipher.\n");
return HITLS_APP_CRYPTO_FAIL;
}
updateLen += hBuffLen;
}
if (remainLen > 0) {
hBuffLen = readLen + encOpt->keySet->blockSize - updateLen;
if (CRYPT_EAL_CipherUpdate(encOpt->keySet->ctx, readBuf + updateLen, remainLen,
resBuf + updateLen, &hBuffLen) != CRYPT_SUCCESS) {
AppPrintError("enc: Failed to update the cipher.\n");
return HITLS_APP_CRYPTO_FAIL;
}
updateLen += hBuffLen;
}
if (updateLen > resLen) {
return HITLS_APP_CRYPTO_FAIL;
}
if (updateLen != 0 && (EncWriteEncoded(encOpt, resBuf, updateLen) != HITLS_APP_SUCCESS)) {
return HITLS_APP_UIO_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t UpdateEncStdinEnd(EncCmdOpt *encOpt, uint8_t *cache, uint32_t cacheLen, uint8_t *resBuf, uint32_t resLen)
{
if (IsXtsCipher(encOpt->cipherId)) {
if (cacheLen < XTS_MIN_DATALEN) {
AppPrintError("enc: The XTS algorithm does not support data less than 16 bytes.\n");
return HITLS_APP_CRYPTO_FAIL;
}
return XTSCipherUpdate(encOpt, cache, cacheLen, resBuf, resLen);
} else {
return StreamCipherUpdate(encOpt, cache, cacheLen, resBuf, resLen);
}
}
static int32_t UpdateEncStdin(EncCmdOpt *encOpt)
{
int32_t ret = HITLS_APP_SUCCESS;
uint32_t readLen;
uint32_t cacheLen = 0;
uint8_t *cacheArea = (uint8_t *)BSL_SAL_Malloc(MAX_BUFSIZE + BUF_READABLE_BLOCK);
uint8_t *readBuf = (uint8_t *)BSL_SAL_Calloc(MAX_BUFSIZE, 1);
uint8_t *resBuf = (uint8_t *)BSL_SAL_Malloc(MAX_BUFSIZE + BUF_READABLE_BLOCK);
if (cacheArea == NULL || readBuf == NULL || resBuf == NULL) {
BSL_SAL_FREE(cacheArea);
BSL_SAL_FREE(readBuf);
BSL_SAL_FREE(resBuf);
AppPrintError("enc: Failed to alloc memory.\n");
return HITLS_APP_MEM_ALLOC_FAIL;
}
bool isEof = false;
while (BSL_UIO_Ctrl(encOpt->encUio->rUio, BSL_UIO_FILE_GET_EOF, IS_SUPPORT_GET_EOF, &isEof) == BSL_SUCCESS) {
readLen = MAX_BUFSIZE;
if (isEof) {
ret = UpdateEncStdinEnd(encOpt, cacheArea, cacheLen, resBuf, MAX_BUFSIZE + BUF_READABLE_BLOCK);
break;
}
if (BSL_UIO_Read(encOpt->encUio->rUio, readBuf, MAX_BUFSIZE, &readLen) != BSL_SUCCESS) {
AppPrintError("enc: Failed to obtain the content from the STDIN\n");
ret = HITLS_APP_UIO_FAIL;
break;
}
if (readLen == 0) {
AppPrintError("enc: Failed to read the input content\n");
ret = HITLS_APP_STDIN_FAIL;
break;
}
if (cacheLen > MAX_BUFSIZE + BUF_READABLE_BLOCK || readLen > UINT32_MAX - cacheLen ||
readLen > MAX_BUFSIZE + BUF_READABLE_BLOCK - cacheLen) {
AppPrintError("enc: Buffer overflow detected\n");
return HITLS_APP_COPY_ARGS_FAILED;
}
memcpy(cacheArea + cacheLen, readBuf, readLen);
cacheLen += readLen;
if (cacheLen < BUF_READABLE_BLOCK) {
continue;
}
uint32_t readableLen = cacheLen - BUF_SAFE_BLOCK;
if (IsXtsCipher(encOpt->cipherId)) {
ret = XTSCipherUpdate(encOpt, cacheArea, readableLen, resBuf, MAX_BUFSIZE + BUF_READABLE_BLOCK);
} else {
ret = StreamCipherUpdate(encOpt, cacheArea, readableLen, resBuf, MAX_BUFSIZE + BUF_READABLE_BLOCK);
}
if (ret != HITLS_APP_SUCCESS) {
break;
}
if (readableLen + BUF_SAFE_BLOCK > MAX_BUFSIZE + BUF_READABLE_BLOCK) {
ret = HITLS_APP_COPY_ARGS_FAILED;
break;
}
memcpy(cacheArea, cacheArea + readableLen, BUF_SAFE_BLOCK);
cacheLen = BUF_SAFE_BLOCK;
}
BSL_SAL_FREE(cacheArea);
BSL_SAL_FREE(readBuf);
BSL_SAL_FREE(resBuf);
return ret;
}
static int32_t UpdateEncFile(EncCmdOpt *encOpt, uint64_t readFileLen)
{
if (readFileLen < XTS_MIN_DATALEN && IsXtsCipher(encOpt->cipherId)) {
AppPrintError("enc: The XTS algorithm does not support data less than 16 bytes.\n");
return HITLS_APP_CRYPTO_FAIL;
}
int32_t ret = HITLS_APP_SUCCESS;
uint8_t *readBuf = (uint8_t *)BSL_SAL_Calloc(MAX_BUFSIZE * REC_DOUBLE, 1);
uint8_t *resBuf = (uint8_t *)BSL_SAL_Malloc(MAX_BUFSIZE * REC_DOUBLE);
if (readBuf == NULL || resBuf == NULL) {
BSL_SAL_FREE(readBuf);
BSL_SAL_FREE(resBuf);
AppPrintError("enc: Failed to alloc memory.\n");
return HITLS_APP_MEM_ALLOC_FAIL;
}
uint32_t readLen = MAX_BUFSIZE * REC_DOUBLE;
uint32_t bufLen = MAX_BUFSIZE * REC_DOUBLE;
while (readFileLen > 0) {
if (readFileLen < MAX_BUFSIZE * REC_DOUBLE) {
bufLen = readFileLen;
readLen = readFileLen;
}
if (readFileLen >= MAX_BUFSIZE * REC_DOUBLE) {
bufLen = MAX_BUFSIZE;
readLen = MAX_BUFSIZE;
}
if (!IsXtsCipher(encOpt->cipherId)) {
bufLen = (readFileLen > MAX_BUFSIZE) ? MAX_BUFSIZE : readFileLen;
readLen = bufLen;
}
if (BSL_UIO_Read(encOpt->encUio->rUio, readBuf, bufLen, &readLen) != BSL_SUCCESS || bufLen != readLen) {
AppPrintError("enc: Failed to read the input content\n");
ret = HITLS_APP_UIO_FAIL;
break;
}
readFileLen -= readLen;
if (IsXtsCipher(encOpt->cipherId)) {
ret = XTSCipherUpdate(encOpt, readBuf, readLen, resBuf, MAX_BUFSIZE * REC_DOUBLE);
} else {
ret = StreamCipherUpdate(encOpt, readBuf, readLen, resBuf, MAX_BUFSIZE * REC_DOUBLE);
}
if (ret != HITLS_APP_SUCCESS) {
break;
}
}
BSL_SAL_FREE(readBuf);
BSL_SAL_FREE(resBuf);
return ret;
}
static int32_t DoCipherUpdateEnc(EncCmdOpt *encOpt, uint64_t readFileLen)
{
int32_t updateRet = HITLS_APP_SUCCESS;
if (readFileLen > 0) {
updateRet = UpdateEncFile(encOpt, readFileLen);
} else {
updateRet = UpdateEncStdin(encOpt);
}
if (updateRet != HITLS_APP_SUCCESS) {
return updateRet;
}
return HITLS_APP_SUCCESS;
}
static int32_t DoCipherUpdateDec(EncCmdOpt *encOpt, uint64_t readFileLen)
{
if (encOpt->cipherBufLen == 0) {
AppPrintError("enc: Failed to read the input content\n");
return HITLS_APP_UIO_FAIL;
}
if (encOpt->cipherBufLen < XTS_MIN_DATALEN && IsXtsCipher(encOpt->cipherId)) {
AppPrintError("enc: The XTS algorithm does not support ciphertext less than 16 bytes.\n");
return HITLS_APP_CRYPTO_FAIL;
}
uint32_t outLen = encOpt->cipherBufLen + encOpt->keySet->blockSize;
uint8_t *resBuf = (uint8_t *)BSL_SAL_Malloc(outLen);
if (resBuf == NULL) {
AppPrintError("enc: Failed to alloc memory.\n");
return HITLS_APP_MEM_ALLOC_FAIL;
}
uint32_t updateLen = outLen;
if (CRYPT_EAL_CipherUpdate(encOpt->keySet->ctx, encOpt->cipherBuf, encOpt->cipherBufLen, resBuf, &updateLen)
!= CRYPT_SUCCESS) {
BSL_SAL_FREE(resBuf);
AppPrintError("enc: Failed to update the cipher.\n");
return HITLS_APP_CRYPTO_FAIL;
}
uint32_t writeLen = 0;
if (updateLen != 0 &&
(BSL_UIO_Write(encOpt->encUio->wUio, resBuf, updateLen, &writeLen) != BSL_SUCCESS || writeLen != updateLen)) {
BSL_SAL_FREE(resBuf);
AppPrintError("enc: Failed to write the cipher text.\n");
return HITLS_APP_UIO_FAIL;
}
BSL_SAL_FREE(resBuf);
(void)readFileLen;
return HITLS_APP_SUCCESS;
}
static int32_t DoCipherUpdate(EncCmdOpt *encOpt)
{
encOpt->keySet->blockSize = HITLS_APP_ENC_BLOCK_SIZE;
uint64_t readFileLen = 0;
if (encOpt->inFile != NULL &&
BSL_UIO_Ctrl(encOpt->encUio->rUio, BSL_UIO_PENDING, sizeof(readFileLen), &readFileLen) != BSL_SUCCESS) {
AppPrintError("enc: Failed to obtain the content length\n");
return HITLS_APP_UIO_FAIL;
}
if (encOpt->inFile == NULL) {
AppPrintError("enc: Need -in option. Please directly enter the file content on the terminal.\n");
}
int32_t updateRet = (encOpt->encTag == HITLS_APP_ENC_TAG_DEC) ? DoCipherUpdateDec(encOpt, readFileLen)
: DoCipherUpdateEnc(encOpt, readFileLen);
if (updateRet != HITLS_APP_SUCCESS) {
return updateRet;
}
uint32_t isAeadId = 0;
if (CRYPT_EAL_CipherGetInfo(encOpt->cipherId, CRYPT_INFO_IS_AEAD, &isAeadId) != CRYPT_SUCCESS) {
return HITLS_APP_CRYPTO_FAIL;
}
if (isAeadId == 1) {
return HITLS_APP_SUCCESS;
}
uint32_t finLen = HITLS_APP_ENC_BLOCK_SIZE;
uint8_t resBuf[MAX_BUFSIZE] = {0};
if (CRYPT_EAL_CipherFinal(encOpt->keySet->ctx, resBuf, &finLen) != CRYPT_SUCCESS) {
AppPrintError("enc: Failed to final the cipher.\n");
return HITLS_APP_CRYPTO_FAIL;
}
if (encOpt->encTag == HITLS_APP_ENC_TAG_ENC) {
if (finLen != 0 && (EncWriteEncoded(encOpt, resBuf, finLen) != HITLS_APP_SUCCESS)) {
return HITLS_APP_UIO_FAIL;
}
if (EncWriteEncodedFinal(encOpt) != HITLS_APP_SUCCESS) {
return HITLS_APP_UIO_FAIL;
}
} else {
uint32_t writeLen = 0;
if (finLen != 0 && (BSL_UIO_Write(encOpt->encUio->wUio, resBuf, finLen, &writeLen) != BSL_SUCCESS ||
writeLen != finLen)) {
return HITLS_APP_UIO_FAIL;
}
}
return HITLS_APP_SUCCESS;
}
static int32_t EncOrDecProc(EncCmdOpt *encOpt)
{
if (GetCipherKey(encOpt) != BSL_SUCCESS) {
return HITLS_APP_CRYPTO_FAIL;
}
encOpt->keySet->ctx = CRYPT_EAL_ProviderCipherNewCtx(APP_GetCurrent_LibCtx(), encOpt->cipherId,
encOpt->provider->providerAttr);
if (encOpt->keySet->ctx == NULL) {
ClearEncDKey(encOpt);
return HITLS_APP_CRYPTO_FAIL;
}
if (CRYPT_EAL_CipherInit(encOpt->keySet->ctx, encOpt->keySet->dKey, encOpt->keySet->dKeyLen, encOpt->keySet->iv,
encOpt->keySet->ivLen, encOpt->encTag) != CRYPT_SUCCESS) {
AppPrintError("enc: Failed to init the cipher.\n");
BSL_SAL_CleanseData(encOpt->keySet->dKey, encOpt->keySet->dKeyLen);
return HITLS_APP_CRYPTO_FAIL;
}
BSL_SAL_CleanseData(encOpt->keySet->dKey, encOpt->keySet->dKeyLen);
if (IsBlockCipher(encOpt->cipherId)) {
if (CRYPT_EAL_CipherSetPadding(encOpt->keySet->ctx, CRYPT_PADDING_PKCS7) != CRYPT_SUCCESS) {
return HITLS_APP_CRYPTO_FAIL;
}
}
#ifdef HITLS_APP_SM_MODE
if (encOpt->smParam->smTag == 1) {
encOpt->smParam->status = HITLS_APP_SM_STATUS_APPORVED;
}
#endif
int32_t ret = HITLS_APP_SUCCESS;
if (encOpt->encTag == HITLS_APP_ENC_TAG_ENC) {
if ((ret = WriteEncFileHeader(encOpt)) != HITLS_APP_SUCCESS) {
return ret;
}
}
if ((ret = DoCipherUpdate(encOpt)) != HITLS_APP_SUCCESS) {
return ret;
}
return HITLS_APP_SUCCESS;
}
static int32_t HandleEnc(EncCmdOpt *encOpt)
{
int32_t ret = HITLS_APP_SUCCESS;
if ((ret = HandleIO(encOpt)) != HITLS_APP_SUCCESS) {
return ret;
}
if ((ret = ApplyForSpace(encOpt)) != HITLS_APP_SUCCESS) {
return ret;
}
if ((ret = HandlePasswd(encOpt)) != HITLS_APP_SUCCESS) {
return ret;
}
if (encOpt->encTag == HITLS_APP_ENC_TAG_ENC && (ret = GenSaltAndIv(encOpt)) != HITLS_APP_SUCCESS) {
return ret;
}
if (encOpt->encTag == HITLS_APP_ENC_TAG_DEC && encOpt->inFile == NULL) {
AppPrintError("enc: In decryption mode, the standard input cannot be used to obtain the ciphertext.\n");
return HITLS_APP_STDIN_FAIL;
}
if (encOpt->encTag == HITLS_APP_ENC_TAG_DEC && (ret = HandleDecFileHeader(encOpt)) != HITLS_APP_SUCCESS) {
return ret;
}
if ((ret = EncOrDecProc(encOpt)) != HITLS_APP_SUCCESS) {
return ret;
}
return HITLS_APP_SUCCESS;
}
int32_t HITLS_EncMain(int argc, char *argv[])
{
int32_t encRet = -1;
EncKeyParam keySet = {NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0};
EncUio encUio = {NULL, NULL};
AppProvider appProvider = {NULL, NULL, NULL};
#ifdef HITLS_APP_SM_MODE
HITLS_APP_SM_Param smParam = {NULL, 0, NULL, NULL, 0, HITLS_APP_SM_STATUS_OPEN};
AppInitParam initParam = {CRYPT_RAND_SHA256, &appProvider, &smParam};
#else
AppInitParam initParam = {CRYPT_RAND_SHA256, &appProvider};
#endif
EncCmdOpt encOpt = {0};
encOpt.version = HITLS_APP_ENC_VERSION;
encOpt.cipherId = -1;
encOpt.mdId = -1;
encOpt.encTag = -1;
encOpt.format = HILTS_APP_FORMAT_UNDEF;
encOpt.keySet = &keySet;
encOpt.encUio = &encUio;
encOpt.provider = &appProvider;
#ifdef HITLS_APP_SM_MODE
encOpt.smParam = &smParam;
#endif
if ((encRet = HITLS_APP_OptBegin(argc, argv, g_encOpts)) != HITLS_APP_SUCCESS) {
AppPrintError("enc: Error in opt begin.\n");
goto End;
}
if ((encRet = HandleOpt(&encOpt)) != HITLS_APP_SUCCESS) {
goto End;
}
if ((encRet = CheckParam(&encOpt)) != HITLS_APP_SUCCESS) {
goto End;
}
encRet = HITLS_APP_Init(&initParam);
if (encRet != HITLS_APP_SUCCESS) {
goto End;
}
if ((encRet = HandleEnc(&encOpt)) != HITLS_APP_SUCCESS) {
goto End;
}
encRet = HITLS_APP_SUCCESS;
End:
HITLS_APP_Deinit(&initParam, encRet);
FreeEnc(&encOpt);
return encRet;
}