diff --git a/crypto/sm/Makefile b/crypto/sm/Makefile new file mode 100644 index 00000000..0f496d79 --- /dev/null +++ b/crypto/sm/Makefile @@ -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" diff --git a/crypto/sm/README.md b/crypto/sm/README.md new file mode 100644 index 00000000..6a28d012 --- /dev/null +++ b/crypto/sm/README.md @@ -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 +``` diff --git a/crypto/sm/sm2-ecdh.c b/crypto/sm/sm2-ecdh.c new file mode 100644 index 00000000..3a9f730c --- /dev/null +++ b/crypto/sm/sm2-ecdh.c @@ -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 +#include + +#include +#include +#include +#include +#include + +#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 */ diff --git a/crypto/sm/sm2-sign-verify.c b/crypto/sm/sm2-sign-verify.c new file mode 100644 index 00000000..d6eef256 --- /dev/null +++ b/crypto/sm/sm2-sign-verify.c @@ -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 +#include + +#include +#include +#include +#include +#include +#include + +#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 */ diff --git a/crypto/sm/sm3-hash.c b/crypto/sm/sm3-hash.c new file mode 100644 index 00000000..9c6dab94 --- /dev/null +++ b/crypto/sm/sm3-hash.c @@ -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 +#include + +#include +#include +#include + +#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 */ diff --git a/crypto/sm/sm4-gcm-encrypt.c b/crypto/sm/sm4-gcm-encrypt.c new file mode 100644 index 00000000..860c11df --- /dev/null +++ b/crypto/sm/sm4-gcm-encrypt.c @@ -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 +#include + +#include +#include +#include +#include + +#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 */