Add SM2/SM3/SM4 examples

wolfCrypt-level ShangMi examples: SM3 hash (GB/T 32905 known answer),
SM4-GCM with tamper detection, SM2 sign/verify including the ZA digest
step, and SM2 ECDH. Requires the wolfSSL/wolfsm overlay.
pull/610/head
Anthony 2026-07-24 15:18:39 -04:00 committed by Anthony Hu
parent dbf6e9ad49
commit eba0390017
6 changed files with 606 additions and 0 deletions

30
crypto/sm/Makefile 100644
View File

@ -0,0 +1,30 @@
CC=gcc
WOLFSSL_INSTALL_DIR=/usr/local
CFLAGS=-Wall -I$(WOLFSSL_INSTALL_DIR)/include
LIBS=-L$(WOLFSSL_INSTALL_DIR)/lib -lwolfssl -lm
all: sm3-hash sm4-gcm-encrypt sm2-sign-verify sm2-ecdh
sm3-hash: sm3-hash.o
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
sm4-gcm-encrypt: sm4-gcm-encrypt.o
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
sm2-sign-verify: sm2-sign-verify.o
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
sm2-ecdh: sm2-ecdh.o
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
.PHONY: clean all check
clean:
rm -f *.o sm3-hash sm4-gcm-encrypt sm2-sign-verify sm2-ecdh
check: all
out=$$(./sm3-hash) && printf '%s' "$$out" | grep -q 'matches GB/T 32905 test vector'
out=$$(./sm4-gcm-encrypt) && printf '%s' "$$out" | grep -q 'Tampered tag rejected as expected'
out=$$(./sm2-sign-verify) && printf '%s' "$$out" | grep -q 'Signature verified'
out=$$(./sm2-ecdh) && printf '%s' "$$out" | grep -q 'Shared secrets match'
@echo "PASS: crypto-sm checks"

View File

@ -0,0 +1,43 @@
# wolfSSL SM2/SM3/SM4 Examples
Demonstrates the Chinese national (ShangMi) cryptographic algorithms at the
wolfCrypt level:
* `sm3-hash.c` - SM3 hash (Chinese national standard GB/T 32905-2016),
checked against the standard's "abc" test vector.
* `sm4-gcm-encrypt.c` - SM4-GCM (GB/T 32907-2016) authenticated encryption
with tamper detection.
* `sm2-sign-verify.c` - SM2 (GB/T 32918) digital signatures, including the
identity-based "ZA" digest step via `wc_ecc_sm2_create_digest()`.
* `sm2-ecdh.c` - ECDH shared-secret agreement on the SM2 curve.
## Building wolfSSL
The SM algorithm implementations ship in the separate
[wolfSSL/wolfsm](https://github.com/wolfSSL/wolfsm) overlay, so install that
into a wolfSSL source tree first:
```
git clone https://github.com/wolfSSL/wolfsm
git clone https://github.com/wolfSSL/wolfssl
cd wolfsm
./install.sh ../wolfssl
cd ../wolfssl
./autogen.sh
./configure --enable-sm2 --enable-sm3 --enable-sm4-gcm
make
sudo make install
```
Other SM4 modes are available with `--enable-sm4-ecb`, `--enable-sm4-cbc`,
`--enable-sm4-ctr` and `--enable-sm4-ccm`.
## Building and running the examples
```
make
./sm3-hash [message]
./sm4-gcm-encrypt
./sm2-sign-verify [message]
./sm2-ecdh
```

View File

@ -0,0 +1,140 @@
/* sm2-ecdh.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* Example of ECDH over the SM2 curve: both sides compute the same shared
* 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. */
#include <stdio.h>
#include <string.h>
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/sm2.h>
#include <wolfssl/wolfcrypt/random.h>
#ifdef WOLFSSL_SM2
static void print_hex(const char* label, const byte* data, word32 len)
{
word32 i;
printf("%s: ", label);
for (i = 0; i < len; i++)
printf("%02x", data[i]);
printf("\n");
}
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);
ret = wc_InitRng(&rng);
if (ret != 0) {
printf("wc_InitRng failed %d\n", ret);
goto exit;
}
rngInit = 1;
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);
if (ret == 0)
ret = wc_ecc_sm2_make_key(&rng, &bob, 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");
#ifdef ECC_TIMING_RESISTANT
/* Timing-resistant point math needs an RNG on the private key. */
ret = wc_ecc_set_rng(&alice, &rng);
if (ret == 0)
ret = wc_ecc_set_rng(&bob, &rng);
if (ret != 0) {
printf("wc_ecc_set_rng failed %d\n", ret);
goto exit;
}
#endif
/* Each side uses its own private key and the peer's public key. */
ret = wc_ecc_sm2_shared_secret(&alice, &bob, secretA, &secretASz);
if (ret == 0)
ret = wc_ecc_sm2_shared_secret(&bob, &alice, secretB, &secretBSz);
if (ret != 0) {
printf("wc_ecc_sm2_shared_secret failed %d\n", ret);
goto exit;
}
print_hex("alice secret", secretA, secretASz);
print_hex("bob secret", secretB, secretBSz);
if (secretASz != secretBSz ||
memcmp(secretA, secretB, secretASz) != 0) {
printf("Shared secrets differ!\n");
ret = -1;
goto exit;
}
printf("Shared secrets match\n");
ret = 0;
exit:
if (bobInit)
wc_ecc_free(&bob);
if (aliceInit)
wc_ecc_free(&alice);
if (rngInit)
wc_FreeRng(&rng);
return ret == 0 ? 0 : 1;
}
#else
int main(void)
{
printf("Please install the wolfsm overlay and build wolfSSL with "
"./configure --enable-sm2\n");
return 0;
}
#endif /* WOLFSSL_SM2 */

