diff --git a/CMakeLists.txt b/CMakeLists.txt index 100c0d2d..57f2626d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -268,11 +268,56 @@ 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) + +option(ENABLE_SM4_ECB "Enable SM4 ECB mode" OFF) +if (ENABLE_SM4_ECB) + message(STATUS "ENABLE_SM4_ECB is ON") + add_definitions(-DENABLE_SM4_ECB) + list(APPEND src src/sm4_ecb.c) + list(APPEND tests sm4_ecb) endif() +option(ENABLE_SM4_OFB "Enable SM4 OFB mode" OFF) +if (ENABLE_SM4_OFB) + message(STATUS "ENABLE_SM4_OFB is ON") + add_definitions(-DENABLE_SM4_OFB) + list(APPEND src src/sm4_ofb.c) + list(APPEND tests sm4_ofb) +endif() + +option(ENABLE_SM4_CFB "Enable SM4 CFB mode" OFF) +if (ENABLE_SM4_CFB) + message(STATUS "ENABLE_SM4_CFB is ON") + add_definitions(-DENABLE_SM4_CFB) + list(APPEND src src/sm4_cfb.c) + list(APPEND tests sm4_cfb) +endif() + +option(ENABLE_SM4_CBC_MAC "Enable SM4-CBC-MAC" OFF) + +option(ENABLE_SM4_CCM "Enable SM4 CCM mode" OFF) +if (ENABLE_SM4_CCM) + message(STATUS "ENABLE_SM4_CCM is ON") + set(ENABLE_SM4_CBC_MAC ON) + add_definitions(-DENABLE_SM4_CCM) + list(APPEND src src/sm4_ccm.c) + list(APPEND tests sm4_ccm) +endif() + +option(ENABLE_SM4_XTS "Enable SM4 XTS mode" OFF) +if (ENABLE_SM4_XTS) + message(STATUS "ENABLE_SM4_XTS is ON") + add_definitions(-DENABLE_SM4_XTS) + list(APPEND src src/sm4_xts.c) + list(APPEND tests sm4_xts) +endif() + + + + + + + option(ENABLE_SM2_EXTS "Enable SM2 Extensions" OFF) if (ENABLE_SM2_EXTS) message(STATUS "ENABLE_SM4_AESNI_AVX") @@ -369,7 +414,6 @@ if (ENABLE_INTEL_RDRAND) endif() -option(ENABLE_SM4_CBC_MAC "Enable SM4-CBC-MAC" OFF) if (ENABLE_SM4_CBC_MAC) message(STATUS "ENABLE_SM4_CBC_MAC is ON") list(APPEND src src/sm4_cbc_mac.c) diff --git a/include/gmssl/sm4.h b/include/gmssl/sm4.h index b0bbe7e5..2cd9e0eb 100644 --- a/include/gmssl/sm4.h +++ b/include/gmssl/sm4.h @@ -119,6 +119,107 @@ int sm4_ctr_encrypt_finish(SM4_CTR_CTX *ctx, uint8_t *out, size_t *outlen); #define sm4_ctr_decrypt_finish(ctx,out,outlen) sm4_ctr_encrypt_finish(ctx,out,outlen) +#ifdef ENABLE_SM4_ECB +// call `sm4_set_decrypt_key` before decrypt +void sm4_ecb_encrypt(const SM4_KEY *key, const uint8_t *in, size_t nblocks, uint8_t *out); + +typedef struct { + SM4_KEY sm4_key; + uint8_t block[SM4_BLOCK_SIZE]; + size_t block_nbytes; +} SM4_ECB_CTX; + +int sm4_ecb_encrypt_init(SM4_ECB_CTX *ctx, const uint8_t key[SM4_BLOCK_SIZE]); +int sm4_ecb_encrypt_update(SM4_ECB_CTX *ctx, + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); +int sm4_ecb_encrypt_finish(SM4_ECB_CTX *ctx, uint8_t *out, size_t *outlen); + +int sm4_ecb_decrypt_init(SM4_ECB_CTX *ctx, const uint8_t key[SM4_BLOCK_SIZE]); +int sm4_ecb_decrypt_update(SM4_ECB_CTX *ctx, + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); +int sm4_ecb_decrypt_finish(SM4_ECB_CTX *ctx, uint8_t *out, size_t *outlen); +#endif + + +#ifdef ENABLE_SM4_OFB +// always call `sm4_set_encrypt_key` before encrypt/decrypt +// `sm4_ofb_encrypt` will change the param `iv` +void sm4_ofb_encrypt(const SM4_KEY *key, uint8_t iv[16], const uint8_t *in, size_t inlen, uint8_t *out); + +typedef struct { + SM4_KEY sm4_key; + uint8_t iv[SM4_BLOCK_SIZE]; + uint8_t block[SM4_BLOCK_SIZE]; + size_t block_nbytes; +} SM4_OFB_CTX; + +int sm4_ofb_encrypt_init(SM4_OFB_CTX *ctx, + const uint8_t key[SM4_BLOCK_SIZE], const uint8_t iv[SM4_BLOCK_SIZE]); +int sm4_ofb_encrypt_update(SM4_OFB_CTX *ctx, + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); +int sm4_ofb_encrypt_finish(SM4_OFB_CTX *ctx, uint8_t *out, size_t *outlen); +#endif + + +#ifdef ENABLE_SM4_CFB +#define SM4_CFB_MIN_SBYTES 1 +#define SM4_CFB_MAX_SBYTES 16 + +// always call `sm4_set_encrypt_key` before encrypt/decrypt +// `sm4_cfb_encrypt/decrypt` will change the param `iv` +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); +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); + +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]); +int sm4_cfb_encrypt_update(SM4_CFB_CTX *ctx, + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); +int sm4_cfb_encrypt_finish(SM4_CFB_CTX *ctx, uint8_t *out, size_t *outlen); + +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]); +int sm4_cfb_decrypt_update(SM4_CFB_CTX *ctx, + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); +int sm4_cfb_decrypt_finish(SM4_CFB_CTX *ctx, uint8_t *out, size_t *outlen); +#endif + + +#ifdef ENABLE_SM4_CCM +#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 + +// make sure inlen < 2^((15 - ivlen) * 8) +int sm4_ccm_encrypt(const 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); +int sm4_ccm_decrypt(const 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, + const uint8_t *tag, size_t taglen, uint8_t *out); +#endif + + +#ifdef ENABLE_SM4_XTS +// call `sm4_set_encrypt_key` to set both `key1` and `key2` +int sm4_xts_encrypt(const SM4_KEY *key1, const SM4_KEY *key2, size_t tweak, + const uint8_t *in, size_t inlen, uint8_t *out); +// call `sm4_set_decrypt_key(key1)` and `sm4_set_encrypt_key(key2)` +int sm4_xts_decrypt(const SM4_KEY *key1, const SM4_KEY *key2, size_t tweak, + const uint8_t *in, size_t inlen, uint8_t *out); +#endif + + #ifdef __cplusplus } #endif diff --git a/src/sm4_ccm.c b/src/sm4_ccm.c index ab701a41..f8a40bbd 100644 --- a/src/sm4_ccm.c +++ b/src/sm4_ccm.c @@ -14,10 +14,6 @@ #include -#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) @@ -29,18 +25,16 @@ static void length_to_bytes(size_t len, size_t nbytes, uint8_t *out) } } -int sm4_ccm_encrypt(SM4_KEY *sm4_key, const uint8_t *iv, size_t ivlen, +int sm4_ccm_encrypt(const 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; + SM4_CBC_MAC_CTX mac_ctx; + const uint8_t zeros[16] = {0}; 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; + uint8_t mac[16]; + size_t inlen_size; if (ivlen < 7 || ivlen > 13) { error_print(); @@ -56,22 +50,21 @@ int sm4_ccm_encrypt(SM4_KEY *sm4_key, const uint8_t *iv, size_t ivlen, } inlen_size = 15 - ivlen; - if (inlen >= (1 << (inlen_size * 8))) { + if (inlen_size < 8 && 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; + // sm4_cbc_mac_init with SM4_KEY + memset(&mac_ctx, 0, sizeof(mac_ctx)); + 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); + sm4_cbc_mac_update(&mac_ctx, block, 16); if (aad && aadlen) { size_t alen; @@ -88,35 +81,123 @@ int sm4_ccm_encrypt(SM4_KEY *sm4_key, const uint8_t *iv, size_t ivlen, block[0] = 0xff; block[1] = 0xff; length_to_bytes(aadlen, 8, block + 2); + alen = 10; } - sm4_cbc_mac_update(&cbc_mac_ctx, block, alen); - - sm4_cbc_mac_update(&cbc_mac_ctx, aad, aadlen); - + sm4_cbc_mac_update(&mac_ctx, block, alen); + sm4_cbc_mac_update(&mac_ctx, aad, aadlen); if (alen + aadlen % 16) { - sm4_cbc_mac_update(&cbc_mac_ctx, zeros, 16 - (alen + aadlen)%16); + sm4_cbc_mac_update(&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); + sm4_encrypt(sm4_key, ctr, block); ctr[15] = 1; sm4_ctr_encrypt(sm4_key, ctr, in, inlen, out); - gmssl_secure_clear(&cbc_mac_ctx, sizeof(cbc_mac_ctx)); + sm4_cbc_mac_update(&mac_ctx, in, inlen); + if (inlen % 16) { + sm4_cbc_mac_update(&mac_ctx, zeros, 16 - inlen % 16); + } + sm4_cbc_mac_finish(&mac_ctx, mac); + gmssl_memxor(tag, mac, block, taglen); + + gmssl_secure_clear(&mac_ctx, sizeof(mac_ctx)); return 1; } +int sm4_ccm_decrypt(const 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, + const uint8_t *tag, size_t taglen, uint8_t *out) +{ + SM4_CBC_MAC_CTX mac_ctx; + const uint8_t zeros[16] = {0}; + uint8_t block[16] = {0}; + uint8_t ctr[16] = {0}; + uint8_t mac[16]; + size_t inlen_size; + + 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_size < 8 && inlen >= (1 << (inlen_size * 8))) { + error_print(); + return -1; + } + + // sm4_cbc_mac_init with SM4_KEY + memset(&mac_ctx, 0, sizeof(mac_ctx)); + mac_ctx.key = *sm4_key; + + 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(&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); + alen = 10; + } + sm4_cbc_mac_update(&mac_ctx, block, alen); + sm4_cbc_mac_update(&mac_ctx, aad, aadlen); + if (alen + aadlen % 16) { + sm4_cbc_mac_update(&mac_ctx, zeros, 16 - (alen + aadlen)%16); + } + } + + 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, block); + + ctr[15] = 1; + sm4_ctr_encrypt(sm4_key, ctr, in, inlen, out); + + sm4_cbc_mac_update(&mac_ctx, out, inlen); // diff from encrypt + if (inlen % 16) { + sm4_cbc_mac_update(&mac_ctx, zeros, 16 - inlen % 16); + } + sm4_cbc_mac_finish(&mac_ctx, mac); + + // diff from encrypt + gmssl_memxor(mac, mac, block, taglen); + if (memcmp(mac, tag, taglen) != 0) { + error_print(); + gmssl_secure_clear(&mac_ctx, sizeof(mac_ctx)); + return -1; + } + + gmssl_secure_clear(&mac_ctx, sizeof(mac_ctx)); + return 1; +} diff --git a/src/sm4_cfb.c b/src/sm4_cfb.c index 4d0573ed..f4bba174 100644 --- a/src/sm4_cfb.c +++ b/src/sm4_cfb.c @@ -63,14 +63,6 @@ void sm4_cfb_decrypt(const SM4_KEY *key, size_t sbytes, uint8_t iv[16], } } -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]) { diff --git a/src/sm4_ecb.c b/src/sm4_ecb.c index 4b869f0b..7a80f5cd 100644 --- a/src/sm4_ecb.c +++ b/src/sm4_ecb.c @@ -22,13 +22,6 @@ void sm4_ecb_encrypt(const SM4_KEY *key, const uint8_t *in, size_t nblocks, uint } } - -typedef struct { - SM4_KEY sm4_key; - uint8_t block[SM4_BLOCK_SIZE]; - size_t block_nbytes; -} SM4_ECB_CTX; - int sm4_ecb_encrypt_init(SM4_ECB_CTX *ctx, const uint8_t key[SM4_BLOCK_SIZE]) { sm4_set_encrypt_key(&ctx->sm4_key, key); @@ -37,7 +30,7 @@ int sm4_ecb_encrypt_init(SM4_ECB_CTX *ctx, const uint8_t key[SM4_BLOCK_SIZE]) return 1; } -int sm4_efb_encrypt_update(SM4_ECB_CTX *ctx, +int sm4_ecb_encrypt_update(SM4_ECB_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) { size_t left; @@ -93,3 +86,29 @@ int sm4_ecb_encrypt_finish(SM4_ECB_CTX *ctx, uint8_t *out, size_t *outlen) return 1; } +int sm4_ecb_decrypt_init(SM4_ECB_CTX *ctx, const uint8_t key[SM4_BLOCK_SIZE]) +{ + sm4_set_decrypt_key(&ctx->sm4_key, key); + memset(ctx->block, 0, SM4_BLOCK_SIZE); + ctx->block_nbytes = 0; + return 1; +} + +int sm4_ecb_decrypt_update(SM4_ECB_CTX *ctx, + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) +{ + if (sm4_ecb_encrypt_update(ctx, in, inlen, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm4_ecb_decrypt_finish(SM4_ECB_CTX *ctx, uint8_t *out, size_t *outlen) +{ + if (sm4_ecb_encrypt_finish(ctx, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} diff --git a/src/sm4_ofb.c b/src/sm4_ofb.c index 748ff4ac..8e028769 100644 --- a/src/sm4_ofb.c +++ b/src/sm4_ofb.c @@ -27,14 +27,6 @@ void sm4_ofb_encrypt(const SM4_KEY *key, uint8_t iv[16], const uint8_t *in, size } } - -typedef struct { - SM4_KEY sm4_key; - uint8_t iv[SM4_BLOCK_SIZE]; - uint8_t block[SM4_BLOCK_SIZE]; - size_t block_nbytes; -} SM4_OFB_CTX; - int sm4_ofb_encrypt_init(SM4_OFB_CTX *ctx, const uint8_t key[SM4_BLOCK_SIZE], const uint8_t iv[SM4_BLOCK_SIZE]) { diff --git a/src/sm4_xts.c b/src/sm4_xts.c new file mode 100644 index 00000000..d473df84 --- /dev/null +++ b/src/sm4_xts.c @@ -0,0 +1,142 @@ +/* + * 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 +#include +#include +#include + + +int sm4_xts_encrypt(const SM4_KEY *key1, const SM4_KEY *key2, size_t tweak, + const uint8_t *in, size_t inlen, uint8_t *out) +{ + uint8_t T[16] = {0}; + uint8_t block[16]; + size_t nblocks, i; + gf128_t a; + + if (inlen < 16) { + error_print(); + return -1; + } + nblocks = inlen / 16 + 1; + + for (i = 0; i < 8; i++) { + T[i] = tweak & 0xff; + tweak >>= 8; + } + sm4_encrypt(key2, T, T); + + for (i = 0; i < nblocks - 2; i++) { + gmssl_memxor(block, in, T, 16); + sm4_encrypt(key1, block, block); + gmssl_memxor(out, block, T, 16); + + a = gf128_from_bytes(T); + a = gf128_mul2(a); + gf128_to_bytes(a, T); + + in += 16; + inlen -= 16; + out += 16; + } + + if (inlen % 16 == 0) { + gmssl_memxor(block, in, T, 16); + sm4_encrypt(key1, block, block); + gmssl_memxor(out, block, T, 16); + + } else { + gmssl_memxor(block, in, T, 16); + sm4_encrypt(key1, block, block); + gmssl_memxor(block, block, T, 16); + + a = gf128_from_bytes(T); + a = gf128_mul2(a); + gf128_to_bytes(a, T); + + in += 16; + inlen -= 16; + + memcpy(out + 16, block, inlen); + memcpy(block, in, inlen); + + gmssl_memxor(block, block, T, 16); + sm4_encrypt(key1, block, block); + gmssl_memxor(out, block, T, 16); + } + + return 1; +} + +int sm4_xts_decrypt(const SM4_KEY *key1, const SM4_KEY *key2, size_t tweak, + const uint8_t *in, size_t inlen, uint8_t *out) +{ + uint8_t T[16] = {0}; + uint8_t block[16]; + size_t nblocks, i; + gf128_t a; + + if (inlen < 16) { + error_print(); + return -1; + } + nblocks = inlen / 16 + 1; + + for (i = 0; i < 8; i++) { + T[i] = tweak & 0xff; + tweak >>= 8; + } + sm4_encrypt(key2, T, T); + + for (i = 0; i < nblocks - 2; i++) { + gmssl_memxor(block, in, T, 16); + sm4_decrypt(key1, block, block); + gmssl_memxor(out, block, T, 16); + + a = gf128_from_bytes(T); + a = gf128_mul2(a); + gf128_to_bytes(a, T); + + in += 16; + inlen -= 16; + out += 16; + } + + if (inlen % 16 == 0) { + gmssl_memxor(block, in, T, 16); + sm4_decrypt(key1, block, block); + gmssl_memxor(out, block, T, 16); + + } else { + uint8_t T1[16]; + + a = gf128_from_bytes(T); + a = gf128_mul2(a); + gf128_to_bytes(a, T1); + + gmssl_memxor(block, in, T1, 16); + sm4_decrypt(key1, block, block); + gmssl_memxor(block, block, T1, 16); + + in += 16; + inlen -= 16; + + memcpy(out + 16, block, inlen); + memcpy(block, in, inlen); + + gmssl_memxor(block, block, T, 16); + sm4_decrypt(key1, block, block); + gmssl_memxor(out, block, T, 16); + } + + return 1; +} + diff --git a/tests/sm4_ccmtest.c b/tests/sm4_ccmtest.c new file mode 100644 index 00000000..ce66f227 --- /dev/null +++ b/tests/sm4_ccmtest.c @@ -0,0 +1,76 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + + +static int test_sm4_ccm(void) +{ + SM4_KEY sm4_key; + uint8_t key[16]; + uint8_t iv[SM4_CCM_MAX_IV_SIZE]; + size_t ivlen[] = { SM4_CCM_MIN_IV_SIZE, SM4_CCM_MIN_IV_SIZE + 1, SM4_CCM_MAX_IV_SIZE }; + uint8_t aad[32]; + size_t aadlen[] = {0, 8, 16, 20, 32 }; + uint8_t plaintext[64]; + size_t len[] = { 4, 16, 36, 64 }; + uint8_t encrypted[sizeof(plaintext)]; + uint8_t decrypted[sizeof(plaintext)]; + uint8_t mac[SM4_CCM_MAX_MAC_SIZE]; + size_t maclen[] = { SM4_CCM_MIN_MAC_SIZE, SM4_CCM_MAX_MAC_SIZE }; + size_t i; + + rand_bytes(key, sizeof(key)); + rand_bytes(iv, sizeof(iv)); + rand_bytes(aad, sizeof(aad)); + rand_bytes(plaintext, sizeof(plaintext)); + + sm4_set_encrypt_key(&sm4_key, key); + + for (i = 0; i < sizeof(ivlen)/sizeof(ivlen[0]); i++) { + + if (sm4_ccm_encrypt(&sm4_key, iv, ivlen[i], aad, sizeof(aad), + plaintext, sizeof(plaintext), encrypted, sizeof(mac), mac) != 1) { + error_print(); + return -1; + } + + if (sm4_ccm_decrypt(&sm4_key, iv, ivlen[i], aad, sizeof(aad), + encrypted, sizeof(encrypted), mac, sizeof(mac), decrypted) != 1) { + error_print(); + return -1; + } + + if (memcmp(decrypted, plaintext, sizeof(plaintext)) != 0) { + error_print(); + return -1; + } + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +int main(void) +{ + if (test_sm4_ccm() != 1) goto err; + printf("%s all tests passed\n", __FILE__); + return 0; +err: + error_print(); + return 1; +} diff --git a/tests/sm4_cfbtest.c b/tests/sm4_cfbtest.c new file mode 100644 index 00000000..8e031e37 --- /dev/null +++ b/tests/sm4_cfbtest.c @@ -0,0 +1,167 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + + +static int test_sm4_cfb(void) +{ + SM4_KEY sm4_key; + uint8_t key[16]; + uint8_t iv[16]; + size_t sbytes[] = { 1, 4, 12, 16 }; + size_t len[] = { 4, 16, 16+2, 32, 48+8 }; + uint8_t plaintext[16 * 4]; + uint8_t encrypted[sizeof(plaintext)]; + uint8_t decrypted[sizeof(plaintext)]; + size_t k, i; + + rand_bytes(key, sizeof(key)); + rand_bytes(iv, sizeof(iv)); + rand_bytes(plaintext, sizeof(plaintext)); + + sm4_set_encrypt_key(&sm4_key, key); + + for (k = 0; k < sizeof(sbytes)/sizeof(sbytes[0]); k++) { + + for (i = 0; i < sizeof(len)/sizeof(len[0]); i++) { + + uint8_t state_iv[16]; + + memcpy(state_iv, iv, sizeof(iv)); + sm4_cfb_encrypt(&sm4_key, sbytes[k], state_iv, plaintext, len[i], encrypted); + + memcpy(state_iv, iv, sizeof(iv)); + sm4_cfb_decrypt(&sm4_key, sbytes[k], state_iv, encrypted, len[i], decrypted); + + if (memcmp(decrypted, plaintext, len[i]) != 0) { + error_print(); + return -1; + } + } + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_sm4_cfb_ctx(void) +{ + + uint8_t key[16]; + uint8_t iv[16]; + size_t sbytes[] = { 1, 4, 16 }; + size_t inlen[] = { 2, 14, 32, 4, 18 }; + uint8_t plaintext[2 + 14 + 32 + 4 + 18]; + size_t k, i; + + rand_bytes(key, sizeof(key)); + rand_bytes(iv, sizeof(iv)); + rand_bytes(plaintext, sizeof(plaintext)); + + for (k = 0; k < sizeof(sbytes)/sizeof(sbytes[0]); k++) { + SM4_CFB_CTX ctx; + uint8_t encrypted[sizeof(plaintext) + 16]; + uint8_t decrypted[sizeof(plaintext) + 16]; + size_t plaintext_len = 0; + size_t encrypted_len = 0; + size_t decrypted_len = 0; + uint8_t *in, *out; + size_t len; + + // encrypt + + if (sm4_cfb_encrypt_init(&ctx, sbytes[k], key, iv) != 1) { + error_print(); + return -1; + } + + in = plaintext; + out = encrypted; + + for (i = 0; i < sizeof(inlen)/sizeof(inlen[0]); i++) { + if (sm4_cfb_encrypt_update(&ctx, in, inlen[i], out, &len) != 1) { + error_print(); + return -1; + } + in += inlen[i]; + out += len; + plaintext_len += inlen[i]; + encrypted_len += len; + } + + if (sm4_cfb_encrypt_finish(&ctx, out, &len) != 1) { + error_print(); + return -1; + } + encrypted_len += len; + + if (encrypted_len != plaintext_len) { + error_print(); + return -1; + } + + // decrypt + + if (sm4_cfb_decrypt_init(&ctx, sbytes[k], key, iv) != 1) { + error_print(); + return -1; + } + + in = encrypted; + out = decrypted; + + for (i = 0; i < sizeof(inlen)/sizeof(inlen[0]); i++) { + if (sm4_cfb_decrypt_update(&ctx, in, inlen[i], out, &len) != 1) { + error_print(); + return -1; + } + in += inlen[i]; + out += len; + decrypted_len += len; + } + + if (sm4_cfb_decrypt_finish(&ctx, out, &len) != 1) { + error_print(); + return -1; + } + decrypted_len += len; + + if (decrypted_len != plaintext_len) { + error_print(); + return -1; + } + if (memcmp(decrypted, plaintext, plaintext_len) != 0) { + error_print(); + return -1; + } + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +int main(void) +{ + if (test_sm4_cfb() != 1) goto err; + if (test_sm4_cfb_ctx() != 1) goto err; + printf("%s all tests passed\n", __FILE__); + return 0; +err: + error_print(); + return 1; +} diff --git a/tests/sm4_ecbtest.c b/tests/sm4_ecbtest.c new file mode 100644 index 00000000..75468d5b --- /dev/null +++ b/tests/sm4_ecbtest.c @@ -0,0 +1,194 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + + +static int test_sm4_ecb(void) +{ + SM4_KEY sm4_key; + uint8_t key[16]; + uint8_t plaintext[16 * 4]; + uint8_t encrypted[16 * 4]; + uint8_t decrypted[16 * 4]; + int i; + + for (i = 0; i < 3; i++) { + rand_bytes(key, sizeof(key)); + rand_bytes(plaintext, sizeof(plaintext)); + + sm4_set_encrypt_key(&sm4_key, key); + sm4_ecb_encrypt(&sm4_key, plaintext, sizeof(plaintext)/16, encrypted); + + sm4_set_decrypt_key(&sm4_key, key); + sm4_ecb_encrypt(&sm4_key, encrypted, sizeof(encrypted)/16, decrypted); + + if (memcmp(decrypted, plaintext, sizeof(plaintext)) != 0) { + error_print(); + return -1; + } + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_sm4_ecb_testvec(void) +{ + SM4_KEY sm4_key; + uint8_t key[16] = { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, + }; + uint8_t plaintext[16 * 4] = { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, + }; + uint8_t ciphertext[sizeof(plaintext)] = { + 0x68,0x1e,0xdf,0x34,0xd2,0x06,0x96,0x5e,0x86,0xb3,0xe9,0x4f,0x53,0x6e,0x42,0x46, + 0x68,0x1e,0xdf,0x34,0xd2,0x06,0x96,0x5e,0x86,0xb3,0xe9,0x4f,0x53,0x6e,0x42,0x46, + 0x68,0x1e,0xdf,0x34,0xd2,0x06,0x96,0x5e,0x86,0xb3,0xe9,0x4f,0x53,0x6e,0x42,0x46, + 0x68,0x1e,0xdf,0x34,0xd2,0x06,0x96,0x5e,0x86,0xb3,0xe9,0x4f,0x53,0x6e,0x42,0x46, + }; + uint8_t encrypted[sizeof(plaintext)] = {0}; + uint8_t decrypted[sizeof(plaintext)] = {0}; + + sm4_set_encrypt_key(&sm4_key, key); + sm4_ecb_encrypt(&sm4_key, plaintext, sizeof(plaintext)/16, encrypted); + + format_bytes(stderr, 0, 0, "", encrypted, sizeof(encrypted)); + + if (memcmp(encrypted, ciphertext, sizeof(ciphertext)) != 0) { + error_print(); + return -1; + } + + sm4_set_decrypt_key(&sm4_key, key); + sm4_ecb_encrypt(&sm4_key, encrypted, sizeof(encrypted)/16, decrypted); + + if (memcmp(decrypted, plaintext, sizeof(plaintext)) != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_sm4_ecb_ctx(void) +{ + SM4_ECB_CTX ctx; + uint8_t key[16]; + size_t inlen[] = { 2, 14, 32, 4, 12 }; + uint8_t plaintext[2 + 14 + 32 + 4 + 12]; + uint8_t encrypted[sizeof(plaintext) + 16]; + uint8_t decrypted[sizeof(plaintext) + 16]; + size_t plaintext_len = 0; + size_t encrypted_len = 0; + size_t decrypted_len = 0; + uint8_t *in, *out; + size_t len; + size_t i; + + rand_bytes(key, sizeof(key)); + rand_bytes(plaintext, sizeof(plaintext)); + + + // encrypt + + if (sm4_ecb_encrypt_init(&ctx, key) != 1) { + error_print(); + return -1; + } + + in = plaintext; + out = encrypted; + + for (i = 0; i < sizeof(inlen)/sizeof(inlen[0]); i++) { + if (sm4_ecb_encrypt_update(&ctx, in, inlen[i], out, &len) != 1) { + error_print(); + return -1; + } + in += inlen[i]; + out += len; + plaintext_len += inlen[i]; + encrypted_len += len; + } + + if (sm4_ecb_encrypt_finish(&ctx, out, &len) != 1) { + error_print(); + return -1; + } + encrypted_len += len; + + if (encrypted_len != plaintext_len) { + error_print(); + return -1; + } + + // decrypt + + if (sm4_ecb_decrypt_init(&ctx, key) != 1) { + error_print(); + return -1; + } + + in = encrypted; + out = decrypted; + + for (i = 0; i < sizeof(inlen)/sizeof(inlen[0]); i++) { + if (sm4_ecb_decrypt_update(&ctx, in, inlen[i], out, &len) != 1) { + error_print(); + return -1; + } + in += inlen[i]; + out += len; + decrypted_len += len; + } + + if (sm4_ecb_decrypt_finish(&ctx, out, &len) != 1) { + error_print(); + return -1; + } + decrypted_len += len; + + if (decrypted_len != plaintext_len) { + error_print(); + return -1; + } + if (memcmp(decrypted, plaintext, plaintext_len) != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + +int main(void) +{ + if (test_sm4_ecb() != 1) goto err; + if (test_sm4_ecb_testvec() != 1) goto err; + if (test_sm4_ecb_ctx() != 1) goto err; + printf("%s all tests passed\n", __FILE__); + return 0; +err: + error_print(); + return 1; +} diff --git a/tests/sm4_ofbtest.c b/tests/sm4_ofbtest.c new file mode 100644 index 00000000..8698d899 --- /dev/null +++ b/tests/sm4_ofbtest.c @@ -0,0 +1,159 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + + +static int test_sm4_ofb(void) +{ + SM4_KEY sm4_key; + uint8_t key[16]; + uint8_t iv[16]; + + size_t len[] = { 4, 16, 16+2, 32, 48+8 }; + uint8_t plaintext[48+8]; + uint8_t encrypted[sizeof(plaintext)]; + uint8_t decrypted[sizeof(plaintext)]; + size_t i; + + rand_bytes(key, sizeof(key)); + rand_bytes(iv, sizeof(iv)); + rand_bytes(plaintext, sizeof(plaintext)); + + sm4_set_encrypt_key(&sm4_key, key); + + for (i = 0; i < sizeof(len)/sizeof(len[0]); i++) { + uint8_t state_iv[16]; + + memcpy(state_iv, iv, sizeof(iv)); + sm4_ofb_encrypt(&sm4_key, state_iv, plaintext, len[i], encrypted); + + memcpy(state_iv, iv, sizeof(iv)); + sm4_ofb_encrypt(&sm4_key, state_iv, encrypted, len[i], decrypted); + + if (memcmp(decrypted, plaintext, len[i]) != 0) { + error_print(); + return -1; + } + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_sm4_ofb_ctx(void) +{ + SM4_OFB_CTX ctx; + uint8_t key[16]; + uint8_t iv[16]; + size_t inlen[] = { 2, 14, 32, 4, 18 }; + uint8_t plaintext[2 + 14 + 32 + 4 + 18]; + uint8_t encrypted[sizeof(plaintext) + 16]; + uint8_t decrypted[sizeof(plaintext) + 16]; + size_t plaintext_len = 0; + size_t encrypted_len = 0; + size_t decrypted_len = 0; + uint8_t *in, *out; + size_t len; + size_t i; + + rand_bytes(key, sizeof(key)); + rand_bytes(iv, sizeof(iv)); + rand_bytes(plaintext, sizeof(plaintext)); + + + // encrypt + + if (sm4_ofb_encrypt_init(&ctx, key, iv) != 1) { + error_print(); + return -1; + } + + in = plaintext; + out = encrypted; + + for (i = 0; i < sizeof(inlen)/sizeof(inlen[0]); i++) { + if (sm4_ofb_encrypt_update(&ctx, in, inlen[i], out, &len) != 1) { + error_print(); + return -1; + } + in += inlen[i]; + out += len; + plaintext_len += inlen[i]; + encrypted_len += len; + } + + if (sm4_ofb_encrypt_finish(&ctx, out, &len) != 1) { + error_print(); + return -1; + } + encrypted_len += len; + + if (encrypted_len != plaintext_len) { + error_print(); + return -1; + } + + // decrypt + + if (sm4_ofb_encrypt_init(&ctx, key, iv) != 1) { + error_print(); + return -1; + } + + in = encrypted; + out = decrypted; + + for (i = 0; i < sizeof(inlen)/sizeof(inlen[0]); i++) { + if (sm4_ofb_encrypt_update(&ctx, in, inlen[i], out, &len) != 1) { + error_print(); + return -1; + } + in += inlen[i]; + out += len; + decrypted_len += len; + } + + if (sm4_ofb_encrypt_finish(&ctx, out, &len) != 1) { + error_print(); + return -1; + } + decrypted_len += len; + + if (decrypted_len != plaintext_len) { + error_print(); + return -1; + } + if (memcmp(decrypted, plaintext, plaintext_len) != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +int main(void) +{ + if (test_sm4_ofb() != 1) goto err; + if (test_sm4_ofb_ctx() != 1) goto err; + printf("%s all tests passed\n", __FILE__); + return 0; +err: + error_print(); + return 1; +} diff --git a/tests/sm4_xtstest.c b/tests/sm4_xtstest.c new file mode 100644 index 00000000..035f586c --- /dev/null +++ b/tests/sm4_xtstest.c @@ -0,0 +1,64 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + + +static int test_sm4_xts(void) +{ + SM4_KEY sm4_key1; + SM4_KEY sm4_key2; + uint8_t key[32]; + size_t len[] = { 16, 16+2, 32, 48+8, 64 }; + uint8_t plaintext[16 * 4]; + uint8_t encrypted[sizeof(plaintext)]; + uint8_t decrypted[sizeof(plaintext)]; + size_t tweak = 0x12345678; + size_t i; + + rand_bytes(key, sizeof(key)); + rand_bytes(plaintext, sizeof(plaintext)); + + for (i = 0; i < sizeof(len)/sizeof(len[0]); i++) { + + sm4_set_encrypt_key(&sm4_key1, key); + sm4_set_encrypt_key(&sm4_key2, key + 16); + sm4_xts_encrypt(&sm4_key1, &sm4_key2, tweak, plaintext, len[i], encrypted); + + sm4_set_decrypt_key(&sm4_key1, key); + sm4_set_encrypt_key(&sm4_key2, key + 16); + sm4_xts_decrypt(&sm4_key1, &sm4_key2, tweak, encrypted, len[i], decrypted); + + if (memcmp(decrypted, plaintext, len[i]) != 0) { + error_print(); + return -1; + } + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +int main(void) +{ + if (test_sm4_xts() != 1) goto err; + printf("%s all tests passed\n", __FILE__); + return 0; +err: + error_print(); + return 1; +}