国密即国家密码局认定的国产密码算法。主要有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