Skip to content

Commit

Permalink
Add more sm4 modes
Browse files Browse the repository at this point in the history
Not tested yet
  • Loading branch information
guanzhi committed Feb 10, 2024
1 parent b58ea74 commit 8ae03e8
Show file tree
Hide file tree
Showing 6 changed files with 533 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,10 @@ if (ENABLE_SM4_AESNI_AVX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
endif()

option(ENABLE_SM4_MORE_MODES "Enable SM4 ECB/CFB/OFB/CCM modes" OFF)
if (ENABLE_SM4_MORE_MODES)
list(APPEND src src/sm4_ecb.c src/sm4_cfb.c src/sm4_ofb.c src/sm4_ccm.c)
endif()

option(ENABLE_SM2_EXTS "Enable SM2 Extensions" OFF)
if (ENABLE_SM2_EXTS)
Expand Down
122 changes: 122 additions & 0 deletions src/sm4_ccm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2014-2024 The GmSSL Project. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*/


#include <gmssl/sm4.h>
#include <gmssl/mem.h>
#include <gmssl/sm4_cbc_mac.h>
#include <gmssl/error.h>


#define SM4_CCM_MIN_IV_SIZE 7
#define SM4_CCM_MAX_IV_SIZE 13
#define SM4_CCM_MIN_MAC_SIZE 4
#define SM4_CCM_MAX_MAC_SIZE 16


static void length_to_bytes(size_t len, size_t nbytes, uint8_t *out)
{
uint8_t *p = out + nbytes;
while (nbytes--) {
*p-- = len & 0xff;
len >>= 8;
}
}

int sm4_ccm_encrypt(SM4_KEY *sm4_key, const uint8_t *iv, size_t ivlen,
const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen,
uint8_t *out, size_t taglen, uint8_t *tag)
{
SM4_CBC_MAC_CTX cbc_mac_ctx;
size_t inlen_size;
uint8_t block[16] = {0};
uint8_t ctr[16] = {0};
uint8_t S0[16];
uint8_t cbc_mac[16];
const uint8_t zeros[16] = {0};
size_t padding_len;

if (ivlen < 7 || ivlen > 13) {
error_print();
return -1;
}
if (!aad && aadlen) {
error_print();
return -1;
}
if (taglen < 4 || taglen > 16 || taglen & 1) {
error_print();
return -1;
}

inlen_size = 15 - ivlen;
if (inlen >= (1 << (inlen_size * 8))) {
error_print();
return -1;
}

// sm4_cbc_mac_init
memset(&cbc_mac_ctx, 0, sizeof(cbc_mac_ctx));
cbc_mac_ctx.key = *sm4_key;

// first block
block[0] |= ((aadlen > 0) & 0x1) << 6;
block[0] |= (((taglen - 2)/2) & 0x7) << 3;
block[0] |= (inlen_size - 1) & 0x7;
memcpy(block + 1, iv, ivlen);
length_to_bytes(inlen, inlen_size, block + 1 + ivlen);
sm4_cbc_mac_update(&cbc_mac_ctx, block, 16);

if (aad && aadlen) {
size_t alen;

if (aadlen < ((1<<16) - (1<<8))) {
length_to_bytes(aadlen, 2, block);
alen = 2;
} else if (aadlen < ((size_t)1<<32)) {
block[0] = 0xff;
block[1] = 0xfe;
length_to_bytes(aadlen, 4, block + 2);
alen = 6;
} else {
block[0] = 0xff;
block[1] = 0xff;
length_to_bytes(aadlen, 8, block + 2);
}
sm4_cbc_mac_update(&cbc_mac_ctx, block, alen);

sm4_cbc_mac_update(&cbc_mac_ctx, aad, aadlen);

if (alen + aadlen % 16) {
sm4_cbc_mac_update(&cbc_mac_ctx, zeros, 16 - (alen + aadlen)%16);
}
}

sm4_cbc_mac_update(&cbc_mac_ctx, in, inlen);

if (inlen % 16) {
sm4_cbc_mac_update(&cbc_mac_ctx, zeros, 16 - inlen%16);
}
sm4_cbc_mac_finish(&cbc_mac_ctx, cbc_mac);

ctr[0] = 0;
ctr[0] |= (inlen_size - 1) & 0x7;
memcpy(ctr + 1, iv, ivlen);
memset(ctr + 1 + ivlen, 0, 15 - ivlen);

sm4_encrypt(sm4_key, ctr, S0);
gmssl_memxor(out, cbc_mac, S0, taglen);

ctr[15] = 1;
sm4_ctr_encrypt(sm4_key, ctr, in, inlen, out);

gmssl_secure_clear(&cbc_mac_ctx, sizeof(cbc_mac_ctx));
return 1;
}

209 changes: 209 additions & 0 deletions src/sm4_cfb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
* Copyright 2014-2024 The GmSSL Project. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*/


#include <gmssl/sm4.h>
#include <gmssl/mem.h>
#include <gmssl/error.h>


void sm4_cfb_encrypt(const SM4_KEY *key, size_t sbytes, uint8_t iv[16],
const uint8_t *in, size_t inlen, uint8_t *out)
{
uint8_t block[16];
size_t len, i;

// assert(1 <= sbytes && sbytes <= 16);

while (inlen) {
len = inlen < sbytes ? inlen : sbytes;
sm4_encrypt(key, iv, block);
gmssl_memxor(out, in, block, len);

// iv = (iv << sbytes) | out
for (i = 0; i < 16 - sbytes; i++) {
iv[i] = iv[sbytes + i];
}
memcpy(iv + i, out, len);

in += len;
out += len;
inlen -= len;
}
}

void sm4_cfb_decrypt(const SM4_KEY *key, size_t sbytes, uint8_t iv[16],
const uint8_t *in, size_t inlen, uint8_t *out)
{
uint8_t block[16];
size_t len, i;

// assert(1 <= sbytes && sbytes <= 16);

while (inlen) {
len = inlen < sbytes ? inlen : sbytes;
sm4_encrypt(key, iv, block);
gmssl_memxor(out, in, block, len);

// iv = (iv << sbytes) | in
for (i = 0; i < 16 - sbytes; i++) {
iv[i] = iv[sbytes + i];
}
memcpy(iv + i, in, len);

in += len;
out += len;
inlen -= len;
}
}

typedef struct {
SM4_KEY sm4_key;
uint8_t iv[SM4_BLOCK_SIZE];
uint8_t block[SM4_BLOCK_SIZE];
size_t block_nbytes;
size_t sbytes;
} SM4_CFB_CTX;

int sm4_cfb_encrypt_init(SM4_CFB_CTX *ctx, size_t sbytes,
const uint8_t key[SM4_BLOCK_SIZE], const uint8_t iv[SM4_BLOCK_SIZE])
{
if (sbytes < 1 || sbytes > 16) {
error_print();
return -1;
}
sm4_set_encrypt_key(&ctx->sm4_key, key);
memcpy(ctx->iv, iv, SM4_BLOCK_SIZE);
memset(ctx->block, 0, SM4_BLOCK_SIZE);
ctx->block_nbytes = 0;
ctx->sbytes = sbytes;
return 1;
}

int sm4_cfb_encrypt_update(SM4_CFB_CTX *ctx,
const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
{
size_t left;
size_t nblocks;
size_t len;

if (ctx->block_nbytes >= ctx->sbytes) {
error_print();
return -1;
}
*outlen = 0;
if (ctx->block_nbytes) {
left = ctx->sbytes - ctx->block_nbytes;
if (inlen < left) {
memcpy(ctx->block + ctx->block_nbytes, in, inlen);
ctx->block_nbytes += inlen;
return 1;
}
memcpy(ctx->block + ctx->block_nbytes, in, left);
sm4_cfb_encrypt(&ctx->sm4_key, ctx->sbytes, ctx->iv, ctx->block, ctx->sbytes, out);
in += left;
inlen -= left;
out += ctx->sbytes;
*outlen += ctx->sbytes;
}
if (inlen >= ctx->sbytes) {
nblocks = inlen / ctx->sbytes;
len = nblocks * ctx->sbytes;
sm4_cfb_encrypt(&ctx->sm4_key, ctx->sbytes, ctx->iv, in, len, out);
in += len;
inlen -= len;
out += len;
*outlen += len;
}
if (inlen) {
memcpy(ctx->block, in, inlen);
}
ctx->block_nbytes = inlen;
return 1;
}

int sm4_cfb_encrypt_finish(SM4_CFB_CTX *ctx, uint8_t *out, size_t *outlen)
{
if (ctx->block_nbytes >= ctx->sbytes) {
error_print();
return -1;
}
sm4_cfb_encrypt(&ctx->sm4_key, ctx->sbytes, ctx->iv, ctx->block, ctx->block_nbytes, out);
*outlen = ctx->block_nbytes;
return 1;
}

int sm4_cfb_decrypt_init(SM4_CFB_CTX *ctx, size_t sbytes,
const uint8_t key[SM4_BLOCK_SIZE], const uint8_t iv[SM4_BLOCK_SIZE])
{
if (sbytes < 1 || sbytes > 16) {
error_print();
return -1;
}
sm4_set_encrypt_key(&ctx->sm4_key, key);
memcpy(ctx->iv, iv, SM4_BLOCK_SIZE);
memset(ctx->block, 0, SM4_BLOCK_SIZE);
ctx->block_nbytes = 0;
ctx->sbytes = sbytes;
return 1;
}

int sm4_cfb_decrypt_update(SM4_CFB_CTX *ctx,
const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
{
size_t left;
size_t nblocks;
size_t len;

if (ctx->block_nbytes >= ctx->sbytes) {
error_print();
return -1;
}
*outlen = 0;
if (ctx->block_nbytes) {
left = ctx->sbytes - ctx->block_nbytes;
if (inlen < left) {
memcpy(ctx->block + ctx->block_nbytes, in, inlen);
ctx->block_nbytes += inlen;
return 1;
}
memcpy(ctx->block + ctx->block_nbytes, in, left);
sm4_cfb_decrypt(&ctx->sm4_key, ctx->sbytes, ctx->iv, ctx->block, ctx->sbytes, out);
in += left;
inlen -= left;
out += ctx->sbytes;
*outlen += ctx->sbytes;
}
if (inlen >= ctx->sbytes) {
nblocks = inlen / ctx->sbytes;
len = nblocks * ctx->sbytes;
sm4_cfb_decrypt(&ctx->sm4_key, ctx->sbytes, ctx->iv, in, len, out);
in += len;
inlen -= len;
out += len;
*outlen += len;
}
if (inlen) {
memcpy(ctx->block, in, inlen);
}
ctx->block_nbytes = inlen;
return 1;
}

int sm4_cfb_decrypt_finish(SM4_CFB_CTX *ctx, uint8_t *out, size_t *outlen)
{
if (ctx->block_nbytes >= ctx->sbytes) {
error_print();
return -1;
}
sm4_cfb_decrypt(&ctx->sm4_key, ctx->sbytes, ctx->iv, ctx->block, ctx->block_nbytes, out);
*outlen = ctx->block_nbytes;
return 1;
}

Loading

0 comments on commit 8ae03e8

Please sign in to comment.