View File

@ -0,0 +1,146 @@
/* sm2-sign-verify.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* Example of SM2 (GB/T 32918) signing and verifying over the SM2 curve.
*
* SM2 does not sign the raw message: the message is first combined with the
* signer's identity and public key into an SM3 digest (the "ZA" hash). */
#include <stdio.h>
#include <string.h>
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/sm2.h>
#include <wolfssl/wolfcrypt/sm3.h>
#include <wolfssl/wolfcrypt/random.h>
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
/* Default identity from GM/T 0009-2012, also used for certificates. */
static const byte sm2_id[] = "1234567812345678";
static void print_hex(const char* label, const byte* data, word32 len)
{
word32 i;
printf("%s: ", label);
for (i = 0; i < len; i++)
printf("%02x", data[i]);
printf("\n");
}
int main(int argc, char* argv[])
{
int ret;
WC_RNG rng;
int rngInit = 0;
ecc_key key;
int keyInit = 0;
byte digest[WC_SM3_DIGEST_SIZE];
byte sig[ECC_MAX_SIG_SIZE];
word32 sigSz = (word32)sizeof(sig);
int verified = 0;
const char* msg = (argc > 1) ? argv[1] : "sm2 sign-verify example";
ret = wc_InitRng(&rng);
if (ret != 0) {
printf("wc_InitRng failed %d\n", ret);
goto exit;
}
rngInit = 1;
ret = wc_ecc_init(&key);
if (ret != 0) {
printf("wc_ecc_init failed %d\n", ret);
goto exit;
}
keyInit = 1;
ret = wc_ecc_sm2_make_key(&rng, &key, WC_ECC_FLAG_NONE);
if (ret != 0) {
printf("wc_ecc_sm2_make_key failed %d\n", ret);
goto exit;
}
printf("Generated SM2 key\n");
/* ZA digest: SM3 over the identity, curve parameters and public key,
* then SM3 over ZA || message. */
ret = wc_ecc_sm2_create_digest(sm2_id, (word16)(sizeof(sm2_id) - 1),
(const byte*)msg, (int)strlen(msg),
WC_HASH_TYPE_SM3, digest,
(int)sizeof(digest), &key);
if (ret != 0) {
printf("wc_ecc_sm2_create_digest failed %d\n", ret);
goto exit;
}
print_hex("digest", digest, sizeof(digest));
ret = wc_ecc_sm2_sign_hash(digest, sizeof(digest), sig, &sigSz, &rng,
&key);
if (ret != 0) {
printf("wc_ecc_sm2_sign_hash failed %d\n", ret);
goto exit;
}
print_hex("signature", sig, sigSz);
ret = wc_ecc_sm2_verify_hash(sig, sigSz, digest, sizeof(digest),
&verified, &key);
if (ret != 0 || verified != 1) {
printf("wc_ecc_sm2_verify_hash failed: ret %d verified %d\n", ret,
verified);
ret = -1;
goto exit;
}
printf("Signature verified\n");
/* A modified digest must not verify. */
digest[0] ^= 0x01;
ret = wc_ecc_sm2_verify_hash(sig, sigSz, digest, sizeof(digest),
&verified, &key);
if (ret == 0 && verified == 1) {
printf("Corrupted digest verified!\n");
ret = -1;
goto exit;
}
printf("Corrupted digest rejected as expected\n");
ret = 0;
exit:
if (keyInit)
wc_ecc_free(&key);
if (rngInit)
wc_FreeRng(&rng);
return ret == 0 ? 0 : 1;
}
#else
int main(void)
{
printf("Please install the wolfsm overlay and build wolfSSL with "
"./configure --enable-sm2 --enable-sm3\n");
return 0;
}
#endif /* WOLFSSL_SM2 && WOLFSSL_SM3 */

