-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Not tested yet
- Loading branch information
Showing
6 changed files
with
533 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
|
Oops, something went wrong.