sm2-ecdh revised

pull/610/head
Aidan Keefe 2026-07-29 12:37:17 -06:00
parent 6715f35753
commit 23c020e186
1 changed files with 140 additions and 37 deletions

View File

@ -23,7 +23,16 @@
* secret from their private key and the peer's public key.
*
* This is plain ECDH on the SM2P256V1 curve, not the full SM2 key exchange
* protocol from GB/T 32918.3. */
* protocol from GB/T 32918.3.
*
* Roles in this example:
* Alice: makes an SM2 key pair, sends her public key to Bob, and combines
* her private key with Bob's public key.
* Bob: does the same in the other direction.
*
* Only public keys are exchanged, so each side is given its own ecc_key for
* the peer, imported from the bytes that crossed the wire. Both then arrive
* at the same secret without it ever being transmitted. */
#include <stdio.h>
#include <string.h>
@ -33,9 +42,14 @@
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/sm2.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#ifdef WOLFSSL_SM2
#define SM2_FIELD_SZ 32 /* SM2P256V1: 256-bit curve */
#define SM2_SECRET_SZ SM2_FIELD_SZ /* ECDH secret is one X ord */
#define SM2_PUB_KEY_SZ (1 + SM2_FIELD_SZ * 2) /* X9.63 point: 04 || X || Y */
static void print_hex(const char* label, const byte* data, word32 len)
{
word32 i;
@ -48,68 +62,148 @@ static void print_hex(const char* label, const byte* data, word32 len)
int main(void)
{
int ret;
WC_RNG rng;
int rngInit = 0;
ecc_key alice;
ecc_key bob;
int aliceInit = 0;
int bobInit = 0;
byte secretA[32];
byte secretB[32];
word32 secretASz = (word32)sizeof(secretA);
word32 secretBSz = (word32)sizeof(secretB);
int ret;
WC_RNG rng;
int rngInit = 0;
/* Every struct below is declared before the first "goto exit" so that the
* cleanup at the bottom always sees initialised members. */
struct {
byte publicKey[SM2_PUB_KEY_SZ]; /* only public data is sent */
word32 publicKeySz;
} Wire = {0};
struct {
ecc_key key; /* Alice's own key pair */
int keyInit;
ecc_key peerKey; /* Alice view: Bob's pubkey */
int peerKeyInit;
byte sharedSecret[SM2_SECRET_SZ];
word32 sharedSecretSz;
} Alice = {0};
struct {
ecc_key key; /* Bob's own key pair */
int keyInit;
ecc_key peerKey; /* Bob view: Alice's pubkey */
int peerKeyInit;
byte sharedSecret[SM2_SECRET_SZ];
word32 sharedSecretSz;
} Bob = {0};
/* --- Init Alice --- */
ret = wc_ecc_init(&Alice.key);
if (ret != 0) goto exit; else Alice.keyInit = 1;
ret = wc_ecc_init(&Alice.peerKey);
if (ret != 0) goto exit; else Alice.peerKeyInit = 1;
Alice.sharedSecretSz = (word32)sizeof(Alice.sharedSecret);
/* --- Init Alice --- */
/* --- Init Bob --- */
ret = wc_ecc_init(&Bob.key);
if (ret != 0) goto exit; else Bob.keyInit = 1;
ret = wc_ecc_init(&Bob.peerKey);
if (ret != 0) goto exit; else Bob.peerKeyInit = 1;
Bob.sharedSecretSz = (word32)sizeof(Bob.sharedSecret);
/* --- Init Bob --- */
/* --- One rng instance for simplicity -- */
ret = wc_InitRng(&rng);
if (ret != 0) {
printf("wc_InitRng failed %d\n", ret);
goto exit;
}
rngInit = 1;
/* --- One rng instance for simplicity -- */
ret = wc_ecc_init(&alice);
if (ret != 0)
goto exit;
aliceInit = 1;
ret = wc_ecc_init(&bob);
if (ret != 0)
goto exit;
bobInit = 1;
ret = wc_ecc_sm2_make_key(&rng, &alice, WC_ECC_FLAG_NONE);
/* --- Each side makes its own SM2 key pair --- */
ret = wc_ecc_sm2_make_key(&rng, &Alice.key, WC_ECC_FLAG_NONE);
if (ret == 0)
ret = wc_ecc_sm2_make_key(&rng, &bob, WC_ECC_FLAG_NONE);
ret = wc_ecc_sm2_make_key(&rng, &Bob.key, WC_ECC_FLAG_NONE);
if (ret != 0) {
printf("wc_ecc_sm2_make_key failed %d\n", ret);
goto exit;
}
printf("Generated two SM2 keys\n");
/* --- Each side makes its own SM2 key pair --- */
#ifdef ECC_TIMING_RESISTANT
/* Timing-resistant point math needs an RNG on the private key. */
ret = wc_ecc_set_rng(&alice, &rng);
/* --- Timing-resistant point math needs an RNG on the private key --- */
ret = wc_ecc_set_rng(&Alice.key, &rng);
if (ret == 0)
ret = wc_ecc_set_rng(&bob, &rng);
ret = wc_ecc_set_rng(&Bob.key, &rng);
if (ret != 0) {
printf("wc_ecc_set_rng failed %d\n", ret);
goto exit;
}
/* --- Timing-resistant point math needs an RNG on the private key --- */
#endif
/* Each side uses its own private key and the peer's public key. */
ret = wc_ecc_sm2_shared_secret(&alice, &bob, secretA, &secretASz);
/* --- Alice sends her public key to Bob --- */
{
/* - Export Alice's public point (simulate sending pubkey only) - */
Wire.publicKeySz = SM2_PUB_KEY_SZ;
ret = wc_ecc_export_x963_ex(&Alice.key, Wire.publicKey,
&Wire.publicKeySz, 0);
if (ret != 0) {printf("Could not export Alice's pubkey\n"); goto exit;}
/* - Export Alice's public point (simulate sending pubkey only) - */
/* - Bob saves the public key he received - */
ret = wc_ecc_import_x963_ex(Wire.publicKey, Wire.publicKeySz,
&Bob.peerKey, ECC_SM2P256V1);
if (ret != 0) {
printf("Bob could not import Alice's pubkey\n");
goto exit;
}
/* - Bob saves the public key he received - */
}
/* --- Alice sends her public key to Bob --- */
/* --- Reset the wire for Bob's public key --- */
memset(&Wire, 0, sizeof(Wire));
/* --- Reset the wire for Bob's public key --- */
/* --- Bob sends his public key to Alice --- */
{
/* - Export Bob's public point (simulate sending pubkey only) - */
Wire.publicKeySz = SM2_PUB_KEY_SZ;
ret = wc_ecc_export_x963_ex(&Bob.key, Wire.publicKey,
&Wire.publicKeySz, 0);
if (ret != 0) {printf("Could not export Bob's pubkey\n"); goto exit;}
/* - Export Bob's public point (simulate sending pubkey only) - */
/* - Alice saves the public key she received - */
ret = wc_ecc_import_x963_ex(Wire.publicKey, Wire.publicKeySz,
&Alice.peerKey, ECC_SM2P256V1);
if (ret != 0) {
printf("Alice could not import Bob's pubkey\n");
goto exit;
}
/* - Alice saves the public key she received - */
}
/* --- Bob sends his public key to Alice --- */
/* --- Each side computes the shared secret --- */
/* Own private key plus the peer's public key. The size in is the buffer
* size available; on return it holds the secret length. */
ret = wc_ecc_sm2_shared_secret(&Alice.key, &Alice.peerKey,
Alice.sharedSecret, &Alice.sharedSecretSz);
if (ret == 0)
ret = wc_ecc_sm2_shared_secret(&bob, &alice, secretB, &secretBSz);
ret = wc_ecc_sm2_shared_secret(&Bob.key, &Bob.peerKey,
Bob.sharedSecret, &Bob.sharedSecretSz);
if (ret != 0) {
printf("wc_ecc_sm2_shared_secret failed %d\n", ret);
goto exit;
}
/* --- Each side computes the shared secret --- */
print_hex("alice secret", secretA, secretASz);
print_hex("bob secret", secretB, secretBSz);
print_hex("alice secret", Alice.sharedSecret, Alice.sharedSecretSz);
print_hex("bob secret", Bob.sharedSecret, Bob.sharedSecretSz);
if (secretASz != secretBSz ||
memcmp(secretA, secretB, secretASz) != 0) {
if (Alice.sharedSecretSz != Bob.sharedSecretSz ||
memcmp(Alice.sharedSecret, Bob.sharedSecret,
Alice.sharedSecretSz) != 0) {
printf("Shared secrets differ!\n");
ret = -1;
goto exit;
@ -118,10 +212,19 @@ int main(void)
ret = 0;
exit:
if (bobInit)
wc_ecc_free(&bob);
if (aliceInit)
wc_ecc_free(&alice);
if (ret != 0)
printf("error %d: %s\n", ret, wc_GetErrorString(ret));
if (Bob.peerKeyInit)
wc_ecc_free(&Bob.peerKey);
if (Bob.keyInit)
wc_ecc_free(&Bob.key);
if (Alice.peerKeyInit)
wc_ecc_free(&Alice.peerKey);
if (Alice.keyInit)
wc_ecc_free(&Alice.key);
if (rngInit)
wc_FreeRng(&rng);