View File

@ -0,0 +1,97 @@
/* sm3-hash.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* Example of incremental SM3 hashing (GB/T 32905-2016), checked against the
* standard's "abc" test vector. */
#include <stdio.h>
#include <string.h>
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/sm3.h>
#ifdef WOLFSSL_SM3
/* SM3("abc") from GB/T 32905-2016 Appendix A. */
static const byte kat_abc[WC_SM3_DIGEST_SIZE] = {
0x66, 0xc7, 0xf0, 0xf4, 0x62, 0xee, 0xed, 0xd9,
0xd1, 0xf2, 0xd4, 0x6b, 0xdc, 0x10, 0xe4, 0xe2,
0x41, 0x67, 0xc4, 0x87, 0x5c, 0xf2, 0xf7, 0xa2,
0x29, 0x7d, 0xa0, 0x2b, 0x8f, 0x4b, 0xa8, 0xe0
};
static void print_hex(const char* label, const byte* data, word32 len)
{
word32 i;
printf("%s: ", label);
for (i = 0; i < len; i++)
printf("%02x", data[i]);
printf("\n");
}
int main(int argc, char* argv[])
{
int ret;
wc_Sm3 sm3;
byte digest[WC_SM3_DIGEST_SIZE];
const char* msg = (argc > 1) ? argv[1] : "abc";
ret = wc_InitSm3(&sm3, NULL, INVALID_DEVID);
if (ret != 0) {
printf("wc_InitSm3 failed %d\n", ret);
return 1;
}
/* Data may be added in as many update calls as needed. */
ret = wc_Sm3Update(&sm3, (const byte*)msg, (word32)strlen(msg));
if (ret == 0)
ret = wc_Sm3Final(&sm3, digest);
wc_Sm3Free(&sm3);
if (ret != 0) {
printf("SM3 hash failed %d\n", ret);
return 1;
}
print_hex("SM3", digest, WC_SM3_DIGEST_SIZE);
if (argc <= 1) {
if (memcmp(digest, kat_abc, WC_SM3_DIGEST_SIZE) != 0) {
printf("Digest does not match GB/T 32905 test vector!\n");
return 1;
}
printf("Digest matches GB/T 32905 test vector\n");
}
return 0;
}
#else
int main(void)
{
printf("Please install the wolfsm overlay and build wolfSSL with "
"./configure --enable-sm3\n");
return 0;
}
#endif /* WOLFSSL_SM3 */

View File

