* 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_CRYPTO_SM4
#include "crypt_sm4_x86_64.h"
#include "crypt_sm4.h"
#include "bsl_err_internal.h"
#include "crypt_utils.h"
#include "crypt_errno.h"
#include <string.h>
#define SM4_KEY_LEN 16
#define XTS_POLYNOMIAL 0xe1
#define LAST_BLOCK_HEAD 240
#define BYTE_MOST_SIG 128
#define BYTE 8
void SM4_XTS_Calculate_Tweak(unsigned char *t, const unsigned int idx)
{
uint32_t j;
uint8_t tweak_in, tweak_out;
tweak_in = 0;
for (j = 0; j < CRYPT_SM4_BLOCKSIZE; j++) {
tweak_out = (t[idx + j] << (BYTE - 1)) & BYTE_MOST_SIG;
t[j] = (t[idx + j] >> 1) + tweak_in;
tweak_in = tweak_out;
}
if (tweak_out) {
t[0] ^= XTS_POLYNOMIAL;
}
}
static void SM4_XTS_Encrypt_Helper(uint32_t left, const uint32_t dataLen, uint8_t* t, uint8_t *x,
const uint8_t* plain, uint8_t* cipher, const uint32_t* dataRk)
{
uint32_t i, j;
uint32_t init;
init = dataLen - left;
if (left >= CRYPT_SM4_BLOCKSIZE) {
left = left % CRYPT_SM4_BLOCKSIZE;
for (i = init; i < (dataLen - left); i += CRYPT_SM4_BLOCKSIZE) {
for (j = 0; j < CRYPT_SM4_BLOCKSIZE; j++) {
t[j + CRYPT_SM4_BLOCKSIZE] = t[j];
}
for (j = 0; j < CRYPT_SM4_BLOCKSIZE; j++) {
x[j] = plain[i + j] ^ t[j];
}
SM4_Encrypt(x, cipher + i, dataRk);
for (j = 0; j < CRYPT_SM4_BLOCKSIZE; j++) {
cipher[i + j] = cipher[i + j] ^ t[j];
}
SM4_XTS_Calculate_Tweak(t, CRYPT_SM4_BLOCKSIZE);
}
}
init = dataLen - left;
if (left != 0) {
for (i = 0; i < left; i++) {
cipher[init + i] = cipher[init - CRYPT_SM4_BLOCKSIZE + i];
x[i] = plain[init + i];
}
for (i = left; i < CRYPT_SM4_BLOCKSIZE; i++) {
x[i] = cipher[init - CRYPT_SM4_BLOCKSIZE + i];
}
for (i = 0; i < CRYPT_SM4_BLOCKSIZE; i++) {
x[i] = x[i] ^ t[i];
}
SM4_Encrypt(x, cipher + init - CRYPT_SM4_BLOCKSIZE, dataRk);
for (i = 0; i < CRYPT_SM4_BLOCKSIZE; i++) {
cipher[init - CRYPT_SM4_BLOCKSIZE + i] = cipher[init - CRYPT_SM4_BLOCKSIZE + i] ^ t[i];
}
}
}
int32_t SM4_XTS_En(uint8_t* cipher, const uint8_t* plain, const uint32_t* dataRk,
const uint8_t* tweak, const uint32_t dataLen)
{
uint32_t left;
uint8_t x[CRYPT_SM4_BLOCKSIZE_16] = {0};
uint8_t t[CRYPT_SM4_BLOCKSIZE_16] = {0};
if (dataLen < CRYPT_SM4_BLOCKSIZE) {
BSL_ERR_PUSH_ERROR(CRYPT_SM4_ERR_MSG_LEN);
return CRYPT_SM4_ERR_MSG_LEN;
}
left = dataLen % CRYPT_SM4_BLOCKSIZE_16;
memcpy(t, tweak, CRYPT_SM4_BLOCKSIZE);
if (dataLen >= CRYPT_SM4_BLOCKSIZE_16) {
SM4_XTS_Encrypt_Blocks(plain, cipher, dataLen, dataRk, t);
}
if (left == 0) {
return CRYPT_SUCCESS;
} else {
if (dataLen >= CRYPT_SM4_BLOCKSIZE_16) {
SM4_XTS_Calculate_Tweak(t, LAST_BLOCK_HEAD);
}
SM4_XTS_Encrypt_Helper(left, dataLen, t, x, plain, cipher, dataRk);
}
return CRYPT_SUCCESS;
}
static void SM4_XTS_Decrypt_Helper(uint32_t left, const uint32_t dataLen, uint8_t* t, uint8_t *x,
uint8_t* plain, const uint8_t* cipher, const uint32_t* dataRk)
{
uint32_t i, j;
uint32_t init;
init = dataLen - left;
if (left >= CRYPT_SM4_BLOCKSIZE) {
left = left % CRYPT_SM4_BLOCKSIZE;
for (i = init; i < (dataLen - left); i += CRYPT_SM4_BLOCKSIZE) {
for (j = 0; j < CRYPT_SM4_BLOCKSIZE; j++) {
t[j + CRYPT_SM4_BLOCKSIZE] = t[j];
}
for (j = 0; j < CRYPT_SM4_BLOCKSIZE; j++) {
x[j] = cipher[i + j] ^ t[j];
}
SM4_Decrypt(x, plain + i, dataRk);
for (j = 0; j < CRYPT_SM4_BLOCKSIZE; j++) {
plain[i + j] = plain[i + j] ^ t[j];
}
SM4_XTS_Calculate_Tweak(t, CRYPT_SM4_BLOCKSIZE);
}
}
init = dataLen - left;
if (left != 0) {
for (j = 0; j < CRYPT_SM4_BLOCKSIZE; j++) {
x[j] = cipher[init - CRYPT_SM4_BLOCKSIZE + j] ^ t[j];
}
SM4_Decrypt(x, plain + init - CRYPT_SM4_BLOCKSIZE, dataRk);
for (j = 0; j < CRYPT_SM4_BLOCKSIZE; j++) {
plain[init - CRYPT_SM4_BLOCKSIZE + j] = plain[init - CRYPT_SM4_BLOCKSIZE + j] ^ t[j];
}
for (i = 0; i < left; i++) {
plain[init + i] = plain[init - CRYPT_SM4_BLOCKSIZE + i];
x[i] = cipher[init + i];
}
for (i = left; i < CRYPT_SM4_BLOCKSIZE; i++) {
x[i] = plain[init - CRYPT_SM4_BLOCKSIZE + i];
}
for (i = 0; i < CRYPT_SM4_BLOCKSIZE; i++) {
x[i] = x[i] ^ t[CRYPT_SM4_BLOCKSIZE + i];
}
SM4_Decrypt(x, plain + init - CRYPT_SM4_BLOCKSIZE, dataRk);
for (i = 0; i < CRYPT_SM4_BLOCKSIZE; i++) {
plain[init - CRYPT_SM4_BLOCKSIZE + i] = plain[init - CRYPT_SM4_BLOCKSIZE + i]
^ t[CRYPT_SM4_BLOCKSIZE + i];
}
}
}
int32_t SM4_XTS_De(uint8_t* plain, const uint8_t* cipher, const uint32_t* dataRk,
const uint8_t* tweak, const uint32_t dataLen)
{
uint32_t j;
uint32_t left;
uint8_t t[CRYPT_SM4_BLOCKSIZE_16] = {0};
uint8_t x[CRYPT_SM4_BLOCKSIZE_16] = {0};
if (dataLen < CRYPT_SM4_BLOCKSIZE) {
BSL_ERR_PUSH_ERROR(CRYPT_SM4_ERR_MSG_LEN);
return CRYPT_SM4_ERR_MSG_LEN;
}
left = dataLen % CRYPT_SM4_BLOCKSIZE_16;
memcpy(t, tweak, CRYPT_SM4_BLOCKSIZE);
if (dataLen >= CRYPT_SM4_BLOCKSIZE_16) {
SM4_XTS_Encrypt_Blocks(cipher, plain, dataLen, dataRk, t);
}
if (left != 0) {
if (dataLen >= CRYPT_SM4_BLOCKSIZE_16) {
SM4_XTS_Calculate_Tweak(t, LAST_BLOCK_HEAD);
for (j = 0; j < CRYPT_SM4_BLOCKSIZE; j++) {
t[j + CRYPT_SM4_BLOCKSIZE] = t[j + LAST_BLOCK_HEAD];
}
}
SM4_XTS_Decrypt_Helper(left, dataLen, t, x, plain, cipher, dataRk);
}
return CRYPT_SUCCESS;
}
int32_t CRYPT_SM4_XTS_SetEncryptKey(CRYPT_SM4_Ctx *ctx, const uint8_t *key, uint32_t len)
{
(void)len;
CRYPT_SM4_Ctx *tmk = (CRYPT_SM4_Ctx *)&ctx[1];
SM4_SetEncKey(key, ctx->rk);
SM4_SetEncKey(key + CRYPT_SM4_BLOCKSIZE, tmk->rk);
return CRYPT_SUCCESS;
}
int32_t CRYPT_SM4_XTS_SetDecryptKey(CRYPT_SM4_Ctx *ctx, const uint8_t *key, uint32_t len)
{
(void)len;
CRYPT_SM4_Ctx *tmk = (CRYPT_SM4_Ctx *)&ctx[1];
SM4_SetDecKey(key, ctx->rk);
SM4_SetEncKey(key + CRYPT_SM4_BLOCKSIZE, tmk->rk);
return CRYPT_SUCCESS;
}
int32_t CRYPT_SM4_XTS_Encrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len, uint8_t *iv)
{
if (ctx == NULL || iv == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
return SM4_XTS_En(out, in, ctx->rk, iv, len);
}
int32_t CRYPT_SM4_XTS_Decrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len, uint8_t *iv)
{
if (ctx == NULL || iv == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
return SM4_XTS_De(out, in, ctx->rk, iv, len);
}
int32_t CRYPT_SM4_SetEncryptKey(CRYPT_SM4_Ctx *ctx, const uint8_t *key, uint32_t len)
{
if (ctx == NULL || key == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
if (len != SM4_KEY_LEN) {
BSL_ERR_PUSH_ERROR(CRYPT_SM4_ERR_KEY_LEN);
return CRYPT_SM4_ERR_KEY_LEN;
}
SM4_SetEncKey(key, ctx->rk);
return CRYPT_SUCCESS;
}
int32_t CRYPT_SM4_SetDecryptKey(CRYPT_SM4_Ctx *ctx, const uint8_t *key, uint32_t len)
{
if (ctx == NULL || key == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
if (len != SM4_KEY_LEN) {
BSL_ERR_PUSH_ERROR(CRYPT_SM4_ERR_KEY_LEN);
return CRYPT_SM4_ERR_KEY_LEN;
}
SM4_SetDecKey(key, ctx->rk);
return CRYPT_SUCCESS;
}
#ifdef HITLS_CRYPTO_ECB
int32_t SM4_ECB_Crypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len)
{
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
if (len < CRYPT_SM4_BLOCKSIZE) {
BSL_ERR_PUSH_ERROR(CRYPT_SM4_ERR_MSG_LEN);
return CRYPT_SM4_ERR_MSG_LEN;
}
SM4_ECB_Encrypt(in, out, len, ctx->rk);
return CRYPT_SUCCESS;
}
int32_t CRYPT_SM4_ECB_Encrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len)
{
return SM4_ECB_Crypt(ctx, in, out, len);
}
int32_t CRYPT_SM4_ECB_Decrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len)
{
return SM4_ECB_Crypt(ctx, in, out, len);
}
#endif
#ifdef HITLS_CRYPTO_CBC
int32_t CRYPT_SM4_CBC_Encrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len, uint8_t *iv)
{
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
if (len < CRYPT_SM4_BLOCKSIZE) {
BSL_ERR_PUSH_ERROR(CRYPT_SM4_ERR_MSG_LEN);
return CRYPT_SM4_ERR_MSG_LEN;
}
SM4_CBC_Encrypt(in, out, len, ctx->rk, iv, 1);
return CRYPT_SUCCESS;
}
int32_t CRYPT_SM4_CBC_Decrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len, uint8_t *iv)
{
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
if (len < CRYPT_SM4_BLOCKSIZE) {
BSL_ERR_PUSH_ERROR(CRYPT_SM4_ERR_MSG_LEN);
return CRYPT_SM4_ERR_MSG_LEN;
}
SM4_CBC_Encrypt(in, out, len, ctx->rk, iv, 0);
return CRYPT_SUCCESS;
}
#endif
#ifdef HITLS_CRYPTO_OFB
int32_t SM4_OFB_Crypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len, uint8_t *iv, uint8_t *offset)
{
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
int tmp = *offset;
SM4_OFB_Encrypt(in, out, len, ctx->rk, iv, &tmp);
*offset = (uint8_t)tmp;
return CRYPT_SUCCESS;
}
int32_t CRYPT_SM4_OFB_Encrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len,
uint8_t *iv, uint8_t *offset)
{
return SM4_OFB_Crypt(ctx, in, out, len, iv, offset);
}
int32_t CRYPT_SM4_OFB_Decrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len,
uint8_t *iv, uint8_t *offset)
{
return SM4_OFB_Crypt(ctx, in, out, len, iv, offset);
}
#endif
#ifdef HITLS_CRYPTO_CFB
int32_t CRYPT_SM4_CFB_Encrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len, uint8_t *iv, uint8_t *offset)
{
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
int tmp = *offset;
SM4_CFB128_Encrypt(in, out, len, ctx->rk, iv, &tmp);
*offset = (uint8_t)tmp;
return CRYPT_SUCCESS;
}
int32_t CRYPT_SM4_CFB_Decrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len, uint8_t *iv, uint8_t *offset)
{
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
int tmp = *offset;
SM4_CFB128_Decrypt(in, out, len, ctx->rk, iv, &tmp);
*offset = (uint8_t)tmp;
return CRYPT_SUCCESS;
}
#endif
#if defined(HITLS_CRYPTO_CTR) || defined(HITLS_CRYPTO_GCM)
int32_t CRYPT_SM4_CTR_Encrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len, uint8_t *iv)
{
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
SM4_CTR_EncryptBlocks(in, out, len, ctx->rk, iv);
return CRYPT_SUCCESS;
}
int32_t CRYPT_SM4_CTR_Decrypt(CRYPT_SM4_Ctx *ctx, const uint8_t *in, uint8_t *out, uint32_t len, uint8_t *iv)
{
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
SM4_CTR_EncryptBlocks(in, out, len, ctx->rk, iv);
return CRYPT_SUCCESS;
}
#endif
#endif