mirror of
https://github.com/guanzhi/GmSSL.git
synced 2026-08-06 11:53:39 +08:00
Update QUIC/SM9/ZUC
This commit is contained in:
@@ -35,6 +35,7 @@ extern int sm2sign_main(int argc, char **argv);
|
||||
extern int sm2verify_main(int argc, char **argv);
|
||||
extern int sm2encrypt_main(int argc, char **argv);
|
||||
extern int sm2decrypt_main(int argc, char **argv);
|
||||
extern int sm2exch_main(int argc, char **argv);
|
||||
extern int sm3_main(int argc, char **argv);
|
||||
extern int sm3hmac_main(int argc, char **argv);
|
||||
extern int sm3_pbkdf2_main(int argc, char **argv);
|
||||
@@ -64,6 +65,9 @@ extern int sm4_cbc_mac_main(int argc, char **argv);
|
||||
#endif
|
||||
#ifdef ENABLE_ZUC
|
||||
extern int zuc_main(int argc, char **argv);
|
||||
extern int zuc256_main(int argc, char **argv);
|
||||
extern int zuc_128_eea3_main(int argc, char **argv);
|
||||
extern int zuc_128_eia3_main(int argc, char **argv);
|
||||
#endif
|
||||
#ifdef ENABLE_GHASH
|
||||
extern int ghash_main(int argc, char **argv);
|
||||
@@ -75,6 +79,7 @@ extern int sm9sign_main(int argc, char **argv);
|
||||
extern int sm9verify_main(int argc, char **argv);
|
||||
extern int sm9encrypt_main(int argc, char **argv);
|
||||
extern int sm9decrypt_main(int argc, char **argv);
|
||||
extern int sm9exch_main(int argc, char **argv);
|
||||
#endif
|
||||
#ifdef ENABLE_CMS
|
||||
extern int cmsparse_main(int argc, char **argv);
|
||||
@@ -92,6 +97,10 @@ extern int tls13_client_main(int argc, char **argv);
|
||||
extern int tls13_server_main(int argc, char **argv);
|
||||
extern int sctverify_main(int argc, char **argv);
|
||||
#endif
|
||||
#ifdef ENABLE_QUIC
|
||||
extern int quic_client_main(int argc, char **argv);
|
||||
extern int quic_server_main(int argc, char **argv);
|
||||
#endif
|
||||
#ifdef ENABLE_SECP256R1
|
||||
extern int p256keygen_main(int argc, char **argv);
|
||||
#endif
|
||||
@@ -147,9 +156,11 @@ static const char *options =
|
||||
" sm2verify Verify SM2 signature\n"
|
||||
" sm2encrypt Encrypt with SM2 public key\n"
|
||||
" sm2decrypt Decrypt with SM2 private key\n"
|
||||
" sm2exch SM2 key exchange\n"
|
||||
" sm3 Generate SM3 hash\n"
|
||||
" sm3hmac Generate SM3 HMAC tag\n"
|
||||
" sm3_pbkdf2 Hash password into key using PBKDF2 algoritm\n"
|
||||
" sm4 Encrypt or decrypt with SM4\n"
|
||||
" sm4_gcm Encrypt or decrypt with SM4 GCM\n"
|
||||
" sm4_cbc Encrypt or decrypt with SM4 CBC\n"
|
||||
" sm4_ctr Encrypt or decrypt with SM4 CTR\n"
|
||||
@@ -179,6 +190,9 @@ static const char *options =
|
||||
#endif
|
||||
#ifdef ENABLE_ZUC
|
||||
" zuc Encrypt or decrypt with ZUC\n"
|
||||
" zuc256 Encrypt or decrypt with ZUC-256\n"
|
||||
" zuc_128_eea3 Encrypt or decrypt with ZUC 128-EEA3\n"
|
||||
" zuc_128_eia3 Generate ZUC 128-EIA3 MAC\n"
|
||||
#endif
|
||||
#ifdef ENABLE_SM9
|
||||
" sm9setup Generate SM9 master secret\n"
|
||||
@@ -187,6 +201,7 @@ static const char *options =
|
||||
" sm9verify Verify SM9 signature\n"
|
||||
" sm9encrypt SM9 public key encryption\n"
|
||||
" sm9decrypt SM9 decryption\n"
|
||||
" sm9exch SM9 key exchange\n"
|
||||
#endif
|
||||
" reqgen Generate certificate signing request (CSR)\n"
|
||||
" reqsign Generate certificate from CSR\n"
|
||||
@@ -259,6 +274,10 @@ static const char *options =
|
||||
" tls12_server TLS 1.2 server\n"
|
||||
" tls13_client TLS 1.3 client\n"
|
||||
" tls13_server TLS 1.3 server\n"
|
||||
#endif
|
||||
#ifdef ENABLE_QUIC
|
||||
" quic_client QUIC client\n"
|
||||
" quic_server QUIC server\n"
|
||||
#endif
|
||||
"\n"
|
||||
"run `gmssl <command> -help` to print help of the given command\n"
|
||||
@@ -326,6 +345,8 @@ int main(int argc, char **argv)
|
||||
return sm2encrypt_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "sm2decrypt")) {
|
||||
return sm2decrypt_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "sm2exch")) {
|
||||
return sm2exch_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "sm3")) {
|
||||
return sm3_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "sm3hmac")) {
|
||||
@@ -373,6 +394,12 @@ int main(int argc, char **argv)
|
||||
#ifdef ENABLE_ZUC
|
||||
} else if (!strcmp(*argv, "zuc")) {
|
||||
return zuc_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "zuc256")) {
|
||||
return zuc256_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "zuc_128_eea3")) {
|
||||
return zuc_128_eea3_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "zuc_128_eia3")) {
|
||||
return zuc_128_eia3_main(argc, argv);
|
||||
#endif
|
||||
#ifdef ENABLE_SM9
|
||||
} else if (!strcmp(*argv, "sm9setup")) {
|
||||
@@ -387,6 +414,8 @@ int main(int argc, char **argv)
|
||||
return sm9encrypt_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "sm9decrypt")) {
|
||||
return sm9decrypt_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "sm9exch")) {
|
||||
return sm9exch_main(argc, argv);
|
||||
#endif
|
||||
#ifdef ENABLE_CMS
|
||||
} else if (!strcmp(*argv, "cmsparse")) {
|
||||
@@ -416,6 +445,12 @@ int main(int argc, char **argv)
|
||||
} else if (!strcmp(*argv, "sctverify")) {
|
||||
return sctverify_main(argc, argv);
|
||||
#endif
|
||||
#ifdef ENABLE_QUIC
|
||||
} else if (!strcmp(*argv, "quic_client")) {
|
||||
return quic_client_main(argc, argv);
|
||||
} else if (!strcmp(*argv, "quic_server")) {
|
||||
return quic_server_main(argc, argv);
|
||||
#endif
|
||||
#ifdef ENABLE_SECP256R1
|
||||
} else if (!strcmp(*argv, "p256keygen")) {
|
||||
return p256keygen_main(argc, argv);
|
||||
|
||||
1270
tools/quic_client.c
Normal file
1270
tools/quic_client.c
Normal file
File diff suppressed because it is too large
Load Diff
35
tools/quic_help.h
Normal file
35
tools/quic_help.h
Normal file
@@ -0,0 +1,35 @@
|
||||
"\n"
|
||||
"Supported cipher suites:\n"
|
||||
#if defined(ENABLE_AES) && defined(ENABLE_SHA2)
|
||||
" TLS_AES_128_GCM_SHA256\n"
|
||||
#ifdef ENABLE_AES_CCM
|
||||
" TLS_AES_128_CCM_SHA256\n"
|
||||
#endif
|
||||
#endif
|
||||
" TLS_SM4_GCM_SM3\n"
|
||||
#ifdef ENABLE_SM4_CCM
|
||||
" TLS_SM4_CCM_SM3\n"
|
||||
#endif
|
||||
"\n"
|
||||
"Examples\n"
|
||||
"\n"
|
||||
" gmssl quic_server -port 4433 -cert p256_tls_server_certs.pem -key p256_tls_server_key.pem \\\n"
|
||||
" -pass P@ssw0rd -cipher_suite TLS_AES_128_GCM_SHA256 -supported_group prime256v1 \\\n"
|
||||
" -sig_alg ecdsa_secp256r1_sha256 -verbose\n"
|
||||
" gmssl quic_client -host 127.0.0.1 -port 4433 -server_name localhost \\\n"
|
||||
" -cipher_suite TLS_AES_128_GCM_SHA256 -supported_group prime256v1 \\\n"
|
||||
" -sig_alg ecdsa_secp256r1_sha256 -get / -verbose\n"
|
||||
"\n"
|
||||
" gmssl quic_server -port 4434 -cert sm2_tls_server_certs.pem -key sm2_tls_server_key.pem \\\n"
|
||||
" -pass P@ssw0rd -cipher_suite TLS_SM4_GCM_SM3 -supported_group sm2p256v1 \\\n"
|
||||
" -sig_alg sm2sig_sm3 -verbose\n"
|
||||
" gmssl quic_client -host 127.0.0.1 -port 4434 -server_name localhost \\\n"
|
||||
" -cipher_suite TLS_SM4_GCM_SM3 -supported_group sm2p256v1 -sig_alg sm2sig_sm3 \\\n"
|
||||
" -get / -verbose\n"
|
||||
"\n"
|
||||
" ngtcp2/examples/osslserver --groups=P-256 --ciphers=TLS_AES_128_GCM_SHA256 \\\n"
|
||||
" -d htdocs 127.0.0.1 4435 p256-key.pem p256-cert.pem\n"
|
||||
" gmssl quic_client -host 127.0.0.1 -port 4435 -server_name localhost \\\n"
|
||||
" -cipher_suite TLS_AES_128_GCM_SHA256 -supported_group prime256v1 \\\n"
|
||||
" -sig_alg ecdsa_secp256r1_sha256 -get / -verbose\n"
|
||||
"\n"
|
||||
1010
tools/quic_server.c
Normal file
1010
tools/quic_server.c
Normal file
File diff suppressed because it is too large
Load Diff
929
tools/sm2exch.c
Normal file
929
tools/sm2exch.c
Normal file
@@ -0,0 +1,929 @@
|
||||
/*
|
||||
* 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 <stdint.h>
|
||||
#include <gmssl/mem.h>
|
||||
#include <gmssl/hex.h>
|
||||
#include <gmssl/pem.h>
|
||||
#include <gmssl/sm2.h>
|
||||
#include <gmssl/x509.h>
|
||||
#include <gmssl/x509_ext.h>
|
||||
|
||||
|
||||
#define SM2EXCH_RA_SIZE 65
|
||||
#define SM2EXCH_RB_SIZE 65
|
||||
#define SM2EXCH_CONFIRM_SIZE 32
|
||||
#define SM2EXCH_RB_SB_SIZE (SM2EXCH_RB_SIZE + SM2EXCH_CONFIRM_SIZE)
|
||||
#define SM2EXCH_SECRET_STATE_SIZE 65
|
||||
#define SM2EXCH_MAX_SHARED_KEY_SIZE 1024
|
||||
#define PEM_SM2_EXCH_PEER_RA "SM2 EXCHANGE PEER RA"
|
||||
|
||||
enum {
|
||||
SM2EXCH_FMT_BIN = 0,
|
||||
SM2EXCH_FMT_HEX = 1,
|
||||
};
|
||||
|
||||
static const char *usage =
|
||||
"-stage init|respond|confirm|finish [options]";
|
||||
|
||||
static const char *options =
|
||||
"\n"
|
||||
"Options\n"
|
||||
"\n"
|
||||
" -stage init|respond|confirm|finish\n"
|
||||
" SM2 key exchange stage\n"
|
||||
" -cert pem Optional local SM2 certificate for checking against -key\n"
|
||||
" -pubkey pem Optional local SM2 public key for checking against -key\n"
|
||||
" -key pem Local SM2 private key in PEM format\n"
|
||||
" -pass str Password to open local private key\n"
|
||||
" -peer_cert pem Peer SM2 key exchange/encryption certificate in PEM format\n"
|
||||
" -peer_pubkey pem Peer SM2 public key in PEM format\n"
|
||||
" -id str Local SM2 identity, '1234567812345678' by default\n"
|
||||
" -id_hex hex Local SM2 identity in hex\n"
|
||||
" -peer_id str Peer SM2 identity, '1234567812345678' by default\n"
|
||||
" -peer_id_hex hex Peer SM2 identity in hex\n"
|
||||
" -in file | stdin Input data for this stage\n"
|
||||
" respond: RA, 65 bytes\n"
|
||||
" confirm: RB || SB, 97 bytes\n"
|
||||
" finish: SA, 32 bytes\n"
|
||||
" -out file | stdout Output data to send to peer\n"
|
||||
" init: RA, 65 bytes\n"
|
||||
" respond: RB || SB, 97 bytes\n"
|
||||
" confirm: SA, 32 bytes\n"
|
||||
" -exch_keyout pem Output local ephemeral private key\n"
|
||||
" -exch_key pem Input local ephemeral private key\n"
|
||||
" -exch_pass str Password for local ephemeral private key\n"
|
||||
" -secret_state_out file\n"
|
||||
" Output 65-byte secret_state point\n"
|
||||
" -secret_state file Input 65-byte secret_state point\n"
|
||||
" -keylen num Shared key length in bytes, 32 by default\n"
|
||||
" -keyout file Output shared key\n"
|
||||
" -hex Encode input/output data in hex, default\n"
|
||||
" -bin Encode input/output data in binary\n"
|
||||
"\n"
|
||||
"Examples\n"
|
||||
"\n"
|
||||
"Public-key file workflow:\n"
|
||||
"\n"
|
||||
" gmssl sm2keygen -pass P@ssw0rd -out alice.pem -pubout alicepub.pem\n"
|
||||
" gmssl sm2keygen -pass P@ssw0rd -out bob.pem -pubout bobpub.pem\n"
|
||||
" gmssl sm2exch -stage init \\\n"
|
||||
" -exch_keyout alice_ra.pem -exch_pass P@ssw0rd -out ra.hex\n"
|
||||
" gmssl sm2exch -stage respond \\\n"
|
||||
" -key bob.pem -pass P@ssw0rd -id Bob \\\n"
|
||||
" -peer_pubkey alicepub.pem -peer_id Alice -in ra.hex \\\n"
|
||||
" -exch_keyout bob_rb.pem -exch_pass P@ssw0rd \\\n"
|
||||
" -secret_state_out bob_secret_state.hex -out rb_sb.hex\n"
|
||||
" gmssl sm2exch -stage confirm \\\n"
|
||||
" -key alice.pem -pass P@ssw0rd -id Alice \\\n"
|
||||
" -peer_pubkey bobpub.pem -peer_id Bob \\\n"
|
||||
" -exch_key alice_ra.pem -exch_pass P@ssw0rd -in rb_sb.hex \\\n"
|
||||
" -keylen 48 -keyout alice_shared_key.hex -out sa.hex\n"
|
||||
" gmssl sm2exch -stage finish \\\n"
|
||||
" -key bob.pem -pass P@ssw0rd -id Bob \\\n"
|
||||
" -peer_pubkey alicepub.pem -peer_id Alice \\\n"
|
||||
" -exch_key bob_rb.pem -exch_pass P@ssw0rd \\\n"
|
||||
" -secret_state bob_secret_state.hex -in sa.hex \\\n"
|
||||
" -keylen 48 -keyout bob_shared_key.hex\n"
|
||||
"\n"
|
||||
"Certificate workflow:\n"
|
||||
"\n"
|
||||
" gmssl sm2exch -stage respond \\\n"
|
||||
" -key bob_enc_key.pem -pass P@ssw0rd -id Bob \\\n"
|
||||
" -peer_cert alice_enc_cert.pem -peer_id Alice -in ra.hex \\\n"
|
||||
" -exch_keyout bob_rb.pem -exch_pass P@ssw0rd \\\n"
|
||||
" -secret_state_out bob_secret_state.hex -out rb_sb.hex\n"
|
||||
" gmssl sm2exch -stage confirm \\\n"
|
||||
" -key alice_enc_key.pem -pass P@ssw0rd -id Alice \\\n"
|
||||
" -peer_cert bob_enc_cert.pem -peer_id Bob \\\n"
|
||||
" -exch_key alice_ra.pem -exch_pass P@ssw0rd -in rb_sb.hex \\\n"
|
||||
" -keyout alice_shared_key.hex -out sa.hex\n"
|
||||
"\n"
|
||||
"Notes\n"
|
||||
"\n"
|
||||
" -cert and -peer_cert read only the first certificate from the PEM file.\n"
|
||||
" If KeyUsage is present, the certificate must allow keyEncipherment or keyAgreement.\n"
|
||||
" RA, RB and secret_state are fixed 65-byte uncompressed SM2 points.\n"
|
||||
" The respond output is RB || SB, fixed 97 bytes.\n"
|
||||
" -hex and -bin affect RA, RB||SB, SA, secret_state and shared key files.\n"
|
||||
"\n";
|
||||
|
||||
static int read_file(const char *file, uint8_t *buf, size_t *len, size_t maxlen)
|
||||
{
|
||||
FILE *fp = stdin;
|
||||
size_t n;
|
||||
|
||||
if (!buf || !len) {
|
||||
return -1;
|
||||
}
|
||||
if (file && !(fp = fopen(file, "rb"))) {
|
||||
return -1;
|
||||
}
|
||||
n = fread(buf, 1, maxlen + 1, fp);
|
||||
if (ferror(fp)) {
|
||||
if (file) fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
if (file) fclose(fp);
|
||||
if (n > maxlen) {
|
||||
return -1;
|
||||
}
|
||||
*len = n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int write_file(const char *file, const uint8_t *buf, size_t len)
|
||||
{
|
||||
FILE *fp = stdout;
|
||||
int ret = -1;
|
||||
|
||||
if (!buf || !len) {
|
||||
return -1;
|
||||
}
|
||||
if (file && !(fp = fopen(file, "wb"))) {
|
||||
return -1;
|
||||
}
|
||||
if (fwrite(buf, 1, len, fp) == len) {
|
||||
ret = 1;
|
||||
}
|
||||
if (file) fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm2exch_read_exact(const char *file, uint8_t *buf, size_t len);
|
||||
|
||||
static int sm2exch_write_data(const char *file, const uint8_t *buf, size_t len, int format)
|
||||
{
|
||||
uint8_t *hexbuf = NULL;
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
if (format == SM2EXCH_FMT_BIN) {
|
||||
return write_file(file, buf, len);
|
||||
}
|
||||
if (!(hexbuf = malloc(len * 2))) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
static const char *hex = "0123456789abcdef";
|
||||
hexbuf[i * 2] = (uint8_t)hex[buf[i] >> 4];
|
||||
hexbuf[i * 2 + 1] = (uint8_t)hex[buf[i] & 0x0f];
|
||||
}
|
||||
ret = write_file(file, hexbuf, len * 2);
|
||||
gmssl_secure_clear(hexbuf, len * 2);
|
||||
free(hexbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm2exch_read_data(const char *file, uint8_t *buf, size_t len, int format)
|
||||
{
|
||||
uint8_t *in = NULL;
|
||||
uint8_t *hex = NULL;
|
||||
size_t inlen;
|
||||
size_t hexlen = 0;
|
||||
size_t outlen;
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
if (format == SM2EXCH_FMT_BIN) {
|
||||
return sm2exch_read_exact(file, buf, len);
|
||||
}
|
||||
if (!(in = malloc(len * 2 + 64)) || !(hex = malloc(len * 2))) {
|
||||
goto end;
|
||||
}
|
||||
if (read_file(file, in, &inlen, len * 2 + 63) != 1) {
|
||||
goto end;
|
||||
}
|
||||
for (i = 0; i < inlen; i++) {
|
||||
if (in[i] == ' ' || in[i] == '\t' || in[i] == '\r' || in[i] == '\n') {
|
||||
continue;
|
||||
}
|
||||
if (hexlen >= len * 2) {
|
||||
goto end;
|
||||
}
|
||||
hex[hexlen++] = in[i];
|
||||
}
|
||||
if (hexlen != len * 2
|
||||
|| hex_to_bytes((char *)hex, hexlen, buf, &outlen) != 1
|
||||
|| outlen != len) {
|
||||
goto end;
|
||||
}
|
||||
ret = 1;
|
||||
end:
|
||||
if (in) {
|
||||
gmssl_secure_clear(in, len * 2 + 64);
|
||||
free(in);
|
||||
}
|
||||
if (hex) {
|
||||
gmssl_secure_clear(hex, len * 2);
|
||||
free(hex);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm2exch_read_point(const char *file, uint8_t point[65], int format)
|
||||
{
|
||||
if (sm2exch_read_data(file, point, 65, format) != 1) {
|
||||
return -1;
|
||||
}
|
||||
if (point[0] != 0x04) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm2exch_read_exact(const char *file, uint8_t *buf, size_t len)
|
||||
{
|
||||
size_t inlen;
|
||||
|
||||
if (read_file(file, buf, &inlen, len) != 1 || inlen != len) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm2exch_cert_check_key_usage(const uint8_t *cert, size_t certlen)
|
||||
{
|
||||
int ret;
|
||||
int critical;
|
||||
const uint8_t *exts;
|
||||
size_t extslen;
|
||||
const uint8_t *val;
|
||||
size_t vlen;
|
||||
int bits;
|
||||
|
||||
if (!cert || !certlen) {
|
||||
return -1;
|
||||
}
|
||||
if ((ret = x509_cert_get_exts(cert, certlen, &exts, &extslen)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
return 1;
|
||||
}
|
||||
if ((ret = x509_exts_get_ext_by_oid(exts, extslen, OID_ce_key_usage,
|
||||
&critical, &val, &vlen)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (x509_key_usage_from_der(&bits, &val, &vlen) != 1
|
||||
|| asn1_length_is_zero(vlen) != 1) {
|
||||
return -1;
|
||||
}
|
||||
if ((bits & (X509_KU_KEY_ENCIPHERMENT | X509_KU_KEY_AGREEMENT)) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm2exch_load_public_key(SM2_KEY *pub_key, const char *pubkeyfile,
|
||||
const char *certfile, const char *prog, const char *label)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
uint8_t cert[4096];
|
||||
size_t certlen;
|
||||
X509_KEY x509_key;
|
||||
int ret;
|
||||
|
||||
if (!pub_key || !prog || !label) {
|
||||
return -1;
|
||||
}
|
||||
if (pubkeyfile && certfile) {
|
||||
if (label[0]) {
|
||||
fprintf(stderr, "gmssl %s: options '-%s_pubkey' and '-%s_cert' conflict\n",
|
||||
prog, label, label);
|
||||
} else {
|
||||
fprintf(stderr, "gmssl %s: options '-pubkey' and '-cert' conflict\n", prog);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (pubkeyfile) {
|
||||
if (!(fp = fopen(pubkeyfile, "rb"))) {
|
||||
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, pubkeyfile, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ret = sm2_public_key_info_from_pem(pub_key, fp);
|
||||
fclose(fp);
|
||||
if (ret != 1) {
|
||||
fprintf(stderr, "gmssl %s: parse public key failed\n", prog);
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (certfile) {
|
||||
if (!(fp = fopen(certfile, "rb"))) {
|
||||
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, certfile, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ret = x509_cert_from_pem(cert, &certlen, sizeof(cert), fp);
|
||||
fclose(fp);
|
||||
if (ret != 1
|
||||
|| x509_cert_get_subject_public_key(cert, certlen, &x509_key) != 1) {
|
||||
fprintf(stderr, "gmssl %s: parse certificate failed\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (x509_key.algor != OID_ec_public_key || x509_key.algor_param != OID_sm2) {
|
||||
fprintf(stderr, "gmssl %s: certificate public key is not SM2\n", prog);
|
||||
return -1;
|
||||
}
|
||||
ret = sm2exch_cert_check_key_usage(cert, certlen);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "gmssl %s: certificate KeyUsage parse failure\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
fprintf(stderr, "gmssl %s: certificate KeyUsage does not allow key exchange/encryption\n", prog);
|
||||
return -1;
|
||||
}
|
||||
*pub_key = x509_key.u.sm2_key;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (label[0]) {
|
||||
fprintf(stderr, "gmssl %s: '-%s_pubkey' or '-%s_cert' option required\n",
|
||||
prog, label, label);
|
||||
} else {
|
||||
fprintf(stderr, "gmssl %s: '-pubkey' or '-cert' option required\n", prog);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int sm2exch_load_private_key(SM2_KEY *key, const char *keyfile,
|
||||
const char *pass, const char *prog)
|
||||
{
|
||||
FILE *fp;
|
||||
int ret;
|
||||
|
||||
if (!keyfile) {
|
||||
fprintf(stderr, "gmssl %s: '-key' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!pass) {
|
||||
fprintf(stderr, "gmssl %s: '-pass' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!(fp = fopen(keyfile, "rb"))) {
|
||||
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, keyfile, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ret = sm2_private_key_info_decrypt_from_pem(key, pass, fp);
|
||||
fclose(fp);
|
||||
if (ret != 1) {
|
||||
fprintf(stderr, "gmssl %s: private key decryption failure\n", prog);
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm2exch_load_exch_key(SM2_KEY *key, uint8_t peer_ra[65],
|
||||
const char *keyfile, const char *pass, const char *prog)
|
||||
{
|
||||
FILE *fp;
|
||||
int ret;
|
||||
size_t len;
|
||||
|
||||
if (!keyfile) {
|
||||
fprintf(stderr, "gmssl %s: '-exch_key' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!pass) {
|
||||
fprintf(stderr, "gmssl %s: '-exch_pass' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!(fp = fopen(keyfile, "rb"))) {
|
||||
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, keyfile, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ret = sm2_private_key_info_decrypt_from_pem(key, pass, fp);
|
||||
if (ret != 1) {
|
||||
fprintf(stderr, "gmssl %s: ephemeral private key decryption failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (peer_ra) {
|
||||
if (pem_read(fp, PEM_SM2_EXCH_PEER_RA, peer_ra, &len, 65) != 1
|
||||
|| len != 65 || peer_ra[0] != 0x04) {
|
||||
fprintf(stderr, "gmssl %s: peer RA not found in exchange key\n", prog);
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
ret = 1;
|
||||
end:
|
||||
fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm2exch_save_exch_key(const SM2_KEY *key, const char *keyfile,
|
||||
const char *pass, const uint8_t peer_ra[65], const char *prog)
|
||||
{
|
||||
FILE *fp;
|
||||
int ret;
|
||||
|
||||
if (!keyfile) {
|
||||
fprintf(stderr, "gmssl %s: '-exch_keyout' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!pass) {
|
||||
fprintf(stderr, "gmssl %s: '-exch_pass' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!(fp = fopen(keyfile, "wb"))) {
|
||||
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, keyfile, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ret = sm2_private_key_info_encrypt_to_pem(key, pass, fp);
|
||||
if (ret == 1 && peer_ra) {
|
||||
ret = pem_write(fp, PEM_SM2_EXCH_PEER_RA, peer_ra, 65);
|
||||
}
|
||||
fclose(fp);
|
||||
if (ret != 1) {
|
||||
fprintf(stderr, "gmssl %s: output ephemeral private key failed\n", prog);
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm2exch_load_local_keys(SM2_KEY *key, const char *keyfile, const char *pass,
|
||||
const char *pubkeyfile, const char *certfile, const char *prog)
|
||||
{
|
||||
SM2_KEY pub_key;
|
||||
|
||||
if (sm2exch_load_private_key(key, keyfile, pass, prog) != 1) {
|
||||
return -1;
|
||||
}
|
||||
if (pubkeyfile || certfile) {
|
||||
if (sm2exch_load_public_key(&pub_key, pubkeyfile, certfile, prog, "") != 1) {
|
||||
return -1;
|
||||
}
|
||||
if (sm2_public_key_equ(key, &pub_key) != 1) {
|
||||
fprintf(stderr, "gmssl %s: private key does not match local public key/certificate\n", prog);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm2exch_derive_key_from_secret_state(int is_initiator,
|
||||
const SM2_KEY *key, const char *id, size_t idlen,
|
||||
const SM2_KEY *peer_public_key, const char *peer_id, size_t peer_idlen,
|
||||
const uint8_t secret_state[65], uint8_t *shared_key, size_t shared_key_len)
|
||||
{
|
||||
SM2_Z256_POINT point;
|
||||
uint8_t za[32];
|
||||
uint8_t zb[32];
|
||||
uint8_t kdf_input[128];
|
||||
int ret = -1;
|
||||
|
||||
if (!key || !id || !peer_public_key || !peer_id
|
||||
|| !secret_state || !shared_key || !shared_key_len) {
|
||||
return -1;
|
||||
}
|
||||
if (sm2_z256_point_from_octets(&point, secret_state, 65) != 1) {
|
||||
return -1;
|
||||
}
|
||||
if (is_initiator) {
|
||||
if (sm2_compute_z(za, &key->public_key, id, idlen) != 1
|
||||
|| sm2_compute_z(zb, &peer_public_key->public_key, peer_id, peer_idlen) != 1) {
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if (sm2_compute_z(za, &peer_public_key->public_key, peer_id, peer_idlen) != 1
|
||||
|| sm2_compute_z(zb, &key->public_key, id, idlen) != 1) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
sm2_z256_point_to_bytes(&point, kdf_input);
|
||||
memcpy(kdf_input + 64, za, sizeof(za));
|
||||
memcpy(kdf_input + 96, zb, sizeof(zb));
|
||||
if (sm2_kdf(kdf_input, sizeof(kdf_input), shared_key_len, shared_key) != 1
|
||||
|| mem_is_zero(shared_key, shared_key_len)) {
|
||||
goto end;
|
||||
}
|
||||
ret = 1;
|
||||
end:
|
||||
gmssl_secure_clear(&point, sizeof(point));
|
||||
gmssl_secure_clear(za, sizeof(za));
|
||||
gmssl_secure_clear(zb, sizeof(zb));
|
||||
gmssl_secure_clear(kdf_input, sizeof(kdf_input));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm2exch_stage_init(const char *exch_keyoutfile, const char *exch_pass,
|
||||
const char *outfile, int format, const char *prog)
|
||||
{
|
||||
SM2_KEY exch_key;
|
||||
uint8_t ra[65];
|
||||
int ret = -1;
|
||||
|
||||
if (sm2_key_generate(&exch_key) != 1
|
||||
|| sm2_z256_point_to_uncompressed_octets(&exch_key.public_key, ra) != 1
|
||||
|| sm2exch_save_exch_key(&exch_key, exch_keyoutfile, exch_pass, NULL, prog) != 1
|
||||
|| sm2exch_write_data(outfile, ra, sizeof(ra), format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: init stage failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
ret = 0;
|
||||
end:
|
||||
gmssl_secure_clear(&exch_key, sizeof(exch_key));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm2exch_stage_respond(const char *keyfile, const char *pass,
|
||||
const char *pubkeyfile, const char *certfile,
|
||||
const char *peer_pubkeyfile, const char *peer_certfile,
|
||||
const char *id, size_t idlen, const char *peer_id, size_t peer_idlen,
|
||||
const char *infile, const char *exch_keyoutfile, const char *exch_pass,
|
||||
const char *secret_stateoutfile, const char *outfile, size_t keylen,
|
||||
int format, const char *prog)
|
||||
{
|
||||
SM2_KEY key;
|
||||
SM2_KEY peer_public_key;
|
||||
SM2_KEY exch_key;
|
||||
uint8_t ra[65];
|
||||
uint8_t rb[65];
|
||||
uint8_t secret_state[65];
|
||||
uint8_t shared_key[SM2EXCH_MAX_SHARED_KEY_SIZE];
|
||||
uint8_t sb[32];
|
||||
uint8_t rb_sb[97];
|
||||
int ret = -1;
|
||||
|
||||
if (!secret_stateoutfile) {
|
||||
fprintf(stderr, "gmssl %s: '-secret_state_out' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (sm2exch_load_local_keys(&key, keyfile, pass, pubkeyfile, certfile, prog) != 1
|
||||
|| sm2exch_load_public_key(&peer_public_key, peer_pubkeyfile, peer_certfile, prog, "peer") != 1
|
||||
|| sm2exch_read_point(infile, ra, format) != 1
|
||||
|| sm2_key_generate(&exch_key) != 1
|
||||
|| sm2_z256_point_to_uncompressed_octets(&exch_key.public_key, rb) != 1) {
|
||||
fprintf(stderr, "gmssl %s: respond stage input failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (sm2_key_exchange(0, &key, id, idlen, &peer_public_key, peer_id, peer_idlen,
|
||||
&exch_key, ra, secret_state, keylen, shared_key) != 1
|
||||
|| sm2_key_exchange_compute_confirm(0, &key, id, idlen,
|
||||
&peer_public_key, peer_id, peer_idlen,
|
||||
&exch_key, ra, secret_state, sb) != 1
|
||||
|| sm2exch_save_exch_key(&exch_key, exch_keyoutfile, exch_pass, ra, prog) != 1
|
||||
|| sm2exch_write_data(secret_stateoutfile, secret_state, sizeof(secret_state), format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: respond stage failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
memcpy(rb_sb, rb, sizeof(rb));
|
||||
memcpy(rb_sb + sizeof(rb), sb, sizeof(sb));
|
||||
if (sm2exch_write_data(outfile, rb_sb, sizeof(rb_sb), format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: output RB||SB failed : %s\n", prog, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
ret = 0;
|
||||
end:
|
||||
gmssl_secure_clear(&key, sizeof(key));
|
||||
gmssl_secure_clear(&peer_public_key, sizeof(peer_public_key));
|
||||
gmssl_secure_clear(&exch_key, sizeof(exch_key));
|
||||
gmssl_secure_clear(secret_state, sizeof(secret_state));
|
||||
gmssl_secure_clear(shared_key, sizeof(shared_key));
|
||||
gmssl_secure_clear(sb, sizeof(sb));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm2exch_stage_confirm(const char *keyfile, const char *pass,
|
||||
const char *pubkeyfile, const char *certfile,
|
||||
const char *peer_pubkeyfile, const char *peer_certfile,
|
||||
const char *id, size_t idlen, const char *peer_id, size_t peer_idlen,
|
||||
const char *exch_keyfile, const char *exch_pass, const char *infile,
|
||||
const char *secret_stateoutfile, const char *keyoutfile, const char *outfile,
|
||||
size_t keylen, int format, const char *prog)
|
||||
{
|
||||
SM2_KEY key;
|
||||
SM2_KEY peer_public_key;
|
||||
SM2_KEY exch_key;
|
||||
uint8_t rb_sb[97];
|
||||
uint8_t secret_state[65];
|
||||
uint8_t shared_key[SM2EXCH_MAX_SHARED_KEY_SIZE];
|
||||
uint8_t sa[32];
|
||||
int vr;
|
||||
int ret = -1;
|
||||
|
||||
if (!keyoutfile) {
|
||||
fprintf(stderr, "gmssl %s: '-keyout' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (sm2exch_load_local_keys(&key, keyfile, pass, pubkeyfile, certfile, prog) != 1
|
||||
|| sm2exch_load_public_key(&peer_public_key, peer_pubkeyfile, peer_certfile, prog, "peer") != 1
|
||||
|| sm2exch_load_exch_key(&exch_key, NULL, exch_keyfile, exch_pass, prog) != 1
|
||||
|| sm2exch_read_data(infile, rb_sb, sizeof(rb_sb), format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: confirm stage input failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (sm2_key_exchange(1, &key, id, idlen, &peer_public_key, peer_id, peer_idlen,
|
||||
&exch_key, rb_sb, secret_state, keylen, shared_key) != 1) {
|
||||
fprintf(stderr, "gmssl %s: key exchange failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if ((vr = sm2_key_exchange_verify_confirm(1, &key, id, idlen,
|
||||
&peer_public_key, peer_id, peer_idlen, &exch_key,
|
||||
rb_sb, secret_state, rb_sb + SM2EXCH_RB_SIZE)) != 1) {
|
||||
fprintf(stderr, "gmssl %s: SB verification %s\n", prog, vr < 0 ? "failure" : "failed");
|
||||
goto end;
|
||||
}
|
||||
if (sm2_key_exchange_compute_confirm(1, &key, id, idlen,
|
||||
&peer_public_key, peer_id, peer_idlen, &exch_key,
|
||||
rb_sb, secret_state, sa) != 1
|
||||
|| sm2exch_write_data(keyoutfile, shared_key, keylen, format) != 1
|
||||
|| sm2exch_write_data(outfile, sa, sizeof(sa), format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: confirm stage failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (secret_stateoutfile
|
||||
&& sm2exch_write_data(secret_stateoutfile, secret_state, sizeof(secret_state), format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: output secret_state failed : %s\n", prog, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
ret = 0;
|
||||
end:
|
||||
gmssl_secure_clear(&key, sizeof(key));
|
||||
gmssl_secure_clear(&peer_public_key, sizeof(peer_public_key));
|
||||
gmssl_secure_clear(&exch_key, sizeof(exch_key));
|
||||
gmssl_secure_clear(secret_state, sizeof(secret_state));
|
||||
gmssl_secure_clear(shared_key, sizeof(shared_key));
|
||||
gmssl_secure_clear(sa, sizeof(sa));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm2exch_stage_finish(const char *keyfile, const char *pass,
|
||||
const char *pubkeyfile, const char *certfile,
|
||||
const char *peer_pubkeyfile, const char *peer_certfile,
|
||||
const char *id, size_t idlen, const char *peer_id, size_t peer_idlen,
|
||||
const char *exch_keyfile, const char *exch_pass, const char *secret_statefile,
|
||||
const char *infile, const char *keyoutfile, size_t keylen, int format,
|
||||
const char *prog)
|
||||
{
|
||||
SM2_KEY key;
|
||||
SM2_KEY peer_public_key;
|
||||
SM2_KEY exch_key;
|
||||
uint8_t ra[65];
|
||||
uint8_t secret_state[65];
|
||||
uint8_t sa[32];
|
||||
uint8_t shared_key[SM2EXCH_MAX_SHARED_KEY_SIZE];
|
||||
int vr;
|
||||
int ret = -1;
|
||||
|
||||
if (!secret_statefile) {
|
||||
fprintf(stderr, "gmssl %s: '-secret_state' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!keyoutfile) {
|
||||
fprintf(stderr, "gmssl %s: '-keyout' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (sm2exch_load_local_keys(&key, keyfile, pass, pubkeyfile, certfile, prog) != 1
|
||||
|| sm2exch_load_public_key(&peer_public_key, peer_pubkeyfile, peer_certfile, prog, "peer") != 1
|
||||
|| sm2exch_load_exch_key(&exch_key, ra, exch_keyfile, exch_pass, prog) != 1
|
||||
|| sm2exch_read_point(secret_statefile, secret_state, format) != 1
|
||||
|| sm2exch_read_data(infile, sa, sizeof(sa), format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: finish stage input failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if ((vr = sm2_key_exchange_verify_confirm(0, &key, id, idlen,
|
||||
&peer_public_key, peer_id, peer_idlen, &exch_key,
|
||||
ra, secret_state, sa)) != 1) {
|
||||
fprintf(stderr, "gmssl %s: SA verification %s\n", prog, vr < 0 ? "failure" : "failed");
|
||||
goto end;
|
||||
}
|
||||
if (sm2exch_derive_key_from_secret_state(0, &key, id, idlen,
|
||||
&peer_public_key, peer_id, peer_idlen,
|
||||
secret_state, shared_key, keylen) != 1
|
||||
|| sm2exch_write_data(keyoutfile, shared_key, keylen, format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: finish stage failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
ret = 0;
|
||||
end:
|
||||
gmssl_secure_clear(&key, sizeof(key));
|
||||
gmssl_secure_clear(&peer_public_key, sizeof(peer_public_key));
|
||||
gmssl_secure_clear(&exch_key, sizeof(exch_key));
|
||||
gmssl_secure_clear(secret_state, sizeof(secret_state));
|
||||
gmssl_secure_clear(shared_key, sizeof(shared_key));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sm2exch_main(int argc, char **argv)
|
||||
{
|
||||
int ret = 1;
|
||||
char *prog = argv[0];
|
||||
char *stage = NULL;
|
||||
char *certfile = NULL;
|
||||
char *pubkeyfile = NULL;
|
||||
char *keyfile = NULL;
|
||||
char *pass = NULL;
|
||||
char *peer_certfile = NULL;
|
||||
char *peer_pubkeyfile = NULL;
|
||||
char *id = NULL;
|
||||
char *peer_id = NULL;
|
||||
char *id_hex = NULL;
|
||||
char *peer_id_hex = NULL;
|
||||
char id_buf[SM2_MAX_ID_LENGTH];
|
||||
size_t id_len = 0;
|
||||
char peer_id_buf[SM2_MAX_ID_LENGTH];
|
||||
size_t peer_id_len = 0;
|
||||
char *infile = NULL;
|
||||
char *outfile = NULL;
|
||||
char *exch_keyfile = NULL;
|
||||
char *exch_keyoutfile = NULL;
|
||||
char *exch_pass = NULL;
|
||||
char *secret_statefile = NULL;
|
||||
char *secret_stateoutfile = NULL;
|
||||
char *keyoutfile = NULL;
|
||||
size_t keylen = 32;
|
||||
int format = SM2EXCH_FMT_HEX;
|
||||
|
||||
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);
|
||||
return 0;
|
||||
} else if (!strcmp(*argv, "-stage")) {
|
||||
if (--argc < 1) goto bad;
|
||||
stage = *(++argv);
|
||||
} else if (!strcmp(*argv, "-cert")) {
|
||||
if (pubkeyfile) {
|
||||
fprintf(stderr, "gmssl %s: options '-cert' and '-pubkey' conflict\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
certfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-pubkey")) {
|
||||
if (certfile) {
|
||||
fprintf(stderr, "gmssl %s: options '-cert' and '-pubkey' conflict\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
pubkeyfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-key")) {
|
||||
if (--argc < 1) goto bad;
|
||||
keyfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-pass")) {
|
||||
if (--argc < 1) goto bad;
|
||||
pass = *(++argv);
|
||||
} else if (!strcmp(*argv, "-peer_cert")) {
|
||||
if (peer_pubkeyfile) {
|
||||
fprintf(stderr, "gmssl %s: options '-peer_cert' and '-peer_pubkey' conflict\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
peer_certfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-peer_pubkey")) {
|
||||
if (peer_certfile) {
|
||||
fprintf(stderr, "gmssl %s: options '-peer_cert' and '-peer_pubkey' conflict\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
peer_pubkeyfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-id")) {
|
||||
if (id_hex) {
|
||||
fprintf(stderr, "gmssl %s: '-id' and '-id_hex' should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
id = *(++argv);
|
||||
id_len = strlen(id);
|
||||
} else if (!strcmp(*argv, "-id_hex")) {
|
||||
if (id) {
|
||||
fprintf(stderr, "gmssl %s: '-id' and '-id_hex' should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
id_hex = *(++argv);
|
||||
if (strlen(id_hex) > sizeof(id_buf) * 2
|
||||
|| hex_to_bytes(id_hex, strlen(id_hex), (uint8_t *)id_buf, &id_len) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid '-id_hex' value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
id = id_buf;
|
||||
} else if (!strcmp(*argv, "-peer_id")) {
|
||||
if (peer_id_hex) {
|
||||
fprintf(stderr, "gmssl %s: '-peer_id' and '-peer_id_hex' should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
peer_id = *(++argv);
|
||||
peer_id_len = strlen(peer_id);
|
||||
} else if (!strcmp(*argv, "-peer_id_hex")) {
|
||||
if (peer_id) {
|
||||
fprintf(stderr, "gmssl %s: '-peer_id' and '-peer_id_hex' should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
peer_id_hex = *(++argv);
|
||||
if (strlen(peer_id_hex) > sizeof(peer_id_buf) * 2
|
||||
|| hex_to_bytes(peer_id_hex, strlen(peer_id_hex), (uint8_t *)peer_id_buf, &peer_id_len) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid '-peer_id_hex' value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
peer_id = peer_id_buf;
|
||||
} else if (!strcmp(*argv, "-in")) {
|
||||
if (--argc < 1) goto bad;
|
||||
infile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-out")) {
|
||||
if (--argc < 1) goto bad;
|
||||
outfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-exch_keyout")) {
|
||||
if (--argc < 1) goto bad;
|
||||
exch_keyoutfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-exch_key")) {
|
||||
if (--argc < 1) goto bad;
|
||||
exch_keyfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-exch_pass")) {
|
||||
if (--argc < 1) goto bad;
|
||||
exch_pass = *(++argv);
|
||||
} else if (!strcmp(*argv, "-secret_state_out")) {
|
||||
if (--argc < 1) goto bad;
|
||||
secret_stateoutfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-secret_state")) {
|
||||
if (--argc < 1) goto bad;
|
||||
secret_statefile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-keylen")) {
|
||||
if (--argc < 1) goto bad;
|
||||
keylen = (size_t)atoi(*(++argv));
|
||||
if (keylen < 1 || keylen > SM2EXCH_MAX_SHARED_KEY_SIZE) {
|
||||
fprintf(stderr, "gmssl %s: invalid '-keylen' value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
} else if (!strcmp(*argv, "-keyout")) {
|
||||
if (--argc < 1) goto bad;
|
||||
keyoutfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-hex")) {
|
||||
format = SM2EXCH_FMT_HEX;
|
||||
} else if (!strcmp(*argv, "-bin")) {
|
||||
format = SM2EXCH_FMT_BIN;
|
||||
} 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 (!stage) {
|
||||
fprintf(stderr, "gmssl %s: '-stage' option required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (!id) {
|
||||
id = SM2_DEFAULT_ID;
|
||||
id_len = SM2_DEFAULT_ID_LENGTH;
|
||||
}
|
||||
if (!peer_id) {
|
||||
peer_id = SM2_DEFAULT_ID;
|
||||
peer_id_len = SM2_DEFAULT_ID_LENGTH;
|
||||
}
|
||||
|
||||
if (!strcmp(stage, "init")) {
|
||||
ret = sm2exch_stage_init(exch_keyoutfile, exch_pass, outfile, format, prog);
|
||||
} else if (!strcmp(stage, "respond")) {
|
||||
ret = sm2exch_stage_respond(keyfile, pass, pubkeyfile, certfile,
|
||||
peer_pubkeyfile, peer_certfile, id, id_len, peer_id, peer_id_len,
|
||||
infile, exch_keyoutfile, exch_pass, secret_stateoutfile,
|
||||
outfile, keylen, format, prog);
|
||||
} else if (!strcmp(stage, "confirm")) {
|
||||
ret = sm2exch_stage_confirm(keyfile, pass, pubkeyfile, certfile,
|
||||
peer_pubkeyfile, peer_certfile, id, id_len, peer_id, peer_id_len,
|
||||
exch_keyfile, exch_pass, infile, secret_stateoutfile,
|
||||
keyoutfile, outfile, keylen, format, prog);
|
||||
} else if (!strcmp(stage, "finish")) {
|
||||
ret = sm2exch_stage_finish(keyfile, pass, pubkeyfile, certfile,
|
||||
peer_pubkeyfile, peer_certfile, id, id_len, peer_id, peer_id_len,
|
||||
exch_keyfile, exch_pass, secret_statefile, infile,
|
||||
keyoutfile, keylen, format, prog);
|
||||
} else {
|
||||
fprintf(stderr, "gmssl %s: invalid '-stage' value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
return ret == 0 ? 0 : 1;
|
||||
}
|
||||
31
tools/sm4.c
31
tools/sm4.c
@@ -27,8 +27,6 @@ enum {
|
||||
SM4_MODE_XTS,
|
||||
SM4_MODE_CCM,
|
||||
SM4_MODE_GCM,
|
||||
SM4_MODE_CBC_SM3_HMAC,
|
||||
SM4_MODE_CTR_SM3_HMAC,
|
||||
};
|
||||
|
||||
static uint8_t *read_content(FILE *infp, size_t *outlen, const char *prog)
|
||||
@@ -188,8 +186,6 @@ static const char *options =
|
||||
" -ctr CTR mode, need 16-byte key and 16-byte iv\n"
|
||||
" -ccm CCM mode, need 16-byte key and any iv length\n"
|
||||
" -gcm GCM mode, need 16-byte key and any iv length\n"
|
||||
" -cbc_sm3_hmac CBC mode with padding and HMAC-SM3 (encrypt-then-mac), need 48-byte key and 16-byte iv\n"
|
||||
" -ctr_sm3_hmac CTR mode with HMAC-SM3 (entrypt-then-mac), need 48-byte key and 16-byte iv\n"
|
||||
" -xts XTS mode\n"
|
||||
"\n"
|
||||
" -encrypt Encrypt\n"
|
||||
@@ -205,13 +201,6 @@ static const char *options =
|
||||
"\n"
|
||||
" echo \"hello\" | gmssl sm4 -gcm -encrypt -key 11223344556677881122334455667788 -iv 112233445566778811223344 -out ciphertext.bin\n"
|
||||
" gmssl sm4 -gcm -decrypt -key 11223344556677881122334455667788 -iv 112233445566778811223344 -in ciphertext.bin\n"
|
||||
"\n"
|
||||
" echo \"hello\" | gmssl sm4 -cbc_sm3_hmac -encrypt \\\n"
|
||||
" -key 112233445566778811223344556677881122334455667788112233445566778811223344556677881122334455667788 \\\n"
|
||||
" -iv 11223344556677881122334455667788 -out ciphertext.bin\n"
|
||||
" gmssl sm4 -cbc_sm3_hmac -decrypt \\\n"
|
||||
" -key 112233445566778811223344556677881122334455667788112233445566778811223344556677881122334455667788 \\\n"
|
||||
" -iv 11223344556677881122334455667788 -in ciphertext.bin\n"
|
||||
"\n";
|
||||
|
||||
int sm4_main(int argc, char **argv)
|
||||
@@ -322,12 +311,6 @@ int sm4_main(int argc, char **argv)
|
||||
} else if (!strcmp(*argv, "-ctr")) {
|
||||
if (mode) goto bad;
|
||||
mode = SM4_MODE_CTR;
|
||||
} else if (!strcmp(*argv, "-cbc_sm3_hmac")) {
|
||||
if (mode) goto bad;
|
||||
mode = SM4_MODE_CBC_SM3_HMAC;
|
||||
} else if (!strcmp(*argv, "-ctr_sm3_hmac")) {
|
||||
if (mode) goto bad;
|
||||
mode = SM4_MODE_CTR_SM3_HMAC;
|
||||
} else if (!strcmp(*argv, "-gcm")) {
|
||||
if (mode) goto bad;
|
||||
mode = SM4_MODE_GCM;
|
||||
@@ -449,9 +432,6 @@ bad:
|
||||
#ifdef ENABLE_SM4_XTS
|
||||
case SM4_MODE_XTS:
|
||||
#endif
|
||||
case SM4_MODE_CBC_SM3_HMAC:
|
||||
case SM4_MODE_CTR_SM3_HMAC:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: mode is not supported\n", prog);
|
||||
goto end;
|
||||
@@ -477,13 +457,6 @@ bad:
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case SM4_MODE_CBC_SM3_HMAC:
|
||||
case SM4_MODE_CTR_SM3_HMAC:
|
||||
if (keylen != 48) {
|
||||
fprintf(stderr, "%s: invalid key length, should be 96 hex digits\n", prog);
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// check iv length
|
||||
@@ -498,8 +471,6 @@ bad:
|
||||
case SM4_MODE_CFB:
|
||||
case SM4_MODE_OFB:
|
||||
case SM4_MODE_CTR:
|
||||
case SM4_MODE_CBC_SM3_HMAC:
|
||||
case SM4_MODE_CTR_SM3_HMAC:
|
||||
if (ivlen != 16) {
|
||||
fprintf(stderr, "%s: invalid IV length, should be 32 hex digits\n", prog);
|
||||
goto end;
|
||||
@@ -613,7 +584,6 @@ bad:
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
#ifdef ENABLE_SM4_ECB
|
||||
case SM4_MODE_ECB: rv = sm4_ecb_encrypt_finish(&sm4_ctx.ecb, outbuf, &outlen); break;
|
||||
@@ -688,7 +658,6 @@ bad:
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
#ifdef ENABLE_SM4_ECB
|
||||
case SM4_MODE_ECB: rv = sm4_ecb_decrypt_finish(&sm4_ctx.ecb, outbuf, &outlen); break;
|
||||
|
||||
771
tools/sm9exch.c
Normal file
771
tools/sm9exch.c
Normal file
@@ -0,0 +1,771 @@
|
||||
/*
|
||||
* 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 <stdint.h>
|
||||
#include <gmssl/mem.h>
|
||||
#include <gmssl/hex.h>
|
||||
#include <gmssl/pem.h>
|
||||
#include <gmssl/sm9.h>
|
||||
|
||||
|
||||
#define SM9EXCH_R_SIZE 32
|
||||
#define SM9EXCH_RA_SIZE 65
|
||||
#define SM9EXCH_RB_SIZE 65
|
||||
#define SM9EXCH_CONFIRM_SIZE 32
|
||||
#define SM9EXCH_RB_SB_SIZE (SM9EXCH_RB_SIZE + SM9EXCH_CONFIRM_SIZE)
|
||||
#define SM9EXCH_EXCH_KEY_SIZE (SM9EXCH_R_SIZE + SM9EXCH_RB_SIZE)
|
||||
#define SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE (SM9EXCH_EXCH_KEY_SIZE + SM9EXCH_RA_SIZE)
|
||||
#define SM9EXCH_MAX_SHARED_KEY_SIZE 1024
|
||||
#define PEM_SM9_EXCH_KEY "SM9 EXCHANGE PRIVATE KEY"
|
||||
|
||||
enum {
|
||||
SM9EXCH_FMT_BIN = 0,
|
||||
SM9EXCH_FMT_HEX = 1,
|
||||
};
|
||||
|
||||
static const char *usage =
|
||||
"-stage init|respond|confirm|finish [options]";
|
||||
|
||||
static const char *options =
|
||||
"\n"
|
||||
"Options\n"
|
||||
"\n"
|
||||
" -stage init|respond|confirm|finish\n"
|
||||
" SM9 key exchange stage\n"
|
||||
" -pubmaster pem SM9 exchange master public key in PEM format\n"
|
||||
" -key pem Local SM9 exchange private key in PEM format\n"
|
||||
" -pass str Password to open local private key\n"
|
||||
" -id str Local SM9 identity\n"
|
||||
" -id_hex hex Local SM9 identity in hex\n"
|
||||
" -peer_id str Peer SM9 identity\n"
|
||||
" -peer_id_hex hex Peer SM9 identity in hex\n"
|
||||
" -in file | stdin Input data for this stage\n"
|
||||
" respond: RA, 65 bytes\n"
|
||||
" confirm: RB || SB, 97 bytes\n"
|
||||
" finish: SA, 32 bytes\n"
|
||||
" -out file | stdout Output data to send to peer\n"
|
||||
" init: RA, 65 bytes\n"
|
||||
" respond: RB || SB, 97 bytes\n"
|
||||
" confirm: SA, 32 bytes\n"
|
||||
" -exch_keyout pem Output local ephemeral exchange state r||R in PEM format\n"
|
||||
" -exch_key pem Input local ephemeral exchange state r||R in PEM format\n"
|
||||
" -keylen num Shared key length in bytes, 32 by default\n"
|
||||
" -keyout file Output shared key\n"
|
||||
" -hex Encode input/output data in hex, default\n"
|
||||
" -bin Encode input/output data in binary\n"
|
||||
"\n"
|
||||
"Examples\n"
|
||||
"\n"
|
||||
" gmssl sm9setup -alg sm9encrypt -pass P@ssw0rd \\\n"
|
||||
" -out sm9_msk.pem -pubout sm9_mpk.pem\n"
|
||||
" gmssl sm9keygen -alg sm9keyagreement -in sm9_msk.pem -inpass P@ssw0rd \\\n"
|
||||
" -id Alice -out alice.pem -outpass 123456\n"
|
||||
" gmssl sm9keygen -alg sm9keyagreement -in sm9_msk.pem -inpass P@ssw0rd \\\n"
|
||||
" -id Bob -out bob.pem -outpass 123456\n"
|
||||
" gmssl sm9exch -stage init \\\n"
|
||||
" -pubmaster sm9_mpk.pem -peer_id Bob \\\n"
|
||||
" -exch_keyout alice_ra.pem -out ra.hex\n"
|
||||
" gmssl sm9exch -stage respond \\\n"
|
||||
" -pubmaster sm9_mpk.pem -key bob.pem -pass 123456 -id Bob \\\n"
|
||||
" -peer_id Alice -in ra.hex \\\n"
|
||||
" -exch_keyout bob_rb.pem -out rb_sb.hex\n"
|
||||
" gmssl sm9exch -stage confirm \\\n"
|
||||
" -pubmaster sm9_mpk.pem -key alice.pem -pass 123456 -id Alice \\\n"
|
||||
" -peer_id Bob -exch_key alice_ra.pem -in rb_sb.hex \\\n"
|
||||
" -keylen 48 -keyout alice_shared_key.hex -out sa.hex\n"
|
||||
" gmssl sm9exch -stage finish \\\n"
|
||||
" -pubmaster sm9_mpk.pem -key bob.pem -pass 123456 -id Bob \\\n"
|
||||
" -peer_id Alice -exch_key bob_rb.pem \\\n"
|
||||
" -in sa.hex -keylen 48 -keyout bob_shared_key.hex\n"
|
||||
"\n"
|
||||
"Notes\n"
|
||||
"\n"
|
||||
" RA and RB are fixed 65-byte uncompressed SM9 curve points.\n"
|
||||
" The respond output is RB || SB, fixed 97 bytes.\n"
|
||||
" The ephemeral exchange state contains secret scalar r, public point R and optional peer point.\n"
|
||||
" -hex and -bin affect RA, RB||SB, SA and shared key files.\n"
|
||||
"\n";
|
||||
|
||||
static int read_file(const char *file, uint8_t *buf, size_t *len, size_t maxlen)
|
||||
{
|
||||
FILE *fp = stdin;
|
||||
size_t n;
|
||||
|
||||
if (!buf || !len) {
|
||||
return -1;
|
||||
}
|
||||
if (file && !(fp = fopen(file, "rb"))) {
|
||||
return -1;
|
||||
}
|
||||
n = fread(buf, 1, maxlen + 1, fp);
|
||||
if (ferror(fp)) {
|
||||
if (file) fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
if (file) fclose(fp);
|
||||
if (n > maxlen) {
|
||||
return -1;
|
||||
}
|
||||
*len = n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int write_file(const char *file, const uint8_t *buf, size_t len)
|
||||
{
|
||||
FILE *fp = stdout;
|
||||
int ret = -1;
|
||||
|
||||
if (!buf || !len) {
|
||||
return -1;
|
||||
}
|
||||
if (file && !(fp = fopen(file, "wb"))) {
|
||||
return -1;
|
||||
}
|
||||
if (fwrite(buf, 1, len, fp) == len) {
|
||||
ret = 1;
|
||||
}
|
||||
if (file) fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm9exch_read_exact(const char *file, uint8_t *buf, size_t len);
|
||||
|
||||
static int sm9exch_write_data(const char *file, const uint8_t *buf, size_t len, int format)
|
||||
{
|
||||
uint8_t *hexbuf = NULL;
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
if (format == SM9EXCH_FMT_BIN) {
|
||||
return write_file(file, buf, len);
|
||||
}
|
||||
if (!(hexbuf = malloc(len * 2))) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
static const char *hex = "0123456789abcdef";
|
||||
hexbuf[i * 2] = (uint8_t)hex[buf[i] >> 4];
|
||||
hexbuf[i * 2 + 1] = (uint8_t)hex[buf[i] & 0x0f];
|
||||
}
|
||||
ret = write_file(file, hexbuf, len * 2);
|
||||
gmssl_secure_clear(hexbuf, len * 2);
|
||||
free(hexbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm9exch_read_data(const char *file, uint8_t *buf, size_t len, int format)
|
||||
{
|
||||
uint8_t *in = NULL;
|
||||
uint8_t *hex = NULL;
|
||||
size_t inlen;
|
||||
size_t hexlen = 0;
|
||||
size_t outlen;
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
if (format == SM9EXCH_FMT_BIN) {
|
||||
return sm9exch_read_exact(file, buf, len);
|
||||
}
|
||||
if (!(in = malloc(len * 2 + 64)) || !(hex = malloc(len * 2))) {
|
||||
goto end;
|
||||
}
|
||||
if (read_file(file, in, &inlen, len * 2 + 63) != 1) {
|
||||
goto end;
|
||||
}
|
||||
for (i = 0; i < inlen; i++) {
|
||||
if (in[i] == ' ' || in[i] == '\t' || in[i] == '\r' || in[i] == '\n') {
|
||||
continue;
|
||||
}
|
||||
if (hexlen >= len * 2) {
|
||||
goto end;
|
||||
}
|
||||
hex[hexlen++] = in[i];
|
||||
}
|
||||
if (hexlen != len * 2
|
||||
|| hex_to_bytes((char *)hex, hexlen, buf, &outlen) != 1
|
||||
|| outlen != len) {
|
||||
goto end;
|
||||
}
|
||||
ret = 1;
|
||||
end:
|
||||
if (in) {
|
||||
gmssl_secure_clear(in, len * 2 + 64);
|
||||
free(in);
|
||||
}
|
||||
if (hex) {
|
||||
gmssl_secure_clear(hex, len * 2);
|
||||
free(hex);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm9exch_read_exact(const char *file, uint8_t *buf, size_t len)
|
||||
{
|
||||
size_t inlen;
|
||||
|
||||
if (read_file(file, buf, &inlen, len) != 1 || inlen != len) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm9exch_read_point_file(const char *file, SM9_Z256_POINT *point, int format)
|
||||
{
|
||||
uint8_t buf[65];
|
||||
|
||||
if (sm9exch_read_data(file, buf, sizeof(buf), format) != 1
|
||||
|| sm9_z256_point_from_uncompressed_octets(point, buf) != 1
|
||||
|| !sm9_z256_point_is_on_curve(point)) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm9exch_load_master_public_key(SM9_EXCH_MASTER_KEY *mpk,
|
||||
const char *mpkfile, const char *prog)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (!mpkfile) {
|
||||
fprintf(stderr, "gmssl %s: '-pubmaster' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!(fp = fopen(mpkfile, "rb"))) {
|
||||
fprintf(stderr, "gmssl %s: open master public key failed : %s\n", prog, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
if (sm9_enc_master_public_key_from_pem(mpk, fp) != 1) {
|
||||
fprintf(stderr, "gmssl %s: parse master public key failed\n", prog);
|
||||
goto end;
|
||||
}
|
||||
ret = 1;
|
||||
end:
|
||||
if (fp) fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm9exch_load_private_key(SM9_EXCH_KEY *key, const char *keyfile,
|
||||
const char *pass, const SM9_EXCH_MASTER_KEY *mpk, const char *prog)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (!keyfile) {
|
||||
fprintf(stderr, "gmssl %s: '-key' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!pass) {
|
||||
fprintf(stderr, "gmssl %s: '-pass' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!(fp = fopen(keyfile, "rb"))) {
|
||||
fprintf(stderr, "gmssl %s: open private key failed : %s\n", prog, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
if (sm9_enc_key_info_decrypt_from_pem(key, pass, fp) != 1) {
|
||||
fprintf(stderr, "gmssl %s: parse private key failed\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (mpk && sm9_z256_point_equ(&key->Ppube, &mpk->Ppube) != 1) {
|
||||
fprintf(stderr, "gmssl %s: private key does not match master public key\n", prog);
|
||||
goto end;
|
||||
}
|
||||
ret = 1;
|
||||
end:
|
||||
if (fp) fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm9exch_generate_R(const SM9_EXCH_MASTER_KEY *mpk,
|
||||
const char *peer_id, size_t peer_idlen, sm9_z256_t r, SM9_Z256_POINT *R)
|
||||
{
|
||||
if (!mpk || !peer_id || !peer_idlen || !r || !R) {
|
||||
return -1;
|
||||
}
|
||||
if (peer_idlen > SM9_MAX_ID_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
sm9_z256_hash1(r, peer_id, peer_idlen, SM9_HID_EXCH);
|
||||
sm9_z256_point_mul(R, r, sm9_z256_generator());
|
||||
sm9_z256_point_add(R, R, &mpk->Ppube);
|
||||
|
||||
do {
|
||||
if (sm9_z256_rand_range(r, sm9_z256_order()) != 1) {
|
||||
return -1;
|
||||
}
|
||||
} while (sm9_z256_is_zero(r));
|
||||
|
||||
sm9_z256_point_mul(R, r, R);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm9exch_save_exch_key(const sm9_z256_t r, const SM9_Z256_POINT *R,
|
||||
const SM9_Z256_POINT *peer_R, const char *keyfile, const char *prog)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
uint8_t buf[SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE];
|
||||
size_t len = SM9EXCH_EXCH_KEY_SIZE;
|
||||
int ret = -1;
|
||||
|
||||
if (!keyfile) {
|
||||
fprintf(stderr, "gmssl %s: '-exch_keyout' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
sm9_z256_to_bytes(r, buf);
|
||||
if (sm9_z256_point_to_uncompressed_octets(R, buf + SM9EXCH_R_SIZE) != 1) {
|
||||
goto end;
|
||||
}
|
||||
if (peer_R) {
|
||||
if (sm9_z256_point_to_uncompressed_octets(peer_R, buf + SM9EXCH_EXCH_KEY_SIZE) != 1) {
|
||||
goto end;
|
||||
}
|
||||
len = SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE;
|
||||
}
|
||||
if (!(fp = fopen(keyfile, "wb"))) {
|
||||
fprintf(stderr, "gmssl %s: open output exchange key failed : %s\n", prog, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
if (pem_write(fp, PEM_SM9_EXCH_KEY, buf, len) != 1) {
|
||||
fprintf(stderr, "gmssl %s: output exchange key failed\n", prog);
|
||||
goto end;
|
||||
}
|
||||
ret = 1;
|
||||
end:
|
||||
gmssl_secure_clear(buf, sizeof(buf));
|
||||
if (fp) fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm9exch_load_exch_key(sm9_z256_t r, SM9_Z256_POINT *R,
|
||||
SM9_Z256_POINT *peer_R, const char *keyfile, const char *prog)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
uint8_t buf[SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE];
|
||||
size_t len;
|
||||
int ret = -1;
|
||||
|
||||
if (!keyfile) {
|
||||
fprintf(stderr, "gmssl %s: '-exch_key' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!(fp = fopen(keyfile, "rb"))) {
|
||||
fprintf(stderr, "gmssl %s: open exchange key failed : %s\n", prog, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
if (pem_read(fp, PEM_SM9_EXCH_KEY, buf, &len, sizeof(buf)) != 1
|
||||
|| (len != SM9EXCH_EXCH_KEY_SIZE && len != SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE)) {
|
||||
fprintf(stderr, "gmssl %s: parse exchange key failed\n", prog);
|
||||
goto end;
|
||||
}
|
||||
sm9_z256_from_bytes(r, buf);
|
||||
if (sm9_z256_is_zero(r)
|
||||
|| sm9_z256_point_from_uncompressed_octets(R, buf + SM9EXCH_R_SIZE) != 1
|
||||
|| !sm9_z256_point_is_on_curve(R)) {
|
||||
fprintf(stderr, "gmssl %s: invalid exchange key\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (peer_R) {
|
||||
if (len != SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE
|
||||
|| sm9_z256_point_from_uncompressed_octets(peer_R, buf + SM9EXCH_EXCH_KEY_SIZE) != 1
|
||||
|| !sm9_z256_point_is_on_curve(peer_R)) {
|
||||
fprintf(stderr, "gmssl %s: peer exchange point not found in exchange key\n", prog);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
ret = 1;
|
||||
end:
|
||||
gmssl_secure_clear(buf, sizeof(buf));
|
||||
if (fp) fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm9exch_stage_init(const char *mpkfile, const char *peer_id,
|
||||
size_t peer_idlen, const char *exch_keyoutfile, const char *outfile,
|
||||
int format, const char *prog)
|
||||
{
|
||||
SM9_EXCH_MASTER_KEY mpk;
|
||||
SM9_Z256_POINT R;
|
||||
sm9_z256_t r;
|
||||
uint8_t ra[65];
|
||||
int ret = -1;
|
||||
|
||||
if (!peer_id) {
|
||||
fprintf(stderr, "gmssl %s: '-peer_id' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (sm9exch_load_master_public_key(&mpk, mpkfile, prog) != 1
|
||||
|| sm9exch_generate_R(&mpk, peer_id, peer_idlen, r, &R) != 1
|
||||
|| sm9_z256_point_to_uncompressed_octets(&R, ra) != 1
|
||||
|| sm9exch_save_exch_key(r, &R, NULL, exch_keyoutfile, prog) != 1
|
||||
|| sm9exch_write_data(outfile, ra, sizeof(ra), format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: init stage failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
ret = 0;
|
||||
end:
|
||||
gmssl_secure_clear(&mpk, sizeof(mpk));
|
||||
gmssl_secure_clear(&R, sizeof(R));
|
||||
gmssl_secure_clear(r, sizeof(r));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm9exch_stage_respond(const char *mpkfile, const char *keyfile,
|
||||
const char *pass, const char *id, size_t idlen,
|
||||
const char *peer_id, size_t peer_idlen, const char *infile,
|
||||
const char *exch_keyoutfile, const char *outfile, size_t keylen,
|
||||
int format, const char *prog)
|
||||
{
|
||||
SM9_EXCH_MASTER_KEY mpk;
|
||||
SM9_EXCH_KEY key;
|
||||
SM9_Z256_POINT ra;
|
||||
SM9_Z256_POINT rb;
|
||||
sm9_z256_t r;
|
||||
uint8_t rb_octets[65];
|
||||
uint8_t shared_key[SM9EXCH_MAX_SHARED_KEY_SIZE];
|
||||
uint8_t sb[32];
|
||||
uint8_t rb_sb[97];
|
||||
int ret = -1;
|
||||
|
||||
if (!id) {
|
||||
fprintf(stderr, "gmssl %s: '-id' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!peer_id) {
|
||||
fprintf(stderr, "gmssl %s: '-peer_id' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (sm9exch_load_master_public_key(&mpk, mpkfile, prog) != 1
|
||||
|| sm9exch_load_private_key(&key, keyfile, pass, &mpk, prog) != 1
|
||||
|| sm9exch_read_point_file(infile, &ra, format) != 1
|
||||
|| sm9exch_generate_R(&mpk, peer_id, peer_idlen, r, &rb) != 1
|
||||
|| sm9_z256_point_to_uncompressed_octets(&rb, rb_octets) != 1) {
|
||||
fprintf(stderr, "gmssl %s: respond stage input failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (sm9_key_exchange(0, &mpk, &key, id, idlen, peer_id, peer_idlen,
|
||||
r, &rb, &ra, keylen, shared_key) != 1
|
||||
|| sm9_key_exchange_compute_confirm(0, &mpk, &key, id, idlen,
|
||||
peer_id, peer_idlen, r, &rb, &ra, sb) != 1
|
||||
|| sm9exch_save_exch_key(r, &rb, &ra, exch_keyoutfile, prog) != 1) {
|
||||
fprintf(stderr, "gmssl %s: respond stage failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
memcpy(rb_sb, rb_octets, sizeof(rb_octets));
|
||||
memcpy(rb_sb + sizeof(rb_octets), sb, sizeof(sb));
|
||||
if (sm9exch_write_data(outfile, rb_sb, sizeof(rb_sb), format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: output RB||SB failed : %s\n", prog, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
ret = 0;
|
||||
end:
|
||||
gmssl_secure_clear(&mpk, sizeof(mpk));
|
||||
gmssl_secure_clear(&key, sizeof(key));
|
||||
gmssl_secure_clear(&ra, sizeof(ra));
|
||||
gmssl_secure_clear(&rb, sizeof(rb));
|
||||
gmssl_secure_clear(r, sizeof(r));
|
||||
gmssl_secure_clear(shared_key, sizeof(shared_key));
|
||||
gmssl_secure_clear(sb, sizeof(sb));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm9exch_stage_confirm(const char *mpkfile, const char *keyfile,
|
||||
const char *pass, const char *id, size_t idlen,
|
||||
const char *peer_id, size_t peer_idlen, const char *exch_keyfile,
|
||||
const char *infile, const char *keyoutfile, const char *outfile,
|
||||
size_t keylen, int format, const char *prog)
|
||||
{
|
||||
SM9_EXCH_MASTER_KEY mpk;
|
||||
SM9_EXCH_KEY key;
|
||||
SM9_Z256_POINT ra;
|
||||
SM9_Z256_POINT rb;
|
||||
sm9_z256_t r;
|
||||
uint8_t rb_sb[97];
|
||||
uint8_t shared_key[SM9EXCH_MAX_SHARED_KEY_SIZE];
|
||||
uint8_t sa[32];
|
||||
int vr;
|
||||
int ret = -1;
|
||||
|
||||
if (!id) {
|
||||
fprintf(stderr, "gmssl %s: '-id' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!peer_id) {
|
||||
fprintf(stderr, "gmssl %s: '-peer_id' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!keyoutfile) {
|
||||
fprintf(stderr, "gmssl %s: '-keyout' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (sm9exch_load_master_public_key(&mpk, mpkfile, prog) != 1
|
||||
|| sm9exch_load_private_key(&key, keyfile, pass, &mpk, prog) != 1
|
||||
|| sm9exch_load_exch_key(r, &ra, NULL, exch_keyfile, prog) != 1
|
||||
|| sm9exch_read_data(infile, rb_sb, sizeof(rb_sb), format) != 1
|
||||
|| sm9_z256_point_from_uncompressed_octets(&rb, rb_sb) != 1
|
||||
|| !sm9_z256_point_is_on_curve(&rb)) {
|
||||
fprintf(stderr, "gmssl %s: confirm stage input failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (sm9_key_exchange(1, &mpk, &key, id, idlen, peer_id, peer_idlen,
|
||||
r, &ra, &rb, keylen, shared_key) != 1) {
|
||||
fprintf(stderr, "gmssl %s: key exchange failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if ((vr = sm9_key_exchange_verify_confirm(1, &mpk, &key, id, idlen,
|
||||
peer_id, peer_idlen, r, &ra, &rb, rb_sb + SM9EXCH_RB_SIZE)) != 1) {
|
||||
fprintf(stderr, "gmssl %s: SB verification %s\n", prog, vr < 0 ? "failure" : "failed");
|
||||
goto end;
|
||||
}
|
||||
if (sm9_key_exchange_compute_confirm(1, &mpk, &key, id, idlen,
|
||||
peer_id, peer_idlen, r, &ra, &rb, sa) != 1
|
||||
|| sm9exch_write_data(keyoutfile, shared_key, keylen, format) != 1
|
||||
|| sm9exch_write_data(outfile, sa, sizeof(sa), format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: confirm stage failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
ret = 0;
|
||||
end:
|
||||
gmssl_secure_clear(&mpk, sizeof(mpk));
|
||||
gmssl_secure_clear(&key, sizeof(key));
|
||||
gmssl_secure_clear(&ra, sizeof(ra));
|
||||
gmssl_secure_clear(&rb, sizeof(rb));
|
||||
gmssl_secure_clear(r, sizeof(r));
|
||||
gmssl_secure_clear(shared_key, sizeof(shared_key));
|
||||
gmssl_secure_clear(sa, sizeof(sa));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm9exch_stage_finish(const char *mpkfile, const char *keyfile,
|
||||
const char *pass, const char *id, size_t idlen,
|
||||
const char *peer_id, size_t peer_idlen, const char *exch_keyfile,
|
||||
const char *infile, const char *keyoutfile, size_t keylen, int format,
|
||||
const char *prog)
|
||||
{
|
||||
SM9_EXCH_MASTER_KEY mpk;
|
||||
SM9_EXCH_KEY key;
|
||||
SM9_Z256_POINT ra;
|
||||
SM9_Z256_POINT rb;
|
||||
sm9_z256_t r;
|
||||
uint8_t sa[32];
|
||||
uint8_t shared_key[SM9EXCH_MAX_SHARED_KEY_SIZE];
|
||||
int vr;
|
||||
int ret = -1;
|
||||
|
||||
if (!id) {
|
||||
fprintf(stderr, "gmssl %s: '-id' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!peer_id) {
|
||||
fprintf(stderr, "gmssl %s: '-peer_id' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (!keyoutfile) {
|
||||
fprintf(stderr, "gmssl %s: '-keyout' option required\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (sm9exch_load_master_public_key(&mpk, mpkfile, prog) != 1
|
||||
|| sm9exch_load_private_key(&key, keyfile, pass, &mpk, prog) != 1
|
||||
|| sm9exch_load_exch_key(r, &rb, &ra, exch_keyfile, prog) != 1
|
||||
|| sm9exch_read_data(infile, sa, sizeof(sa), format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: finish stage input failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if ((vr = sm9_key_exchange_verify_confirm(0, &mpk, &key, id, idlen,
|
||||
peer_id, peer_idlen, r, &rb, &ra, sa)) != 1) {
|
||||
fprintf(stderr, "gmssl %s: SA verification %s\n", prog, vr < 0 ? "failure" : "failed");
|
||||
goto end;
|
||||
}
|
||||
if (sm9_key_exchange(0, &mpk, &key, id, idlen, peer_id, peer_idlen,
|
||||
r, &rb, &ra, keylen, shared_key) != 1
|
||||
|| sm9exch_write_data(keyoutfile, shared_key, keylen, format) != 1) {
|
||||
fprintf(stderr, "gmssl %s: finish stage failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
ret = 0;
|
||||
end:
|
||||
gmssl_secure_clear(&mpk, sizeof(mpk));
|
||||
gmssl_secure_clear(&key, sizeof(key));
|
||||
gmssl_secure_clear(&ra, sizeof(ra));
|
||||
gmssl_secure_clear(&rb, sizeof(rb));
|
||||
gmssl_secure_clear(r, sizeof(r));
|
||||
gmssl_secure_clear(shared_key, sizeof(shared_key));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sm9exch_main(int argc, char **argv)
|
||||
{
|
||||
int ret = 1;
|
||||
char *prog = argv[0];
|
||||
char *stage = NULL;
|
||||
char *mpkfile = NULL;
|
||||
char *keyfile = NULL;
|
||||
char *pass = NULL;
|
||||
char *id = NULL;
|
||||
char *peer_id = NULL;
|
||||
char *id_hex = NULL;
|
||||
char *peer_id_hex = NULL;
|
||||
char id_buf[SM9_MAX_ID_SIZE];
|
||||
size_t id_len = 0;
|
||||
char peer_id_buf[SM9_MAX_ID_SIZE];
|
||||
size_t peer_id_len = 0;
|
||||
char *infile = NULL;
|
||||
char *outfile = NULL;
|
||||
char *exch_keyfile = NULL;
|
||||
char *exch_keyoutfile = NULL;
|
||||
char *keyoutfile = NULL;
|
||||
size_t keylen = 32;
|
||||
int format = SM9EXCH_FMT_HEX;
|
||||
|
||||
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);
|
||||
return 0;
|
||||
} else if (!strcmp(*argv, "-stage")) {
|
||||
if (--argc < 1) goto bad;
|
||||
stage = *(++argv);
|
||||
} else if (!strcmp(*argv, "-pubmaster")) {
|
||||
if (--argc < 1) goto bad;
|
||||
mpkfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-key")) {
|
||||
if (--argc < 1) goto bad;
|
||||
keyfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-pass")) {
|
||||
if (--argc < 1) goto bad;
|
||||
pass = *(++argv);
|
||||
} else if (!strcmp(*argv, "-id")) {
|
||||
if (id_hex) {
|
||||
fprintf(stderr, "gmssl %s: '-id' and '-id_hex' should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
id = *(++argv);
|
||||
id_len = strlen(id);
|
||||
} else if (!strcmp(*argv, "-id_hex")) {
|
||||
if (id) {
|
||||
fprintf(stderr, "gmssl %s: '-id' and '-id_hex' should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
id_hex = *(++argv);
|
||||
if (strlen(id_hex) > sizeof(id_buf) * 2
|
||||
|| hex_to_bytes(id_hex, strlen(id_hex), (uint8_t *)id_buf, &id_len) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid '-id_hex' value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
id = id_buf;
|
||||
} else if (!strcmp(*argv, "-peer_id")) {
|
||||
if (peer_id_hex) {
|
||||
fprintf(stderr, "gmssl %s: '-peer_id' and '-peer_id_hex' should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
peer_id = *(++argv);
|
||||
peer_id_len = strlen(peer_id);
|
||||
} else if (!strcmp(*argv, "-peer_id_hex")) {
|
||||
if (peer_id) {
|
||||
fprintf(stderr, "gmssl %s: '-peer_id' and '-peer_id_hex' should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
peer_id_hex = *(++argv);
|
||||
if (strlen(peer_id_hex) > sizeof(peer_id_buf) * 2
|
||||
|| hex_to_bytes(peer_id_hex, strlen(peer_id_hex), (uint8_t *)peer_id_buf, &peer_id_len) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid '-peer_id_hex' value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
peer_id = peer_id_buf;
|
||||
} else if (!strcmp(*argv, "-in")) {
|
||||
if (--argc < 1) goto bad;
|
||||
infile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-out")) {
|
||||
if (--argc < 1) goto bad;
|
||||
outfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-exch_keyout")) {
|
||||
if (--argc < 1) goto bad;
|
||||
exch_keyoutfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-exch_key")) {
|
||||
if (--argc < 1) goto bad;
|
||||
exch_keyfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-keylen")) {
|
||||
if (--argc < 1) goto bad;
|
||||
keylen = (size_t)atoi(*(++argv));
|
||||
if (keylen < 1 || keylen > SM9EXCH_MAX_SHARED_KEY_SIZE) {
|
||||
fprintf(stderr, "gmssl %s: invalid '-keylen' value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
} else if (!strcmp(*argv, "-keyout")) {
|
||||
if (--argc < 1) goto bad;
|
||||
keyoutfile = *(++argv);
|
||||
} else if (!strcmp(*argv, "-hex")) {
|
||||
format = SM9EXCH_FMT_HEX;
|
||||
} else if (!strcmp(*argv, "-bin")) {
|
||||
format = SM9EXCH_FMT_BIN;
|
||||
} 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 (!stage) {
|
||||
fprintf(stderr, "gmssl %s: '-stage' option required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (id && id_len > SM9_MAX_ID_SIZE) {
|
||||
fprintf(stderr, "gmssl %s: local identity too long\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (peer_id && peer_id_len > SM9_MAX_ID_SIZE) {
|
||||
fprintf(stderr, "gmssl %s: peer identity too long\n", prog);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!strcmp(stage, "init")) {
|
||||
ret = sm9exch_stage_init(mpkfile, peer_id, peer_id_len,
|
||||
exch_keyoutfile, outfile, format, prog);
|
||||
} else if (!strcmp(stage, "respond")) {
|
||||
ret = sm9exch_stage_respond(mpkfile, keyfile, pass, id, id_len,
|
||||
peer_id, peer_id_len, infile, exch_keyoutfile,
|
||||
outfile, keylen, format, prog);
|
||||
} else if (!strcmp(stage, "confirm")) {
|
||||
ret = sm9exch_stage_confirm(mpkfile, keyfile, pass, id, id_len,
|
||||
peer_id, peer_id_len, exch_keyfile, infile,
|
||||
keyoutfile, outfile, keylen, format, prog);
|
||||
} else if (!strcmp(stage, "finish")) {
|
||||
ret = sm9exch_stage_finish(mpkfile, keyfile, pass, id, id_len,
|
||||
peer_id, peer_id_len, exch_keyfile, infile,
|
||||
keyoutfile, keylen, format, prog);
|
||||
} else {
|
||||
fprintf(stderr, "gmssl %s: invalid '-stage' value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
return ret == 0 ? 0 : 1;
|
||||
}
|
||||
@@ -17,12 +17,13 @@
|
||||
#include <gmssl/error.h>
|
||||
|
||||
|
||||
static const char *usage = "-alg (sm9sign|sm9encrypt) -in master_key.pem -inpass str -id str [-out pem] -outpass str";
|
||||
static const char *usage = "-alg (sm9sign|sm9encrypt|sm9keyagreement) -in master_key.pem -inpass str -id str [-out pem] -outpass str";
|
||||
|
||||
static const char *options =
|
||||
"Options\n"
|
||||
"\n"
|
||||
" -alg sm9sign|sm9encrypt Generate maeter key for sm9sign or sm9encrypt\n"
|
||||
" -alg sm9sign|sm9encrypt|sm9keyagreement\n"
|
||||
" Generate user's private key for sm9sign, sm9encrypt or sm9keyagreement\n"
|
||||
" -in pem SM9 master private key in PEM format\n"
|
||||
" -inpass pass Password to decrypt the master private key\n"
|
||||
" -id str User's identity\n"
|
||||
@@ -36,6 +37,7 @@ static const char *options =
|
||||
"\n"
|
||||
" $ gmssl sm9setup -alg sm9encrypt -pass P@ssw0rd -out sm9enc_msk.pem\n"
|
||||
" $ gmssl sm9keygen -alg sm9encrypt -in sm9enc_msk.pem -inpass P@ssw0rd -id Alice -out sm9enc.pem -outpass 123456\n"
|
||||
" $ gmssl sm9keygen -alg sm9keyagreement -in sm9enc_msk.pem -inpass P@ssw0rd -id Alice -out sm9exch.pem -outpass 123456\n"
|
||||
"\n";
|
||||
|
||||
int sm9keygen_main(int argc, char **argv)
|
||||
@@ -60,19 +62,20 @@ int sm9keygen_main(int argc, char **argv)
|
||||
argv++;
|
||||
|
||||
if (argc < 1) {
|
||||
fprintf(stderr, "usage: %s %s\n", prog, options);
|
||||
fprintf(stderr, "usage: gmssl %s %s\n", prog, usage);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (argc > 0) {
|
||||
if (!strcmp(*argv, "-help")) {
|
||||
fprintf(stdout, "usage: %s %s\n", prog, options);
|
||||
fprintf(stdout, "usage: gmssl %s %s\n", prog, usage);
|
||||
fprintf(stdout, "%s\n", 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);
|
||||
fprintf(stdout, "%s: invalid alg '%s', should be sm9sign, sm9encrypt or sm9keyagreement\n", prog, alg);
|
||||
goto end;
|
||||
}
|
||||
} else if (!strcmp(*argv, "-in")) {
|
||||
@@ -135,6 +138,14 @@ bad:
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case OID_sm9keyagreement:
|
||||
if (sm9_enc_master_key_info_decrypt_from_pem(&enc_msk, inpass, infp) != 1
|
||||
|| sm9_exch_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;
|
||||
|
||||
150
tools/zuc256.c
Normal file
150
tools/zuc256.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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/zuc.h>
|
||||
#include <gmssl/hex.h>
|
||||
|
||||
|
||||
static const char *usage = "-key hex -iv hex [-in file] [-out file]";
|
||||
|
||||
static const char *help =
|
||||
"Options\n"
|
||||
"\n"
|
||||
" -key hex ZUC-256 key in HEX format, 32 bytes\n"
|
||||
" -iv hex ZUC-256 IV in HEX format, 23 bytes\n"
|
||||
" -in file | stdin Input data\n"
|
||||
" -out file | stdout Output data\n"
|
||||
"\n"
|
||||
"Examples\n"
|
||||
"\n"
|
||||
" gmssl zuc256 -key 0000000000000000000000000000000000000000000000000000000000000000 \\\n"
|
||||
" -iv 0000000000000000000000000000000000000000000000 -in plaintext.bin -out ciphertext.bin\n"
|
||||
"\n";
|
||||
|
||||
int zuc256_main(int argc, char **argv)
|
||||
{
|
||||
int ret = 1;
|
||||
char *prog = argv[0];
|
||||
char *keyhex = NULL;
|
||||
char *ivhex = NULL;
|
||||
char *infile = NULL;
|
||||
char *outfile = NULL;
|
||||
uint8_t key[ZUC256_KEY_SIZE];
|
||||
uint8_t iv[ZUC256_IV_SIZE];
|
||||
size_t keylen;
|
||||
size_t ivlen;
|
||||
FILE *infp = stdin;
|
||||
FILE *outfp = stdout;
|
||||
ZUC_STATE zuc_state;
|
||||
uint8_t inbuf[4096];
|
||||
uint8_t outbuf[4096];
|
||||
size_t inlen;
|
||||
|
||||
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", help);
|
||||
ret = 0;
|
||||
goto end;
|
||||
} else if (!strcmp(*argv, "-key")) {
|
||||
if (--argc < 1) goto bad;
|
||||
keyhex = *(++argv);
|
||||
if (strlen(keyhex) != sizeof(key) * 2) {
|
||||
fprintf(stderr, "gmssl %s: key should be 32 bytes\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: IV should be 23 bytes\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, "-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 (!keyhex) {
|
||||
fprintf(stderr, "gmssl %s: option '-key' required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (!ivhex) {
|
||||
fprintf(stderr, "gmssl %s: option '-iv' required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
|
||||
zuc256_init(&zuc_state, key, iv);
|
||||
while ((inlen = fread(inbuf, 1, sizeof(inbuf), infp)) > 0) {
|
||||
zuc_encrypt(&zuc_state, inbuf, inlen, outbuf);
|
||||
if (fwrite(outbuf, 1, inlen, outfp) != inlen) {
|
||||
fprintf(stderr, "gmssl %s: output failure : %s\n", prog, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if (ferror(infp)) {
|
||||
fprintf(stderr, "gmssl %s: read failure : %s\n", prog, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
gmssl_secure_clear(&zuc_state, sizeof(zuc_state));
|
||||
gmssl_secure_clear(key, sizeof(key));
|
||||
gmssl_secure_clear(iv, sizeof(iv));
|
||||
gmssl_secure_clear(inbuf, sizeof(inbuf));
|
||||
gmssl_secure_clear(outbuf, sizeof(outbuf));
|
||||
if (infile && infp) fclose(infp);
|
||||
if (outfile && outfp) fclose(outfp);
|
||||
return ret;
|
||||
}
|
||||
310
tools/zuc_128_eea3.c
Normal file
310
tools/zuc_128_eea3.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* 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 <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <gmssl/mem.h>
|
||||
#include <gmssl/zuc.h>
|
||||
#include <gmssl/hex.h>
|
||||
#include <gmssl/endian.h>
|
||||
|
||||
|
||||
static const char *usage =
|
||||
"-key hex -count num -bearer num -direction num [-in file|-in_hex hex] [-out file]";
|
||||
|
||||
static const char *help =
|
||||
"Options\n"
|
||||
"\n"
|
||||
" -key hex 128-EEA3 confidentiality key, 16 bytes\n"
|
||||
" -count num COUNT parameter, 32-bit integer, decimal or 0x-prefixed hex\n"
|
||||
" -bearer num BEARER parameter, 5-bit integer in [0, 31]\n"
|
||||
" -direction num DIRECTION parameter, 0 or 1\n"
|
||||
" -in_hex hex Input bytes in HEX format\n"
|
||||
" -in file | stdin Input file path\n"
|
||||
" `-in_hex` and `-in` should not be used together\n"
|
||||
" If neither `-in_hex` nor `-in` specified, read from stdin\n"
|
||||
" -out file | stdout Output ciphertext bytes. If not specified, output to stdout\n"
|
||||
"\n"
|
||||
"Examples\n"
|
||||
"\n"
|
||||
" gmssl zuc_128_eea3 -key 173d14ba5003731d7a60049470f00a29 \\\n"
|
||||
" -count 0x66035492 -bearer 15 -direction 0 \\\n"
|
||||
" -in_hex 6cf65340735552ab0c9752fa6f9025fe0bd675d9005875b2 -out ciphertext.bin\n"
|
||||
"\n";
|
||||
|
||||
static int parse_uint64(const char *s, uint64_t max, uint64_t *out)
|
||||
{
|
||||
char *end = NULL;
|
||||
unsigned long long v;
|
||||
|
||||
if (!s || !*s) {
|
||||
return -1;
|
||||
}
|
||||
errno = 0;
|
||||
v = strtoull(s, &end, 0);
|
||||
if (errno || *end || v > max) {
|
||||
return -1;
|
||||
}
|
||||
*out = (uint64_t)v;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint8_t *read_content(FILE *infp, size_t *outlen, const char *prog)
|
||||
{
|
||||
const size_t initial_size = 4096;
|
||||
const size_t max_size = 512 * 1024 * 1024;
|
||||
uint8_t *buf = NULL;
|
||||
size_t bufsiz = initial_size;
|
||||
size_t len = 0;
|
||||
|
||||
if (!(buf = (uint8_t *)malloc(bufsiz))) {
|
||||
fprintf(stderr, "gmssl %s: malloc failure\n", prog);
|
||||
return NULL;
|
||||
}
|
||||
for (;;) {
|
||||
size_t n;
|
||||
|
||||
if (len == bufsiz) {
|
||||
uint8_t *tmp;
|
||||
|
||||
if (bufsiz >= max_size) {
|
||||
fprintf(stderr, "gmssl %s: input too long, should be less than %zu\n", prog, max_size);
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
bufsiz *= 2;
|
||||
if (bufsiz > max_size) {
|
||||
bufsiz = max_size;
|
||||
}
|
||||
if (!(tmp = (uint8_t *)realloc(buf, bufsiz))) {
|
||||
fprintf(stderr, "gmssl %s: realloc failure\n", prog);
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
buf = tmp;
|
||||
}
|
||||
|
||||
n = fread(buf + len, 1, bufsiz - len, infp);
|
||||
len += n;
|
||||
|
||||
if (feof(infp)) {
|
||||
break;
|
||||
}
|
||||
if (ferror(infp)) {
|
||||
fprintf(stderr, "gmssl %s: read failure : %s\n", prog, strerror(errno));
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
*outlen = len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int zuc_128_eea3_main(int argc, char **argv)
|
||||
{
|
||||
int ret = 1;
|
||||
char *prog = argv[0];
|
||||
char *keyhex = NULL;
|
||||
char *inhex = NULL;
|
||||
char *infile = NULL;
|
||||
char *outfile = NULL;
|
||||
uint8_t key[ZUC_KEY_SIZE];
|
||||
size_t keylen;
|
||||
uint8_t *in = NULL;
|
||||
size_t inlen = 0;
|
||||
uint8_t *padded = NULL;
|
||||
ZUC_UINT32 *inwords = NULL;
|
||||
ZUC_UINT32 *outwords = NULL;
|
||||
uint8_t *out = NULL;
|
||||
size_t nbits;
|
||||
size_t nbytes = 0;
|
||||
size_t nwords = 0;
|
||||
size_t i;
|
||||
uint64_t v;
|
||||
ZUC_UINT32 count = 0;
|
||||
ZUC_UINT5 bearer = 0;
|
||||
ZUC_BIT direction = 0;
|
||||
int count_set = 0;
|
||||
int bearer_set = 0;
|
||||
int direction_set = 0;
|
||||
FILE *infp = stdin;
|
||||
FILE *outfp = stdout;
|
||||
|
||||
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", help);
|
||||
ret = 0;
|
||||
goto end;
|
||||
} else if (!strcmp(*argv, "-key")) {
|
||||
if (--argc < 1) goto bad;
|
||||
keyhex = *(++argv);
|
||||
if (strlen(keyhex) != sizeof(key) * 2) {
|
||||
fprintf(stderr, "gmssl %s: key should be 16 bytes\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, "-count")) {
|
||||
if (--argc < 1) goto bad;
|
||||
if (parse_uint64(*(++argv), UINT32_MAX, &v) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid COUNT value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
count = (ZUC_UINT32)v;
|
||||
count_set = 1;
|
||||
} else if (!strcmp(*argv, "-bearer")) {
|
||||
if (--argc < 1) goto bad;
|
||||
if (parse_uint64(*(++argv), 31, &v) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid BEARER value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
bearer = (ZUC_UINT5)v;
|
||||
bearer_set = 1;
|
||||
} else if (!strcmp(*argv, "-direction")) {
|
||||
if (--argc < 1) goto bad;
|
||||
if (parse_uint64(*(++argv), 1, &v) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid DIRECTION value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
direction = (ZUC_BIT)v;
|
||||
direction_set = 1;
|
||||
} else if (!strcmp(*argv, "-in_hex")) {
|
||||
if (infile) {
|
||||
fprintf(stderr, "gmssl %s: `-in` and `-in_hex` should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
inhex = *(++argv);
|
||||
} else if (!strcmp(*argv, "-in")) {
|
||||
if (inhex) {
|
||||
fprintf(stderr, "gmssl %s: `-in` and `-in_hex` should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
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 (!keyhex) {
|
||||
fprintf(stderr, "gmssl %s: option '-key' required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (!count_set || !bearer_set || !direction_set) {
|
||||
fprintf(stderr, "gmssl %s: options '-count', '-bearer' and '-direction' are required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (inhex) {
|
||||
if (strlen(inhex) % 2) {
|
||||
fprintf(stderr, "gmssl %s: invalid input hex length\n", prog);
|
||||
goto end;
|
||||
}
|
||||
nbytes = strlen(inhex) / 2;
|
||||
if (!(in = (uint8_t *)malloc(nbytes ? nbytes : 1))) {
|
||||
fprintf(stderr, "gmssl %s: malloc failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (hex_to_bytes(inhex, strlen(inhex), in, &inlen) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid input hex digits\n", prog);
|
||||
goto end;
|
||||
}
|
||||
} else if (!(in = read_content(infp, &inlen, prog))) {
|
||||
goto end;
|
||||
}
|
||||
nbytes = inlen;
|
||||
nbits = inlen * 8;
|
||||
nwords = (nbits + 31) / 32;
|
||||
|
||||
if (!(padded = (uint8_t *)calloc(nwords ? nwords : 1, sizeof(uint32_t)))
|
||||
|| !(inwords = (ZUC_UINT32 *)calloc(nwords ? nwords : 1, sizeof(uint32_t)))
|
||||
|| !(outwords = (ZUC_UINT32 *)calloc(nwords ? nwords : 1, sizeof(uint32_t)))
|
||||
|| !(out = (uint8_t *)calloc(nwords ? nwords : 1, sizeof(uint32_t)))) {
|
||||
fprintf(stderr, "gmssl %s: malloc failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
memcpy(padded, in, inlen);
|
||||
for (i = 0; i < nwords; i++) {
|
||||
inwords[i] = GETU32(padded + i * 4);
|
||||
}
|
||||
|
||||
zuc_eea_encrypt(inwords, outwords, nbits, key, count, bearer, direction);
|
||||
for (i = 0; i < nwords; i++) {
|
||||
PUTU32(out + i * 4, outwords[i]);
|
||||
}
|
||||
|
||||
if (nbytes && fwrite(out, 1, nbytes, outfp) != nbytes) {
|
||||
fprintf(stderr, "gmssl %s: output failure : %s\n", prog, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
gmssl_secure_clear(key, sizeof(key));
|
||||
if (in) {
|
||||
gmssl_secure_clear(in, inlen);
|
||||
free(in);
|
||||
}
|
||||
if (padded) {
|
||||
gmssl_secure_clear(padded, (nwords ? nwords : 1) * sizeof(uint32_t));
|
||||
free(padded);
|
||||
}
|
||||
if (inwords) {
|
||||
gmssl_secure_clear(inwords, (nwords ? nwords : 1) * sizeof(uint32_t));
|
||||
free(inwords);
|
||||
}
|
||||
if (outwords) {
|
||||
gmssl_secure_clear(outwords, (nwords ? nwords : 1) * sizeof(uint32_t));
|
||||
free(outwords);
|
||||
}
|
||||
if (out) {
|
||||
gmssl_secure_clear(out, (nwords ? nwords : 1) * sizeof(uint32_t));
|
||||
free(out);
|
||||
}
|
||||
if (infile && infp) fclose(infp);
|
||||
if (outfile && outfp) fclose(outfp);
|
||||
return ret;
|
||||
}
|
||||
299
tools/zuc_128_eia3.c
Normal file
299
tools/zuc_128_eia3.c
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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 <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <gmssl/mem.h>
|
||||
#include <gmssl/zuc.h>
|
||||
#include <gmssl/hex.h>
|
||||
#include <gmssl/endian.h>
|
||||
|
||||
|
||||
static const char *usage =
|
||||
"-key hex -count num -bearer num -direction num [-in file|-in_hex hex] [-hex|-bin] [-out file]";
|
||||
|
||||
static const char *help =
|
||||
"Options\n"
|
||||
"\n"
|
||||
" -key hex 128-EIA3 integrity key, 16 bytes\n"
|
||||
" -count num COUNT parameter, 32-bit integer, decimal or 0x-prefixed hex\n"
|
||||
" -bearer num BEARER parameter, 5-bit integer in [0, 31]\n"
|
||||
" -direction num DIRECTION parameter, 0 or 1\n"
|
||||
" -in_hex hex Input message bytes in HEX format\n"
|
||||
" -in file | stdin Input file path\n"
|
||||
" `-in_hex` and `-in` should not be used together\n"
|
||||
" If neither `-in_hex` nor `-in` specified, read from stdin\n"
|
||||
" -hex Output MAC as hex string (by default)\n"
|
||||
" -bin Output MAC as binary\n"
|
||||
" `-hex` and `-bin` should not be used together\n"
|
||||
" -out file | stdout Output file path. If not specified, output to stdout\n"
|
||||
"\n"
|
||||
"Examples\n"
|
||||
"\n"
|
||||
" gmssl zuc_128_eia3 -key 00000000000000000000000000000000 \\\n"
|
||||
" -count 0 -bearer 0 -direction 0 -in_hex 00\n"
|
||||
"\n";
|
||||
|
||||
static int parse_uint64(const char *s, uint64_t max, uint64_t *out)
|
||||
{
|
||||
char *end = NULL;
|
||||
unsigned long long v;
|
||||
|
||||
if (!s || !*s) {
|
||||
return -1;
|
||||
}
|
||||
errno = 0;
|
||||
v = strtoull(s, &end, 0);
|
||||
if (errno || *end || v > max) {
|
||||
return -1;
|
||||
}
|
||||
*out = (uint64_t)v;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint8_t *read_content(FILE *infp, size_t *outlen, const char *prog)
|
||||
{
|
||||
const size_t initial_size = 4096;
|
||||
const size_t max_size = 512 * 1024 * 1024;
|
||||
uint8_t *buf = NULL;
|
||||
size_t bufsiz = initial_size;
|
||||
size_t len = 0;
|
||||
|
||||
if (!(buf = (uint8_t *)malloc(bufsiz))) {
|
||||
fprintf(stderr, "gmssl %s: malloc failure\n", prog);
|
||||
return NULL;
|
||||
}
|
||||
for (;;) {
|
||||
size_t n;
|
||||
|
||||
if (len == bufsiz) {
|
||||
uint8_t *tmp;
|
||||
|
||||
if (bufsiz >= max_size) {
|
||||
fprintf(stderr, "gmssl %s: input too long, should be less than %zu\n", prog, max_size);
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
bufsiz *= 2;
|
||||
if (bufsiz > max_size) {
|
||||
bufsiz = max_size;
|
||||
}
|
||||
if (!(tmp = (uint8_t *)realloc(buf, bufsiz))) {
|
||||
fprintf(stderr, "gmssl %s: realloc failure\n", prog);
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
buf = tmp;
|
||||
}
|
||||
|
||||
n = fread(buf + len, 1, bufsiz - len, infp);
|
||||
len += n;
|
||||
|
||||
if (feof(infp)) {
|
||||
break;
|
||||
}
|
||||
if (ferror(infp)) {
|
||||
fprintf(stderr, "gmssl %s: read failure : %s\n", prog, strerror(errno));
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
*outlen = len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int zuc_128_eia3_main(int argc, char **argv)
|
||||
{
|
||||
int ret = 1;
|
||||
char *prog = argv[0];
|
||||
char *keyhex = NULL;
|
||||
char *inhex = NULL;
|
||||
char *infile = NULL;
|
||||
char *outfile = NULL;
|
||||
int outformat = 0;
|
||||
uint8_t key[ZUC_KEY_SIZE];
|
||||
size_t keylen;
|
||||
uint8_t *in = NULL;
|
||||
size_t inlen = 0;
|
||||
size_t nbits;
|
||||
size_t nbytes = 0;
|
||||
uint64_t v;
|
||||
ZUC_UINT32 count = 0;
|
||||
ZUC_UINT5 bearer = 0;
|
||||
ZUC_BIT direction = 0;
|
||||
ZUC_UINT32 macword;
|
||||
uint8_t mac[ZUC_MAC_SIZE];
|
||||
int count_set = 0;
|
||||
int bearer_set = 0;
|
||||
int direction_set = 0;
|
||||
FILE *infp = stdin;
|
||||
FILE *outfp = stdout;
|
||||
size_t i;
|
||||
|
||||
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", help);
|
||||
ret = 0;
|
||||
goto end;
|
||||
} else if (!strcmp(*argv, "-key")) {
|
||||
if (--argc < 1) goto bad;
|
||||
keyhex = *(++argv);
|
||||
if (strlen(keyhex) != sizeof(key) * 2) {
|
||||
fprintf(stderr, "gmssl %s: key should be 16 bytes\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, "-count")) {
|
||||
if (--argc < 1) goto bad;
|
||||
if (parse_uint64(*(++argv), UINT32_MAX, &v) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid COUNT value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
count = (ZUC_UINT32)v;
|
||||
count_set = 1;
|
||||
} else if (!strcmp(*argv, "-bearer")) {
|
||||
if (--argc < 1) goto bad;
|
||||
if (parse_uint64(*(++argv), 31, &v) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid BEARER value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
bearer = (ZUC_UINT5)v;
|
||||
bearer_set = 1;
|
||||
} else if (!strcmp(*argv, "-direction")) {
|
||||
if (--argc < 1) goto bad;
|
||||
if (parse_uint64(*(++argv), 1, &v) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid DIRECTION value\n", prog);
|
||||
goto end;
|
||||
}
|
||||
direction = (ZUC_BIT)v;
|
||||
direction_set = 1;
|
||||
} else if (!strcmp(*argv, "-in_hex")) {
|
||||
if (infile) {
|
||||
fprintf(stderr, "gmssl %s: `-in` and `-in_hex` should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (--argc < 1) goto bad;
|
||||
inhex = *(++argv);
|
||||
} else if (!strcmp(*argv, "-in")) {
|
||||
if (inhex) {
|
||||
fprintf(stderr, "gmssl %s: `-in` and `-in_hex` should not be used together\n", prog);
|
||||
goto end;
|
||||
}
|
||||
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, "-hex")) {
|
||||
if (outformat == 2) {
|
||||
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 == 1) {
|
||||
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++;
|
||||
}
|
||||
|
||||
if (!keyhex) {
|
||||
fprintf(stderr, "gmssl %s: option '-key' required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (!count_set || !bearer_set || !direction_set) {
|
||||
fprintf(stderr, "gmssl %s: options '-count', '-bearer' and '-direction' are required\n", prog);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (inhex) {
|
||||
if (strlen(inhex) % 2) {
|
||||
fprintf(stderr, "gmssl %s: invalid input hex length\n", prog);
|
||||
goto end;
|
||||
}
|
||||
nbytes = strlen(inhex) / 2;
|
||||
if (!(in = (uint8_t *)malloc(nbytes ? nbytes : 1))) {
|
||||
fprintf(stderr, "gmssl %s: malloc failure\n", prog);
|
||||
goto end;
|
||||
}
|
||||
if (hex_to_bytes(inhex, strlen(inhex), in, &inlen) != 1) {
|
||||
fprintf(stderr, "gmssl %s: invalid input hex digits\n", prog);
|
||||
goto end;
|
||||
}
|
||||
} else if (!(in = read_content(infp, &inlen, prog))) {
|
||||
goto end;
|
||||
}
|
||||
nbytes = inlen;
|
||||
nbits = inlen * 8;
|
||||
|
||||
macword = zuc_eia_generate_mac((ZUC_UINT32 *)in, nbits, key, count, bearer, direction);
|
||||
PUTU32(mac, macword);
|
||||
|
||||
if (outformat == 2) {
|
||||
if (fwrite(mac, 1, sizeof(mac), outfp) != sizeof(mac)) {
|
||||
fprintf(stderr, "gmssl %s: output failure : %s\n", prog, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < sizeof(mac); i++) {
|
||||
fprintf(outfp, "%02x", mac[i]);
|
||||
}
|
||||
fprintf(outfp, "\n");
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
gmssl_secure_clear(key, sizeof(key));
|
||||
gmssl_secure_clear(mac, sizeof(mac));
|
||||
if (in) {
|
||||
gmssl_secure_clear(in, inlen);
|
||||
free(in);
|
||||
}
|
||||
if (infile && infp) fclose(infp);
|
||||
if (outfile && outfp) fclose(outfp);
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user