@ -0,0 +1,150 @@
/* sm4-gcm-encrypt.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* Example of SM4-GCM (GB/T 32907-2016 block cipher in GCM mode) authenticated
* encryption: encrypt, decrypt, and reject a tampered tag. */
#include <stdio.h>
#include <string.h>
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/sm4.h>
#include <wolfssl/wolfcrypt/random.h>
#if defined(WOLFSSL_SM4) && defined(WOLFSSL_SM4_GCM)
#define NONCE_SZ 12
#define TAG_SZ 16
static void print_hex(const char* label, const byte* data, word32 len)
{
word32 i;
printf("%s: ", label);
for (i = 0; i < len; i++)
printf("%02x", data[i]);
printf("\n");
}
int main(void)
{
int ret;
wc_Sm4 sm4;
int sm4Init = 0;
WC_RNG rng;
int rngInit = 0;
byte key[SM4_KEY_SIZE];
byte nonce[NONCE_SZ];
byte tag[TAG_SZ];
const char* msg = "sm4-gcm example plaintext";
const char* aad = "example aad";
byte cipher[64];
byte plain[64];
word32 msgSz = (word32)strlen(msg);
ret = wc_InitRng(&rng);
if (ret != 0) {
printf("wc_InitRng failed %d\n", ret);
goto exit;
}
rngInit = 1;
ret = wc_Sm4Init(&sm4, NULL, INVALID_DEVID);
if (ret != 0) {
printf("wc_Sm4Init failed %d\n", ret);
goto exit;
}
sm4Init = 1;
/* Fresh random key; a nonce must never repeat under the same key. */
ret = wc_RNG_GenerateBlock(&rng, key, sizeof(key));
if (ret == 0)
ret = wc_RNG_GenerateBlock(&rng, nonce, sizeof(nonce));
if (ret != 0) {
printf("wc_RNG_GenerateBlock failed %d\n", ret);
goto exit;
}
ret = wc_Sm4GcmSetKey(&sm4, key, sizeof(key));
if (ret != 0) {
printf("wc_Sm4GcmSetKey failed %d\n", ret);
goto exit;
}
ret = wc_Sm4GcmEncrypt(&sm4, cipher, (const byte*)msg, msgSz, nonce,
sizeof(nonce), tag, sizeof(tag), (const byte*)aad,
(word32)strlen(aad));
if (ret != 0) {
printf("wc_Sm4GcmEncrypt failed %d\n", ret);
goto exit;
}
print_hex("key ", key, sizeof(key));
print_hex("nonce ", nonce, sizeof(nonce));
print_hex("ciphertext", cipher, msgSz);
print_hex("tag ", tag, sizeof(tag));
ret = wc_Sm4GcmDecrypt(&sm4, plain, cipher, msgSz, nonce, sizeof(nonce),
tag, sizeof(tag), (const byte*)aad,
(word32)strlen(aad));
if (ret != 0) {
printf("wc_Sm4GcmDecrypt failed %d\n", ret);
goto exit;
}
if (memcmp(plain, msg, msgSz) != 0) {
printf("Decrypted plaintext mismatch!\n");
ret = -1;
goto exit;
}
printf("Decrypt success\n");
/* A tampered tag must fail authentication. */
tag[0] ^= 0x01;
ret = wc_Sm4GcmDecrypt(&sm4, plain, cipher, msgSz, nonce, sizeof(nonce),
tag, sizeof(tag), (const byte*)aad,
(word32)strlen(aad));
if (ret == 0) {
printf("Tampered tag accepted!\n");
ret = -1;
goto exit;
}
printf("Tampered tag rejected as expected\n");
ret = 0;
exit:
if (sm4Init)
wc_Sm4Free(&sm4);
if (rngInit)
wc_FreeRng(&rng);
return ret == 0 ? 0 : 1;
}
#else
int main(void)
{
printf("Please install the wolfsm overlay and build wolfSSL with "
"./configure --enable-sm4-gcm\n");
return 0;
}
#endif /* WOLFSSL_SM4 && WOLFSSL_SM4_GCM */