diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cf9f50b0..9d1f3738d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,6 +147,7 @@ set(tools tools/sm9decrypt.c tools/zuc.c tools/rand.c + tools/ghash.c tools/pbkdf2.c tools/certgen.c tools/certparse.c @@ -353,6 +354,7 @@ 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 tools tools/sm4_xts.c) list(APPEND tests sm4_xts) endif() diff --git a/include/gmssl/ghash.h b/include/gmssl/ghash.h index 1b793cdcb..73fbca86d 100644 --- a/include/gmssl/ghash.h +++ b/include/gmssl/ghash.h @@ -25,6 +25,7 @@ extern "C" { #define GHASH_SIZE (16) +// h = ENC_k(0^128) void ghash(const uint8_t h[16], const uint8_t *aad, size_t aadlen, const uint8_t *c, size_t clen, uint8_t out[16]); diff --git a/src/sm4_xts.c b/src/sm4_xts.c index 81417e711..864c71fa2 100644 --- a/src/sm4_xts.c +++ b/src/sm4_xts.c @@ -311,5 +311,3 @@ int sm4_xts_decrypt_finish(SM4_XTS_CTX *ctx, uint8_t *out, size_t *outlen) *outlen = 0; return 1; } - - diff --git a/tools/ghash.c b/tools/ghash.c new file mode 100644 index 000000000..d80e5d594 --- /dev/null +++ b/tools/ghash.c @@ -0,0 +1,190 @@ +/* + * 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 + + +static const char *usage = "[-in_str str|-in file] [-hex|-bin] [-out file]"; + +static const char *help = +"Options\n" +"\n" +" -h hex H value of GHASH, a ciphertext block of encrypted zeros\n" +" -aad str Authenticated-only message\n" +" -aad_hex hex Authenticated-only data in HEX format\n" +" -in_str str To be hashed string\n" +" -in file | stdin To be hashed file path\n" +" `-in_str` and `-in` should not be used together\n" +" If neither `-in` nor `-in_str` specified, read from stdin\n" +" -hex Output hash value as hex string (by default)\n" +" -bin Output hash value as binary\n" +" -out file | stdout Output file path. If not specified, output to stdout\n" +"\n" +"Examples\n" +"\n" +" $ TEXT=`gmssl rand -outlen 20 -hex`\n" +" $ KEY=`gmssl rand -outlen 16 -hex`\n" +" $ AAD=\"The AAD Data\"\n" +" $ gmssl ghash -h $KEY -aad $AAD -in_str $TEXT\n" +"\n"; + + +int ghash_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *hhex = NULL; + uint8_t *aad = NULL; + uint8_t *aad_buf = NULL; + size_t aadlen = 0; + char *in_str = NULL; + char *infile = NULL; + int outformat = 0; + char *outfile = NULL; + uint8_t h[16]; + size_t hlen; + FILE *infp = stdin; + FILE *outfp = stdout; + GHASH_CTX ghash_ctx; + uint8_t dgst[GHASH_SIZE]; + int i; + + argc--; + argv++; + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + printf("usage: gmssl %s %s\n", prog, usage); + printf("%s\n", help); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-h")) { + if (--argc < 1) goto bad; + hhex = *(++argv); + if (strlen(hhex) != sizeof(h) * 2) { + fprintf(stderr, "gmssl %s: invalid H value length\n", prog); + goto end; + } + if (hex_to_bytes(hhex, strlen(hhex), h, &hlen) != 1) { + fprintf(stderr, "gmssl %s: invalid H hex digits\n", prog); + goto end; + } + } else if (!strcmp(*argv, "-aad")) { + if (--argc < 1) goto bad; + if (aad) { + fprintf(stderr, "gmssl %s: `-aad` or `aad_hex` has been specified\n", prog); + goto bad; + } + aad = (uint8_t *)(*(++argv)); + aadlen = strlen((char *)aad); + } else if (!strcmp(*argv, "-aad_hex")) { + if (--argc < 1) goto bad; + if (aad) { + fprintf(stderr, "gmssl %s: `-aad` or `aad_hex` has been specified\n", prog); + goto bad; + } + aad = (uint8_t *)(*(++argv)); + if (!(aad_buf = malloc(strlen((char *)aad)/2 + 1))) { + fprintf(stderr, "gmssl %s: malloc failure\n", prog); + goto end; + } + if (hex_to_bytes((char *)aad, strlen((char *)aad), aad_buf, &aadlen) != 1) { + fprintf(stderr, "gmssl %s: `-aad_hex` invalid HEX format argument\n", prog); + goto end; + } + aad = aad_buf; + } else if (!strcmp(*argv, "-in_str")) { + if (infile) { + fprintf(stderr, "gmssl %s: `-in` and `-in_str` should not be used together\n", prog); + goto end; + } + if (--argc < 1) goto bad; + in_str = *(++argv); + } else if (!strcmp(*argv, "-in")) { + if (in_str) { + fprintf(stderr, "gmssl %s: `-in` and `-in_str` should not be used together\n", prog); + goto end; + } + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "rb"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-hex")) { + if (outformat > 0) { + fprintf(stderr, "gmssl %s: `-hex` and `-bin` should not be used together\n", prog); + goto end; + } + outformat = 1; + } else if (!strcmp(*argv, "-bin")) { + if (outformat > 0) { + fprintf(stderr, "gmssl %s: `-hex` and `-bin` should not be used together\n", prog); + goto end; + } + outformat = 2; + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "wb"))) { + fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else { + fprintf(stderr, "gmssl %s: illegal option '%s'\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "gmssl %s: '%s' option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + ghash_init(&ghash_ctx, h, aad, aadlen); + + if (in_str) { + ghash_update(&ghash_ctx, (uint8_t *)in_str, strlen(in_str)); + + } else { + uint8_t buf[4096]; + size_t len; + while ((len = fread(buf, 1, sizeof(buf), infp)) > 0) { + ghash_update(&ghash_ctx, buf, len); + } + memset(buf, 0, sizeof(buf)); + } + ghash_finish(&ghash_ctx, dgst); + memset(&ghash_ctx, 0, sizeof(ghash_ctx)); + + if (outformat > 1) { + if (fwrite(dgst, 1, sizeof(dgst), outfp) != sizeof(dgst)) { + fprintf(stderr, "gmssl %s: output failure : %s\n", prog, strerror(errno)); + goto end; + } + } else { + for (i = 0; i < sizeof(dgst); i++) { + fprintf(outfp, "%02x", dgst[i]); + } + fprintf(outfp, "\n"); + } + ret = 0; +end: + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + return ret; +} diff --git a/tools/gmssl.c b/tools/gmssl.c index 998900aba..adfdfa7b8 100644 --- a/tools/gmssl.c +++ b/tools/gmssl.c @@ -43,10 +43,12 @@ extern int sm4_cfb_main(int argc, char **argv); extern int sm4_ofb_main(int argc, char **argv); extern int sm4_ccm_main(int argc, char **argv); extern int sm4_gcm_main(int argc, char **argv); +extern int sm4_xts_main(int argc, char **argv); extern int sm4_cbc_sm3_hmac_main(int argc, char **argv); extern int sm4_ctr_sm3_hmac_main(int argc, char **argv); extern int sm4_cbc_mac_main(int argc, char **argv); extern int zuc_main(int argc, char **argv); +extern int ghash_main(int argc, char **argv); extern int sm9setup_main(int argc, char **argv); extern int sm9keygen_main(int argc, char **argv); extern int sm9sign_main(int argc, char **argv); @@ -95,9 +97,11 @@ static const char *options = " sm4_ofb Encrypt or decrypt with SM4 OFB\n" " sm4_ccm Encrypt or decrypt with SM4 CCM\n" " sm4_gcm Encrypt or decrypt with SM4 GCM\n" + " sm4_xts Encrypt or decrypt with SM4 XTS\n" " sm4_cbc_sm3_hmac Encrypt or decrypt with SM4 CBC with SM3-HMAC\n" " sm4_ctr_sm3_hmac Encrypt or decrypt with SM4 CTR with SM3-HMAC\n" " sm4_cbc_mac Generate SM4 CBC-MAC\n" + " ghash Generate GHASH\n" " zuc Encrypt or decrypt with ZUC\n" " sm9setup Generate SM9 master secret\n" " sm9keygen Generate SM9 private key\n" @@ -224,12 +228,20 @@ int main(int argc, char **argv) #endif } else if (!strcmp(*argv, "sm4_gcm")) { return sm4_gcm_main(argc, argv); +#if ENABLE_SM4_XTS + } else if (!strcmp(*argv, "sm4_xts")) { + return sm4_xts_main(argc, argv); +#endif } else if (!strcmp(*argv, "sm4_cbc_sm3_hmac")) { return sm4_cbc_sm3_hmac_main(argc, argv); } else if (!strcmp(*argv, "sm4_ctr_sm3_hmac")) { return sm4_ctr_sm3_hmac_main(argc, argv); + } else if (!strcmp(*argv, "ghash")) { + return ghash_main(argc, argv); +#if ENABLE_SM4_CBC_MAC } else if (!strcmp(*argv, "sm4_cbc_mac")) { return sm4_cbc_mac_main(argc, argv); +#endif } else if (!strcmp(*argv, "zuc")) { return zuc_main(argc, argv); } else if (!strcmp(*argv, "sm9setup")) { diff --git a/tools/sm4_ccm.c b/tools/sm4_ccm.c index 6e4b2f3c4..bf5230a05 100755 --- a/tools/sm4_ccm.c +++ b/tools/sm4_ccm.c @@ -257,7 +257,7 @@ int sm4_ccm_main(int argc, char **argv) if (enc) { outlen = inlen + taglen; if (!(outbuf = (uint8_t *)malloc(outlen))) { - fprintf(stderr, "%s: malloc failure\n", prog); + fprintf(stderr, "gmssl %s: malloc failure\n", prog); goto end; } tag = outbuf + inlen; @@ -268,14 +268,14 @@ int sm4_ccm_main(int argc, char **argv) } else { if (inlen < taglen) { - fprintf(stderr, "%s: input length (%zu bytes) shorter than tag length (%d bytes)\n", + fprintf(stderr, "gmssl %s: input length (%zu bytes) shorter than tag length (%d bytes)\n", prog, inlen, taglen); goto end; } outlen = inlen - taglen; tag = inbuf + inlen - taglen; if (!(outbuf = (uint8_t *)malloc(outlen))) { - fprintf(stderr, "%s: malloc failure\n", prog); + fprintf(stderr, "gmssl %s: malloc failure\n", prog); goto end; } if (sm4_ccm_decrypt(&sm4_key, iv, ivlen, aad, aadlen, inbuf, inlen - taglen, diff --git a/tools/sm4_gcm.c b/tools/sm4_gcm.c index f9054f52b..94ac7f062 100755 --- a/tools/sm4_gcm.c +++ b/tools/sm4_gcm.c @@ -143,7 +143,7 @@ int sm4_gcm_main(int argc, char **argv) if (--argc < 1) goto bad; taglen = atoi(*(++argv)); if (taglen < SM4_GCM_MIN_TAG_SIZE || taglen > SM4_GCM_MAX_TAG_SIZE) { - fprintf(stderr, "%s: `-taglen` invalid integer argument\n", prog); + fprintf(stderr, "gmssl %s: `-taglen` invalid integer argument\n", prog); goto end; } } else if (!strcmp(*argv, "-in")) { diff --git a/tools/sm4_xts.c b/tools/sm4_xts.c new file mode 100755 index 000000000..a3333f888 --- /dev/null +++ b/tools/sm4_xts.c @@ -0,0 +1,222 @@ +/* + * 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 const char *usage = "{-encrypt|-decrypt} -key hex -iv hex -data_unit_size num [-in file] [-out file]"; + +static const char *options = +"Options\n" +"\n" +" -encrypt Encrypt\n" +" -decrypt Decrypt\n" +" -key hex Symmetric key in HEX format, 32 bytes\n" +" -iv hex IV (tweak in XTS), 16 bytes\n" +" -data_unit_size num Encrypted disk sector size, typically 512 or 4096 bytes\n" +" -in file | stdin Input data\n" +" -out file | stdout Output data\n" +"\n" +"Examples\n" +"\n" +" $ DATA=`gmssl rand -outlen 2048`\n" +" $ KEY=`gmssl rand -outlen 32 -hex`\n" +" $ IV=`gmssl rand -outlen 16 -hex`\n" +" $ echo -n $DATA | gmssl sm4_xts -encrypt -key $KEY -iv $IV -data_unit_size 512 -out sm4_xts_ciphertext.bin\n" +" $ gmssl sm4_xts -decrypt -key $KEY -iv $IV -data_unit_size 512 -in sm4_xts_ciphertext.bin\n" +"\n"; + +int sm4_xts_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + int enc = -1; + char *keyhex = NULL; + char *ivhex = NULL; + int data_unit_size = 512; + char *infile = NULL; + char *outfile = NULL; + uint8_t key[32]; + size_t keylen; + uint8_t iv[16]; + size_t ivlen; + FILE *infp = stdin; + FILE *outfp = stdout; + SM4_XTS_CTX ctx; + uint8_t *buf = NULL; + size_t buflen; + size_t inlen; + size_t outlen; + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: gmssl %s %s\n", prog, usage); + return 1; + } + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + printf("usage: gmssl %s %s\n", prog, usage); + printf("%s\n", options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-encrypt")) { + if (enc == 0) { + fprintf(stderr, "gmssl %s: `-encrypt` `-decrypt` should not be used together\n", prog); + goto end; + } + enc = 1; + } else if (!strcmp(*argv, "-decrypt")) { + if (enc == 1) { + fprintf(stderr, "gmssl %s: `-encrypt` `-decrypt` should not be used together\n", prog); + goto end; + } + enc = 0; + } else if (!strcmp(*argv, "-key")) { + if (--argc < 1) goto bad; + keyhex = *(++argv); + if (strlen(keyhex) != sizeof(key) * 2) { + fprintf(stderr, "gmssl %s: invalid key length\n", prog); + goto end; + } + if (hex_to_bytes(keyhex, strlen(keyhex), key, &keylen) != 1) { + fprintf(stderr, "gmssl %s: invalid key hex digits\n", prog); + goto end; + } + } else if (!strcmp(*argv, "-iv")) { + if (--argc < 1) goto bad; + ivhex = *(++argv); + if (strlen(ivhex) != sizeof(iv) * 2) { + fprintf(stderr, "gmssl %s: invalid IV length\n", prog); + goto end; + } + if (hex_to_bytes(ivhex, strlen(ivhex), iv, &ivlen) != 1) { + fprintf(stderr, "gmssl %s: invalid IV hex digits\n", prog); + goto end; + } + } else if (!strcmp(*argv, "-data_unit_size")) { + if (--argc < 1) goto bad; + data_unit_size = atoi(*(++argv)); + if (data_unit_size < 16) { + fprintf(stderr, "gmssl %s: `-data_unit_size` should be larger than SM4 block size\n", prog); + goto end; + } + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "rb"))) { + fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "wb"))) { + fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else { + fprintf(stderr, "gmssl %s: illegal option `%s`\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "gmssl %s: `%s` option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (enc < 0) { + fprintf(stderr, "gmssl %s: option -encrypt or -decrypt should be set\n", prog); + goto end; + } + if (!keyhex) { + fprintf(stderr, "gmssl %s: option `-key` missing\n", prog); + goto end; + } + if (!ivhex) { + fprintf(stderr, "gmssl %s: option `-iv` missing\n", prog); + goto end; + } + + if (enc) { + if (sm4_xts_encrypt_init(&ctx, key, iv, data_unit_size) != 1) { + error_print(); + goto end; + } + } else { + if (sm4_xts_decrypt_init(&ctx, key, iv, data_unit_size) != 1) { + error_print(); + goto end; + } + } + + buflen = data_unit_size * 16; + if (!(buf = (uint8_t *)malloc(buflen))) { + fprintf(stderr, "gmssl %s: malloc failure\n", prog); + goto end; + } + + while ((inlen = fread(buf, 1, buflen, infp)) > 0) { + if (enc) { + if (sm4_xts_encrypt_update(&ctx, buf, inlen, buf, &outlen) != 1) { + error_print(); + goto end; + } + } else { + if (sm4_xts_decrypt_update(&ctx, buf, inlen, buf, &outlen) != 1) { + error_print(); + goto end; + } + } + if (fwrite(buf, 1, outlen, outfp) != outlen) { + fprintf(stderr, "gmssl %s: output failure : %s\n", prog, strerror(errno)); + goto end; + } + } + + if (enc) { + if (sm4_xts_encrypt_finish(&ctx, buf, &outlen) != 1) { + error_print(); + goto end; + } + } else { + if (sm4_xts_decrypt_finish(&ctx, buf, &outlen) != 1) { + error_print(); + goto end; + } + } + if (fwrite(buf, 1, outlen, outfp) != outlen) { + fprintf(stderr, "gmssl %s: output failure : %s\n", prog, strerror(errno)); + goto end; + } + + + ret = 0; + +end: + gmssl_secure_clear(key, sizeof(key)); + gmssl_secure_clear(iv, sizeof(iv)); + gmssl_secure_clear(&ctx, sizeof(ctx)); + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + if (buf) free(buf); + return ret; +}