From d649643d4bb486b20e83506ecc07b005b0f8a651 Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Fri, 20 May 2022 16:56:50 +0800 Subject: [PATCH] Add SM9 tools --- include/gmssl/sm9.h | 14 ++++++ tools/sm9decrypt.c | 99 +++++++++++++++++++++++++++++++++++- tools/sm9encrypt.c | 86 +++++++++++++++++++++++++++++++- tools/sm9keygen.c | 111 ++++++++++++++++++++++++++++++++++++++++- tools/sm9setup.c | 119 +++++++++++++++++++++++++++++++++++++++++++- tools/sm9sign.c | 101 ++++++++++++++++++++++++++++++++++++- tools/sm9verify.c | 109 +++++++++++++++++++++++++++++++++++++++- 7 files changed, 629 insertions(+), 10 deletions(-) diff --git a/include/gmssl/sm9.h b/include/gmssl/sm9.h index 718e5f7e..637edc58 100644 --- a/include/gmssl/sm9.h +++ b/include/gmssl/sm9.h @@ -445,6 +445,8 @@ typedef struct { int sm9_do_sign(const SM9_SIGN_KEY *key, const SM3_CTX *sm3_ctx, SM9_SIGNATURE *sig); int sm9_do_verify(const SM9_SIGN_MASTER_KEY *mpk, const char *id, size_t idlen, const SM3_CTX *sm3_ctx, const SM9_SIGNATURE *sig); + +#define SM9_MAX_SIGNATURE_SIZE 512 // TODO: calcalate this size int sm9_signature_to_der(const SM9_SIGNATURE *sig, uint8_t **out, size_t *outlen); int sm9_signature_from_der(SM9_SIGNATURE *sig, const uint8_t **in, size_t *inlen); @@ -516,6 +518,10 @@ int sm9_ciphertext_to_der(const sm9_point_t *C1, const uint8_t *c2, size_t c2len int sm9_ciphertext_from_der(sm9_point_t *C1, const uint8_t **c2, size_t *c2len, const uint8_t *c3[SM3_HMAC_SIZE], const uint8_t **in, size_t *inlen); +#define SM9_MAX_PLAINTEXT_SIZE 512 // FIXME +#define SM9_MAX_CIPHERTEXT_SIZE 512 // FIXME + + int sm9_kem_encrypt(const SM9_ENC_MASTER_KEY *mpk, const char *id, size_t idlen, size_t klen, uint8_t *kbuf, sm9_point_t *C); int sm9_kem_decrypt(const SM9_ENC_KEY *key, const char *id, size_t idlen, const sm9_point_t *C, size_t klen, uint8_t *kbuf); @@ -542,6 +548,14 @@ int sm9_enc_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_E int sm9_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen); int sm9_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen); +const char *sm9_oid_name(int oid); +int sm9_oid_from_name(const char *name); +int sm9_oid_to_der(int oid, uint8_t **out, size_t *outlen); +int sm9_oid_from_der(int *oid, const uint8_t **in, size_t *inlen); +int sm9_algor_to_der(int alg, int params, uint8_t **out, size_t *outlen); +int sm9_algor_from_der(int *alg, int *params, const uint8_t **in, size_t *inlen); + + # ifdef __cplusplus } diff --git a/tools/sm9decrypt.c b/tools/sm9decrypt.c index 7c5209d4..51c2c677 100644 --- a/tools/sm9decrypt.c +++ b/tools/sm9decrypt.c @@ -49,12 +49,107 @@ #include #include #include +#include #include #include +static const char *options = "[-in file] -key file -pass str -id str [-out file]"; + int sm9decrypt_main(int argc, char **argv) { - fprintf(stderr, "%s: not implemented\n", argv[0]); - return 1; + int ret = 1; + char *prog = argv[0]; + char *infile = NULL; + char *keyfile = NULL; + char *pass = NULL; + char *id = NULL; + char *outfile = NULL; + FILE *keyfp = NULL; + FILE *infp = stdin; + FILE *outfp = stdout; + SM9_ENC_KEY key; + uint8_t inbuf[SM9_MAX_CIPHERTEXT_SIZE]; + uint8_t outbuf[SM9_MAX_CIPHERTEXT_SIZE]; + size_t inlen, outlen; + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + fprintf(stdout, "usage: %s %s\n", prog, options); + return 0; + } else if (!strcmp(*argv, "-key")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + if (!(keyfp = fopen(keyfile, "r"))) { + error_print(); + goto end; + } + } else if (!strcmp(*argv, "-pass")) { + if (--argc < 1) goto bad; + pass = *(++argv); + } else if (!strcmp(*argv, "-id")) { + if (--argc < 1) goto bad; + id = *(++argv); + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(outfile, "r"))) { + error_print(); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + error_print(); + goto end; + } + } else { +bad: + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + return 1; + } + + argc--; + argv++; + } + + if (!keyfile || !pass || !id) { + error_print(); + goto end; + } + + if (sm9_enc_key_info_decrypt_from_pem(&key, pass, keyfp) != 1) { + error_print(); + goto end; + } + if ((inlen = fread(inbuf, 1, sizeof(inbuf), infp)) <= 0) { + error_print(); + goto end; + } + if (sm9_decrypt(&key, id, strlen(id), inbuf, inlen, outbuf, &outlen) != 1) { + error_print(); + goto end; + } + if (outlen != fwrite(outbuf, 1, outlen, outfp)) { + error_print(); + goto end; + } + ret = 0; + +end: + gmssl_secure_clear(&key, sizeof(key)); + gmssl_secure_clear(outbuf, sizeof(outbuf)); + if (keyfp) fclose(keyfp); + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + return ret; } diff --git a/tools/sm9encrypt.c b/tools/sm9encrypt.c index 767c4db7..55ffa745 100644 --- a/tools/sm9encrypt.c +++ b/tools/sm9encrypt.c @@ -53,8 +53,90 @@ #include +static const char *options = "-pubmaster file -id str [-in file] [-out file]"; + + int sm9encrypt_main(int argc, char **argv) { - fprintf(stderr, "%s: not implemented\n", argv[0]); - return 1; + int ret = 1; + char *prog = argv[0]; + char *mpkfile = NULL; + char *id = NULL; + char *infile = NULL; + char *outfile = NULL; + FILE *mpkfp = NULL; + FILE *infp = stdin; + FILE *outfp = stdout; + SM9_ENC_MASTER_KEY mpk; + uint8_t inbuf[SM9_MAX_PLAINTEXT_SIZE]; + uint8_t outbuf[SM9_MAX_CIPHERTEXT_SIZE]; + size_t inlen, outlen = sizeof(outbuf); + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + fprintf(stdout, "usage: %s %s\n", prog, options); + return 0; + } else if (!strcmp(*argv, "-pubmaster")) { + if (--argc < 1) goto bad; + mpkfile = *(++argv); + if (!(mpkfp = fopen(mpkfile, "r"))) { + error_print(); + goto end; + } + } else if (!strcmp(*argv, "-id")) { + if (--argc < 1) goto bad; + id = *(++argv); + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(outfile, "r"))) { + error_print(); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + error_print(); + goto end; + } + } else { +bad: + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + return 1; + } + + argc--; + argv++; + } + + if (!mpkfile || !id) { + error_print(); + goto end; + } + if ((inlen = fread(inbuf, 1, sizeof(inbuf), infp)) <= 0) { + error_print(); + goto end; + } + if (sm9_encrypt(&mpk, id, strlen(id), inbuf, inlen, outbuf, &outlen) != 1) { + error_print(); + goto end; + } + if (outlen != fwrite(outbuf, 1, outlen, outfp)) { + error_print(); + goto end; + } + ret = 0; +end: + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + return ret; } diff --git a/tools/sm9keygen.c b/tools/sm9keygen.c index b3aa2e28..44ba9a46 100644 --- a/tools/sm9keygen.c +++ b/tools/sm9keygen.c @@ -49,12 +49,121 @@ #include #include #include +#include +#include #include #include +static const char *options = "-alg (sm9sign|sm9encrypt) -in master_key.pem -inpass str -id str [-out pem] -outpass str"; int sm9keygen_main(int argc, char **argv) { - fprintf(stderr, "%s: not implemented\n", argv[0]); + int ret = -1; + char *prog = argv[0]; + char *alg = NULL; + char *infile = NULL; + char *inpass = NULL; + char *id = NULL; + char *outfile = NULL; + char *outpass = NULL; + int oid = 0; + FILE *infp = stdin; + FILE *outfp = stdout; + SM9_SIGN_MASTER_KEY sign_msk; + SM9_ENC_MASTER_KEY enc_msk; + SM9_SIGN_KEY sign_key; + SM9_ENC_KEY enc_key; + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + fprintf(stdout, "usage: %s %s\n", prog, options); + return 0; + } else if (!strcmp(*argv, "-alg")) { + if (--argc < 1) goto bad; + alg = *(++argv); + if ((oid = sm9_oid_from_name(alg)) < 1) { + fprintf(stdout, "%s: invalid alg '%s', should be sm9sign or sm9encrypt\n", prog, alg); + goto end; + } + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "r"))) { + error_print(); + goto end; + } + } else if (!strcmp(*argv, "-inpass")) { + if (--argc < 1) goto bad; + inpass = *(++argv); + } else if (!strcmp(*argv, "-id")) { + if (--argc < 1) goto bad; + id = *(++argv); + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + error_print(); + goto end; + } + } else if (!strcmp(*argv, "-outpass")) { + if (--argc < 1) goto bad; + outpass = *(++argv); + } else { +bad: + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + return 1; + } + + + argc--; + argv++; + } + + if (!id) { + fprintf(stderr, "%s: option '-id' is required\n", prog); + goto end; + } + if (!inpass || !outpass) { + error_print(); + goto end; + } + + switch (oid) { + case OID_sm9sign: + if (sm9_sign_master_key_info_decrypt_from_pem(&sign_msk, inpass, infp) != 1 + || sm9_sign_master_key_extract_key(&sign_msk, id, strlen(id), &sign_key) != 1 + || sm9_sign_key_info_encrypt_to_pem(&sign_key, outpass, outfp) != 1) { + error_print(); + goto end; + } + break; + case OID_sm9encrypt: + if (sm9_enc_master_key_info_decrypt_from_pem(&enc_msk, inpass, infp) != 1 + || sm9_enc_master_key_extract_key(&enc_msk, id, strlen(id), &enc_key) != 1 + || sm9_enc_key_info_encrypt_to_pem(&enc_key, outpass, outfp) != 1) { + error_print(); + goto end; + } + break; + default: + error_print(); + goto end; + } + ret = 0; +end: + gmssl_secure_clear(&sign_msk, sizeof(sign_msk)); + gmssl_secure_clear(&enc_msk, sizeof(enc_msk)); + gmssl_secure_clear(&sign_key, sizeof(sign_key)); + gmssl_secure_clear(&enc_key, sizeof(enc_key)); + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); return 1; } diff --git a/tools/sm9setup.c b/tools/sm9setup.c index fbac6424..d5b2f292 100644 --- a/tools/sm9setup.c +++ b/tools/sm9setup.c @@ -49,12 +49,129 @@ #include #include #include +#include +#include #include #include +static const char *options = "-alg (sm9sign|sm9encrypt) [-pass password] [-out pem] [-pubout pem]"; int sm9setup_main(int argc, char **argv) { - fprintf(stderr, "%s: not implemented\n", argv[0]); + int ret = 1; + char *prog = argv[0]; + char *alg = NULL; + char *pass = NULL; + char *outfile = NULL; + char *puboutfile = NULL; + int oid; + FILE *outfp = stdout; + FILE *puboutfp = stdout; + SM9_SIGN_MASTER_KEY sign_msk; + SM9_ENC_MASTER_KEY enc_msk; + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + fprintf(stdout, "usage: %s %s\n", prog, options); + return 0; + } else if (!strcmp(*argv, "-alg")) { + if (--argc < 1) goto bad; + alg = *(++argv); + if ((oid = sm9_oid_from_name(alg)) < 1) { + fprintf(stdout, "%s: invalid alg '%s', should be sm9sign or sm9encrypt\n", prog, alg); + goto end; + } + } else if (!strcmp(*argv, "-pass")) { + if (--argc < 1) goto bad; + pass = *(++argv); + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + error_print(); + goto end; + } + } else if (!strcmp(*argv, "-pubout")) { + if (--argc < 1) goto bad; + puboutfile = *(++argv); + if (!(puboutfp = fopen(puboutfile, "w"))) { + error_print(); + goto end; + } + } else { +bad: + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + return 1; + } + + argc--; + argv++; + } + + if (!alg) { + error_print(); + return -1; + } + if (!pass) { + error_print(); + return -1; + } + + switch (oid) { + case OID_sm9sign: + if (sm9_sign_master_key_generate(&sign_msk) != 1 + || sm9_sign_master_key_info_encrypt_to_pem(&sign_msk, pass, outfp) != 1 + || sm9_sign_master_public_key_to_pem(&sign_msk, puboutfp) != 1) { + error_print(); + goto end; + } + break; + case OID_sm9encrypt: + if (sm9_enc_master_key_generate(&enc_msk) != 1 + || sm9_enc_master_key_info_encrypt_to_pem(&enc_msk, pass, outfp) != 1 + || sm9_enc_master_public_key_to_pem(&enc_msk, puboutfp) != 1) { + error_print(); + goto end; + } + break; + default: + error_print(); + goto end; + } + ret = 0; + +end: + gmssl_secure_clear(&sign_msk, sizeof(sign_msk)); + gmssl_secure_clear(&enc_msk, sizeof(enc_msk)); + if (outfile && outfp) fclose(outfp); + if (puboutfile && puboutfp) fclose(puboutfp); return 1; } + + + + + + + + + + + + + + + + + + + + diff --git a/tools/sm9sign.c b/tools/sm9sign.c index eb350939..5a9995f9 100644 --- a/tools/sm9sign.c +++ b/tools/sm9sign.c @@ -49,12 +49,109 @@ #include #include #include +#include #include #include +static const char *options = "[-in file] -key file -pass str [-out file]"; + + int sm9sign_main(int argc, char **argv) { - fprintf(stderr, "%s: not implemented\n", argv[0]); - return 1; + int ret = 1; + char *prog = argv[0]; + char *infile = NULL; + char *keyfile = NULL; + char *pass = NULL; + char *outfile = NULL; + FILE *infp = stdin; + FILE *keyfp = NULL; + FILE *outfp = stdout; + SM9_SIGN_KEY key; + SM9_SIGN_CTX ctx; + uint8_t buf[4096]; + ssize_t len; + uint8_t sig[SM9_MAX_SIGNATURE_SIZE]; + size_t siglen; + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + fprintf(stdout, "usage: %s %s\n", prog, options); + return 0; + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "w"))) { + error_print(); + goto end; + } + } else if (!strcmp(*argv, "-key")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + if (!(keyfp = fopen(keyfile, "w"))) { + error_print(); + goto end; + } + } else if (!strcmp(*argv, "-pass")) { + if (--argc < 1) goto bad; + pass = *(++argv); + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + error_print(); + goto end; + } + } else { +bad: + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + return 1; + } + + argc--; + argv++; + } + + if (!keyfile || !pass) { + error_print(); + goto end; + } + + if (sm9_sign_key_info_decrypt_from_pem(&key, pass, keyfp) != 1) { + error_print(); + return -1; + } + + if (sm9_sign_init(&ctx) != 1) { + error_print(); + goto end; + } + while ((len = fread(buf, 1, sizeof(buf), infp)) > 0) { + if (sm9_sign_update(&ctx, buf, len) != 1) { + error_print(); + goto end; + } + } + if (sm9_sign_finish(&ctx, &key, sig, &siglen) != 1) { + error_print(); + goto end; + } + ret = 0; + +end: + gmssl_secure_clear(&key, sizeof(key)); + gmssl_secure_clear(&ctx, sizeof(ctx)); + gmssl_secure_clear(buf, sizeof(buf)); + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + return ret; } diff --git a/tools/sm9verify.c b/tools/sm9verify.c index 95c6fffc..bbdfe42a 100644 --- a/tools/sm9verify.c +++ b/tools/sm9verify.c @@ -53,8 +53,113 @@ #include +static const char *options = "[-in file] -pubmaster file -id str -sig file"; + int sm9verify_main(int argc, char **argv) { - fprintf(stderr, "%s: not implemented\n", argv[0]); - return 1; + int ret = 1; + char *prog = argv[0]; + char *infile = NULL; + char *mpkfile = NULL; + char *id = NULL; + char *sigfile = NULL; + FILE *infp = stdin; + FILE *mpkfp = NULL; + FILE *sigfp = NULL; + SM9_SIGN_MASTER_KEY mpk; + SM9_SIGN_CTX ctx; + uint8_t buf[4096]; + ssize_t len; + uint8_t sig[SM9_MAX_SIGNATURE_SIZE]; + ssize_t siglen; + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + fprintf(stdout, "usage: %s %s\n", prog, options); + return 0; + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "w"))) { + error_print(); + goto end; + } + } else if (!strcmp(*argv, "-pubmaster")) { + if (--argc < 1) goto bad; + mpkfile = *(++argv); + if (!(mpkfp = fopen(mpkfile, "w"))) { + error_print(); + goto end; + } + } else if (!strcmp(*argv, "-id")) { + if (--argc < 1) goto bad; + id = *(++argv); + } else if (!strcmp(*argv, "-sig")) { + if (--argc < 1) goto bad; + sigfile = *(++argv); + if (!(sigfp = fopen(sigfile, "w"))) { + error_print(); + goto end; + } + } else { +bad: + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + return 1; + } + + argc--; + argv++; + } + + if (!mpkfile || !id || !sigfile) { + error_print(); + goto end; + } + + if (sm9_sign_master_public_key_from_pem(&mpk, mpkfp) != 1) { + error_print(); + goto end; + } + + if ((siglen = fread(sig, 1, sizeof(sig), sigfp)) <= 0) { + error_print(); + goto end; + } + + if (sm9_verify_init(&ctx) != 1) { + error_print(); + goto end; + } + while ((len = fread(buf, 1, sizeof(buf), infp)) > 0) { + if (sm9_verify_update(&ctx, buf, len) != 1) { + error_print(); + goto end; + } + } + if ((ret = sm9_verify_finish(&ctx, sig, siglen, &mpk, id, strlen(id))) != 1) { + error_print(); + goto end; + } + +end: + if (infile && infp) fclose(infp); + if (mpkfile && mpkfp) fclose(mpkfp); + if (sigfile && sigfp) fclose(sigfp); + return ret; } + + + + + + + +