sm2,sm3,sm4国密算法的纯c语言版本,使用于任何嵌入式平台


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

http://files.cnblogs.com/files/TaiYangXiManYouZhe/Sm2_sm3_sm4_c%E8%AF%AD%E8%A8%80%E5%AE%9E%E7%8E%B0.zip

当使用特定的芯片进行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 *mip = mirsys(20,0); mip->IOBASE = 16; p = mirvar(0); a = mirvar(0); b = mirvar(0); n = mirvar(0); x = mirvar(0); y = mirvar(0); key1 = mirvar(0); cinstr(p,cfig->p); cinstr(a,cfig->a); cinstr(b,cfig->b); cinstr(n,cfig->n); cinstr(x,cfig->x); cinstr(y,cfig->y); ecurve_init(a,b,p,MR_PROJECTIVE); g = epoint_init(); epoint_set(x,y,0,g); irand(time(NULL)); bigrand(n,key1); ////私钥db ecurve_mult(key1,g,g); //计算Pb epoint_get(g,x,y); *wxlen = big_to_bytes(32, x, (char *)wx, TRUE); *wylen = big_to_bytes(32, y, (char *)wy, TRUE); *privkeylen = big_to_bytes(32, key1, (char *)privkey, TRUE); mirkill(key1); mirkill(p); mirkill(a); mirkill(b); mirkill(n); mirkill(x); mirkill(y); epoint_free(g); mirexit(); } int kdf(unsigned char *zl, unsigned char *zr, int klen, unsigned char *kbuf) { /* return 0: kbuf = 0, 不可 1: kbuf 可 */ unsigned char buf[70]; unsigned char digest[32]; unsigned int ct = 0x00000001; //初始化一个32比特构成的计数器ct=0x00000001 int i, m, n; unsigned char *p; memcpy(buf, zl, 32); memcpy(buf+32, zr, 32); m = klen / 32; n = klen % 32; p = kbuf; for(i = 0; i < m; i++) { buf[64] = (ct >> 24) & 0xFF; buf[65] = (ct >> 16) & 0xFF; buf[66] = (ct >> 8) & 0xFF; buf[67] = ct & 0xFF; sm3(buf, 68, p); p += 32; ct++; } /*对i从1到?klen/v?执行:b.1)计算Hai=Hv(Z ∥ ct);b.2) ct++*/ if(n != 0) { buf[64] = (ct >> 24) & 0xFF; buf[65] = (ct >> 16) & 0xFF; buf[66] = (ct >> 8) & 0xFF; buf[67] = ct & 0xFF; sm3(buf, 68, digest); } /*若klen/v是整数,令Ha!?klen/v? = Ha?klen/v?,否则令Ha!?klen/v?为Ha?klen/v?最左边的(klen ? (v × ?klen/v?))比特*/ memcpy(p, digest, n); /*令K = Ha1||Ha2|| ||*/ for(i = 0; i < klen; i++) { if(kbuf[i] != 0) break; } if(i < klen) return 1; else return 0; } int sm2_encrypt(unsigned char *msg,int msglen, unsigned char *wx,int wxlen, unsigned char *wy,int wylen, unsigned char *outmsg) { struct FPECC *cfig = &Ecc256; big x2, y2, c1, c2, k; big a,b,p,n,x,y; epoint *g, *w; int ret = -1; int i; unsigned char zl[32], zr[32]; unsigned char *tmp; miracl *mip; tmp = malloc(msglen+64); if(tmp == NULL) return -1; mip = mirsys(20, 0); mip->IOBASE = 16; p=mirvar(0); a=mirvar(0); b=mirvar(0); n=mirvar(0); x=mirvar(0); y=mirvar(0); k=mirvar(0); x2=mirvar(0); y2=mirvar(0); c1=mirvar(0); c2=mirvar(0); cinstr(p,cfig->p); cinstr(a,cfig->a); cinstr(b,cfig->b); cinstr(n,cfig->n); cinstr(x,cfig->x); cinstr(y,cfig->y); ecurve_init(a,b,p,MR_PROJECTIVE); g=epoint_init(); w=epoint_init(); epoint_set(x,y,0,g); bytes_to_big(wxlen,(char *)wx,x); bytes_to_big(wylen,(char *)wy,y); epoint_set(x,y,0,w); irand(time(NULL)); sm2_encrypt_again: #if SM2_DEBUG bytes_to_big(32, (char *)radom1, k); #else do { bigrand(n, k); } while (k->len == 0); #endif ecurve_mult(k, g, g); epoint_get(g, c1, c2); big_to_bytes(32, c1, (char *)outmsg, TRUE); big_to_bytes(32, c2, (char *)outmsg+32, TRUE); //计算椭圆曲线点C1 if(point_at_infinity(w)) goto exit_sm2_encrypt; //计算椭圆曲线点S ecurve_mult(k, w, w); epoint_get(w, x2, y2); big_to_bytes(32, x2, (char *)zl, TRUE); big_to_bytes(32, y2, (char *)zr, TRUE); //计算椭圆曲线点[k]PB if (kdf(zl, zr, msglen, outmsg+64) == 0) goto sm2_encrypt_again; //计算t = KDF,如果t全零,返回A1 for(i = 0; i < msglen; i++) { outmsg[64+i] ^= msg[i]; } //计算C2 memcpy(tmp, zl, 32); memcpy(tmp+32, msg, msglen); memcpy(tmp+32+msglen, zr, 32); sm3(tmp, 64+msglen, &outmsg[64+msglen]); //计算C3 ret = msglen+64+32; printf("key:"); cotnum(k, stdout); //输出C,C在outmsg exit_sm2_encrypt: mirkill(x2); mirkill(y2); mirkill(c1); mirkill(c2); mirkill(k); mirkill(a); mirkill(b); mirkill(p); mirkill(n); mirkill(x); mirkill(y); epoint_free(g); epoint_free(w); mirexit(); free(tmp); return ret; } int sm2_decrypt(unsigned char *msg,int msglen, unsigned char *privkey, int privkeylen, unsigned char *outmsg) { struct FPECC *cfig = &Ecc256; big x2, y2, c, k; big a,b,p,n,x,y,key1; epoint *g; unsigned char c3[32]; unsigned char zl[32], zr[32]; int i, ret = -1; unsigned char *tmp; miracl *mip; if(msglen < 96) return 0; msglen -= 96; tmp = malloc(msglen+64); if(tmp == NULL) return 0; mip = mirsys(20, 0); mip->IOBASE = 16; x2=mirvar(0); y2=mirvar(0); c=mirvar(0); k = mirvar(0); p = mirvar(0); a = mirvar(0); b = mirvar(0); n = mirvar(0); x = mirvar(0); y = mirvar(0); key1 = mirvar(0); bytes_to_big(privkeylen,(char *)privkey,key1); cinstr(p,cfig->p); cinstr(a,cfig->a); cinstr(b,cfig->b); cinstr(n,cfig->n); cinstr(x,cfig->x); cinstr(y,cfig->y); ecurve_init(a,b,p,MR_PROJECTIVE); g = epoint_init(); bytes_to_big(32, (char *)msg, x); bytes_to_big(32, (char *)msg+32, y); if(!epoint_set(x,y,0,g)) goto exit_sm2_decrypt; //检验是否为椭圆曲线 if(point_at_infinity(g)) goto exit_sm2_decrypt; //计算S ecurve_mult(key1, g, g); epoint_get(g, x2, y2); big_to_bytes(32, x2, (char *)zl, TRUE); big_to_bytes(32, y2, (char *)zr, TRUE); //计算[db]c1 if (kdf(zl, zr, msglen, outmsg) == 0) goto exit_sm2_decrypt; //计算t for(i = 0; i < msglen; i++) { outmsg[i] ^= msg[i+64]; } //计算M到outsmg memcpy(tmp, zl, 32); memcpy(tmp+32, outmsg, msglen); memcpy(tmp+32+msglen, zr, 32); sm3(tmp, 64+msglen, c3);//计算u if(memcmp(c3, msg+64+msglen, 32) != 0) goto exit_sm2_decrypt; ret = msglen; exit_sm2_decrypt: mirkill(x2); mirkill(y2); mirkill(c); mirkill(k); mirkill(p); mirkill(a); mirkill(b); mirkill(n); mirkill(x); mirkill(y); mirkill(key1); epoint_free(g); mirexit(); free(tmp); return ret; } int main() { printf("sm2 test....\n"); unsigned char dB[] = { 0x16,0x49,0xAB,0x77,0xA0,0x06,0x37,0xBD,0x5E,0x2E,0xFE,0x28,0x3F,0xBF,0x35,0x35,0x34,0xAA,0x7F,0x7C,0xB8,0x94,0x63,0xF2,0x08,0xDD,0xBC,0x29,0x20,0xBB,0x0D,0xA0 }; unsigned char xB[] = { 0x43,0x5B,0x39,0xCC,0xA8,0xF3,0xB5,0x08,0xC1,0x48,0x8A,0xFC,0x67,0xBE,0x49,0x1A,0x0F,0x7B,0xA0,0x7E,0x58,0x1A,0x0E,0x48,0x49,0xA5,0xCF,0x70,0x62,0x8A,0x7E,0x0A }; unsigned char yB[] = { 0x75,0xDD,0xBA,0x78,0xF1,0x5F,0xEE,0xCB,0x4C,0x78,0x95,0xE2,0xC1,0xCD,0xF5,0xFE,0x01,0xDE,0xBB,0x2C,0xDB,0xAD,0xF4,0x53,0x99,0xCC,0xF7,0x7B,0xBA,0x07,0x6A,0x42 }; unsigned char tx[256]; unsigned char etx[256]; unsigned char mtx[256]; FILE *fp=0; int wxlen, wylen, privkeylen,len; //fopen(&fp, "5.txt", "r"); //len=fread_s(tx, 256,sizeof(unsigned char), 256, fp); fp = fopen("5.txt","r"); len=fread(tx,1,256,fp); tx[len] = "\0"; sm2_keygen(xB, &wxlen, yB, &wylen, dB, &privkeylen); printf("dB: "); PrintBuf(dB, 32); printf("xB: "); PrintBuf(xB, 32); printf("yB: "); PrintBuf(yB, 32); sm2_encrypt(tx,len,xB,32,yB,32,etx); printf("\n``````````````````this is encrypt```````````````````\n"); PrintBuf(etx, 64 +len + 32); printf("\n``````````````````this is decrypt```````````````````\n"); sm2_decrypt(etx,64+len+32,dB,32,mtx); if(sm2_decrypt(etx,64+len+32,dB,32,mtx) < 0) printf("sm2_decrypt error!\n"); else { PrintBuf(mtx, len); Printch(mtx, len); } printf("\n``````````````````this is end```````````````````````\n"); return 0; }
#include <string.h> #include <stdlib.h> #include <stdio.h> #include <time.h> #include "sm3.h" #define nl2c(l,c) (*((c)++) = (unsigned char)(((l) >> 24) & 0xff), \ *((c)++) = (unsigned char)(((l) >> 16) & 0xff), \ *((c)++) = (unsigned char)(((l) >> 8) & 0xff), \ *((c)++) = (unsigned char)(((l) ) & 0xff)) #define c_2_nl(c) ((*(c) << 24) | (*(c+1) << 16) | (*(c+2) << 8) | *(c+3)) #define ROTATE(X, C) (((X) << (C)) | ((X) >> (32 - (C)))) #define TH 0x79cc4519 #define TL 0x7a879d8a #define FFH(X, Y, Z) ((X) ^ (Y) ^ (Z)) #define FFL(X, Y, Z) (((X) & (Y)) | ((X) & (Z)) | ((Y) & (Z))) #define GGH(X, Y, Z) ((X) ^ (Y) ^ (Z)) #define GGL(X, Y, Z) (((X) & (Y)) | ((~X) & (Z))) #define P0(X) ((X) ^ (((X) << 9) | ((X) >> 23)) ^ (((X) << 17) | ((X) >> 15))) #define P1(X) ((X) ^ (((X) << 15) | ((X) >> 17)) ^ (((X) << 23) | ((X) >> 9))) #define DEBUG_SM3 0 void sm3_block(SM3_CTX *ctx) { register int j, k; register unsigned long t; register unsigned long ss1, ss2, tt1, tt2; register unsigned long a, b, c, d, e, f, g, h; unsigned long w[132]; for(j = 0; j < 16; j++) w[j] = ctx->data[j]; for(j = 16; j < 68; j++) { t = w[j-16] ^ w[j-9] ^ ROTATE(w[j-3], 15); w[j] = P1(t) ^ ROTATE(w[j-13], 7) ^ w[j-6]; } for(j = 0, k = 68; j < 64; j++, k++) { w[k] = w[j] ^ w[j+4]; } a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3]; e = ctx->h[4]; f = ctx->h[5]; g = ctx->h[6]; h = ctx->h[7]; for(j = 0; j < 16; j++) { ss1 = ROTATE(ROTATE(a, 12) + e + ROTATE(TH, j), 7); ss2 = ss1 ^ ROTATE(a, 12); tt1 = FFH(a, b, c) + d + ss2 + w[68 + j]; tt2 = GGH(e, f, g) + h + ss1 + w[j]; d = c; c = ROTATE(b, 9); b = a; a = tt1; h = g; g = ROTATE(f, 19); f = e; e = P0(tt2); } for(j = 16; j < 33; j++) { ss1 = ROTATE(ROTATE(a, 12) + e + ROTATE(TL, j), 7); ss2 = ss1 ^ ROTATE(a, 12); tt1 = FFL(a, b, c) + d + ss2 + w[68 + j]; tt2 = GGL(e, f, g) + h + ss1 + w[j]; d = c; c = ROTATE(b, 9); b = a; a = tt1; h = g; g = ROTATE(f, 19); f = e; e = P0(tt2); } for(j = 33; j < 64; j++) { ss1 = ROTATE(ROTATE(a, 12) + e + ROTATE(TL, (j-32)), 7); ss2 = ss1 ^ ROTATE(a, 12); tt1 = FFL(a, b, c) + d + ss2 + w[68 + j]; tt2 = GGL(e, f, g) + h + ss1 + w[j]; d = c; c = ROTATE(b, 9); b = a; a = tt1; h = g; g = ROTATE(f, 19); f = e; e = P0(tt2); } ctx->h[0] ^= a ; ctx->h[1] ^= b ; ctx->h[2] ^= c ; ctx->h[3] ^= d ; ctx->h[4] ^= e ; ctx->h[5] ^= f ; ctx->h[6] ^= g ; ctx->h[7] ^= h ; } void SM3_Init (SM3_CTX *ctx) { ctx->h[0] = 0x7380166fUL; ctx->h[1] = 0x4914b2b9UL; ctx->h[2] = 0x172442d7UL; ctx->h[3] = 0xda8a0600UL; ctx->h[4] = 0xa96f30bcUL; ctx->h[5] = 0x163138aaUL; ctx->h[6] = 0xe38dee4dUL; ctx->h[7] = 0xb0fb0e4eUL; ctx->Nl = 0; ctx->Nh = 0; ctx->num = 0; } void SM3_Update(SM3_CTX *ctx, const void *data, unsigned int len) { unsigned char *d; unsigned long l; int i, sw, sc; if (len == 0) return; l = (ctx->Nl + (len << 3)) & 0xffffffffL; if (l < ctx->Nl) /* overflow */ ctx->Nh++; ctx->Nh += (len >> 29); ctx->Nl = l; d = (unsigned char *)data; while (len >= SM3_CBLOCK) { ctx->data[0] = c_2_nl(d); d += 4; ctx->data[1] = c_2_nl(d); d += 4; ctx->data[2] = c_2_nl(d); d += 4; ctx->data[3] = c_2_nl(d); d += 4; ctx->data[4] = c_2_nl(d); d += 4; ctx->data[5] = c_2_nl(d); d += 4; ctx->data[6] = c_2_nl(d); d += 4; ctx->data[7] = c_2_nl(d); d += 4; ctx->data[8] = c_2_nl(d); d += 4; ctx->data[9] = c_2_nl(d); d += 4; ctx->data[10] = c_2_nl(d); d += 4; ctx->data[11] = c_2_nl(d); d += 4; ctx->data[12] = c_2_nl(d); d += 4; ctx->data[13] = c_2_nl(d); d += 4; ctx->data[14] = c_2_nl(d); d += 4; ctx->data[15] = c_2_nl(d); d += 4; sm3_block(ctx); len -= SM3_CBLOCK; } if(len > 0) { memset(ctx->data, 0, 64); ctx->num = len + 1; sw = len >> 2; sc = len & 0x3; for(i = 0; i < sw; i++) { ctx->data[i] = c_2_nl(d); d += 4; } switch(sc) { case 0: ctx->data[i] = 0x80000000; break; case 1: ctx->data[i] = (d[0] << 24) | 0x800000; break; case 2: ctx->data[i] = (d[0] << 24) | (d[1] << 16) | 0x8000; break; case 3: ctx->data[i] = (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | 0x80; break; } } } void SM3_Final(unsigned char *md, SM3_CTX *ctx) { if(ctx->num == 0) { memset(ctx->data, 0, 64); ctx->data[0] = 0x80000000; ctx->data[14] = ctx->Nh; ctx->data[15] = ctx->Nl; } else { if(ctx->num <= SM3_LAST_BLOCK) { ctx->data[14] = ctx->Nh; ctx->data[15] = ctx->Nl; } else { sm3_block(ctx); memset(ctx->data, 0, 56); ctx->data[14] = ctx->Nh; ctx->data[15] = ctx->Nl; } } sm3_block(ctx); nl2c(ctx->h[0], md); nl2c(ctx->h[1], md); nl2c(ctx->h[2], md); nl2c(ctx->h[3], md); nl2c(ctx->h[4], md); nl2c(ctx->h[5], md); nl2c(ctx->h[6], md); nl2c(ctx->h[7], md); } unsigned char *sm3(const unsigned char *d, unsigned int n, unsigned char *md) { SM3_CTX ctx; SM3_Init(&ctx); SM3_Update(&ctx, d, n); SM3_Final(md, &ctx); memset(&ctx, 0, sizeof(ctx)); return(md); }

