國密即國家密碼局認定的國產密碼算法。主要有SM1,SM2,SM3,SM4。密鑰長度和分組長度均為128位。
SM1 為對稱加密。其加密強度與AES相當。該算法不公開,調用該算法時,需要通過加密芯片的接口進行調用。
SM2為非對稱加密,基於ECC。該算法已公開。由於該算法基於ECC,故其簽名速度與秘鑰生成速度都快於RSA。ECC 256位(SM2采用的就是ECC 256位的一種)安全強度比RSA 2048位高,但運算速度快於RSA。
SM3 消息摘要。可以用MD5作為對比理解。該算法已公開。校驗結果為256位。
SM4 無線局域網標准的分組數據算法。對稱加密,密鑰長度和分組長度均為128位。
由於SM1、SM4加解密的分組大小為128bit,故對消息進行加解密時,若消息長度過長,需要進行分組,要消息長度不足,則要進行填充。
SM2,SM3,SM4的相關文檔可以參考如下鏈接:
http://218.241.108.63/wiki/index.php/首頁
SM2,SM3,SM4的C代碼如下:使用了openssl開源庫。
當使用特定的芯片進行SM1或其他國密算法加密時,若用多個線程調用加密卡的API時,要考慮芯片對於多線程的支持情況。
以下為不使用openssl庫的另一種實現方案,基於Miracl大數運算庫,可移植。
主要難點就是移植Miracl庫,裁剪配置,測試加解密算法。針對不同平台如32位或64位,以及平台的大小端進行配置。
如果Miracl庫移植ok了,那么基於Miracl庫的sm2算法應沒多大問題。
Miracl庫里文件較多,且從官網下載的代碼,在linux系統上是很容易編譯。
但是想用在單片機上,需要一些移植和配置。
只需要包含需要的文件就行了。

以下是編譯過程。

然后需要新建一個sm2.c文件、sm2.h,用於實現sm2功能函數;一個sm3.c文件、一個sm3.h文件,用於實現sm3功能函數(之所以要增加sm3的功能是因為sm2算法中需要sm3計算hash值功能。 下面給出生成密鑰對的示例:
#include <stdio.h> #include <stdlib.h> #include<string.h> #include <memory.h> #include <time.h> #include "sm2.h" #define SM2_PAD_ZERO TRUE #define SM2_DEBUG 0 struct FPECC{ char *p; char *a; char *b; char *n; char *x; char *y; }; /*SM2*/ struct FPECC Ecc256 = { "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", }; unsigned char radom1[] = { 0x4C,0x62,0xEE,0xFD,0x6E,0xCF,0xC2,0xB9,0x5B,0x92,0xFD,0x6C,0x3D,0x95,0x75,0x14,0x8A,0xFA,0x17,0x42,0x55,0x46,0xD4,0x90,0x18,0xE5,0x38,0x8D,0x49,0xDD,0x7B,0x4F }; void PrintBuf(unsigned char *buf, int buflen) { int i; for (i = 0; i < buflen; i++) { if (i % 32 != 31) printf("%02x", buf[i]); else printf("%02x\n", buf[i]); } printf("\n"); //return 0; } void Printch(unsigned char *buf, int buflen) { int i; for (i = 0; i < buflen; i++) { if (i % 32 != 31) printf("%c", buf[i]); else printf("%c\n", buf[i]); } printf("\n"); //return 0; } void sm2_keygen(unsigned char *wx, int *wxlen, unsigned char *wy, int *wylen,unsigned char *privkey, int *privkeylen) { struct FPECC *cfig = &Ecc256; epoint *g; big a,b,p,n,x,y,key1; miracl