mirror of
https://github.com/guanzhi/GmSSL.git
synced 2026-05-06 16:36:16 +08:00
Add SPHINCS+ commands to gmssl
Add `sphincskeygen`, `sphincssign`, `sphincsverify`
This commit is contained in:
@@ -56,7 +56,7 @@ option(ENABLE_SM2_EXTS "Enable SM2 Extensions" OFF)
|
||||
|
||||
option(ENABLE_LMS_HSS "Enable LMS/HSS signature" ON)
|
||||
option(ENABLE_XMSS "Enable XMSS/XMSS^MT signature" ON)
|
||||
option(ENABLE_SPHINCS "Enable SPHINCS+ signature" OFF)
|
||||
option(ENABLE_SPHINCS "Enable SPHINCS+ signature" ON)
|
||||
option(ENABLE_KYBER "Enable Kyber" OFF)
|
||||
|
||||
option(ENABLE_SHA1 "Enable SHA1" ON)
|
||||
@@ -454,7 +454,7 @@ if (ENABLE_SPHINCS)
|
||||
message(STATUS "ENABLE_SPHINCS is ON")
|
||||
add_definitions(-DENABLE_SPHINCS)
|
||||
list(APPEND src src/sphincs.c)
|
||||
#list(APPEND tools tools/sphincskeygen.c tools/sphincssign.c tools/sphincsverify.c)
|
||||
list(APPEND tools tools/sphincskeygen.c tools/sphincssign.c tools/sphincsverify.c)
|
||||
list(APPEND tests sphincs)
|
||||
|
||||
option(ENABLE_SPHINCS_CROSSCHECK "Enable SPHINCS SHA-256 cross-check" ON)
|
||||
@@ -486,6 +486,7 @@ if (ENABLE_SHA2)
|
||||
message(STATUS "ENABLE_SHA2 is ON")
|
||||
add_definitions(-DENABLE_SHA2)
|
||||
list(APPEND src src/sha256.c src/sha512.c)
|
||||
list(APPEND src src/sha256_hmac.c)
|
||||
list(APPEND tests sha224 sha256 sha384 sha512)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -32,12 +32,20 @@ extern "C" {
|
||||
# define hash256_update sha256_update
|
||||
# define hash256_finish sha256_finish
|
||||
# define HASH256_BLOCK_SIZE SHA256_BLOCK_SIZE
|
||||
# define HASH256_HMAC_CTX SHA256_HMAC_CTX
|
||||
# define hash256_hmac_init sha256_hmac_init
|
||||
# define hash256_hmac_update sha256_hmac_update
|
||||
# define hash256_hmac_finish sha256_hmac_finish
|
||||
#else
|
||||
# define HASH256_CTX SM3_CTX
|
||||
# define hash256_init sm3_init
|
||||
# define hash256_update sm3_update
|
||||
# define hash256_finish sm3_finish
|
||||
# define HASH256_BLOCK_SIZE SM3_BLOCK_SIZE
|
||||
# define HASH256_HMAC_CTX SM3_HMAC_CTX
|
||||
# define hash256_hmac_init sm3_hmac_init
|
||||
# define hash256_hmac_update sm3_hmac_update
|
||||
# define hash256_hmac_finish sm3_hmac_finish
|
||||
#endif
|
||||
|
||||
|
||||
@@ -256,7 +264,6 @@ void sphincs_wots_pk_to_root(const sphincs_wots_key_t pk,
|
||||
total: 30 bytes, 1 MGF1-SM3 output
|
||||
|
||||
|
||||
|
||||
SPHINCS+_128f/SM3
|
||||
|
||||
1. fors_index: 6 * 33 = 198 bits = 25 bytes
|
||||
@@ -266,6 +273,14 @@ void sphincs_wots_pk_to_root(const sphincs_wots_key_t pk,
|
||||
|
||||
*/
|
||||
|
||||
#define SPHINCS_TBS_SIZE 30 // sphincs+_128s
|
||||
|
||||
#define SPHINCS_TBS_FORS_SIZE 21
|
||||
#define SPHINCS_TBS_TREE_ADDRESS_SIZE 7
|
||||
#define SPHINCS_TBS_KEYPAIR_ADDRESS_SIZE 2
|
||||
|
||||
|
||||
// #define SPHINCS_TBS_SIZE 34 // sphincs+_128f
|
||||
|
||||
|
||||
void sphincs_xmss_tree_hash(
|
||||
@@ -285,9 +300,15 @@ void sphincs_xmss_build_root(const sphincs_hash128_t wots_root, uint32_t tree_in
|
||||
|
||||
typedef struct {
|
||||
sphincs_wots_sig_t wots_sig;
|
||||
sphincs_hash128_t auth_path[22]; // sphincs+_128f height = 22
|
||||
sphincs_hash128_t auth_path[SPHINCS_XMSS_HEIGHT];
|
||||
} SPHINCS_XMSS_SIGNATURE;
|
||||
|
||||
int sphincs_xmss_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const SPHINCS_XMSS_SIGNATURE *sig);
|
||||
int sphincs_xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen);
|
||||
int sphincs_xmss_signature_to_bytes(const SPHINCS_XMSS_SIGNATURE *sig, uint8_t **out, size_t *outlen);
|
||||
int sphincs_xmss_signature_from_bytes(SPHINCS_XMSS_SIGNATURE *sig, const uint8_t **in, size_t *inlen);
|
||||
|
||||
|
||||
void sphincs_xmss_sign(const sphincs_hash128_t secret,
|
||||
const sphincs_hash128_t seed, const sphincs_adrs_t adrs, uint32_t keypair_address,
|
||||
const sphincs_hash128_t tbs_root, // to be signed xmss_root or fors_forest_root
|
||||
@@ -361,6 +382,8 @@ typedef struct {
|
||||
#define SPHINCS_PUBLIC_KEY_SIZE sizeof(SPHINCS_PUBLIC_KEY)
|
||||
#define SPHINCS_PRIVATE_KEY_SIZE sizeof(SPHINCS_KEY)
|
||||
|
||||
int sphincs_key_generate(SPHINCS_KEY *key);
|
||||
|
||||
int sphincs_public_key_to_bytes(const SPHINCS_KEY *key, uint8_t **out, size_t *outlen);
|
||||
int sphincs_public_key_from_bytes(SPHINCS_KEY *key, const uint8_t **in, size_t *inlen);
|
||||
int sphincs_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SPHINCS_KEY *key);
|
||||
@@ -370,12 +393,15 @@ int sphincs_private_key_print(FILE *fp, int fmt, int ind, const char *label, con
|
||||
void sphincs_key_cleanup(SPHINCS_KEY *key);
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
sphincs_hash128_t random;
|
||||
SPHINCS_FORS_SIGNATURE fors_sig;
|
||||
SPHINCS_XMSS_SIGNATURE xmss_sigs[SPHINCS_HYPERTREE_LAYERS];
|
||||
} SPHINCS_SIGNATURE;
|
||||
|
||||
#define SPHINCS_SIGNATURE_SIZE sizeof(SPHINCS_SIGNATURE)
|
||||
int sphincs_signature_to_bytes(const SPHINCS_SIGNATURE *sig, uint8_t **out, size_t *outlen);
|
||||
int sphincs_signature_from_bytes(SPHINCS_SIGNATURE *sig, const uint8_t **in, size_t *inlen);
|
||||
int sphincs_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const SPHINCS_SIGNATURE *sig);
|
||||
@@ -383,6 +409,41 @@ int sphincs_signature_print(FILE *fp, int fmt, int ind, const char *label, const
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
HASH256_HMAC_CTX hmac_ctx;
|
||||
HASH256_CTX hash_ctx;
|
||||
SPHINCS_SIGNATURE sig;
|
||||
int state; // after init 0, after prepare 1, after update 2
|
||||
size_t round1_msglen;
|
||||
size_t round2_msglen;
|
||||
SPHINCS_KEY key;
|
||||
} SPHINCS_SIGN_CTX;
|
||||
|
||||
int sphincs_sign_init_ex(SPHINCS_SIGN_CTX *ctx, const SPHINCS_KEY *key, int randomize);
|
||||
int sphincs_sign_init(SPHINCS_SIGN_CTX *ctx, const SPHINCS_KEY *key);
|
||||
int sphincs_sign_prepare(SPHINCS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
|
||||
int sphincs_sign_update(SPHINCS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
|
||||
int sphincs_sign_finish_ex(SPHINCS_SIGN_CTX *ctx, SPHINCS_SIGNATURE *sig);
|
||||
int sphincs_sign_finish(SPHINCS_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen);
|
||||
int sphincs_verify_init_ex(SPHINCS_SIGN_CTX *ctx, const SPHINCS_KEY *key, const SPHINCS_SIGNATURE *sig);
|
||||
int sphincs_verify_init(SPHINCS_SIGN_CTX *ctx, const SPHINCS_KEY *key, const uint8_t *sig, size_t siglen);
|
||||
int sphincs_verify_update(SPHINCS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
|
||||
int sphincs_verify_finish(SPHINCS_SIGN_CTX *ctx);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -425,29 +425,212 @@ static int test_sphincs_fors_sign(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int test_sphincs_sign(void)
|
||||
{
|
||||
SPHINCS_KEY key;
|
||||
SPHINCS_KEY _key;
|
||||
SPHINCS_KEY *key = &_key;
|
||||
uint8_t msg[100] = {1, 2, 3, 0};
|
||||
SPHINCS_SIGNATURE _sig;
|
||||
SPHINCS_SIGNATURE *sig = &_sig;
|
||||
HASH256_CTX hash_ctx;
|
||||
HASH256_HMAC_CTX hmac_ctx;
|
||||
hash256_t dgst;
|
||||
|
||||
|
||||
sphincs_hash128_t opt_rand;
|
||||
|
||||
|
||||
sphincs_adrs_t adrs = {0};
|
||||
sphincs_hash128_t random;
|
||||
sphincs_hash128_t fors_forest_root;
|
||||
|
||||
uint8_t tree_address_buf[8] = {0};
|
||||
uint8_t keypair_address_buf[4] = {0};
|
||||
|
||||
uint64_t tree_address;
|
||||
uint32_t keypair_address;
|
||||
|
||||
int randomize = 0;
|
||||
uint32_t i;
|
||||
|
||||
uint8_t tbs[SPHINCS_TBS_SIZE];
|
||||
|
||||
if (sphincs_key_generate(key) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
uint32_t tree_index;
|
||||
uint32_t leaf_index;
|
||||
// set opt_rand
|
||||
memcpy(opt_rand, key->public_key.seed, sizeof(sphincs_hash128_t));
|
||||
if (randomize) {
|
||||
if (rand_bytes(opt_rand, sizeof(opt_rand)) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果R是用M生成的,这意味着M要读取2遍,这就没办法用init/update范式了
|
||||
|
||||
// R = PRF_msg(sk_prf, optrand, M) = HMAC(sk_prf, opt_rand|M)
|
||||
hash256_hmac_init(&hmac_ctx, key->sk_prf, sizeof(sphincs_hash128_t));
|
||||
hash256_hmac_update(&hmac_ctx, opt_rand, sizeof(sphincs_hash128_t));
|
||||
hash256_hmac_update(&hmac_ctx, msg, sizeof(msg));
|
||||
hash256_hmac_finish(&hmac_ctx, dgst);
|
||||
memcpy(sig->random, dgst, sizeof(sphincs_hash128_t));
|
||||
|
||||
// dgst = HASH256(R|seed|root|M)
|
||||
hash256_init(&hash_ctx);
|
||||
hash256_update(&hash_ctx, sig->random, sizeof(sphincs_hash128_t));
|
||||
hash256_update(&hash_ctx, key->public_key.seed, sizeof(sphincs_hash128_t));
|
||||
hash256_update(&hash_ctx, key->public_key.root, sizeof(sphincs_hash128_t));
|
||||
hash256_update(&hash_ctx, msg, sizeof(msg));
|
||||
hash256_finish(&hash_ctx, dgst);
|
||||
|
||||
// tbs = H_msg(R, seed, root, M) = MGF1(R|seed|dgst, tbs_len)
|
||||
for (i = 0; i < (SPHINCS_TBS_SIZE + 31)/32; i++) {
|
||||
uint8_t count[4];
|
||||
PUTU32(count, i);
|
||||
hash256_init(&hash_ctx);
|
||||
hash256_update(&hash_ctx, sig->random, sizeof(sphincs_hash128_t));
|
||||
hash256_update(&hash_ctx, key->public_key.seed, sizeof(sphincs_hash128_t));
|
||||
hash256_update(&hash_ctx, dgst, sizeof(dgst));
|
||||
hash256_update(&hash_ctx, count, sizeof(count));
|
||||
hash256_finish(&hash_ctx, tbs + sizeof(dgst) * i);
|
||||
}
|
||||
|
||||
|
||||
// get tree_address from tbs
|
||||
memcpy(tree_address_buf + 8 - 7, tbs + 21, 7);
|
||||
tree_address = GETU64(tree_address_buf); // 54 bits
|
||||
tree_address >>= 10;
|
||||
|
||||
// get keypair_address from tbs
|
||||
memcpy(keypair_address_buf + 4 - 2, tbs + 21 + 7, 2);
|
||||
keypair_address = GETU32(keypair_address_buf);
|
||||
keypair_address >>= (16 - 9);
|
||||
|
||||
|
||||
|
||||
format_bytes(stderr, 0, 4, "tree_address", tree_address_buf, 8);
|
||||
format_bytes(stderr, 0, 4, "keypair_address", keypair_address_buf, 4);
|
||||
|
||||
|
||||
fprintf(stderr, "tree_address %zu\n", (size_t)tree_address);
|
||||
fprintf(stderr, "keypair_address %zu\n", (size_t)keypair_address);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// fors_sign
|
||||
sphincs_adrs_set_layer_address(adrs, 0);
|
||||
sphincs_adrs_set_tree_address(adrs, tree_index);
|
||||
sphincs_adrs_set_tree_address(adrs, tree_address);
|
||||
sphincs_adrs_set_type(adrs, SPHINCS_ADRS_TYPE_FORS_TREE);
|
||||
sphincs_adrs_set_keypair_address(adrs, leaf_index);
|
||||
sphincs_adrs_set_keypair_address(adrs, keypair_address);
|
||||
sphincs_fors_sign(key->secret, key->public_key.seed, adrs, tbs, &sig->fors_sig);
|
||||
|
||||
// fors_sig => fors_forest_root
|
||||
sphincs_fors_sig_to_root(&sig->fors_sig, key->public_key.seed, adrs, tbs, fors_forest_root);
|
||||
|
||||
|
||||
error_print();
|
||||
|
||||
|
||||
|
||||
// hypertree_sign fors_forest_root
|
||||
sphincs_adrs_set_type(adrs, SPHINCS_ADRS_TYPE_TREE);
|
||||
sphincs_hypertree_sign(key->secret, key->public_key.seed, tree_address, keypair_address,
|
||||
fors_forest_root, sig->xmss_sigs);
|
||||
|
||||
|
||||
error_print();
|
||||
|
||||
|
||||
|
||||
// sphincs_verify
|
||||
// --------------
|
||||
|
||||
|
||||
// fors_sig => fors_forest_root
|
||||
sphincs_adrs_set_layer_address(adrs, 0);
|
||||
sphincs_adrs_set_tree_address(adrs, tree_address);
|
||||
sphincs_adrs_set_type(adrs, SPHINCS_ADRS_TYPE_FORS_TREE);
|
||||
sphincs_adrs_set_keypair_address(adrs, keypair_address);
|
||||
|
||||
sphincs_fors_sig_to_root(&sig->fors_sig, key->public_key.seed, adrs, tbs, fors_forest_root);
|
||||
|
||||
// hypertree_verify
|
||||
sphincs_adrs_set_type(adrs, SPHINCS_ADRS_TYPE_TREE);
|
||||
|
||||
if (sphincs_hypertree_verify(key->public_key.root, key->public_key.seed,
|
||||
tree_address, keypair_address, fors_forest_root, sig->xmss_sigs) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
printf("%s() ok\n", __FUNCTION__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int test_sphincs_sign_update(void)
|
||||
{
|
||||
SPHINCS_KEY key;
|
||||
SPHINCS_SIGN_CTX ctx;
|
||||
SPHINCS_SIGNATURE sig;
|
||||
uint8_t msg[100] = { 1,2,3 };
|
||||
|
||||
if (sphincs_key_generate(&key) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sphincs_sign_init(&ctx, &key) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
if (sphincs_sign_prepare(&ctx, msg, sizeof(msg)) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
if (sphincs_sign_update(&ctx, msg, sizeof(msg)) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
if (sphincs_sign_finish_ex(&ctx, &sig) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// verify
|
||||
|
||||
if (sphincs_verify_init_ex(&ctx, &key, &sig) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
if (sphincs_verify_update(&ctx, msg, sizeof(msg)) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
if (sphincs_verify_finish(&ctx) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
printf("%s() ok\n", __FUNCTION__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (test_sphincs_fors_sign() != 1) goto err;
|
||||
if (test_sphincs_sign_update() != 1) goto err;
|
||||
// if (test_sphincs_sign() != 1) goto err;
|
||||
// if (test_sphincs_fors_sign() != 1) goto err;
|
||||
//if (test_sphincs_xmss_build_tree() != 1) goto err;
|
||||
//if (test_sphincs_hypertree() != 1) goto err;
|
||||
// if (test_sphincs_hypertree_sign() != 1) goto err;
|
||||
|
||||
@@ -80,6 +80,11 @@ extern int xmssmtkeygen_main(int argc, char **argv);
|
||||
extern int xmssmtsign_main(int argc, char **argv);
|
||||
extern int xmssmtverify_main(int argc, char **argv);
|
||||
#endif
|
||||
#ifdef ENABLE_SPHINCS
|
||||
extern int sphincskeygen_main(int argc, char **argv);
|
||||
extern int sphincssign_main(int argc, char **argv);
|
||||
extern int sphincsverify_main(int argc, char **argv);
|
||||
#endif
|
||||
#ifdef ENABLE_KYBER
|
||||
extern int kyberkeygen_main(int argc, char **argv);
|
||||
extern int kyberencap_main(int argc, char **argv);
|
||||
@@ -165,6 +170,11 @@ static const char *options =
|
||||
" xmssmtsign Generate XMSS^MT-SM3 signature\n"
|
||||
" xmssmtverify Verify XMSS^MT-SM3 signature\n"
|
||||
#endif
|
||||
#ifdef ENABLE_SPHINCS
|
||||
" sphincskeygen Generate SPHINCS+_128s-SM3 keypair\n"
|
||||
" sphincssign Generate SPHINCS+_128s-SM3 signature\n"
|
||||
" sphincsverify Verify SPHINCS+_128s-SM3 signature\n"
|
||||
#endif
|
||||
#ifdef ENABLE_KYBER
|
||||
" kyberkeygen Generate Kyber keypair\n"
|
||||
" kyberencap Kyber KEM encap\n"
|
||||
@@ -352,6 +362,14 @@ int main(int argc, char **argv)
|
||||
} else if (!strcmp(*argv, "xmssmtverify")) {
|
||||
return xmssmtverify_main(argc, argv);
|
||||
#endif
|
||||
#ifdef ENABLE_SPHINCS
|
||||
} else if (!strcmp(*argv, "sphincskeygen")) {
|
||||
return sphincskeygen_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "sphincssign")) {
|
||||
return sphincssign_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "sphincsverify")) {
|
||||
return sphincsverify_main(argc, argv);
|
||||
#endif
|
||||
#ifdef ENABLE_KYBER
|
||||
} else if (!strcmp(*argv, "kyberkeygen")) {
|
||||
return kyberkeygen_main(argc, argv);
|
||||
|
||||
132
tools/sphincskeygen.c
Normal file
132
tools/sphincskeygen.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2014-2026 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 <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <gmssl/mem.h>
|
||||
#include <gmssl/error.h>
|
||||
#include <gmssl/sphincs.h>
|
||||
|
||||
|
||||
static const char *usage = "-out file [-pubout file] [-verbose]\n";
|
||||
|
||||
static const char *options =
|
||||
"Options\n"
|
||||
" -out file Output private key\n"
|
||||
" -pubout file Output public key\n"
|
||||
" -verbose Print public key\n"
|
||||
"\n";
|
||||
|
||||
int sphincskeygen_main(int argc, char **argv)
|
||||
{
|
||||
int ret = 1;
|
||||
char *prog = argv[0];
|
||||
char *outfile = NULL;
|
||||
char *puboutfile = NULL;
|
||||
int verbose = 0;
|
||||
FILE *outfp = NULL;
|
||||
FILE *puboutfp = stdout;
|
||||
SPHINCS_KEY key;
|
||||
uint8_t out[SPHINCS_PRIVATE_KEY_SIZE];
|
||||
uint8_t *pout = out;
|
||||
size_t outlen = 0;
|
||||
uint8_t pubout[SPHINCS_PUBLIC_KEY_SIZE];
|
||||
uint8_t *ppubout = pubout;
|
||||
size_t puboutlen = 0;
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
|
||||
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, "-out")) {
|
||||
if (--argc < 1) goto bad;
|
||||
outfile = *(++argv);
|
||||
if (!(outfp = fopen(outfile, "wb"))) {
|
||||
fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
} else if (!strcmp(*argv, "-pubout")) {
|
||||
if (--argc < 1) goto bad;
|
||||
puboutfile = *(++argv);
|
||||
if (!(puboutfp = fopen(puboutfile, "wb"))) {
|
||||
fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
} else if (!strcmp(*argv, "-verbose")) {
|
||||
verbose = 1;
|
||||
} else {
|
||||
fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv);
|
||||
goto end;
|
||||
bad:
|
||||
fprintf(stderr, "%s: `%s` option value missing\n", prog, *argv);
|
||||
goto end;
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (!outfp) {
|
||||
fprintf(stderr, "%s: `-out` option required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (sphincs_key_generate(&key) != 1) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
if (verbose) {
|
||||
sphincs_public_key_print(stderr, 0, 0, "sphincs_public_key", &key);
|
||||
}
|
||||
|
||||
if (sphincs_private_key_to_bytes(&key, &pout, &outlen) != 1) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
if (fwrite(out, 1, outlen, outfp) != outlen) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (sphincs_public_key_to_bytes(&key, &ppubout, &puboutlen) != 1) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
if (puboutlen != sizeof(pubout)) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
if (fwrite(pubout, 1, puboutlen, puboutfp) != puboutlen) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
end:
|
||||
sphincs_key_cleanup(&key);
|
||||
gmssl_secure_clear(out, sizeof(out));
|
||||
if (outfile && outfp) fclose(outfp);
|
||||
if (puboutfile && puboutfp) fclose(puboutfp);
|
||||
return ret;
|
||||
}
|
||||
175
tools/sphincssign.c
Normal file
175
tools/sphincssign.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2014-2026 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 <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <gmssl/mem.h>
|
||||
#include <gmssl/error.h>
|
||||
#include <gmssl/endian.h>
|
||||
#include <gmssl/sphincs.h>
|
||||
|
||||
|
||||
static const char *usage = "-key file [-in file] [-out file] [-verbose]\n";
|
||||
|
||||
static const char *options =
|
||||
"Options\n"
|
||||
" -key file Input private key file\n"
|
||||
" -in file Input data file (if not using stdin)\n"
|
||||
" -out file Output signature file\n"
|
||||
" -verbose Print public key and signature\n"
|
||||
"\n";
|
||||
|
||||
int sphincssign_main(int argc, char **argv)
|
||||
{
|
||||
int ret = 1;
|
||||
char *prog = argv[0];
|
||||
char *keyfile = NULL;
|
||||
char *infile = NULL;
|
||||
char *outfile = NULL;
|
||||
int verbose = 0;
|
||||
FILE *keyfp = NULL;
|
||||
FILE *infp = stdin;
|
||||
FILE *outfp = stdout;
|
||||
uint8_t keybuf[SPHINCS_PRIVATE_KEY_SIZE];
|
||||
const uint8_t *cp = keybuf;
|
||||
size_t keylen = sizeof(keybuf);
|
||||
SPHINCS_KEY key;
|
||||
SPHINCS_SIGN_CTX ctx;
|
||||
uint8_t sig[SPHINCS_SIGNATURE_SIZE];
|
||||
size_t siglen;
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
|
||||
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: %s %s\n", prog, usage);
|
||||
printf("%s\n", options);
|
||||
ret = 0;
|
||||
goto end;
|
||||
} else if (!strcmp(*argv, "-key")) {
|
||||
if (--argc < 1) goto bad;
|
||||
keyfile = *(++argv);
|
||||
if (!(keyfp = fopen(keyfile, "rb+"))) {
|
||||
fprintf(stderr, "%s: open '%s' failure: %s\n", prog, keyfile, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
} else if (!strcmp(*argv, "-in")) {
|
||||
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, "-out")) {
|
||||
if (--argc < 1) goto bad;
|
||||
outfile = *(++argv);
|
||||
if (!(outfp = fopen(outfile, "wb"))) {
|
||||
fprintf(stderr, "%s: open '%s' failure: %s\n", prog, outfile, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
} else if (!strcmp(*argv, "-verbose")) {
|
||||
verbose = 1;
|
||||
} else {
|
||||
fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv);
|
||||
goto end;
|
||||
bad:
|
||||
fprintf(stderr, "%s: `%s` option value missing\n", prog, *argv);
|
||||
goto end;
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (!keyfile) {
|
||||
fprintf(stderr, "%s: `-key` option required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (fread(keybuf, 1, keylen, keyfp) != keylen) {
|
||||
fprintf(stderr, "%s: read private key failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (sphincs_private_key_from_bytes(&key, &cp, &keylen) != 1) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
if (keylen) {
|
||||
error_print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
sphincs_public_key_print(stderr, 0, 0, "sphincs_public_key", &key);
|
||||
}
|
||||
|
||||
if (sphincs_sign_init(&ctx, &key) != 1) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
uint8_t buf[1024];
|
||||
size_t len = fread(buf, 1, sizeof(buf), infp);
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
if (sphincs_sign_prepare(&ctx, buf, len) != 1) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
rewind(infp);
|
||||
while (1) {
|
||||
uint8_t buf[1024];
|
||||
size_t len = fread(buf, 1, sizeof(buf), infp);
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
if (sphincs_sign_update(&ctx, buf, len) != 1) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (sphincs_sign_finish(&ctx, sig, &siglen) != 1) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
if (fwrite(sig, 1, siglen, outfp) != siglen) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
if (verbose) {
|
||||
sphincs_signature_print(stderr, 0, 0, "sphincs_signature", sig, siglen);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
sphincs_key_cleanup(&key);
|
||||
gmssl_secure_clear(keybuf, keylen);
|
||||
gmssl_secure_clear(&ctx, sizeof(ctx));
|
||||
if (keyfp) fclose(keyfp);
|
||||
if (infp && infp != stdin) fclose(infp);
|
||||
if (outfp && outfp != stdout) fclose(outfp);
|
||||
return ret;
|
||||
}
|
||||
158
tools/sphincsverify.c
Normal file
158
tools/sphincsverify.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2014-2026 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 <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <gmssl/mem.h>
|
||||
#include <gmssl/error.h>
|
||||
#include <gmssl/sphincs.h>
|
||||
|
||||
static const char *usage = "-pubkey file [-in file] -sig file [-verbose]\n";
|
||||
|
||||
static const char *options =
|
||||
"Options\n"
|
||||
" -pubkey file Input public key file\n"
|
||||
" -in file Input data file (if not using stdin)\n"
|
||||
" -sig file Input signature file\n"
|
||||
" -verbose Print public key and signature\n"
|
||||
"\n";
|
||||
|
||||
int sphincsverify_main(int argc, char **argv)
|
||||
{
|
||||
int ret = 1;
|
||||
char *prog = argv[0];
|
||||
char *pubkeyfile = NULL;
|
||||
char *infile = NULL;
|
||||
char *sigfile = NULL;
|
||||
int verbose = 0;
|
||||
FILE *pubkeyfp = NULL;
|
||||
FILE *infp = stdin;
|
||||
FILE *sigfp = NULL;
|
||||
uint8_t pubkeybuf[SPHINCS_PUBLIC_KEY_SIZE];
|
||||
size_t pubkeylen = SPHINCS_PUBLIC_KEY_SIZE;
|
||||
const uint8_t *cp = pubkeybuf;
|
||||
uint8_t sig[SPHINCS_SIGNATURE_SIZE];
|
||||
size_t siglen;
|
||||
SPHINCS_KEY key;
|
||||
SPHINCS_SIGN_CTX ctx;
|
||||
int vr;
|
||||
|
||||
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: %s %s\n", prog, usage);
|
||||
printf("%s\n", options);
|
||||
ret = 0;
|
||||
goto end;
|
||||
} else if (!strcmp(*argv, "-pubkey")) {
|
||||
if (--argc < 1) goto bad;
|
||||
pubkeyfile = *(++argv);
|
||||
if (!(pubkeyfp = fopen(pubkeyfile, "rb"))) {
|
||||
fprintf(stderr, "%s: open '%s' failure: %s\n", prog, pubkeyfile, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
} else if (!strcmp(*argv, "-in")) {
|
||||
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, "-sig")) {
|
||||
if (--argc < 1) goto bad;
|
||||
sigfile = *(++argv);
|
||||
if (!(sigfp = fopen(sigfile, "rb"))) {
|
||||
fprintf(stderr, "%s: open '%s' failure: %s\n", prog, sigfile, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
} else if (!strcmp(*argv, "-verbose")) {
|
||||
verbose = 1;
|
||||
} else {
|
||||
fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv);
|
||||
goto end;
|
||||
bad:
|
||||
fprintf(stderr, "%s: `%s` option value missing\n", prog, *argv);
|
||||
goto end;
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (!pubkeyfile) {
|
||||
fprintf(stderr, "%s: `-key` option required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (!sigfile) {
|
||||
fprintf(stderr, "%s: `-sig` option required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (fread(pubkeybuf, 1, pubkeylen, pubkeyfp) != pubkeylen) {
|
||||
fprintf(stderr, "%s: read public key failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (sphincs_public_key_from_bytes(&key, &cp, &pubkeylen) != 1) {
|
||||
error_print();
|
||||
fprintf(stderr, "%s: invalid public key data\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (verbose) {
|
||||
sphincs_public_key_print(stderr, 0, 0, "sphincs_public_key", &key);
|
||||
}
|
||||
|
||||
// read signature even if signature not compatible with the public key
|
||||
if ((siglen = fread(sig, 1, SPHINCS_SIGNATURE_SIZE, sigfp)) != SPHINCS_SIGNATURE_SIZE) {
|
||||
fprintf(stderr, "%s: read signature failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (verbose) {
|
||||
sphincs_signature_print(stderr, 0, 0, "sphincs_signature", sig, siglen);
|
||||
}
|
||||
if (sphincs_verify_init(&ctx, &key, sig, siglen) != 1) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
uint8_t buf[1024];
|
||||
size_t len = fread(buf, 1, sizeof(buf), infp);
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
if (sphincs_verify_update(&ctx, buf, len) != 1) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if ((vr = sphincs_verify_finish(&ctx)) < 0) {
|
||||
error_print();
|
||||
goto end;
|
||||
}
|
||||
fprintf(stdout, "verify : %s\n", vr == 1 ? "success" : "failure");
|
||||
if (vr == 1) {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
if (pubkeyfp) fclose(pubkeyfp);
|
||||
if (infp && infp != stdin) fclose(infp);
|
||||
if (sigfp) fclose(sigfp);
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user