diff --git a/CMakeLists.txt b/CMakeLists.txt index cdb70120..1ac9b1a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,8 @@ option(ENABLE_SM4_CBC_MAC "Enable SM4-CBC-MAC" ON) option(ENABLE_SM2_EXTS "Enable SM2 Extensions" OFF) +option(ENABLE_SECP256R1 "Enable ECDH/ECDSA on curve secp256r1" ON) + option(ENABLE_LMS "Enable LMS/HSS signature" ON) option(ENABLE_XMSS "Enable XMSS/XMSS^MT signature" ON) option(ENABLE_SPHINCS "Enable SPHINCS+ signature" ON) @@ -108,6 +110,7 @@ set(src src/sm4_cbc_sm3_hmac.c src/sm4_ctr_sm3_hmac.c src/pkcs8.c + src/bn.c src/ec.c src/rsa.c src/asn1.c @@ -128,6 +131,7 @@ set(src src/tls_trace.c src/tlcp.c src/tls12.c + src/tls12_handshake.c src/tls13.c src/file.c src/file.c @@ -203,6 +207,7 @@ set(tests gf128 ghash pkcs8 + bn ec asn1 hex @@ -419,6 +424,14 @@ if (ENABLE_SM2_EXTS) endif() +if (ENABLE_SECP256R1) + message(STATUS "ENABLE_SECP256R1 is ON") + add_definitions(-DENABLE_SECP256R1) + list(APPEND src src/secp256r1.c src/secp256r1_key.c src/ecdsa.c) + list(APPEND tests secp256r1 secp256r1_key ecdsa) +endif() + + if (ENABLE_LMS) message(STATUS "ENABLE_LMS is ON") add_definitions(-DENABLE_LMS) diff --git a/include/gmssl/bn.h b/include/gmssl/bn.h new file mode 100644 index 00000000..3588b2e1 --- /dev/null +++ b/include/gmssl/bn.h @@ -0,0 +1,86 @@ +/* + * 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 + */ + + + +#ifndef GMSSL_BN_H +#define GMSSL_BN_H + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +void bn_set_word(uint32_t *r, uint32_t a, size_t k); +void bn_copy(uint32_t *r, const uint32_t *a, size_t k); +int bn_cmp(const uint32_t *a, const uint32_t *b, size_t k); +int bn_is_zero(const uint32_t *a, size_t k); +int bn_is_one(const uint32_t *a, size_t k); +int bn_add(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k); +int bn_sub(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k); +void bn_mul(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k); +void bn_mul_lo(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k); +void bn_to_bytes(const uint32_t *a, size_t k, uint8_t *out); +void bn_from_bytes(uint32_t *a, size_t k, const uint8_t *in); +int bn_print(FILE *fp, int fmt, int ind, const char *label, const uint32_t *a, size_t k); + +void bn_mod_add(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, size_t k); +void bn_mod_sub(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, size_t k); +void bn_mod_neg(uint32_t *r, const uint32_t *a, const uint32_t *p, size_t k); + +// multiplication with barrett reduction, need caller prepare temp values +// u = floor(2^512 / p) for bn256 +void bn_barrett_mod_mul(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, + const uint32_t *u, // uint32_t u[k + 1] + uint32_t *tmp, // uint32_t tmp[6*k + 4] + size_t k); +void bn_barrett_mod_sqr(uint32_t *r, const uint32_t *a, const uint32_t *p, + const uint32_t *u, // uint32_t u[k + 1] + uint32_t *tmp, // uint32_t tmp[6*k + 4] + size_t k); +void bn_barrett_mod_exp(uint32_t *r, const uint32_t *a, const uint32_t *e, const uint32_t *p, + const uint32_t *u, // uint32_t u[k + 1] + uint32_t *tmp, // uint32_t tmp[7*k + 4] + size_t k); +void bn_barrett_mod_inv(uint32_t *r, const uint32_t *a, const uint32_t *p, + const uint32_t *u, // uint32_t u[k + 1] + uint32_t *tmp, // uint32_t tmp[8*k + 4] + size_t k); + +// montgomery multiplication, all values in montgomery format, need caller prepare temp values +void bn_mont_mod_mul(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[5 * k] + size_t k); +void bn_mont_mod_sqr(uint32_t *r, const uint32_t *a, const uint32_t *p, const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[5 * k] + size_t k); +void bn_mont_mod_exp(uint32_t *r, const uint32_t *a, const uint32_t *e, const uint32_t *p, const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[6 * k] + size_t k); +void bn_mont_mod_inv(uint32_t *r, const uint32_t *a, const uint32_t *p, const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[7 * k] + size_t k); +void bn_mont_set(uint32_t *r, const uint32_t *a, const uint32_t *one_sqr, const uint32_t *p, const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[5 * k] + size_t k); +void bn_mont_get(uint32_t *r, const uint32_t *a, const uint32_t *p, const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[5 * k] + size_t k); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/ecdsa.h b/include/gmssl/ecdsa.h new file mode 100644 index 00000000..e93a821d --- /dev/null +++ b/include/gmssl/ecdsa.h @@ -0,0 +1,68 @@ +/* + * 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 + */ + + +#ifndef GMSSL_ECDSA_H +#define GMSSL_ECDSA_H + + +#include +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + secp256r1_t r; + secp256r1_t s; +} ECDSA_SIGNATURE; + +#define ECDSA_SIGNATURE_COMPACT_SIZE 70 +#define ECDSA_SIGNATURE_TYPICAL_SIZE 71 +#define ECDSA_SIGNATURE_MAX_SIZE 72 + +int ecdsa_signature_to_der(const ECDSA_SIGNATURE *sig, uint8_t **out, size_t *outlen); +int ecdsa_signature_from_der(ECDSA_SIGNATURE *sig, const uint8_t **in, size_t *inlen); +int ecdsa_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const ECDSA_SIGNATURE *sig); +int ecdsa_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen); + +int ecdsa_do_sign_ex(const SECP256R1_KEY *key, const secp256r1_t k, const uint8_t dgst[32], ECDSA_SIGNATURE *sig); +int ecdsa_do_sign(const SECP256R1_KEY *key, const uint8_t dgst[32], ECDSA_SIGNATURE *sig); +int ecdsa_do_verify(const SECP256R1_KEY *key, const uint8_t dgst[32], const ECDSA_SIGNATURE *sig); +int ecdsa_sign(const SECP256R1_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *siglen); +int ecdsa_sign_fixlen(const SECP256R1_KEY *key, const uint8_t dgst[32], size_t siglen, uint8_t *sig); +int ecdsa_verify(const SECP256R1_KEY *key, const uint8_t dgst[32], const uint8_t *sig, size_t siglen); + + +typedef struct { + SHA256_CTX sha256_ctx; + SECP256R1_KEY key; + ECDSA_SIGNATURE sig; +} ECDSA_SIGN_CTX; + +int ecdsa_sign_init(ECDSA_SIGN_CTX *ctx, const SECP256R1_KEY *key); +int ecdsa_sign_update(ECDSA_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); +int ecdsa_sign_finish(ECDSA_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen); +int ecdsa_sign_finish_fixlen(ECDSA_SIGN_CTX *ctx, size_t siglen, uint8_t *sig); +int ecdsa_verify_init(ECDSA_SIGN_CTX *ctx, const SECP256R1_KEY *key, const uint8_t *sig, size_t siglen); +int ecdsa_verify_update(ECDSA_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); +int ecdsa_verify_finish(ECDSA_SIGN_CTX *ctx); + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/oid.h b/include/gmssl/oid.h index 7f6a8208..e47eb652 100644 --- a/include/gmssl/oid.h +++ b/include/gmssl/oid.h @@ -210,6 +210,7 @@ enum { +#define OID_secp256r1 OID_prime256v1 #define oid_cnt(nodes) (sizeof(nodes)/sizeof((nodes)[0])) diff --git a/include/gmssl/secp256r1.h b/include/gmssl/secp256r1.h new file mode 100644 index 00000000..f5707612 --- /dev/null +++ b/include/gmssl/secp256r1.h @@ -0,0 +1,108 @@ +/* + * 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 + */ + + + +#ifndef GMSSL_SECP256R1_H +#define GMSSL_SECP256R1_H + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +// p = 2^256 - 2^224 + 2^192 + 2^96 - 1 +// = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF +// a = -3 +// b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b +// x = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296 +// y = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5 +// n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 +// h = 1 + + +typedef uint32_t secp256r1_t[8]; + +#define SECP256R1_K (sizeof(secp256r1_t)/sizeof(uint32_t)) + +extern const secp256r1_t SECP256R1_P; +extern const secp256r1_t SECP256R1_B; +extern const secp256r1_t SECP256R1_N; +extern const uint32_t SECP256R1_U_P[9]; +extern const uint32_t SECP256R1_U_N[9]; + +int secp256r1_is_zero(const secp256r1_t a); +int secp256r1_is_one(const secp256r1_t a); +int secp256r1_cmp(const secp256r1_t a, const secp256r1_t b); +void secp256r1_set_zero(secp256r1_t r); +void secp256r1_set_one(secp256r1_t r); +void secp256r1_copy(secp256r1_t r, const secp256r1_t a); +void secp256r1_to_32bytes(const secp256r1_t a, uint8_t out[32]); +void secp256r1_from_32bytes(secp256r1_t r, const uint8_t in[32]); +int secp256r1_print(FILE *fp, int fmt, int ind, const char *label, const secp256r1_t a); + +void secp256r1_modp_add(secp256r1_t r, const secp256r1_t a, const secp256r1_t b); +void secp256r1_modp_dbl(secp256r1_t r, const secp256r1_t a); +void secp256r1_modp_tri(secp256r1_t r, const secp256r1_t a); +void secp256r1_modp_sub(secp256r1_t r, const secp256r1_t a, const secp256r1_t b); +void secp256r1_modp_neg(secp256r1_t r, const secp256r1_t a); +void secp256r1_modp_haf(secp256r1_t r, const secp256r1_t a); +void secp256r1_modp_mul(secp256r1_t r, const secp256r1_t a, const secp256r1_t b); +void secp256r1_modp_sqr(secp256r1_t r, const secp256r1_t a); +void secp256r1_modp_exp(secp256r1_t r, const secp256r1_t a, const secp256r1_t e); +void secp256r1_modp_inv(secp256r1_t r, const secp256r1_t a); + +void secp256r1_modn(secp256r1_t r, const secp256r1_t a); +void secp256r1_modn_add(secp256r1_t r, const secp256r1_t a, const secp256r1_t b); +void secp256r1_modn_dbl(secp256r1_t r, const secp256r1_t a); +void secp256r1_modn_tri(secp256r1_t r, const secp256r1_t a); +void secp256r1_modn_sub(secp256r1_t r, const secp256r1_t a, const secp256r1_t b); +void secp256r1_modn_neg(secp256r1_t r, const secp256r1_t a); +void secp256r1_modn_mul(secp256r1_t r, const secp256r1_t a, const secp256r1_t b); +void secp256r1_modn_sqr(secp256r1_t r, const secp256r1_t a); +void secp256r1_modn_exp(secp256r1_t r, const secp256r1_t a, const secp256r1_t e); +void secp256r1_modn_inv(secp256r1_t r, const secp256r1_t a); + + +typedef struct { + secp256r1_t X; + secp256r1_t Y; + secp256r1_t Z; +} SECP256R1_POINT; + +extern const SECP256R1_POINT SECP256R1_POINT_G; + +void secp256r1_point_set_infinity(SECP256R1_POINT *R); +int secp256r1_point_is_at_infinity(const SECP256R1_POINT *P); +int secp256r1_point_is_on_curve(const SECP256R1_POINT *P); +int secp256r1_point_equ(const SECP256R1_POINT *P, const SECP256R1_POINT *Q); +int secp256r1_point_set_xy(SECP256R1_POINT *R, const secp256r1_t x, const secp256r1_t y); +int secp256r1_point_get_xy(const SECP256R1_POINT *P, secp256r1_t x, secp256r1_t y); +void secp256r1_point_copy(SECP256R1_POINT *R, const SECP256R1_POINT *P); +void secp256r1_point_dbl(SECP256R1_POINT *R, const SECP256R1_POINT *P); +void secp256r1_point_add(SECP256R1_POINT *R, const SECP256R1_POINT *P, const SECP256R1_POINT *Q); +void secp256r1_point_neg(SECP256R1_POINT *R, const SECP256R1_POINT *P); +void secp256r1_point_sub(SECP256R1_POINT *R, const SECP256R1_POINT *P, const SECP256R1_POINT *Q); +void secp256r1_point_mul(SECP256R1_POINT *R, const secp256r1_t k, const SECP256R1_POINT *P); +void secp256r1_point_mul_generator(SECP256R1_POINT *R, const secp256r1_t k); +int secp256r1_point_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_POINT *P); +int secp256r1_point_to_uncompressed_octets(const SECP256R1_POINT *P, uint8_t octets[65]); +int secp256r1_point_from_uncompressed_octets(SECP256R1_POINT *P, const uint8_t octets[65]); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/secp256r1_key.h b/include/gmssl/secp256r1_key.h new file mode 100644 index 00000000..b8d2dfca --- /dev/null +++ b/include/gmssl/secp256r1_key.h @@ -0,0 +1,56 @@ +/* + * 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 + */ + +#ifndef GMSSL_SECP256R1_KEY_H +#define GMSSL_SECP256R1_KEY_H + + +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + SECP256R1_POINT public_key; + secp256r1_t private_key; +} SECP256R1_KEY; + +int secp256r1_key_generate(SECP256R1_KEY *key); +int secp256r1_key_set_private_key(SECP256R1_KEY *key, const secp256r1_t private_key); +int secp256r1_public_key_equ(const SECP256R1_KEY *key, const SECP256R1_KEY *pub); +void secp256r1_key_cleanup(SECP256R1_KEY *key); + +int secp256r1_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_KEY *key); +int secp256r1_private_key_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_KEY *key); + +int secp256r1_public_key_to_bytes(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen); +int secp256r1_public_key_from_bytes(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen); +int secp256r1_public_key_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen); +int secp256r1_public_key_from_der(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen); +int secp256r1_private_key_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen); +int secp256r1_private_key_from_der(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen); +int secp256r1_private_key_info_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen); +int secp256r1_private_key_info_from_der(SECP256R1_KEY *key, const uint8_t **attrs, size_t *attrslen, + const uint8_t **in, size_t *inlen); +int secp256r1_private_key_info_encrypt_to_der(const SECP256R1_KEY *ec_key, const char *pass, + uint8_t **out, size_t *outlen); +int secp256r1_private_key_info_decrypt_from_der(SECP256R1_KEY *ec_key, + const uint8_t **attrs, size_t *attrs_len, + const char *pass, const uint8_t **in, size_t *inlen); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/tls.h b/include/gmssl/tls.h index 426df5d2..fbbc7803 100644 --- a/include/gmssl/tls.h +++ b/include/gmssl/tls.h @@ -752,6 +752,11 @@ typedef struct { BLOCK_CIPHER_KEY server_write_key; int quiet; + + // handshake state for state machine + int state; + SM3_CTX sm3_ctx; + SM2_SIGN_CTX sign_ctx; } TLS_CONNECT; diff --git a/include/gmssl/x509_key.h b/include/gmssl/x509_key.h index 063827e8..1d7480c8 100644 --- a/include/gmssl/x509_key.h +++ b/include/gmssl/x509_key.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -51,11 +53,13 @@ typedef struct { XMSS_KEY xmss_key; XMSSMT_KEY xmssmt_key; SPHINCS_KEY sphincs_key; + SECP256R1_KEY secp256r1_key; } u; } X509_KEY; int x509_key_set_sm2_key(X509_KEY *x509_key, const SM2_KEY *sm2_key); +int x509_key_set_secp256r1_key(X509_KEY *x509_key, const SECP256R1_KEY *secp256r1_key); int x509_key_set_lms_key(X509_KEY *x509_key, const LMS_KEY *lms_key); int x509_key_set_hss_key(X509_KEY *x509_key, const HSS_KEY *hss_key); int x509_key_set_xmss_key(X509_KEY *x509_key, const XMSS_KEY *xmss_key); @@ -107,6 +111,7 @@ typedef union { typedef struct { union { SM2_SIGN_CTX sm2_sign_ctx; + ECDSA_SIGN_CTX ecdsa_sign_ctx; SM2_VERIFY_CTX sm2_verify_ctx; HSS_SIGN_CTX hss_sign_ctx; XMSS_SIGN_CTX xmss_sign_ctx; diff --git a/src/bn.c b/src/bn.c new file mode 100644 index 00000000..cde0df90 --- /dev/null +++ b/src/bn.c @@ -0,0 +1,379 @@ +/* + * 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 +#include +#include +#include +#include + + +void bn_set_word(uint32_t *r, uint32_t a, size_t k) +{ + r[0] = a; + while (k-- > 1) { + r[k] = 0; + } +} + +void bn_copy(uint32_t *r, const uint32_t *a, size_t k) +{ + while (k-- > 0) { + r[k] = a[k]; + } +} + +int bn_cmp(const uint32_t *a, const uint32_t *b, size_t k) +{ + while (k-- > 0) { + if (a[k] > b[k]) return 1; + else if (a[k] < b[k]) return -1; + } + return 0; +} + +int bn_is_zero(const uint32_t *a, size_t k) +{ + while (k-- > 0) { + if (a[k]) { + return 0; + } + } + return 1; +} + +int bn_is_one(const uint32_t *a, size_t k) +{ + if (a[0] != 1) { + return 0; + } + while (k-- > 1) { + if (a[k]) { + return 0; + } + } + return 1; +} + +int bn_add(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k) +{ + uint64_t w = 0; + size_t i; + for (i = 0; i < k; i++) { + w += (uint64_t)a[i] + (uint64_t)b[i]; + r[i] = w & 0xffffffff; + w >>= 32; + } + return (int)w; +} + +int bn_sub(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k) +{ + int64_t w = 0; + size_t i; + for (i = 0; i < k; i++) { + w += (int64_t)a[i] - (int64_t)b[i]; + r[i] = w & 0xffffffff; + w >>= 32; + } + return (int)w; +} + +void bn_mul(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k) +{ + uint64_t w; + size_t i, j; + for (i = 0; i < k; i++) { + r[i] = 0; + } + for (i = 0; i < k; i++) { + w = 0; + for (j = 0; j < k; j++) { + w += (uint64_t)r[i + j] + (uint64_t)a[i] * (uint64_t)b[j]; + r[i + j] = w & 0xffffffff; + w >>= 32; + } + r[i + k] = w; + } +} + +void bn_mul_lo(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k) +{ + uint64_t w; + size_t i, j; + for (i = 0; i < k; i++) { + r[i] = 0; + } + for (i = 0; i < k; i++) { + w = 0; + for (j = 0; j < k - i; j++) { + w += (uint64_t)r[i + j] + (uint64_t)a[i] * (uint64_t)b[j]; + r[i + j] = w & 0xffffffff; + w >>= 32; + } + } +} + +void bn_to_bytes(const uint32_t *a, size_t k, uint8_t *out) +{ + while (k-- > 0) { + PUTU32(out, a[k]); + out += 4; + } +} + +void bn_from_bytes(uint32_t *a, size_t k, const uint8_t *in) +{ + while (k-- > 0) { + a[k] = GETU32(in); + in += 4; + } +} + +int bn_print(FILE *fp, int fmt, int ind, const char *label, const uint32_t *a, size_t k) +{ + fprintf(fp, "%s: ", label); + + int i; + for (i = 0; i < k; i++) { + fprintf(fp, "0x%08x, ", a[i]); + } + fprintf(fp, "\n"); + + while (k-- > 0) { + fprintf(fp, "%08x", a[k]); + } + fprintf(fp, "\n"); + return 1; +} + +void bn_mod_add(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, size_t k) +{ + int carry; + carry = bn_add(r, a, b, k); + + if (carry) { + bn_sub(r, r, p, k); + } else if (bn_cmp(r, p, k) >= 0) { + bn_sub(r, r, p, k); + } +} + +void bn_mod_sub(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, size_t k) +{ + if (bn_cmp(a, b, k) >= 0) { + bn_sub(r, a, b, k); + } else { + bn_sub(r, b, a, k); + bn_sub(r, p, r, k); + } +} + +void bn_mod_neg(uint32_t *r, const uint32_t *a, const uint32_t *p, size_t k) +{ + bn_sub(r, p, a, k); +} + +void bn_barrett_mod_mul(uint32_t *r, // uint32_t r[k] = a * b mod p + const uint32_t *a, // uint32_t a[k] + const uint32_t *b, // uint32_t b[k] + const uint32_t *p, // uint32_t p[k] + const uint32_t *u, // uint32_t u[k + 1] = floor((2^32)^(2*k) / p) + uint32_t *tmp, // uint32_t tmp[6*k + 4] + size_t k) +{ + uint32_t *p_; // uint32_t p_[k + 1]; + uint32_t *z; // uint32_t z[2 * k]; + uint32_t *q; // uint32_t q[2 * (k + 1)]; + uint32_t *t_; // uint32_t t_[k + 1]; + size_t i; + + p_ = tmp; tmp += k + 1; + z = tmp; tmp += 2 * k; + q = tmp; tmp += 2 * (k + 1); + t_ = tmp; tmp += k + 1; + + for (i = 0; i < k; i++) { + p_[i] = p[i]; + } + p_[k] = 0; + + bn_mul(z, a, b, k); + bn_mul(q, z + k - 1, u, k + 1); + bn_mul_lo(t_, q + k + 1, p_, k + 1); + bn_sub(t_, z, t_, k + 1); + + // reduce at most twice + if (bn_cmp(t_, p_, k + 1) >= 0) { + bn_sub(t_, t_, p_, k + 1); + } + if (bn_cmp(t_, p_, k) >= 0) { + bn_sub(t_, t_, p_, k); + } + bn_copy(r, t_, k); +} + +void bn_barrett_mod_sqr(uint32_t *r, const uint32_t *a, const uint32_t *p, + const uint32_t *u, // uint32_t u[k + 1] + uint32_t *tmp, // uint32_t tmp[6*k + 4] + size_t k) +{ + bn_barrett_mod_mul(r, a, a, p, u, tmp, k); +} + +void bn_barrett_mod_exp(uint32_t *r, const uint32_t *a, const uint32_t *e, const uint32_t *p, + const uint32_t *u, // + uint32_t *tmp, // uint32_t tmp[7*k + 4] + size_t k) +{ + uint32_t *t; // uint32_t t[k]; + uint32_t w; + int i, j; + + // t = 1 + t = tmp; tmp += k; + bn_set_word(t, 1, k); + + for (i = k - 1; i >= 0; i--) { + w = e[i]; + for (j = 0; j < 32; j++) { + bn_barrett_mod_sqr(t, t, p, u, tmp, k); + if (w & 0x80000000) { + bn_barrett_mod_mul(t, t, a, p, u, tmp, k); + } + w <<= 1; + } + } + + bn_copy(r, t, k); +} + +// FIXME: 如果 a = 0 (mod p) 会发生什么 +void bn_barrett_mod_inv(uint32_t *r, const uint32_t *a, const uint32_t *p, const uint32_t *u, + uint32_t *tmp, // uint32_t tmp[8*k + 4] + size_t k) +{ + uint32_t *e; // uint32_t e[k]; + + // e = p - 2 + e = tmp; tmp += k; + bn_set_word(e, 2, k); + bn_sub(e, p, e, k); + + // a^-1 = a^(p - 2) (mod p) + bn_barrett_mod_exp(r, a, e, p, u, tmp, k); +} + +// mont(aR, bR) = aR * bR * R^-1 = abR (mod p) +void bn_mont_mod_mul(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, + const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[5 * k] + size_t k) +{ + uint32_t *z; // uint32_t z[k * 2]; + uint32_t *c; // uint32_t c[k * 2]; + uint32_t *t; // uint32_t t[k]; + + z = tmp; tmp += 2 * k; + c = tmp; tmp += 2 * k; + t = tmp; tmp += k; + + bn_mul(z, a, b, k); + bn_mul_lo(t, z, p_inv_neg, k); + bn_mul(c, t, p, k); + bn_add(c, c, z, k * 2); + if (bn_cmp(c + k, p, k) >= 0) { + bn_sub(c + k, c + k, p, k); + } + + bn_copy(r, c + k, k); +} + +void bn_mont_mod_sqr(uint32_t *r, const uint32_t *a, const uint32_t *p, + const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[5 * k] + size_t k) +{ + bn_mont_mod_mul(r, a, a, p, p_inv_neg, tmp, k); +} + +void bn_mont_mod_exp( + uint32_t *r, + const uint32_t *a, + const uint32_t *e, + const uint32_t *p, + const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[6 * k]; + size_t k) +{ + uint32_t *t; // uint32_t t[k]; + uint32_t w; + int i, j; + + // t = 1 + t = tmp; tmp += k; + bn_set_word(t, 1, k); + + for (i = k - 1; i >= 0; i--) { + w = e[i]; + for (j = 0; j < 32; j++) { + bn_mont_mod_sqr(t, t, p, p_inv_neg, tmp, k); + if (w & 0x80000000) { + bn_mont_mod_mul(t, t, a, p, p_inv_neg, tmp, k); + } + w <<= 1; + } + } + + bn_copy(r, t, k); +} + +// FIXME: 如果 a = 0 (mod p) 会发生什么 +void bn_mont_mod_inv(uint32_t *r, const uint32_t *a, const uint32_t *p, + const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[7 * k]; + size_t k) +{ + uint32_t *e; // uint32_t e[k]; + + // e = p - 2 + e = tmp; tmp += k; + bn_set_word(e, 2, k); + bn_sub(e, p, e, k); + + // a^-1 = a^(p - 2) (mod p) + bn_mont_mod_exp(r, a, e, p, p_inv_neg, tmp, k); +} + +// mont(a, R^2) = a * R^2 * R^-1 = a * R mod p +void bn_mont_set(uint32_t *r, + const uint32_t *a, + const uint32_t *R_sqr, + const uint32_t *p, + const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[5 * k] + size_t k) +{ + bn_mont_mod_mul(r, a, R_sqr, p, p_inv_neg, tmp, k); +} + +// mont(aR, 1) = aR * 1 * R^-1 = a (mod p) +void bn_mont_get(uint32_t *r, + const uint32_t *a, + const uint32_t *p, + const uint32_t *p_inv_neg, + uint32_t *tmp, // uint32_t tmp[5 * k] + size_t k) +{ + uint32_t one[k]; + bn_set_word(one, 1, k); + bn_mont_mod_mul(r, a, one, p, p_inv_neg, tmp, k); +} + diff --git a/src/ecdh.c b/src/ecdh.c new file mode 100644 index 00000000..e9873d96 --- /dev/null +++ b/src/ecdh.c @@ -0,0 +1,12 @@ +/* + * 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 + */ + + + + diff --git a/src/ecdsa.c b/src/ecdsa.c new file mode 100644 index 00000000..9ed40a5e --- /dev/null +++ b/src/ecdsa.c @@ -0,0 +1,387 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int ecdsa_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const ECDSA_SIGNATURE *sig) +{ + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + secp256r1_print(fp, fmt, ind, "r", sig->r); + secp256r1_print(fp, fmt, ind, "s", sig->s); + return 1; +} + +int ecdsa_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sigbuf, size_t siglen) +{ + ECDSA_SIGNATURE sig; + + if (ecdsa_signature_from_der(&sig, &sigbuf, &siglen) != 1) { + error_print(); + return -1; + } + ecdsa_signature_print_ex(fp, fmt, ind, label, &sig); + if (siglen) { + error_print(); + return -1; + } + return 1; +} + +int ecdsa_do_sign_ex(const SECP256R1_KEY *key, const secp256r1_t k, const uint8_t dgst[32], ECDSA_SIGNATURE *sig) +{ + secp256r1_t e; + secp256r1_t x1; + secp256r1_t y1; + secp256r1_t k_inv; + SECP256R1_POINT P; + + // e = hash(m) + secp256r1_from_32bytes(e, dgst); + secp256r1_modn(e, e); + + // (x1, y1) = k*G + secp256r1_point_mul_generator(&P, k); + secp256r1_point_get_xy(&P, x1, y1); + + // r = x1 mod n + secp256r1_modn(sig->r, x1); + + // s = k^-1 * (e + d * r) mod n + secp256r1_modn_inv(k_inv, k); + secp256r1_modn_mul(sig->s, key->private_key, sig->r); + secp256r1_modn_add(sig->s, sig->s, e); + secp256r1_modn_mul(sig->s, sig->s, k_inv); + + return 1; +} + +int ecdsa_do_sign(const SECP256R1_KEY *key, const uint8_t dgst[32], ECDSA_SIGNATURE *sig) +{ + secp256r1_t k; + + // rand k in [1, n-1] + do { + if (rand_bytes((uint8_t *)k, sizeof(k)) != 1) { + error_print(); + return -1; + } + } while (secp256r1_is_zero(k) || secp256r1_cmp(k, SECP256R1_N) >= 0); + + if (ecdsa_do_sign_ex(key, k, dgst, sig) != 1) { + error_print(); + return -1; + } + return 1; +} + + +int ecdsa_do_verify(const SECP256R1_KEY *key, const uint8_t dgst[32], const ECDSA_SIGNATURE *sig) +{ + secp256r1_t e; + secp256r1_t w; + secp256r1_t u1; + secp256r1_t u2; + secp256r1_t x1; + secp256r1_t y1; + SECP256R1_POINT P; + SECP256R1_POINT Q; + SECP256R1_POINT R; + + // check r, s in [1, n-1] + if (secp256r1_is_zero(sig->r) + || secp256r1_cmp(sig->r, SECP256R1_N) >= 0 + || secp256r1_is_zero(sig->s) + || secp256r1_cmp(sig->s, SECP256R1_N) >= 0) { + error_print(); + return -1; + } + + // e = hash(m) + secp256r1_from_32bytes(e, dgst); + secp256r1_modn(e, e); + + // w = s^-1 (mod n) + secp256r1_modn_inv(w, sig->s); + + // u1 = e * w (mod n) + secp256r1_modn_mul(u1, e, w); + + // u2 = r * w (mod n) + secp256r1_modn_mul(u2, sig->r, w); + + // (x1, y1) = u1*G + u2*Q + secp256r1_point_mul_generator(&P, u1); + secp256r1_point_mul(&Q, u2, &key->public_key); + secp256r1_point_add(&R, &P, &Q); + secp256r1_point_get_xy(&R, x1, y1); + + // x1 = x1 mod n + secp256r1_modn(x1, x1); + + if (secp256r1_cmp(x1, sig->r) != 0) { + return 0; + } + return 1; +} + +int ecdsa_signature_to_der(const ECDSA_SIGNATURE *sig, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + uint8_t r[32]; + uint8_t s[32]; + + if (!sig) { + return 0; + } + + secp256r1_to_32bytes(sig->r, r); + secp256r1_to_32bytes(sig->s, s); + + if (asn1_integer_to_der(r, 32, NULL, &len) != 1 + || asn1_integer_to_der(s, 32, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_integer_to_der(r, 32, out, outlen) != 1 + || asn1_integer_to_der(s, 32, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int ecdsa_signature_from_der(ECDSA_SIGNATURE *sig, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + const uint8_t *r; + const uint8_t *s; + size_t dlen, rlen, slen; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_integer_from_der(&r, &rlen, &d, &dlen) != 1 + || asn1_integer_from_der(&s, &slen, &d, &dlen) != 1 + || asn1_length_le(rlen, 32) != 1 + || asn1_length_le(slen, 32) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + + secp256r1_from_32bytes(sig->r, r); + secp256r1_from_32bytes(sig->s, s); + + return 1; +} + +int ecdsa_sign(const SECP256R1_KEY *key, const uint8_t dgst[32], uint8_t *sigbuf, size_t *siglen) +{ + ECDSA_SIGNATURE sig; + + if (ecdsa_do_sign(key, dgst, &sig) != 1) { + error_print(); + return -1; + } + *siglen = 0; + if (ecdsa_signature_to_der(&sig, &sigbuf, siglen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int ecdsa_sign_fixlen(const SECP256R1_KEY *key, const uint8_t dgst[32], size_t siglen, uint8_t *sig) +{ + unsigned int trys = 200; + uint8_t buf[ECDSA_SIGNATURE_MAX_SIZE]; + size_t len; + + switch (siglen) { + case ECDSA_SIGNATURE_COMPACT_SIZE: + case ECDSA_SIGNATURE_TYPICAL_SIZE: + case ECDSA_SIGNATURE_MAX_SIZE: + break; + default: + error_print(); + return -1; + } + + while (trys--) { + if (ecdsa_sign(key, dgst, buf, &len) != 1) { + error_print(); + return -1; + } + if (len == siglen) { + memcpy(sig, buf, len); + return 1; + } + } + + // might caused by bad randomness + error_print(); + return -1; +} + + +int ecdsa_verify(const SECP256R1_KEY *key, const uint8_t dgst[32], const uint8_t *sigbuf, size_t siglen) +{ + int ret; + ECDSA_SIGNATURE sig; + + if (ecdsa_signature_from_der(&sig, &sigbuf, &siglen) != 1) { + error_print(); + return -1; + } + if (siglen) { + error_print(); + return -1; + } + if ((ret = ecdsa_do_verify(key, dgst, &sig)) < 0) { + error_print(); + return -1; + } + return ret; +} + +int ecdsa_sign_init(ECDSA_SIGN_CTX *ctx, const SECP256R1_KEY *key) +{ + if (!ctx || !key) { + error_print(); + return -1; + } + memset(ctx, 0, sizeof(ECDSA_SIGN_CTX)); + + ctx->key = *key; + + sha256_init(&ctx->sha256_ctx); + + return 1; +} + +int ecdsa_sign_update(ECDSA_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +{ + if (!ctx) { + error_print(); + return -1; + } + if (data && datalen) { + sha256_update(&ctx->sha256_ctx, data, datalen); + } + return 1; +} + +int ecdsa_sign_finish(ECDSA_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen) +{ + uint8_t dgst[32]; + + if (!ctx || !sig || !siglen) { + error_print(); + return -1; + } + + sha256_finish(&ctx->sha256_ctx, dgst); + + if (ecdsa_sign(&ctx->key, dgst, sig, siglen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int ecdsa_sign_finish_fixlen(ECDSA_SIGN_CTX *ctx, size_t siglen, uint8_t *sig) +{ + uint8_t dgst[32]; + + if (!ctx || !sig || !siglen) { + error_print(); + return -1; + } + + sha256_finish(&ctx->sha256_ctx, dgst); + + if (ecdsa_sign_fixlen(&ctx->key, dgst, siglen, sig) != 1) { + error_print(); + return -1; + } + return 1; +} + + + + + + +int ecdsa_verify_init(ECDSA_SIGN_CTX *ctx, const SECP256R1_KEY *key, const uint8_t *sig, size_t siglen) +{ + if (!ctx || !key || !sig || !siglen) { + error_print(); + return -1; + } + + if (ecdsa_signature_from_der(&ctx->sig, &sig, &siglen) != 1) { + error_print(); + return -1; + } + if (siglen) { + error_print(); + return -1; + } + + ctx->key = *key; + + sha256_init(&ctx->sha256_ctx); + + return 1; +} + + +int ecdsa_verify_update(ECDSA_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +{ + if (!ctx) { + error_print(); + return -1; + } + if (data && datalen) { + sha256_update(&ctx->sha256_ctx, data, datalen); + } + return 1; +} + + +int ecdsa_verify_finish(ECDSA_SIGN_CTX *ctx) +{ + uint8_t dgst[32]; + int ret; + + if (!ctx) { + error_print(); + return -1; + } + + sha256_finish(&ctx->sha256_ctx, dgst); + + if ((ret = ecdsa_do_verify(&ctx->key, dgst, &ctx->sig)) < 0) { + error_print(); + return -1; + } + return ret; +} + diff --git a/src/secp256r1.c b/src/secp256r1.c new file mode 100644 index 00000000..aff453c6 --- /dev/null +++ b/src/secp256r1.c @@ -0,0 +1,593 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + + +const secp256r1_t SECP256R1_P = { + 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0xffffffff, +}; + +const secp256r1_t SECP256R1_B = { + 0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0, + 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8, +}; + +const secp256r1_t SECP256R1_N = { + 0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, +}; + +const uint32_t SECP256R1_U_P[9] = { + 0x00000003, 0x00000000, 0xffffffff, 0xfffffffe, + 0xfffffffe, 0xfffffffe, 0xffffffff, 0x00000000, + 0x00000001, +}; + +const uint32_t SECP256R1_U_N[9] = { + 0xeedf9bfe, 0x012ffd85, 0xdf1a6c21, 0x43190552, + 0xffffffff, 0xfffffffe, 0xffffffff, 0x00000000, + 0x00000001, +}; + +int secp256r1_is_zero(const secp256r1_t a) { + return bn_is_zero(a, SECP256R1_K); +} + +int secp256r1_is_one(const secp256r1_t a) { + return bn_is_one(a, SECP256R1_K); +} + +int secp256r1_cmp(const secp256r1_t a, const secp256r1_t b) { + return bn_cmp(a, b, SECP256R1_K); +} + +void secp256r1_set_zero(secp256r1_t r) { + bn_set_word(r, 0, SECP256R1_K); +} + +void secp256r1_set_one(secp256r1_t r) { + bn_set_word(r, 1, SECP256R1_K); +} + +void secp256r1_copy(secp256r1_t r, const secp256r1_t a) { + bn_copy(r, a, SECP256R1_K); +} + +void secp256r1_to_32bytes(const secp256r1_t a, uint8_t out[32]) { + bn_to_bytes(a, SECP256R1_K, out); +} + +void secp256r1_from_32bytes(secp256r1_t r, const uint8_t in[32]) { + bn_from_bytes(r, SECP256R1_K, in); +} + +int secp256r1_print(FILE *fp, int fmt, int ind, const char *label, const secp256r1_t a) { + uint8_t bytes[32]; + secp256r1_to_32bytes(a, bytes); + format_bytes(fp, fmt, ind, label, bytes, 32); + return 1; +} + +void secp256r1_modp_add(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) { + bn_mod_add(r, a, b, SECP256R1_P, SECP256R1_K); +} + +void secp256r1_modp_dbl(secp256r1_t r, const secp256r1_t a) { + bn_mod_add(r, a, a, SECP256R1_P, SECP256R1_K); +} + +void secp256r1_modp_tri(secp256r1_t r, const secp256r1_t a) { + secp256r1_t tmp; + + // 这里就出错了,真是太奇怪了! + bn_mod_add(tmp, a, a, SECP256R1_P, SECP256R1_K); + bn_mod_add(r, tmp, a, SECP256R1_P, SECP256R1_K); +} + +void secp256r1_modp_sub(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) { + bn_mod_sub(r, a, b, SECP256R1_P, SECP256R1_K); +} + +void secp256r1_modp_neg(secp256r1_t r, const secp256r1_t a) { + bn_mod_neg(r, a, SECP256R1_P, SECP256R1_K); +} + +void secp256r1_modp_haf(secp256r1_t r, const secp256r1_t a) { + int c = 0; + if (a[0] & 1) { + c = bn_add(r, a, SECP256R1_P, SECP256R1_K); + } else { + bn_copy(r, a, SECP256R1_K); + } + + r[0] = (r[0] >> 1) | ((r[1] & 1) << 31); + r[1] = (r[1] >> 1) | ((r[2] & 1) << 31); + r[2] = (r[2] >> 1) | ((r[3] & 1) << 31); + r[3] = (r[3] >> 1) | ((r[4] & 1) << 31); + r[4] = (r[4] >> 1) | ((r[5] & 1) << 31); + r[5] = (r[5] >> 1) | ((r[6] & 1) << 31); + r[6] = (r[6] >> 1) | ((r[7] & 1) << 31); + r[7] = (r[7] >> 1) | ((c & 1) << 31); +} + +void secp256r1_modp_mul(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) { + uint32_t tmp[6*8 + 4]; + bn_barrett_mod_mul(r, a, b, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K); +} + +void secp256r1_modp_sqr(secp256r1_t r, const secp256r1_t a) { + uint32_t tmp[6*8 + 4]; + bn_barrett_mod_mul(r, a, a, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K); +} + +void secp256r1_modp_exp(secp256r1_t r, const secp256r1_t a, const secp256r1_t e) { + uint32_t tmp[7*8 + 4]; + bn_barrett_mod_exp(r, a, e, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K); +} + +// FIXME: 如果 a = 0 (mod p) 会发生什么 +void secp256r1_modp_inv(secp256r1_t r, const secp256r1_t a) { + uint32_t tmp[8*8 + 4]; + bn_barrett_mod_inv(r, a, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K); +} + + +void secp256r1_modn(secp256r1_t r, const secp256r1_t a) { + if (bn_cmp(a, SECP256R1_N, SECP256R1_K) >= 0) { + bn_sub(r, a, SECP256R1_N, SECP256R1_K); + } else { + bn_copy(r, a, SECP256R1_K); + } +} + +void secp256r1_modn_add(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) { + bn_mod_add(r, a, b, SECP256R1_N, SECP256R1_K); +} + +void secp256r1_modn_dbl(secp256r1_t r, const secp256r1_t a) { + bn_mod_add(r, a, a, SECP256R1_N, SECP256R1_K); +} + +void secp256r1_modn_tri(secp256r1_t r, const secp256r1_t a) { + secp256r1_t tmp; + bn_mod_add(tmp, a, a, SECP256R1_N, SECP256R1_K); + bn_mod_add(r, tmp, a, SECP256R1_N, SECP256R1_K); +} + +void secp256r1_modn_sub(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) { + bn_mod_sub(r, a, b, SECP256R1_N, SECP256R1_K); +} + +void secp256r1_modn_neg(secp256r1_t r, const secp256r1_t a) { + bn_mod_neg(r, a, SECP256R1_N, SECP256R1_K); +} + +void secp256r1_modn_mul(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) { + uint32_t tmp[6*8 + 4]; + bn_barrett_mod_mul(r, a, b, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K); +} + +void secp256r1_modn_sqr(secp256r1_t r, const secp256r1_t a) { + uint32_t tmp[6*8 + 4]; + bn_barrett_mod_mul(r, a, a, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K); +} + +void secp256r1_modn_exp(secp256r1_t r, const secp256r1_t a, const secp256r1_t e) { + uint32_t tmp[7*8 + 4]; + bn_barrett_mod_exp(r, a, e, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K); +} + +// FIXME: 如果 a = 0 (mod p) 会发生什么 +void secp256r1_modn_inv(secp256r1_t r, const secp256r1_t a) { + uint32_t tmp[8*8 + 4]; + bn_barrett_mod_inv(r, a, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K); +} + + +const SECP256R1_POINT SECP256R1_POINT_G = { + { 0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81, + 0x63a440f2, 0xf8bce6e5, 0xe12c4247, 0x6b17d1f2, }, + { 0x37bf51f5, 0xcbb64068, 0x6b315ece, 0x2bce3357, + 0x7c0f9e16, 0x8ee7eb4a, 0xfe1a7f9b, 0x4fe342e2, }, + { 1,0,0,0,0,0,0,0, }, +}; + +void secp256r1_point_set_infinity(SECP256R1_POINT *R) +{ + secp256r1_set_one(R->X); + secp256r1_set_one(R->Y); + secp256r1_set_zero(R->Z); +} + +int secp256r1_point_is_at_infinity(const SECP256R1_POINT *P) +{ + if (secp256r1_is_zero(P->Z)) { + return 1; + } + return 0; +} + +int secp256r1_point_is_on_curve(const SECP256R1_POINT *P) +{ + secp256r1_t t0; + secp256r1_t t1; + secp256r1_t t2; + + if (secp256r1_point_is_at_infinity(P)) { + return 1; + } + + // check Y^2 + 3 * X * Z^4 == X^3 + b * Z^6 + + // t0 = Y^2 + secp256r1_modp_sqr(t0, P->Y); + + // t1 = Z^2 + secp256r1_modp_sqr(t1, P->Z); + + // t2 = Z^4 + secp256r1_modp_sqr(t2, t1); + + // t1 = Z^6 + secp256r1_modp_mul(t1, t1, t2); + + // t1 = b * Z^6 + secp256r1_modp_mul(t1, t1, SECP256R1_B); + + // t2 = X * Z^4 + secp256r1_modp_mul(t2, t2, P->X); + + // t0 = Y^2 + 3 * X * Z^4 + secp256r1_modp_add(t0, t0, t2); + secp256r1_modp_add(t0, t0, t2); + secp256r1_modp_add(t0, t0, t2); + + // t2 = X^2 + secp256r1_modp_sqr(t2, P->X); + + // t2 = X^3 + secp256r1_modp_mul(t2, t2, P->X); + + // t1 = b * Z^6 + X^3 + secp256r1_modp_add(t1, t1, t2); + + if (secp256r1_cmp(t0, t1) != 0) { + return 0; + } + return 1; +} + +void secp256r1_point_copy(SECP256R1_POINT *R, const SECP256R1_POINT *P) +{ + secp256r1_copy(R->X, P->X); + secp256r1_copy(R->Y, P->Y); + secp256r1_copy(R->Z, P->Z); +} + +int secp256r1_point_set_xy(SECP256R1_POINT *R, const secp256r1_t x, const secp256r1_t y) +{ + if (secp256r1_cmp(x, SECP256R1_P) >= 0) { + error_print(); + return -1; + } + if (secp256r1_cmp(y, SECP256R1_P) >= 0) { + error_print(); + return -1; + } + secp256r1_copy(R->X, x); + secp256r1_copy(R->Y, y); + secp256r1_set_one(R->Z); + + + if (!secp256r1_point_is_on_curve(R)) { + error_print(); + return -1; + } + return 1; +} + +int secp256r1_point_get_xy(const SECP256R1_POINT *P, secp256r1_t x, secp256r1_t y) +{ + secp256r1_t Z_inv; + + if (secp256r1_point_is_at_infinity(P)) { + return 0; + } + secp256r1_modp_inv(Z_inv, P->Z); + secp256r1_modp_mul(y, P->Y, Z_inv); + secp256r1_modp_sqr(Z_inv, Z_inv); + secp256r1_modp_mul(x, P->X, Z_inv); + secp256r1_modp_mul(y, y, Z_inv); + return 1; +} + +void secp256r1_point_dbl(SECP256R1_POINT *R, const SECP256R1_POINT *P) +{ + /* + secp256r1_t T_0; + secp256r1_t T_1; + secp256r1_t T_2; + secp256r1_t T_3; + secp256r1_t T_4; + + if (secp256r1_point_is_at_infinity(P)) { + secp256r1_point_set_infinity(R); + return; + } + + secp256r1_modp_sqr(T_0, P->X); + secp256r1_modp_tri(T_0, T_0); + secp256r1_modp_sqr(T_1, T_0); + secp256r1_modp_sqr(T_2, P->Y); + secp256r1_modp_mul(T_3, P->X, T_2); + secp256r1_modp_dbl(T_3, T_3); + secp256r1_modp_dbl(T_3, T_3); + secp256r1_modp_dbl(T_4, T_3); + secp256r1_modp_sub(T_1, T_1, T_4); + secp256r1_modp_sub(T_3, T_3, T_1); + secp256r1_modp_mul(T_0, T_0, T_3); + secp256r1_modp_dbl(T_2, T_2); + secp256r1_modp_sqr(T_2, T_2); + secp256r1_modp_dbl(T_2, T_2); + secp256r1_modp_sub(T_0, T_0, T_2); + secp256r1_modp_mul(T_2, P->Y, P->Z); + secp256r1_modp_dbl(T_2, T_2); + + secp256r1_copy(R->X, T_1); + secp256r1_copy(R->Y, T_0); + secp256r1_copy(R->Z, T_2); + */ + + const uint32_t *X1 = P->X; + const uint32_t *Y1 = P->Y; + const uint32_t *Z1 = P->Z; + uint32_t *X3 = R->X; + uint32_t *Y3 = R->Y; + uint32_t *Z3 = R->Z; + secp256r1_t S; + secp256r1_t M; + secp256r1_t Zsqr; + secp256r1_t tmp0; + + // 1. S = 2Y + secp256r1_modp_dbl(S, Y1); + + // 2. Zsqr = Z^2 + secp256r1_modp_sqr(Zsqr, Z1); + + // 3. S = S^2 = 4Y^2 + secp256r1_modp_sqr(S, S); + + // 4. Z = Z*Y + secp256r1_modp_mul(Z3, Z1, Y1); + + // 5. Z = 2*Z = 2*Y*Z ===> Z3 + secp256r1_modp_dbl(Z3, Z3); + + // 6. M = X + Zsqr = X + Z^2 + secp256r1_modp_add(M, X1, Zsqr); + + // 7. Zsqr = X - Zsqr = X - Z^2 + secp256r1_modp_sub(Zsqr, X1, Zsqr); + + // 8. Y = S^2 = 16Y^4 + secp256r1_modp_sqr(Y3, S); + + // 9. Y = Y/2 = 8Y^4 + secp256r1_modp_haf(Y3, Y3); + + // 10. M = M * Zsqr = (X + Z^2)*(X - Z^2) = X^2 - Z^4 + secp256r1_modp_mul(M, M, Zsqr); + + // 11. M = 3M = 3X^2 - 3Z^4 + secp256r1_modp_tri(M, M); + + // 12. S = S * X = 4X*Y^2 + secp256r1_modp_mul(S, S, X1); + + // 13. tmp0 = 2 * S = 8X*Y^2 + secp256r1_modp_dbl(tmp0, S); + + // 14. X = M^2 = (3X^2 - 3Z^4)^2 + secp256r1_modp_sqr(X3, M); + + // 15. X = X - tmp0 = (3X^2 - 3Z^4)^2 - 8X*Y^2 ===> X3 + secp256r1_modp_sub(X3, X3, tmp0); + + // 16. S = S - X3 = 4X*Y^2 - X3 + secp256r1_modp_sub(S, S, X3); + + // 17. S = S * M = (3X^2 - 3Z^4)*(4X*Y^2 - X3) + secp256r1_modp_mul(S, S, M); + + // 18. Y = S - Y = (3X^2 - 3Z^4)*(4X*Y^2 - X3) - 8Y^4 ===> Y3 + secp256r1_modp_sub(Y3, S, Y3); +} + +void secp256r1_point_add(SECP256R1_POINT *R, const SECP256R1_POINT *P, const SECP256R1_POINT *Q) +{ + secp256r1_t T_1; + secp256r1_t T_2; + secp256r1_t T_3; + secp256r1_t T_4; + secp256r1_t T_5; + secp256r1_t T_6; + secp256r1_t T_7; + secp256r1_t T_8; + + if (secp256r1_point_is_at_infinity(P)) { + *R = *Q; + return; + } + if (secp256r1_point_is_at_infinity(Q)) { + *R = *P; + return; + } + + // 这里的代码是来自zkrypt的,不确定是否有问题 + secp256r1_modp_sqr(T_1, P->Z); // T_1 = Z_1^2 + secp256r1_modp_sqr(T_2, Q->Z); // T_2 = Z_2^2 + secp256r1_modp_mul(T_3, Q->X, T_1); // T_3 = X_2 * Z_1^2 + secp256r1_modp_mul(T_4, P->X, T_2); // T_4 = X_1 * Z_2^2 + secp256r1_modp_add(T_5, T_3, T_4); // T_5 = X_2 * Z_1^2 + X_1 * Z_2^2 = C + secp256r1_modp_sub(T_3, T_3, T_4); // T_3 = X_2 * Z_1^2 - X_1 * Z_2^2 = B + secp256r1_modp_mul(T_1, T_1, P->Z); // T_1 = Z_1^3 + secp256r1_modp_mul(T_1, T_1, Q->Y); // T_1 = Y_2 * Z_1^3 + secp256r1_modp_mul(T_2, T_2, Q->Z); // T_2 = Z_2^3 + secp256r1_modp_mul(T_2, T_2, P->Y); // T_2 = Y_1 * Z_2^3 + secp256r1_modp_add(T_6, T_1, T_2); // T_6 = Y_2 * Z_1^3 + Y_1 * Z_2^3 = D + secp256r1_modp_sub(T_1, T_1, T_2); // T_1 = Y_2 * Z_1^3 - Y_1 * Z_2^3 = A + + if (secp256r1_is_zero(T_1) && secp256r1_is_zero(T_3)) { + secp256r1_point_dbl(R, P); + return; + } + + if (secp256r1_is_one(T_1) && secp256r1_is_zero(T_6)) { + secp256r1_point_set_infinity(R); + return; + } + + secp256r1_modp_sqr(T_6, T_1); // T_6 = A^2 + secp256r1_modp_mul(T_7, T_3, P->Z); // T_7 = B * Z_1 + secp256r1_modp_mul(T_7, T_7, Q->Z); // T_7 = B * Z_1 * Z_2 = Z_3 + secp256r1_modp_sqr(T_8, T_3); // T_8 = B^2 + secp256r1_modp_mul(T_5, T_5, T_8); // T_5 = B^2 * C + secp256r1_modp_mul(T_3, T_3, T_8); // T_3 = B^3 + secp256r1_modp_mul(T_4, T_4, T_8); // T_4 = B^2 * X_1 * Z_2^2 + secp256r1_modp_sub(T_6, T_6, T_5); // T_6 = A^2 - B^2 * C = X_3 + secp256r1_modp_sub(T_4, T_4, T_6); // T_4 = B^2 * X_1 * Z_2^2 - X_3 + secp256r1_modp_mul(T_1, T_1, T_4); // T_1 = A * (B^2 * X_1 * Z_2^2 - X_3) + secp256r1_modp_mul(T_2, T_2, T_3); // T_2 = B^3 * Y_1 * Z_1^3 + secp256r1_modp_sub(T_1, T_1, T_2); // T_1 = A * (B^2 * X_1 * Z_2^2 - X_3) - B^3 * Y_1 * Z_1^3 = Y_3 + + secp256r1_copy(R->X, T_6); + secp256r1_copy(R->Y, T_1); + secp256r1_copy(R->Z, T_7); +} + +void secp256r1_point_neg(SECP256R1_POINT *R, const SECP256R1_POINT *P) +{ + if (secp256r1_point_is_at_infinity(P)) { + secp256r1_point_set_infinity(R); + return; + } + secp256r1_copy(R->X, P->X); + secp256r1_modp_neg(R->Y, P->Y); + secp256r1_copy(R->Z, P->Z); +} + +void secp256r1_point_sub(SECP256R1_POINT *R, const SECP256R1_POINT *P, const SECP256R1_POINT *Q) +{ + SECP256R1_POINT T; + secp256r1_point_neg(&T, Q); + secp256r1_point_add(R, P, &T); +} + +void secp256r1_point_mul(SECP256R1_POINT *R, const secp256r1_t k, const SECP256R1_POINT *P) +{ + uint32_t bits; + int nbits; + int i; + + secp256r1_point_set_infinity(R); + + for (i = 7; i >= 0; i--) { + bits = k[i]; + nbits = 32; + while (nbits-- > 0) { + secp256r1_point_dbl(R, R); + if (bits & 0x80000000) { + secp256r1_point_add(R, R, P); + } + bits <<= 1; + } + } +} + +void secp256r1_point_mul_generator(SECP256R1_POINT *R, const secp256r1_t k) +{ + secp256r1_point_mul(R, k, &SECP256R1_POINT_G); +} + +int secp256r1_point_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_POINT *P) +{ + uint8_t bytes[32]; + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + secp256r1_to_32bytes(P->X, bytes); + format_bytes(fp, fmt, ind, "X", bytes, 32); + secp256r1_to_32bytes(P->Y, bytes); + format_bytes(fp, fmt, ind, "Y", bytes, 32); + secp256r1_to_32bytes(P->Z, bytes); + format_bytes(fp, fmt, ind, "Z", bytes, 32); + return 1; +} + +int secp256r1_point_to_uncompressed_octets(const SECP256R1_POINT *P, uint8_t octets[65]) +{ + secp256r1_t x; + secp256r1_t y; + + if (secp256r1_point_get_xy(P, x, y) != 1) { + error_print(); + return -1; + } + octets[0] = 0x04; + secp256r1_to_32bytes(x, octets + 1); + secp256r1_to_32bytes(y, octets + 33); + return 1; +} + +int secp256r1_point_from_uncompressed_octets(SECP256R1_POINT *P, const uint8_t octets[65]) +{ + secp256r1_t x; + secp256r1_t y; + + if (octets[0] != 0x04) { + error_print(); + return -1; + } + secp256r1_from_32bytes(x, octets + 1); + secp256r1_from_32bytes(y, octets + 33); + + if (secp256r1_point_set_xy(P, x, y) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp256r1_point_equ(const SECP256R1_POINT *P, const SECP256R1_POINT *Q) +{ + uint8_t p_octets[65]; + uint8_t q_octets[65]; + + (void)secp256r1_point_to_uncompressed_octets(P, p_octets); + (void)secp256r1_point_to_uncompressed_octets(Q, q_octets); + + if (memcmp(p_octets, q_octets, 65) == 0) { + return 1; + } else { + return 0; + } +} + + diff --git a/src/secp256r1_key.c b/src/secp256r1_key.c new file mode 100644 index 00000000..d3b68f99 --- /dev/null +++ b/src/secp256r1_key.c @@ -0,0 +1,506 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int secp256r1_key_generate(SECP256R1_KEY *key) +{ + do { + if (rand_bytes((uint8_t *)key->private_key, sizeof(secp256r1_t)) != 1) { + error_print(); + return -1; + } + } while (secp256r1_is_zero(key->private_key) || secp256r1_cmp(key->private_key, SECP256R1_N) >= 0); + + secp256r1_point_mul_generator(&key->public_key, key->private_key); + + return 1; +} + +int secp256r1_key_set_private_key(SECP256R1_KEY *key, const secp256r1_t private_key) +{ + if (!key || !private_key) { + error_print(); + return -1; + } + if (secp256r1_is_zero(private_key) || secp256r1_cmp(private_key, SECP256R1_N) >= 0) { + error_print(); + return -1; + } + memset(key, 0, sizeof(SECP256R1_KEY)); + + secp256r1_copy(key->private_key, private_key); + secp256r1_point_mul_generator(&key->public_key, key->private_key); + return 1; +} + +int secp256r1_public_key_equ(const SECP256R1_KEY *key, const SECP256R1_KEY *pub) +{ + if (secp256r1_point_equ(&key->public_key, &pub->public_key) == 1) { + return 1; + } else { + return 0; + } +} + + +void secp256r1_key_cleanup(SECP256R1_KEY *key) +{ + if (key) { + gmssl_secure_clear(key->private_key, sizeof(secp256r1_t)); + memset(key, 0, sizeof(SECP256R1_KEY)); + } +} + + +// SM2将这个命名为_to_octets,应该更准确一些 +int secp256r1_public_key_to_bytes(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen) +{ + if (!key || !outlen) { + error_print(); + return -1; + } + if (out && *out) { + if (secp256r1_point_to_uncompressed_octets(&key->public_key, *out) != 1) { + error_print(); + return -1; + } + *out += 65; + } + *outlen += 65; + return 1; +} + +int secp256r1_public_key_from_bytes(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen) +{ + secp256r1_t x; + secp256r1_t y; + + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen < 65) { + error_print(); + return -1; + } + memset(key, 0, sizeof(SECP256R1_KEY)); + + if (secp256r1_point_from_uncompressed_octets(&key->public_key, *in) != 1) { + error_print(); + return -1; + } + *in += 65; + *inlen -= 65; + + return 1; +} + +int secp256r1_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_KEY *key) +{ + secp256r1_t x; + secp256r1_t y; + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + + secp256r1_print(fp, fmt, ind, "X", key->public_key.X); + secp256r1_print(fp, fmt, ind, "Y", key->public_key.Y); + secp256r1_print(fp, fmt, ind, "Z", key->public_key.Z); + + secp256r1_point_get_xy(&key->public_key, x, y); + secp256r1_print(fp, fmt, ind, "x", x); + secp256r1_print(fp, fmt, ind, "y", y); + return 1; +} + +int secp256r1_private_key_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_KEY *key) +{ + uint8_t buf[32]; + + secp256r1_to_32bytes(key->private_key, buf); + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + if (secp256r1_public_key_print(fp, fmt, ind, "public_key", key) != 1) { + error_print(); + return -1; + } + format_bytes(fp, fmt, ind, "private_key", buf, 32); + return 1; +} + +int secp256r1_public_key_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen) +{ + uint8_t octets[65]; + uint8_t *p = octets; + size_t len = 0; + + if (!key) { + return 0; + } + + // different from SM2 + if (out && *out) { + if (secp256r1_public_key_to_bytes(key, &p, &len) != 1) { + error_print(); + return -1; + } + } + + if (asn1_bit_octets_to_der(octets, sizeof(octets), out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp256r1_public_key_from_der(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + + if ((ret = asn1_bit_octets_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (secp256r1_public_key_from_bytes(key, &d, &dlen) != 1) { + error_print(); + return -1; + } + if (dlen) { + error_print(); + return -1; + } + return 1; +} + + + + + + + + + + + + + + + + + + + + + +int secp256r1_private_key_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen) +{ + int curve = OID_secp256r1; + uint8_t params[64]; + uint8_t pubkey[128]; + uint8_t *params_ptr = params; + uint8_t *pubkey_ptr = pubkey; + size_t params_len = 0; + size_t pubkey_len = 0; + uint8_t prikey[32]; + size_t len = 0; + + if (!key) { + error_print(); + return -1; + } + if (ec_named_curve_to_der(curve, ¶ms_ptr, ¶ms_len) != 1 + || secp256r1_public_key_to_der(key, &pubkey_ptr, &pubkey_len) != 1) { + error_print(); + return -1; + } + // fprintf(stderr, "%s %d: params_len = %zu\n", params_len); + // fprintf(stderr, "%s %d: pubkey_len = %zu\n", pubkey_len); + secp256r1_to_32bytes(key->private_key, prikey); + if (asn1_int_to_der(EC_private_key_version, NULL, &len) != 1 + || asn1_octet_string_to_der(prikey, 32, NULL, &len) != 1 + || asn1_explicit_to_der(0, params, params_len, NULL, &len) != 1 + || asn1_explicit_to_der(1, pubkey, pubkey_len, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(EC_private_key_version, out, outlen) != 1 + || asn1_octet_string_to_der(prikey, 32, out, outlen) != 1 + || asn1_explicit_to_der(0, params, params_len, out, outlen) != 1 + || asn1_explicit_to_der(1, pubkey, pubkey_len, out, outlen) != 1) { + gmssl_secure_clear(prikey, 32); + error_print(); + return -1; + } + gmssl_secure_clear(prikey, 32); + return 1; +} + +int secp256r1_private_key_from_der(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + int ver; + const uint8_t *prikey; + const uint8_t *params; + const uint8_t *pubkey; + size_t prikey_len, params_len, pubkey_len; + int curve; + SECP256R1_KEY tmp_key; + secp256r1_t private_key; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&ver, &d, &dlen) != 1 + || asn1_octet_string_from_der(&prikey, &prikey_len, &d, &dlen) != 1 + || asn1_explicit_from_der(0, ¶ms, ¶ms_len, &d, &dlen) != 1 + || asn1_explicit_from_der(1, &pubkey, &pubkey_len, &d, &dlen) != 1 + || asn1_check(ver == EC_private_key_version) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + if (!params || !pubkey) { + error_print(); + return -1; + } + + // public_key + if (ec_named_curve_from_der(&curve, ¶ms, ¶ms_len) != 1 + || asn1_check(curve == OID_secp256r1) != 1 + || asn1_length_is_zero(params_len) != 1) { + error_print(); + return -1; + } + if (secp256r1_public_key_from_der(&tmp_key, &pubkey, &pubkey_len) != 1 + || asn1_length_is_zero(pubkey_len) != 1) { + error_print(); + return -1; + } + + // private_key + if (!prikey || prikey_len != 32) { + error_print(); + return -1; + } + secp256r1_from_32bytes(private_key, prikey); + if (secp256r1_key_set_private_key(key, private_key) != 1) { + gmssl_secure_clear(private_key, 32); + error_print(); + return -1; + } + gmssl_secure_clear(private_key, 32); + + // check + if (secp256r1_public_key_equ(key, &tmp_key) != 1) { + secp256r1_key_cleanup(key); + error_print(); + return -1; + } + + return 1; +} + +int secp256r1_private_key_info_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen) +{ + int algor = OID_ec_public_key; + int algor_param = OID_secp256r1; + size_t len = 0; + uint8_t prikey[256]; + uint8_t *p = prikey; + size_t prikey_len = 0; + + if (secp256r1_private_key_to_der(key, &p, &prikey_len) != 1) { + error_print(); + return -1; + } + //fprintf(stderr, "%s %d: prikey_len = %zu\n", __FILE__, __LINE__, prikey_len); + + if (asn1_int_to_der(PKCS8_private_key_info_version, NULL, &len) != 1 + || x509_public_key_algor_to_der(algor, algor_param, NULL, &len) != 1 + || asn1_octet_string_to_der(prikey, prikey_len, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(PKCS8_private_key_info_version, out, outlen) != 1 + || x509_public_key_algor_to_der(algor, algor_param, out, outlen) != 1 + || asn1_octet_string_to_der(prikey, prikey_len, out, outlen) != 1) { + memset(prikey, 0, sizeof(prikey)); + error_print(); + return -1; + } + memset(prikey, 0, sizeof(prikey)); + return 1; +} + +int secp256r1_private_key_info_from_der(SECP256R1_KEY *key, const uint8_t **attrs, size_t *attrslen, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + int version; + int algor; + int algor_param; + const uint8_t *prikey; + size_t prikey_len; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&version, &d, &dlen) != 1 + || x509_public_key_algor_from_der(&algor, &algor_param, &d, &dlen) != 1 + || asn1_octet_string_from_der(&prikey, &prikey_len, &d, &dlen) != 1 + || asn1_implicit_set_from_der(0, attrs, attrslen, &d, &dlen) < 0 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + if (asn1_check(version == PKCS8_private_key_info_version) != 1 + || asn1_check(algor == OID_ec_public_key) != 1 + || asn1_check(algor_param == OID_secp256r1) != 1 + || secp256r1_private_key_from_der(key, &prikey, &prikey_len) != 1 + || asn1_length_is_zero(prikey_len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp256r1_private_key_info_encrypt_to_der(const SECP256R1_KEY *ec_key, const char *pass, + uint8_t **out, size_t *outlen) +{ + int ret = -1; + uint8_t pkey_info[512]; + uint8_t *p = pkey_info; + size_t pkey_info_len = 0; + uint8_t salt[16]; + int iter = 65536; + uint8_t iv[16]; + uint8_t key[16]; + SM4_KEY sm4_key; + uint8_t enced_pkey_info[sizeof(pkey_info) + 32]; + size_t enced_pkey_info_len; + + if (!ec_key || !pass || !outlen) { + error_print(); + return -1; + } + if (secp256r1_private_key_info_to_der(ec_key, &p, &pkey_info_len) != 1 + || rand_bytes(salt, sizeof(salt)) != 1 + || rand_bytes(iv, sizeof(iv)) != 1 + || sm3_pbkdf2(pass, strlen(pass), salt, sizeof(salt), iter, sizeof(key), key) != 1) { + error_print(); + goto end; + } + /* + if (pkey_info_len != sizeof(pkey_info)) { + error_print(); + goto end; + } + */ + sm4_set_encrypt_key(&sm4_key, key); + if (sm4_cbc_padding_encrypt( + &sm4_key, iv, pkey_info, pkey_info_len, + enced_pkey_info, &enced_pkey_info_len) != 1 + || pkcs8_enced_private_key_info_to_der( + salt, sizeof(salt), iter, sizeof(key), OID_hmac_sm3, + OID_sm4_cbc, iv, sizeof(iv), + enced_pkey_info, enced_pkey_info_len, out, outlen) != 1) { + error_print(); + goto end; + } + + ret = 1; +end: + gmssl_secure_clear(pkey_info, sizeof(pkey_info)); + gmssl_secure_clear(key, sizeof(key)); + gmssl_secure_clear(&sm4_key, sizeof(sm4_key)); + return ret; +} + +int secp256r1_private_key_info_decrypt_from_der(SECP256R1_KEY *ec_key, + const uint8_t **attrs, size_t *attrs_len, + const char *pass, const uint8_t **in, size_t *inlen) +{ + int ret = -1; + const uint8_t *salt; + size_t saltlen; + int iter; + int keylen; + int prf; + int cipher; + const uint8_t *iv; + size_t ivlen; + uint8_t key[16]; + SM4_KEY sm4_key; + const uint8_t *enced_pkey_info; + size_t enced_pkey_info_len; + uint8_t pkey_info[256]; + const uint8_t *cp = pkey_info; + size_t pkey_info_len; + + if (!ec_key || !attrs || !attrs_len || !pass || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (pkcs8_enced_private_key_info_from_der(&salt, &saltlen, &iter, &keylen, &prf, + &cipher, &iv, &ivlen, &enced_pkey_info, &enced_pkey_info_len, in, inlen) != 1 + || asn1_check(keylen == -1 || keylen == 16) != 1 + || asn1_check(prf == - 1 || prf == OID_hmac_sm3) != 1 + || asn1_check(cipher == OID_sm4_cbc) != 1 + || asn1_check(ivlen == 16) != 1 + || asn1_length_le(enced_pkey_info_len, sizeof(pkey_info)) != 1) { + error_print(); + return -1; + } + if (sm3_pbkdf2(pass, strlen(pass), salt, saltlen, iter, sizeof(key), key) != 1) { + error_print(); + goto end; + } + sm4_set_decrypt_key(&sm4_key, key); + if (sm4_cbc_padding_decrypt(&sm4_key, iv, enced_pkey_info, enced_pkey_info_len, + pkey_info, &pkey_info_len) != 1 + || secp256r1_private_key_info_from_der(ec_key, attrs, attrs_len, &cp, &pkey_info_len) != 1 + || asn1_length_is_zero(pkey_info_len) != 1) { + error_print(); + goto end; + } + ret = 1; +end: + gmssl_secure_clear(&sm4_key, sizeof(sm4_key)); + gmssl_secure_clear(key, sizeof(key)); + gmssl_secure_clear(pkey_info, sizeof(pkey_info)); + return ret; +} + + + + + + diff --git a/src/tls12.c b/src/tls12.c index aac2f480..decc82b0 100644 --- a/src/tls12.c +++ b/src/tls12.c @@ -1,4 +1,4 @@ -/* +/* * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may diff --git a/src/tls12_handshake.c b/src/tls12_handshake.c new file mode 100644 index 00000000..5a6a6d1f --- /dev/null +++ b/src/tls12_handshake.c @@ -0,0 +1,309 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +enum { + TLS_state_client_hello, + TLS_state_server_hello, + TLS_state_server_certificate, + TLS_state_server_key_exchange, + TLS_state_server_certificate_request, + TLS_state_server_hello_done, + TLS_state_client_certificate, + TLS_state_client_key_exchange, + TLS_state_client_certificate_verify, + TLS_state_client_change_cipher_spec, + TLS_state_client_finished, + TLS_state_server_change_cipher_spec, + TLS_state_server_finished, +}; + +static const int tls12_ciphers[] = { + TLS_cipher_ecdhe_sm4_cbc_sm3, +}; + +int tls_send_client_hello(TLS_CONNECT *conn) +{ + const int ec_point_formats[] = { TLS_point_uncompressed }; + size_t ec_point_formats_cnt = sizeof(ec_point_formats)/sizeof(ec_point_formats[0]); + const int supported_groups[] = { TLS_curve_sm2p256v1 }; + size_t supported_groups_cnt = sizeof(supported_groups)/sizeof(supported_groups[0]); + const int signature_algors[] = { TLS_sig_sm2sig_sm3 }; + size_t signature_algors_cnt = sizeof(signature_algors)/sizeof(signature_algors[0]); + + uint8_t *record; + size_t recordlen; + uint8_t client_random[32]; + uint8_t client_exts[TLS_MAX_EXTENSIONS_SIZE]; + size_t client_exts_len; + uint8_t *p; + + record = conn->record; + + tls_record_set_protocol(record, TLS_protocol_tls1); + + sm3_init(&conn->sm3_ctx); + if (conn->client_certs_len) + sm2_sign_init(&conn->sign_ctx, &conn->sign_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH); + + + tls_random_generate(client_random); + + p = client_exts; + client_exts_len = 0; + tls_ec_point_formats_ext_to_bytes(ec_point_formats, ec_point_formats_cnt, &p, &client_exts_len); + tls_supported_groups_ext_to_bytes(supported_groups, supported_groups_cnt, &p, &client_exts_len); + tls_signature_algorithms_ext_to_bytes(signature_algors, signature_algors_cnt, &p, &client_exts_len); + + if (tls_record_set_handshake_client_hello(conn->record, &recordlen, + conn->protocol, client_random, NULL, 0, + tls12_ciphers, sizeof(tls12_ciphers)/sizeof(tls12_ciphers[0]), + client_exts, client_exts_len) != 1) { + error_print(); + return -1; + } + tls_trace("send ClientHello\n"); + tls12_record_trace(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&conn->sm3_ctx, record + 5, recordlen - 5); + if (conn->client_certs_len) { + sm2_sign_update(&conn->sign_ctx, record + 5, recordlen - 5); + } + + return 1; +} + +int tls_recv_server_hello(TLS_CONNECT *conn) +{ + uint8_t *record = conn->record; + size_t recordlen; + + tls_trace("recv ServerHello\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + tls_send_alert(conn, TLS_alert_unexpected_message); + return -1; + } + tls12_record_trace(stderr, record, recordlen, 0, 0); + if (tls_record_protocol(record) != conn->protocol) { + error_print(); + tls_send_alert(conn, TLS_alert_protocol_version); + return -1; + } + + // 这些值要放在哪儿呢?是否放在CONNECT中 + int protocol; + int cipher_suite; + uint8_t server_random[32]; + const uint8_t *random; + const uint8_t *session_id; + size_t session_id_len; + const uint8_t *server_exts; + size_t server_exts_len; + + // 扩展的协商结果,-1 表示服务器不支持该扩展(未给出响应) + int ec_point_format = -1; + int supported_group = -1; + int signature_algor = -1; + + if (tls_record_get_handshake_server_hello(record, + &protocol, &random, &session_id, &session_id_len, &cipher_suite, + &server_exts, &server_exts_len) != 1) { + error_print(); + tls_send_alert(conn, TLS_alert_unexpected_message); + return -1; + } + if (protocol != conn->protocol) { + error_print(); + tls_send_alert(conn, TLS_alert_protocol_version); + return -1; + } + // tls12_ciphers 应该改为conn的内部变量 + if (tls_cipher_suite_in_list(cipher_suite, tls12_ciphers, sizeof(tls12_ciphers)/sizeof(tls12_ciphers[0])) != 1) { + error_print(); + tls_send_alert(conn, TLS_alert_handshake_failure); + return -1; + } + if (!server_exts) { + error_print(); + tls_send_alert(conn, TLS_alert_unexpected_message); + return -1; + } + if (tls_process_server_hello_exts(server_exts, server_exts_len, &ec_point_format, &supported_group, &signature_algor) != 1 + || ec_point_format < 0 + || supported_group < 0 + || signature_algor < 0) { + error_print(); + tls_send_alert(conn, TLS_alert_unexpected_message); + return -1; + } + + memcpy(server_random, random, 32); + memcpy(conn->session_id, session_id, session_id_len); + conn->cipher_suite = cipher_suite; + sm3_update(&conn->sm3_ctx, record + 5, recordlen - 5); + if (conn->client_certs_len) { + sm2_sign_update(&conn->sign_ctx, record + 5, recordlen - 5); + } + + return 1; +} + +int tls_recv_server_certificate(TLS_CONNECT *conn) +{ + const int depth = 5; + uint8_t *record = conn->record; + size_t recordlen; + int verify_result; + + // recv ServerCertificate + tls_trace("recv ServerCertificate\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_protocol(record) != conn->protocol) { + error_print(); + tls_send_alert(conn, TLS_alert_unexpected_message); + return -1; + } + tls12_record_trace(stderr, record, recordlen, 0, 0); + + if (tls_record_get_handshake_certificate(record, + conn->server_certs, &conn->server_certs_len) != 1) { + error_print(); + tls_send_alert(conn, TLS_alert_unexpected_message); + return -1; + } + sm3_update(&conn->sm3_ctx, record + 5, recordlen - 5); + if (conn->client_certs_len) + sm2_sign_update(&conn->sign_ctx, record + 5, recordlen - 5); + + // verify ServerCertificate + if (x509_certs_verify(conn->server_certs, conn->server_certs_len, X509_cert_chain_server, + conn->ca_certs, conn->ca_certs_len, depth, &verify_result) != 1) { + error_print(); + tls_send_alert(conn, TLS_alert_bad_certificate); + return -1; + } + + return 1; +} + +int tls_recv_server_key_exchange(TLS_CONNECT *conn) +{ + return 1; +} + +int tls_recv_server_certificate_request(TLS_CONNECT *conn) +{ + return 1; +} + +int tls_recv_server_hello_done(TLS_CONNECT *conn) +{ + return 1; +} + +int tls_send_client_certificate(TLS_CONNECT *conn) +{ + return 1; +} + +int tls_send_client_key_exchange(TLS_CONNECT *conn) +{ + return 1; +} + +int tls_send_certificate_verify(TLS_CONNECT *conn) +{ + return 1; +} + +int tls_send_client_finished(TLS_CONNECT *conn) +{ + return 1; +} + +int tls_recv_server_change_cipher_spec(TLS_CONNECT *conn) +{ + return 1; +} + +int tls_recv_server_finished(TLS_CONNECT *conn) +{ + return 1; +} + + +int tls12_client_handshake(TLS_CONNECT *conn) +{ + int ret; + + switch (conn->state) { + case TLS_state_client_hello: + ret = tls_send_client_hello(conn); + break; + case TLS_state_server_hello: + ret = tls_recv_server_hello(conn); + break; + case TLS_state_server_certificate: + ret = tls_recv_server_certificate(conn); + break; + case TLS_state_server_key_exchange: + ret = tls_recv_server_key_exchange(conn); + break; + case TLS_state_server_certificate_request: + ret = tls_recv_server_certificate_request(conn); + break; + case TLS_state_server_hello_done: + ret = tls_recv_server_hello_done(conn); + break; + case TLS_state_client_certificate: + ret = tls_send_client_certificate(conn); + break; + case TLS_state_client_key_exchange: + ret = tls_send_client_key_exchange(conn); + break; + case TLS_state_client_certificate_verify: + ret = tls_send_certificate_verify(conn); + case TLS_state_client_change_cipher_spec: + break; + case TLS_state_client_finished: + ret = tls_send_client_finished(conn); + break; + case TLS_state_server_change_cipher_spec: + ret = tls_recv_server_change_cipher_spec(conn); + break; + case TLS_state_server_finished: + ret = tls_recv_server_finished(conn); + break; + default: + error_print(); + return -1; + } + return 1; +} + + diff --git a/src/x509_key.c b/src/x509_key.c index 58ca39c9..5fa33c30 100644 --- a/src/x509_key.c +++ b/src/x509_key.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -79,13 +78,16 @@ int x509_key_generate(X509_KEY *key, int algor, int algor_param) switch (algor) { case OID_ec_public_key: - if (algor_param != OID_sm2) { - error_print(); - return -1; - } - if (sm2_key_generate(&key->u.sm2_key) != 1) { - error_print(); - return -1; + if (algor_param == OID_sm2) { + if (sm2_key_generate(&key->u.sm2_key) != 1) { + error_print(); + return -1; + } + } else if (algor_param == OID_secp256r1) { + if (secp256r1_key_generate(&key->u.secp256r1_key) != 1) { + error_print(); + return -1; + } } break; case OID_lms_hashsig: @@ -156,7 +158,17 @@ int x509_public_key_print(FILE *fp, int fmt, int ind, const char *label, const X { switch (key->algor) { case OID_ec_public_key: - if (sm2_public_key_print(fp, fmt, ind, label, &key->u.sm2_key) != 1) { + if (key->algor_param == OID_sm2) { + if (sm2_public_key_print(fp, fmt, ind, label, &key->u.sm2_key) != 1) { + error_print(); + return -1; + } + } else if (key->algor_param == OID_secp256r1) { + if (secp256r1_public_key_print(fp, fmt, ind, label, &key->u.secp256r1_key) != 1) { + error_print(); + return -1; + } + } else { error_print(); return -1; } @@ -208,6 +220,15 @@ int x509_key_set_sm2_key(X509_KEY *x509_key, const SM2_KEY *sm2_key) return 1; } +int x509_key_set_secp256r1_key(X509_KEY *x509_key, const SECP256R1_KEY *secp256r1_key) +{ + memset(x509_key, 0, sizeof(X509_KEY)); + x509_key->algor = OID_ec_public_key; + x509_key->algor_param = OID_secp256r1; + x509_key->u.secp256r1_key = *secp256r1_key; + return 1; +} + int x509_key_set_lms_key(X509_KEY *x509_key, const LMS_KEY *lms_key) { memset(x509_key, 0, sizeof(X509_KEY)); @@ -288,11 +309,21 @@ int x509_public_key_digest(const X509_KEY *key, uint8_t dgst[32]) switch (key->algor) { case OID_ec_public_key: - if (sm2_z256_point_to_uncompressed_octets(&key->u.sm2_key.public_key, bits) != 1) { + if (key->algor_param == OID_sm2) { + if (sm2_z256_point_to_uncompressed_octets(&key->u.sm2_key.public_key, bits) != 1) { + error_print(); + return -1; + } + len = 65; + } else if (key->algor_param == OID_secp256r1) { + if (secp256r1_public_key_to_bytes(&key->u.secp256r1_key, &p, &len) != 1) { + error_print(); + return -1; + } + } else { error_print(); return -1; } - len = 65; break; case OID_hss_lms_hashsig: if (hss_public_key_to_bytes(&key->u.hss_key, &p, &len) != 1) { @@ -340,7 +371,17 @@ int x509_public_key_equ(const X509_KEY *key, const X509_KEY *pub) } switch (key->algor) { case OID_ec_public_key: - if (sm2_public_key_equ(&key->u.sm2_key, &pub->u.sm2_key) != 1) { + if (key->algor_param == OID_sm2) { + if (sm2_public_key_equ(&key->u.sm2_key, &pub->u.sm2_key) != 1) { + error_print(); + return -1; + } + } else if (key->algor_param == OID_secp256r1) { + if (secp256r1_public_key_equ(&key->u.secp256r1_key, &pub->u.secp256r1_key) != 1) { + error_print(); + return -1; + } + } else { error_print(); return -1; } @@ -456,11 +497,22 @@ int x509_sign_init(X509_SIGN_CTX *ctx, X509_KEY *key, const char *signer_id, siz ctx->sign_algor = key->algor; break; case OID_ec_public_key: - if (sm2_sign_init(&ctx->u.sm2_sign_ctx, &key->u.sm2_key, signer_id, signer_idlen) != 1) { + if (key->algor_param == OID_sm2) { + if (sm2_sign_init(&ctx->u.sm2_sign_ctx, &key->u.sm2_key, signer_id, signer_idlen) != 1) { + error_print(); + return -1; + } + ctx->sign_algor = OID_sm2sign_with_sm3; + } else if (key->algor_param == OID_secp256r1) { + if (ecdsa_sign_init(&ctx->u.ecdsa_sign_ctx, &key->u.secp256r1_key) != 1) { + error_print(); + return -1; + } + ctx->sign_algor = OID_ecdsa_with_sha256; + } else { error_print(); return -1; } - ctx->sign_algor = OID_sm2sign_with_sm3; break; default: error_print(); @@ -497,6 +549,12 @@ int x509_sign_update(X509_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) return -1; } break; + case OID_ecdsa_with_sha256: + if (ecdsa_sign_update(&ctx->u.ecdsa_sign_ctx, data, datalen) != 1) { + error_print(); + return -1; + } + break; default: error_print(); return -1; @@ -536,6 +594,13 @@ int x509_sign_finish(X509_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen) return -1; } break; + case OID_ecdsa_with_sha256: + *siglen = ECDSA_SIGNATURE_TYPICAL_SIZE; + if (ecdsa_sign_finish_fixlen(&ctx->u.ecdsa_sign_ctx, *siglen, sig) != 1) { + error_print(); + return -1; + } + break; default: error_print(); return -1; @@ -574,17 +639,28 @@ int x509_verify_init(X509_SIGN_CTX *ctx, const X509_KEY *key, const char *signer ctx->sign_algor = key->algor; break; case OID_ec_public_key: - if (sm2_verify_init(&ctx->u.sm2_verify_ctx, &key->u.sm2_key, signer_id, signer_idlen) != 1) { + if (key->algor_param == OID_sm2) { + if (sm2_verify_init(&ctx->u.sm2_verify_ctx, &key->u.sm2_key, signer_id, signer_idlen) != 1) { + error_print(); + return -1; + } + ctx->sign_algor = OID_sm2sign_with_sm3; + if (siglen > sizeof(ctx->sig)) { + error_print(); + return -1; + } + memcpy(ctx->sig, sig, siglen); + ctx->siglen = siglen; + } else if (key->algor_param == OID_secp256r1) { + if (ecdsa_verify_init(&ctx->u.ecdsa_sign_ctx, &key->u.secp256r1_key, sig, siglen) != 1) { + error_print(); + return -1; + } + ctx->sign_algor = OID_ecdsa_with_sha256; + } else { error_print(); return -1; } - ctx->sign_algor = OID_sm2sign_with_sm3; - if (siglen > sizeof(ctx->sig)) { - error_print(); - return -1; - } - memcpy(ctx->sig, sig, siglen); - ctx->siglen = siglen; break; default: error_print(); @@ -620,6 +696,12 @@ int x509_verify_update(X509_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) return -1; } break; + case OID_ecdsa_with_sha256: + if (ecdsa_verify_update(&ctx->u.ecdsa_sign_ctx, data, datalen) != 1) { + error_print(); + return -1; + } + break; default: error_print(); return -1; @@ -652,7 +734,13 @@ int x509_verify_finish(X509_SIGN_CTX *ctx) } break; case OID_sm2sign_with_sm3: - if ((ret = sm2_verify_update(&ctx->u.sm2_verify_ctx, ctx->sig, ctx->siglen)) < 0) { + if ((ret = sm2_verify_finish(&ctx->u.sm2_verify_ctx, ctx->sig, ctx->siglen)) < 0) { + error_print(); + return -1; + } + break; + case OID_ecdsa_with_sha256: + if ((ret = ecdsa_verify_finish(&ctx->u.ecdsa_sign_ctx)) < 0) { error_print(); return -1; } @@ -698,8 +786,15 @@ int x509_public_key_info_to_der(const X509_KEY *x509_key, uint8_t **out, size_t } break; case OID_ec_public_key: - sm2_z256_point_to_uncompressed_octets(&x509_key->u.sm2_key.public_key, p); - keylen = 65; + if (x509_key->algor_param == OID_sm2) { + sm2_z256_point_to_uncompressed_octets(&x509_key->u.sm2_key.public_key, p); + keylen = 65; + } else if (x509_key->algor_param == OID_secp256r1) { + if (secp256r1_public_key_to_bytes(&x509_key->u.secp256r1_key, &p, &keylen) != 1) { + error_print(); + return -1; + } + } break; default: error_print(); @@ -758,15 +853,25 @@ int x509_public_key_info_from_der(X509_KEY *x509_key, const uint8_t **in, size_t switch (algor) { case OID_ec_public_key: - if (algor_param != OID_sm2) { + if (publen != 65) { error_print(); return -1; } - if (sm2_z256_point_from_octets(&x509_key->u.sm2_key.public_key, pub, publen) != 1) { + if (algor_param == OID_sm2) { + if (sm2_z256_point_from_octets(&x509_key->u.sm2_key.public_key, pub, publen) != 1) { + error_print(); + return -1; + } + publen = 0; + } else if (algor_param == OID_secp256r1) { + if (secp256r1_public_key_from_bytes(&x509_key->u.secp256r1_key, &pub, &publen) != 1) { + error_print(); + return -1; + } + } else { error_print(); return -1; } - publen = 0; break; case OID_hss_lms_hashsig: if (hss_public_key_from_bytes(&x509_key->u.hss_key, &pub, &publen) != 1) { @@ -806,6 +911,7 @@ int x509_public_key_info_from_der(X509_KEY *x509_key, const uint8_t **in, size_t return 1; } +// FIXME: this function can not parse depends on algor_param int x509_private_key_from_file(X509_KEY *key, int algor, const char *pass, FILE *fp) { if (!key || !fp) { @@ -821,6 +927,7 @@ int x509_private_key_from_file(X509_KEY *key, int algor, const char *pass, FILE error_print(); return -1; } + // FIXME: secp256r1 if (sm2_private_key_info_decrypt_from_pem(&key->u.sm2_key, pass, fp) != 1) { error_print(); return -1; @@ -901,8 +1008,12 @@ void x509_key_cleanup(X509_KEY *key) if (key) { switch (key->algor) { case OID_ec_public_key: - //sm2_key_cleanup(&key->u.sm2_key); - gmssl_secure_clear(&key->u.sm2_key, sizeof(SM2_KEY)); + if (key->algor_param == OID_sm2) { + //sm2_key_cleanup(&key->u.sm2_key); + gmssl_secure_clear(&key->u.sm2_key, sizeof(SM2_KEY)); + } else if (key->algor_param == OID_secp256r1) { + secp256r1_key_cleanup(&key->u.secp256r1_key); + } break; case OID_lms_hashsig: lms_key_cleanup(&key->u.lms_key); diff --git a/tests/bntest.c b/tests/bntest.c new file mode 100644 index 00000000..a57be233 --- /dev/null +++ b/tests/bntest.c @@ -0,0 +1,128 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + + +static int test_print_consts(void) +{ + // secp256r1 parameters + char *p = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"; + char *b = "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"; + char *x = "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"; + char *y = "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"; + char *n = "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"; + char *u_p = "0000000100000000fffffffffffffffefffffffefffffffeffffffff0000000000000003"; // floor(2^512/p) + char *u_n = "0000000100000000fffffffffffffffeffffffff43190552df1a6c21012ffd85eedf9bfe"; // floor(2^512/n) + + int k = 8; + uint32_t bn[9]; + uint8_t buf[36]; + size_t len; + + hex_to_bytes(p, 64, buf, &len); + bn_from_bytes(bn, k, buf); + bn_print(stderr, 0, 4, "p", bn, k); + + hex_to_bytes(b, 64, buf, &len); + bn_from_bytes(bn, k, buf); + bn_print(stderr, 0, 4, "a", bn, k); + + hex_to_bytes(x, 64, buf, &len); + bn_from_bytes(bn, k, buf); + bn_print(stderr, 0, 4, "x", bn, k); + + hex_to_bytes(y, 64, buf, &len); + bn_from_bytes(bn, k, buf); + bn_print(stderr, 0, 4, "y", bn, k); + + hex_to_bytes(n, 64, buf, &len); + bn_from_bytes(bn, k, buf); + bn_print(stderr, 0, 4, "n", bn, k); + + hex_to_bytes(u_p, 72, buf, &len); + bn_from_bytes(bn, k + 1, buf); + bn_print(stderr, 0, 4, "u_p = 2^512//p", bn, k + 1); + + hex_to_bytes(u_n, 72, buf, &len); + bn_from_bytes(bn, k + 1, buf); + bn_print(stderr, 0, 4, "u_n = 2^512//n", bn, k + 1); + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp256r1(void) +{ + char *x_hex = "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"; + char *p_hex = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"; + + int c; + + uint32_t a[8]; + uint32_t r[8]; + uint8_t buf[32]; + size_t len; + + hex_to_bytes(x_hex, 64, buf, &len); + + bn_from_bytes(a, 8, buf); + + + + + + bn_add(r, a, a, 8); + bn_add(r, r, a, 8); + + bn_print(stderr, 0, 4, "3*x", a, 8); + + uint32_t p[8]; + + hex_to_bytes(p_hex, 64, buf, &len); + bn_from_bytes(p, 8, buf); + + + c = bn_sub(r, a, p, 8); + printf("carray = %d\n", c); + + + // 我知道了,这里有一个进位被忽略了 + if (bn_cmp(a, p, 8) >= 0) { + error_print(); + } else { + error_print(); + } + + + + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +int main(void) +{ + if (test_print_consts() != 1) goto err; + if (test_secp256r1() != 1) goto err; + + printf("%s all tests passed\n", __FILE__); + return 0; +err: + error_print(); + return 1; +} diff --git a/tests/ecdsatest.c b/tests/ecdsatest.c new file mode 100644 index 00000000..0d46e726 --- /dev/null +++ b/tests/ecdsatest.c @@ -0,0 +1,92 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* +d 0x5 +xP 0x51590b7a515140d2d784c85608668fdfef8c82fd1f5be52421554a0dc3d033ed +yP 0xe0c17da8904a727d8ae1bf36bf8a79260d012f00d4d80888d1d0bb44fda16da4 +x1 0x5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c +r 0x5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c +s 0x48a928086a55111cf99d39f886293cff41a8dda957c43b0851846697f76199ef +x1 0x5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c +v 0x5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c +*/ + +// 这个签名是没有问题的,看来验证签名是有问题的 +static int test_ecdsa(void) +{ + SECP256R1_KEY key; + ECDSA_SIGNATURE sig; + uint8_t dgst[32]; + secp256r1_t d; + secp256r1_t k; + + // d = 5 + bn_set_word(d, 5, 8); + secp256r1_key_set_private_key(&key, d); + + secp256r1_key_generate(&key); + + secp256r1_private_key_print(stderr, 0, 0, "private_key", &key); + + // k = 3 + bn_set_word(k, 3, 8); + + // e = 2 + memset(dgst, 0, 31); + dgst[31] = 2; + + /* + if (ecdsa_do_sign_ex(&key, k, dgst, &sig) != 1) { + error_print(); + return -1; + } + */ + + if (ecdsa_do_sign(&key, dgst, &sig) != 1) { + error_print(); + return -1; + } + + + + secp256r1_print(stderr, 0, 0, "r", sig.r); + secp256r1_print(stderr, 0, 0, "s", sig.s); + + + if (ecdsa_do_verify(&key, dgst, &sig) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +int main(void) +{ + if (test_ecdsa() != 1) goto err; + + printf("%s all tests passed\n", __FILE__); + return 0; +err: + error_print(); + return 1; +} diff --git a/tests/secp256r1_keytest.c b/tests/secp256r1_keytest.c new file mode 100644 index 00000000..081c47a1 --- /dev/null +++ b/tests/secp256r1_keytest.c @@ -0,0 +1,292 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + + +static int test_secp256r1_key_generate(void) +{ + SECP256R1_KEY key; + + if (secp256r1_key_generate(&key) != 1) { + error_print(); + return -1; + } + secp256r1_public_key_print(stderr, 0, 4, "public_key", &key); + secp256r1_private_key_print(stderr, 0, 4, "private_key", &key); + secp256r1_key_cleanup(&key); + secp256r1_private_key_print(stderr, 0, 4, "private_key", &key); + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp256r1_key_set_private_key(void) +{ + SECP256R1_KEY key; + secp256r1_t private_key; + uint8_t bytes[32]; + size_t len; + + // key = 1 + memset(bytes, 0, sizeof(bytes)); + bytes[31] = 1; + secp256r1_from_32bytes(private_key, bytes); + if (secp256r1_key_set_private_key(&key, private_key) != 1) { + error_print(); + return -1; + } + secp256r1_private_key_print(stderr, 0, 4, "private_key = 1", &key); + + + // key = n-1 + hex_to_bytes("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550", 64, bytes, &len); + secp256r1_from_32bytes(private_key, bytes); + if (secp256r1_key_set_private_key(&key, private_key) != 1) { + error_print(); + return -1; + } + + + // key = 0, should fail + memset(bytes, 0, sizeof(bytes)); + secp256r1_from_32bytes(private_key, bytes); + if (secp256r1_key_set_private_key(&key, private_key) >= 0) { + error_print(); + return -1; + } + + // key = n, should fail + hex_to_bytes("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 64, bytes, &len); + secp256r1_from_32bytes(private_key, bytes); + if (secp256r1_key_set_private_key(&key, private_key) >= 0) { + error_print(); + return -1; + } + + // key = 0xff..f, should fail + memset(bytes, 0xff, sizeof(bytes)); + secp256r1_from_32bytes(private_key, bytes); + if (secp256r1_key_set_private_key(&key, private_key) >= 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp256r1_public_key_to_bytes(void) +{ + SECP256R1_KEY key; + SECP256R1_KEY key1; + uint8_t bytes[512]; + uint8_t *p = bytes; + const uint8_t *cp = bytes; + size_t len = 0; + + if (secp256r1_key_generate(&key) != 1) { + error_print(); + return -1; + } + if (secp256r1_public_key_to_bytes(&key, &p, &len) != 1) { + error_print(); + return -1; + } + if (secp256r1_public_key_from_bytes(&key1, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + if (secp256r1_public_key_equ(&key, &key1) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp256r1_public_key_to_der(void) +{ + SECP256R1_KEY key; + SECP256R1_KEY key1; + uint8_t bytes[512]; + uint8_t *p = bytes; + const uint8_t *cp = bytes; + size_t len = 0; + + if (secp256r1_key_generate(&key) != 1) { + error_print(); + return -1; + } + if (secp256r1_public_key_to_der(&key, &p, &len) != 1) { + error_print(); + return -1; + } + if (secp256r1_public_key_from_der(&key1, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + if (secp256r1_public_key_equ(&key, &key1) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp256r1_private_key_to_der(void) +{ + SECP256R1_KEY key; + SECP256R1_KEY key1; + uint8_t bytes[512]; + uint8_t *p = bytes; + const uint8_t *cp = bytes; + size_t len = 0; + + if (secp256r1_key_generate(&key) != 1) { + error_print(); + return -1; + } + if (secp256r1_private_key_to_der(&key, &p, &len) != 1) { + error_print(); + return -1; + } + if (secp256r1_private_key_from_der(&key1, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + if (secp256r1_public_key_equ(&key, &key1) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp256r1_private_key_info_to_der(void) +{ + SECP256R1_KEY key; + SECP256R1_KEY key1; + uint8_t bytes[512]; + uint8_t *p = bytes; + const uint8_t *cp = bytes; + size_t len = 0; + const uint8_t *attrs; + size_t attrslen; + + if (secp256r1_key_generate(&key) != 1) { + error_print(); + return -1; + } + if (secp256r1_private_key_info_to_der(&key, &p, &len) != 1) { + error_print(); + return -1; + } + if (secp256r1_private_key_info_from_der(&key1, &attrs, &attrslen, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + if (secp256r1_public_key_equ(&key, &key1) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp256r1_private_key_info_encrypt_to_der(void) +{ + SECP256R1_KEY key; + SECP256R1_KEY key1; + uint8_t bytes[512]; + uint8_t *p = bytes; + const uint8_t *cp = bytes; + size_t len = 0; + char *pass = "password"; + const uint8_t *attrs; + size_t attrslen; + + if (secp256r1_key_generate(&key) != 1) { + error_print(); + return -1; + } + if (secp256r1_private_key_info_encrypt_to_der(&key, pass, &p, &len) != 1) { + error_print(); + return -1; + } + if (secp256r1_private_key_info_decrypt_from_der(&key1, &attrs, &attrslen, pass, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + if (secp256r1_public_key_equ(&key, &key1) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + + + + + + + + +int main(void) +{ + if (test_secp256r1_key_generate() != 1) goto err; +// if (test_secp256r1_key_set_private_key() != 1) goto err; + if (test_secp256r1_public_key_to_bytes() != 1) goto err; + if (test_secp256r1_public_key_to_der() != 1) goto err; + if (test_secp256r1_private_key_to_der() != 1) goto err; + if (test_secp256r1_private_key_info_to_der() != 1) goto err; + if (test_secp256r1_private_key_info_encrypt_to_der() != 1) goto err; + + printf("%s all tests passed\n", __FILE__); + return 0; +err: + error_print(); + return 1; +} + diff --git a/tests/secp256r1test.c b/tests/secp256r1test.c new file mode 100644 index 00000000..76d7202f --- /dev/null +++ b/tests/secp256r1test.c @@ -0,0 +1,481 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + + +static const char *secp256r1_p = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"; +static const char *secp256r1_b = "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"; +static const char *secp256r1_x = "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"; +static const char *secp256r1_y = "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"; +static const char *secp256r1_n = "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"; + +static int test_secp256r1(void) +{ + secp256r1_t a; + secp256r1_t b; + secp256r1_t r; + uint8_t buf[32]; + + secp256r1_set_zero(a); + if (!secp256r1_is_zero(a)) { + error_print(); + return -1; + } + secp256r1_to_32bytes(a, buf); + format_bytes(stderr, 0, 4, "0", buf, sizeof(buf)); + + secp256r1_set_one(b); + if (!secp256r1_is_one(b)) { + error_print(); + return -1; + } + secp256r1_to_32bytes(b, buf); + format_bytes(stderr, 0, 4, "1", buf, sizeof(buf)); + + if (secp256r1_cmp(a, b) >= 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + +// 这个测试是有问题的,mod_add很多情况下是引发进位和借位的! +static int test_secp256r1_modp(void) +{ + secp256r1_t x; + secp256r1_t y; + secp256r1_t r; + secp256r1_t v; + uint8_t buf[32]; + size_t len; + + hex_to_bytes("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 64, buf, &len); + secp256r1_from_32bytes(x, buf); + + hex_to_bytes("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 64, buf, &len); + secp256r1_from_32bytes(y, buf); + + secp256r1_modp_add(r, x, y); + hex_to_bytes("bafb14d5df46c1e387a4d22fdfb3df08a2d1b0d8991c926fc05779ae1058148b", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modp_dbl(r, x); + hex_to_bytes("d62fa3e5c258848ff179cdcac74881e4ee06fb025bd66741e942728bb131852c", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modp_tri(r, x); + hex_to_bytes("414775d9a384c6d6ea36b4b02aecc2d7650a788289c19ae2dde3abd189ca47c3", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modp_sub(r, x, y); + hex_to_bytes("1b348f0fe311c2ac69d4fb9ae794a2dc4b354a29c2b9d4d228eaf8dda0d970a1", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + + error_print(); + return -1; + } + + secp256r1_modp_sub(r, y, x); + hex_to_bytes("e4cb70ef1cee3d54962b0465186b5d23b4cab5d73d462b2dd71507225f268f5e", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modp_neg(r, x); + hex_to_bytes("94e82e0c1ed3bdb90743191a9c5bbf0d88fc827fd214cc5f0b5ec6ba27673d69", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modp_mul(r, x, y); + hex_to_bytes("823cd15f6dd3c71933565064513a6b2bd183e554c6a08622f713ebbbface98be", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modp_sqr(r, x); + hex_to_bytes("98f6b84d29bef2b281819a5e0e3690d833b699495d694dd1002ae56c426b3f8c", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modp_exp(r, x, y); + hex_to_bytes("2f3db69bc9d93323c351f3e768d332806ad3a7652ea632e89e23312f7b5f9f96", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modp_inv(r, x); + hex_to_bytes("e060cbb088706d5d24936933b69b16ab707d656273744b65664c49e577f35238", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modp_inv(r, y); + hex_to_bytes("fa27a3da2c00618a828f8cd65c1a919effc67bf68b4dbb05bbdaa775c45d4034", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + +static int test_secp256r1_modn(void) +{ + secp256r1_t x; + secp256r1_t y; + secp256r1_t r; + secp256r1_t v; + uint8_t buf[32]; + size_t len; + + hex_to_bytes("d62fa3e5c258848ff179cdcac74881e4ee06fb025bd66741e942728bb131852c", 64, buf, &len); + secp256r1_from_32bytes(x, buf); + + hex_to_bytes("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 64, buf, &len); + secp256r1_from_32bytes(y, buf); + + secp256r1_modn_add(r, x, y); + hex_to_bytes("2612e6c9c073042a8061b91543581ffb5cee33ac1ff0278bc13ee830ec8db1d0", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modn_dbl(r, x); + hex_to_bytes("ac5f47cc84b1091ee2f39b958e9103ca1f26fb5710952ffedecb1a5465ffe507", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modn_tri(r, x); + hex_to_bytes("828eebb347098dadd46d696055d985af5046fbabc553f8bbd453c21d1ace44e2", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modn_sub(r, x, y); + hex_to_bytes("864c6102c43e04f46291e2804b38e3cec238c7aaf0a508731d8c322379723337", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modn_sub(r, y, x); + hex_to_bytes("79b39efc3bc1fb0c9d6e1d7fb4c71c30faae3302b6729611d62d989f82f0f21a", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modn_neg(r, x); + hex_to_bytes("29d05c193da77b710e86323538b77e1acedfffab4b4137430a7758374b31a025", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modn_mul(r, x, y); + hex_to_bytes("2a876a4e5df28cd6c2f3951aa6b65c55e2d6eb1883b463aee5d95035999c9a30", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modn_mul(r, y, x); + hex_to_bytes("2a876a4e5df28cd6c2f3951aa6b65c55e2d6eb1883b463aee5d95035999c9a30", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modn_sqr(r, x); + hex_to_bytes("22f25cab8043b82c9a5a6f0ca72c2122700737b557a11ba95ee80bddf671471f", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modn_exp(r, x, y); + hex_to_bytes("31e8d728b341541057e09242800bcd7321b523284104340f3ac3bedb55b516c7", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + secp256r1_modn_inv(r, x); + hex_to_bytes("a546ddb0e12a46eedab8425e77558aa3e56b7fec1d73fd94c03235e2f2298172", 64, buf, &len); + secp256r1_from_32bytes(v, buf); + if (secp256r1_cmp(r, v) != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + + +static int test_secp256r1_point_at_infinity(void) +{ + SECP256R1_POINT P; + secp256r1_point_set_infinity(&P); + + if (!secp256r1_point_is_at_infinity(&P)) { + error_print(); + return -1; + } + secp256r1_point_print(stderr, 0, 4, "point_at_infinity", &P); + + if (!secp256r1_point_is_on_curve(&P)) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp256r1_point_set_xy(void) +{ + SECP256R1_POINT P; + secp256r1_t x; + secp256r1_t y; + secp256r1_t x1; + secp256r1_t y1; + uint8_t bytes[32]; + size_t len; + + hex_to_bytes(secp256r1_x, 64, bytes, &len); + secp256r1_from_32bytes(x, bytes); + + hex_to_bytes(secp256r1_y, 64, bytes, &len); + secp256r1_from_32bytes(y, bytes); + + if (secp256r1_point_set_xy(&P, x, y) != 1) { + error_print(); + return -1; + } + + secp256r1_point_get_xy(&P, x1, y1); + + if (secp256r1_cmp(x, x1) != 0 + || secp256r1_cmp(y, y1) != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp256r1_point_is_on_curve(void) +{ + if (secp256r1_point_is_on_curve(&SECP256R1_POINT_G) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + +// 这两个计算是应该分开的! +static int test_secp256r1_point_dbl_add(void) +{ + SECP256R1_POINT P; + SECP256R1_POINT Q; + secp256r1_t x; + secp256r1_t y; + secp256r1_t x1; + secp256r1_t y1; + uint8_t bytes[32]; + size_t len; + + // test 2*G + secp256r1_point_dbl(&P, &SECP256R1_POINT_G); + secp256r1_point_get_xy(&P, x, y); + + secp256r1_point_print(stderr, 0, 4, "2*G", &P); + + hex_to_bytes("7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978", 64, bytes, &len); + secp256r1_from_32bytes(x1, bytes); + hex_to_bytes("07775510db8ed040293d9ac69f7430dbba7dade63ce982299e04b79d227873d1", 64, bytes, &len); + secp256r1_from_32bytes(y1, bytes); + + if (secp256r1_cmp(x, x1) != 0 || secp256r1_cmp(y, y1) != 0) { + error_print(); + return -1; + } + + // test 2*G + G + secp256r1_point_add(&Q, &P, &SECP256R1_POINT_G); + secp256r1_point_get_xy(&Q, x, y); + + hex_to_bytes("5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c", 64, bytes, &len); + secp256r1_from_32bytes(x1, bytes); + hex_to_bytes("8734640c4998ff7e374b06ce1a64a2ecd82ab036384fb83d9a79b127a27d5032", 64, bytes, &len); + secp256r1_from_32bytes(y1, bytes); + + if (secp256r1_cmp(x, x1) != 0 || secp256r1_cmp(y, y1) != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static const char *secp256r1_x_2G = "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978"; +static const char *secp256r1_y_2G = "07775510db8ed040293d9ac69f7430dbba7dade63ce982299e04b79d227873d1"; +static const char *secp256r1_x_3G = "5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c"; +static const char *secp256r1_y_3G = "8734640c4998ff7e374b06ce1a64a2ecd82ab036384fb83d9a79b127a27d5032"; + + +static int test_secp256r1_point_mul(void) +{ + SECP256R1_POINT P; + secp256r1_t x; + secp256r1_t y; + secp256r1_t x1; + secp256r1_t y1; + secp256r1_t k; + uint8_t bytes[32] = {0}; + size_t len; + + // k = 3 + bytes[31] = 3; + secp256r1_from_32bytes(k, bytes); + + secp256r1_point_mul_generator(&P, k); + secp256r1_point_get_xy(&P, x, y); // 这个必须返回错误啊,否则没办法判断是否为无穷远点呢! + + hex_to_bytes(secp256r1_x_3G, 64, bytes, &len); + secp256r1_from_32bytes(x1, bytes); + hex_to_bytes(secp256r1_y_3G, 64, bytes, &len); + secp256r1_from_32bytes(y1, bytes); + + if (secp256r1_cmp(x, x1) != 0 || secp256r1_cmp(y, y1) != 0) { + error_print(); + return -1; + } + + // k = n + hex_to_bytes(secp256r1_n, 64, bytes, &len); + secp256r1_from_32bytes(k, bytes); + + secp256r1_point_mul_generator(&P, k); + + if (secp256r1_point_is_at_infinity(&P) != 1) { + error_print(); + return -1; + } + + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp256r1_point_to_uncompressed_octets(void) +{ + SECP256R1_POINT P; + uint8_t octets[65]; + + + secp256r1_point_copy(&P, &SECP256R1_POINT_G); + + if (secp256r1_point_to_uncompressed_octets(&P, octets) != 1) { + error_print(); + return -1; + } + if (secp256r1_point_from_uncompressed_octets(&P, octets) != 1) { + error_print(); + return -1; + } + + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + +int main(void) +{ + if (test_secp256r1() != 1) goto err; + if (test_secp256r1_modp() != 1) goto err; + if (test_secp256r1_modn() != 1) goto err; + if (test_secp256r1_point_at_infinity() != 1) goto err; + if (test_secp256r1_point_is_on_curve() != 1) goto err; + if (test_secp256r1_point_set_xy() != 1) goto err; + if (test_secp256r1_point_dbl_add() != 1) goto err; + if (test_secp256r1_point_mul() != 1) goto err; + if (test_secp256r1_point_to_uncompressed_octets() != 1) goto err; + + + printf("%s all tests passed\n", __FILE__); + return 0; +err: + error_print(); + return 1; +}