makefile文件:

############################################################################
#makefile
############################################################################

#**************************************************************************** # Cross complie path #**************************************************************************** #GCC_PATH=D:\msysgit\mingw #CHAIN_ROOT=/home/yang/imax283/ctools/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin #CROSS_COMPILE=$(CHAIN_ROOT)/arm-none-linux-gnueabi- #CHAIN_ROOT= /home/yang/b503/ctools/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin #CROSS_COMPILE=$(CHAIN_ROOT)/arm-linux-gnueabihf- CROSS_COMPILE = CC := $(CROSS_COMPILE)gcc CXX := $(CROSS_COMPILE)g++ AS := $(CROSS_COMPILE)as AR := $(CROSS_COMPILE)ar LD := $(CROSS_COMPILE)ld RANLIB := $(CROSS_COMPILE)ranlib OBJDUMP:= $(CROSS_COMPILE)objdump OBJCOPY:= $(CROSS_COMPILE)objcopy STRIP := $(CROSS_COMPILE)strip #**************************************************************************** # Flags #**************************************************************************** CFLAGS= LDSCRIPT= -L./ -lsm2 LDFLAGS= #**************************************************************************** # Source files #**************************************************************************** SRC_C=$(shell find . -name "*.c") OBJ_C=$(patsubst %.c, %.o, $(SRC_C)) SRCS := $(SRC_C) $(SRC_C) OBJS := $(OBJ_C) #**************************************************************************** # Targets of the build #**************************************************************************** TARGET := test .PHONY: clean all: prebuild $(TARGET) #**************************************************************************** # TARGET #**************************************************************************** prebuild: @echo Building exe... $(TARGET) : $(OBJS) @echo Generating exe... $(CC) -o $(TARGET) $(OBJS) $(LDSCRIPT) @echo OK! %.o : %.c $(CC) -c $(CFLAGS) $< -o $@ clean: @echo The following files: rm -f $(TARGET) *.so find . -name "*.[od]" |xargs rm @echo Removed!

测试结果:

 

 

 

 

 

 

本文参与腾讯云自媒体分享计划,欢迎正在阅


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM