SM2橢圓曲線公鑰密碼演算法,完整c程式碼,前人栽樹,後人乘涼
阿新 • • 發佈:2019-01-06
某電信安資訊保安數學基礎實驗要求實現SM2橢圓曲線公鑰密碼演算法
這是基於mircal庫實現的,沒有mircal庫的下載我以前的部落格發的檔案,根據教程在vs上搭建。
一共四個檔案 SM2.c SM2.h SM3.c SM3.h
SM2.c
#include <stdio.h> #include <stdlib.h> #include <memory.h> #include <time.h> #include<string.h> #include "sm2.h" void Buf_Out(unsigned char *buf, int buflen) //每32項為一行輸出buf { int i; printf("\n"); for (i = 0; i < buflen; i++) { if (i % 32 != 31) printf("%02x", buf[i]); else printf("%02x\n", buf[i]); } printf("\n"); return; } #define SEED_CONST 0x1BD8C95A struct QXCS { char *p;//橢圓曲線的引數 char *a; char *b; char *n; //G的階 char *x; //g=(x,y) char *y; }; struct QXCS pdf = {"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF","FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93","FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7","BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", }; //接收方B的私鑰和公鑰產生 void sm2_keygen(unsigned char *wx, int *wxlen, unsigned char *wy, int *wylen,unsigned char *privkey, int *privkeylen) { struct QXCS *cfig = &pdf; epoint *g,*pB; big a,b,p,n,x,y,key1; miracl *mip = mirsys(20,0); //初始化大數系統 mip->IOBASE = 16; //輸入為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); //將大數字符串轉換成大數,這裡是16進位制的字串轉換大數 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(); pB = epoint_init(); epoint_set(x,y,0,g); //g=(x,y)為基點G //產生私鑰 irand(time(NULL)+SEED_CONST); //初始化種子 bigrand(n,key1); //生成隨機數key1 ecurve_mult(key1,g,pB); //pB=key1*g epoint_get(pB,x,y); //取pB上的點(x,y)x和y即為公鑰 *wxlen = big_to_bytes(0, x, (char *)wx, FALSE); //公鑰寫入wx,長度wxlen *wylen = big_to_bytes(0, y, (char *)wy, FALSE); *privkeylen = big_to_bytes(0, key1, (char *)privkey, FALSE); mirkill(key1); mirkill(p); mirkill(a); mirkill(b); mirkill(n); mirkill(x); mirkill(y); epoint_free(g); epoint_free(pB); mirexit(); } int kdf(unsigned char *zl, unsigned char *zr, int klen, unsigned char *kbuf) //zl,zr為(x2,y2) { unsigned char buf[70]; unsigned char digest[32]; unsigned int ct = 0x00000001; int i, m, n; unsigned char *p; memcpy(buf, zl, 32); //把x2,y2傳入buf memcpy(buf+32, zr, 32); m = klen / 32; n = klen % 32; p = kbuf; for(i = 0; i < m; i++) //buf 64-70 { buf[64] = (ct >> 24) & 0xFF; //ct前8位 buf[65] = (ct >> 16) & 0xFF; buf[66] = (ct >> 8) & 0xFF; buf[67] = ct & 0xFF; sm3(buf, 68, p); //sm3後結果放在p中 p += 32; 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); } memcpy(p, digest, n); for(i = 0; i < klen; i++) { if(kbuf[i] != 0) //kbuf中有i+1個0 break; } if(i < klen) return 1; //kbuf(t)中的bit全是0, kdf判斷通過,執行下一步C2=M異或t else return 0; } int A_encrypt(char *msg,int msglen, char *wx,int wxlen, char *wy,int wylen, char *outmsg)//wx,wy公鑰的x,y的座標 { struct QXCS *cfig = &pdf; big x2, y2, x1, y1, k; big a,b,p,n,x,y; epoint *g, *w, *pb, *c1,*kpb; 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; //讀入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); x1=mirvar(0); y1=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); //g=(x,y) ecurve_init(a,b,p,MR_PROJECTIVE); //橢圓曲線方程初始化 y2 =x3 + Ax + B mod p g=epoint_init(); //點座標初始化 pb=epoint_init(); kpb = epoint_init(); c1= epoint_init(); w= epoint_init(); epoint_set(x,y,0,g); //點座標設定 g=(x,y),現在無值 bytes_to_big(wxlen,(char *)wx,x); //把公鑰wx和wy賦值給x,y bytes_to_big(wylen,(char *)wy,y); epoint_set(x,y,0,pb); //=(x1,y1) //選擇小於n的隨機數k irand(time(NULL)+SEED_CONST); sm2_encrypt_again: do { bigrand(n, k); } while(k->len == 0); ecurve_mult(k, g, c1); // 點乘c1=k*g(第三個=第一個*第二個) epoint_get(c1, x1, y1); //從c1裡面得到x1,y1 big_to_bytes(32, x1, (char *)outmsg, TRUE); big_to_bytes(32, y1, (char *)outmsg+32, TRUE); if(point_at_infinity(pb)) //如果s是無窮點,返回1,報錯退出 goto exit_sm2_encrypt; ecurve_mult(k, pb, kpb); //kpb=K*pb epoint_get(kpb, x2, y2); //從kpb得到x2,y2 big_to_bytes(32, x2, (char *)zl, TRUE); //把大數x2,y2變為位元組放入zl,zr big_to_bytes(32, y2, (char *)zr, TRUE); //t=KDF(x2||y2,klen) if (kdf(zl, zr, msglen, outmsg+64) == 0) //如果kdf返回的值為0,從頭開始重新計算 goto sm2_encrypt_again; for(i = 0; i < msglen; i++) { outmsg[64+i] ^= msg[i]; } //tmp=x2 || M| |y2 相連 memcpy(tmp, zl, 32); memcpy(tmp+32, msg, msglen); memcpy(tmp+32+msglen, zr, 32); //C3=outmsg=hash(SM3)(tmp) sm3(tmp, 64+msglen, &outmsg[64+msglen]); ret = msglen+64+32; exit_sm2_encrypt: //退出釋放記憶體 mirkill(x2); mirkill(y2); mirkill(x1); mirkill(y1); mirkill(k); mirkill(a); mirkill(b); mirkill(p); mirkill(n); mirkill(x); mirkill(y); epoint_free(g); //釋放點記憶體 epoint_free(w); epoint_free(pb); epoint_free(kpb); mirexit(); free(tmp); return ret; } //B收到密文後開始解密運算 int decrypt(char *msg,int msglen, char *privkey, int privkeylen,char *outmsg) { struct QXCS *cfig = &pdf; big x2, y2, c, k; big a,b,p,n,x,y,key1,dB; epoint *g,*C1,*dBC1; 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); dB= mirvar(0); bytes_to_big(privkeylen,(char *)privkey,dB); 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); //初始化橢圓曲線 y2=x3+Ax+B (mod p) g = epoint_init(); dBC1 = epoint_init(); C1 = epoint_init(); bytes_to_big(32, (char *)msg, x); //從msg中分別取出32位放入x和y bytes_to_big(32, (char *)msg+32, y); if(!epoint_set(x,y,0,C1)) //初始化點C1=(x,y)點C1=(x,y)是否在橢圓曲線 上 goto exit_sm2_decrypt; if(point_at_infinity(C1)) //如果s(test)是無窮遠點,報錯並退出 goto exit_sm2_decrypt; ecurve_mult(dB, C1, dBC1); //dBC1=dB*c1 epoint_get(dBC1, x2, y2); //從dBC1中讀取x2,y2 big_to_bytes(32, x2, (char *)zl, TRUE); big_to_bytes(32, y2, (char *)zr, TRUE); if (kdf(zl, zr, msglen, outmsg) == 0) //判斷:t=kdf不是全0,才繼續 goto exit_sm2_decrypt; for(i = 0; i < msglen; i++) //M'(outmsg)=C2 ^ t(outmsg) { outmsg[i] ^= msg[i+64];//密文從65位開始為c2 } memcpy(tmp, zl, 32); memcpy(tmp+32, outmsg, msglen); memcpy(tmp+32+msglen, zr, 32); sm3(tmp, 64+msglen, c3); if(memcmp(c3, msg+64+msglen, 32) != 0)//判斷u=c3則繼續 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); mirkill(dB); epoint_free(g); epoint_free(dBC1); mirexit(); free(tmp); return ret; } int main() { unsigned char dB[32]; //存放私鑰 unsigned char xB[32]; //存放公鑰pb(x,y) unsigned char yB[32]; unsigned char tx[256]="0"; unsigned char etx[256] ; unsigned char mtx[256] ="0"; int j; struct QXCS *cfig = &pdf; printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<SM2橢圓曲線公鑰密碼>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" ); printf("由pdf給出的引數:\n\tp:%s\n\ta:%s\n\tb:%s\n\tn:%s\n\tG(x):%s\n\tG(y):%s\n", cfig->p, cfig->a, cfig->b, cfig->n, cfig->x, cfig->y); FILE *fp; fopen_s(&fp,"7.txt", "r+"); fgets(tx, 200, fp); fclose(fp); printf("\n檔案中明文為:\n\t%s\n", tx); int msglen = strlen(tx); int wxlen, wylen, privkeylen; sm2_keygen(xB, &wxlen, yB, &wylen, dB, &privkeylen); //公鑰(xB,yB)dB私鑰 空值進入,產生公私鑰 printf("\n\t公鑰x座標:"); for (j = 0; j< wxlen; j++) printf("%02x", xB[j]); printf("\n\t公鑰y座標:"); for (j = 0; j < wylen; j++) printf("%02x", yB[j]); printf("\n\t私鑰:"); for (j = 0; j< privkeylen; j++) printf("%02x", dB[j]); printf("\n"); A_encrypt(tx,msglen,xB,32,yB,32,etx); //傳入明文和公鑰xb,yb printf("加密結果: "); Buf_Out(etx, 64+msglen+32); decrypt(etx,64+msglen+32,dB,32,mtx); //傳入密文與私鑰pb if(decrypt(etx,64+msglen+32,dB,32,mtx) < 0) printf("sm2_decrypt error!\n"); else{ printf("\n解密結果: "); Buf_Out(mtx, msglen); printf("解密出的明文為:\n\t%s\n", mtx); } return 0; }
SM2.h
#ifndef __SM2_HEADER_2015_12_28__ #define __SM2_HEADER_2015_12_28__ #include "sm3.h" #include "miracl.h" #ifdef __cplusplus extern "C"{ #endif int sm3_e(unsigned char *userid, int userid_len, unsigned char *xa, int xa_len, unsigned char *ya, int ya_len, unsigned char *msg, int msg_len, unsigned char *e); /* 功能:根據使用者ID及公鑰,求用於簽名或驗籤的訊息HASH值 [輸入] userid: 使用者ID [輸入] userid_len: userid的位元組數 [輸入] xa: 公鑰的X座標 [輸入] xa_len: xa的位元組數 [輸入] ya: 公鑰的Y座標 [輸入] ya_len: ya的位元組數 [輸入] msg:要簽名的訊息 [輸入] msg_len: msg的位元組數 [輸出] e:32位元組,用於簽名或驗籤 返回值: -1:記憶體不足 0:成功 */ void sm2_keygen(unsigned char *wx,int *wxlen, unsigned char *wy,int *wylen,unsigned char *privkey, int *privkeylen); /* 功能:生成SM2公私鑰對 [輸出] wx: 公鑰的X座標,不足32位元組在前面加0x00 [輸出] wxlen: wx的位元組數,32 [輸出] wy: 公鑰的Y座標,不足32位元組在前面加0x00 [輸出] wylen: wy的位元組數,32 [輸出] privkey:私鑰,不足32位元組在前面加0x00 [輸出] privkeylen: privkey的位元組數,32 */ void sm2_sign(unsigned char *hash,int hashlen,unsigned char *privkey,int privkeylen,unsigned char *cr,int *rlen,unsigned char *cs,int *slen); /* 功能:SM2簽名 [輸入] hash: sm3_e()的結果 [輸入] hashlen: hash的位元組數,應為32 [輸入] privkey: 私鑰 [輸入] privkeylen: privkeylen的位元組數 [輸出] cr: 簽名結果的第一部分,不足32位元組在前面加0x00。 [輸出] rlen:cr的位元組數,32 [輸出] cs: 簽名結果的第二部分,不足32位元組在前面加0x00。 [輸出] slen:cs的位元組數,32 */ int sm2_verify(unsigned char *hash,int hashlen,unsigned char *cr,int rlen,unsigned char *cs,int slen, unsigned char *wx,int wxlen, unsigned char *wy,int wylen); /* 功能:驗證SM2簽名 [輸入] hash: sm3_e()的結果 [輸入] hashlen: hash的位元組數,應為32 [輸入] cr: 簽名結果的第一部分 [輸入] rlen:cr的位元組數 [輸入] cs: 簽名結果的第二部分。 [輸入] slen:cs的位元組數 [輸入] wx: 公鑰的X座標 [輸入] wxlen: wx的位元組數,不超過32位元組 [輸入] wy: 公鑰的Y座標 [輸入] wylen: wy的位元組數,不超過32位元組 返回值: 0:驗證失敗 1:驗證通過 */ int A_encrypt(char *msg,int msglen, char *wx,int wxlen, char *wy,int wylen,char *outmsg); /* 功能:用SM2公鑰加密資料。加密結果比輸入資料多96位元組! [輸入] msg 要加密的資料 [輸入] msglen:msg的位元組數 [輸入] wx: 公鑰的X座標 [輸入] wxlen: wx的位元組數,不超過32位元組 [輸入] wy: 公鑰的Y座標 [輸入] wylen: wy的位元組數,不超過32位元組 [輸出] outmsg: 加密結果,比輸入資料多96位元組!,C1(64位元組)和C3(32位元組)保留前導0x00 返回值: -1: 加密失敗 msglen+96: 加密成功 */ int decrypt(char *msg,int msglen, char *privkey, int privkeylen, char *outmsg); /* 功能:用SM2私鑰解密資料。解密結果比輸入資料少96位元組! [輸入] msg 要解密的資料,是sm2_encrypt()加密的結果,不少於96位元組。 [輸入] msglen:msg的位元組數 [輸入] privkey: 私鑰 [輸入] privkeylen: privkeylen的位元組數 [輸出] outmsg: 解密結果,比輸入資料少96位元組! 返回值: -1: 解密失敗 msglen-96: 解密成功 */ void sm2_keyagreement_a1_3(unsigned char *kx1, int *kx1len, unsigned char *ky1, int *ky1len, unsigned char *ra, int *ralen ); /* 功能:金鑰協商的發起方呼叫此函式產生一對臨時公鑰(kx1, ky1)和相應的隨機數。公鑰傳送給對方,隨機數ra自己儲存。 [輸出] kx1: 公鑰的X座標,不足32位元組在前面加0x00 [輸出] kx1len:kx1的位元組數,32 [輸出] ky1: 公鑰的Y座標,不足32位元組在前面加0x00 [輸出] ky1len:ky1的位元組數,32 [輸出] ra: 隨機數,不足32位元組在前面加0x00 [輸出] ralen: ra的位元組數,32 返回值:無 */ int sm2_keyagreement_b1_9( unsigned char *kx1, int kx1len, unsigned char *ky1, int ky1len, unsigned char *pax, int paxlen, unsigned char *pay, int paylen, unsigned char *private_b, int private_b_len, unsigned char *pbx, int pbxlen, unsigned char *pby, int pbylen, unsigned char *ida, int idalen, unsigned char *idb, int idblen, unsigned int kblen, unsigned char *kbbuf, unsigned char *kx2, int *kx2len, unsigned char *ky2, int *ky2len, unsigned char *xv, int *xvlen, unsigned char *yv, int *yvlen, unsigned char *sb ); /* 功能:金鑰協商的接收方呼叫此函式協商出金鑰kbbuf,同時產生一對臨時公鑰(kx2, ky2)以及(xv, yv)、sb。(kx2, ky2)和sb傳送給對方,kbbuf和(xv, yv)自己儲存。 說明: [輸入] (kx1, ky1)是發起方產生的臨時公鑰 [輸入] (pax, pay)是發起方的公鑰 [輸入] private_b是接收方的私鑰 [輸入] (pbx, pby)是接收方的公鑰 [輸入] ida是發起方的使用者標識 [輸入] idb是接收方的使用者標識 [輸入] kblen是要約定的金鑰位元組數 [輸出] kbbuf是協商金鑰輸出緩衝區 [輸出] (kx2, ky2)是接收方產生的臨時公鑰,不足32位元組在前面加0x00 [輸出] (xv, yv)是接收方產生的中間結果,自己儲存,用於驗證協商的正確性。,不足32位元組在前面加0x00。如果(xv, yv)=NULL,則不輸出。 [輸出] sb是接收方產生的32位元組的HASH值,要傳送給發起方,用於驗證協商的正確性。如果為sb=NULL,則不輸出。 返回值:0-失敗 1-成功 */ int sm2_keyagreement_a4_10( unsigned char *kx1, int kx1len, unsigned char *ky1, int ky1len, unsigned char *pax, int paxlen, unsigned char *pay, int paylen, unsigned char *private_a, int private_a_len, unsigned char *pbx, int pbxlen, unsigned char *pby, int pbylen, unsigned char *ida, int idalen, unsigned char *idb, int idblen, unsigned char *kx2, int kx2len, unsigned char *ky2, int ky2len, unsigned char *ra, int ralen, unsigned int kalen, unsigned char *kabuf, unsigned char *s1, unsigned char *sa ); /* 功能:金鑰協商的發起方呼叫此函式協商出金鑰kabuf,同時產生s1和sa。s1和kabuf自己儲存,sa傳送給接收方,用於確認協商過程的正確性。 說明: [輸入] (kx1, ky1)是發起方產生的臨時公鑰 [輸入] (pax, pay)是發起方的公鑰 [輸入] private_a是發起方的私鑰 [輸入] (pbx, pby)是接收方的公鑰 [輸入] ida是發起方的使用者標識 [輸入] idb是接收方的使用者標識 [輸入] (kx2, ky2)是接收方產生的臨時公鑰 [輸入] ra是發起方呼叫sm2_keyagreement_a1_3產生的隨機數 [輸入] kalen是要約定的金鑰位元組數 [輸出] kabuf是協商金鑰輸出緩衝區 [輸出] s1和sa是發起方產生的32位元組的HASH值,s1自己儲存(應等於sb),sa要傳送給接收方,用於驗證協商的正確性。如果s1和sa為NULL,則不輸出。 返回值:0-失敗 1-成功 */ void sm2_keyagreement_b10( unsigned char *pax, int paxlen, unsigned char *pay, int paylen, unsigned char *pbx, int pbxlen, unsigned char *pby, int pbylen, unsigned char *kx1, int kx1len, unsigned char *ky1, int ky1len, unsigned char *kx2, int kx2len, unsigned char *ky2, int ky2len, unsigned char *xv, int xvlen, unsigned char *yv, int yvlen, unsigned char *ida, int idalen, unsigned char *idb, int idblen, unsigned char *s2 ); /* 功能:金鑰協商的接收方呼叫此函式產生s2,用於驗證協商過程的正確性。 說明: [輸入] (pax, pay)是發起方的公鑰 [輸入] (pbx, pby)是接收方的公鑰 [輸入] (kx1, ky1)是發起方產生的臨時公鑰 [輸入] (kx2, ky2)是接收方產生的臨時公鑰 [輸入] (xv, yv)是接收方產生的中間結果 [輸入] ida是發起方的使用者標識 [輸入] idb是接收方的使用者標識 [輸出] s2是接收方產生的32位元組的HASH值,應等於sa。 返回值:無 */ #ifdef __cplusplus } #endif #endif
SM3.c
#include <string.h> #include <stdlib.h> #include <stdio.h> #include <time.h> #include "sm3.h" void sm3_block(SM3_CTX *ctx) { int j, k; unsigned long t; unsigned long ss1, ss2, tt1, tt2; 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); } #if 0 int main() { unsigned char data[] = "abc"; /*66c7f0f4 62eeedd9 d1f2d46b dc10e4e2 4167c487 5cf2f7a2 297da02b 8f4ba8e0*/ unsigned char data1[] = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"; /*debe9ff9 2275b8a1 38604889 c18e5a4d 6fdb70e5 387e5765 293dcba3 9c0c5732*/ unsigned char md[SM3_DIGEST_LENGTH]; clock_t start,end; double tt; int j; memset(md, 0, sizeof(md)); sm3(data, 3, md); #if DEBUG_SM3 PrintBuf(md, 32); #endif memset(md, 0, sizeof(md)); sm3(data1, 64, md); #if DEBUG_SM3 PrintBuf(md, 32); #endif start = clock(); for(j=0;j<1000000;j++) { sm3(data1, 55, md); } end = clock(); tt = (double)(end-start)/CLOCKS_PER_SEC; printf("speed:%lfMbps\n", (double)512/tt); return 0; } #endif
SM3.h
#ifndef __SM3_HEADER__
#define __SM3_HEADER__
#ifdef __cplusplus
extern "C"{
#endif
#define SM3_LBLOCK 16
#define SM3_CBLOCK 64
#define SM3_DIGEST_LENGTH 32
#define SM3_LAST_BLOCK 56
typedef struct SM3state_st
{
unsigned long h[8];
unsigned long Nl,Nh;
unsigned long data[SM3_LBLOCK];
unsigned int num;
} SM3_CTX;
void SM3_Init (SM3_CTX *ctx);
void SM3_Update(SM3_CTX *ctx, const void *data, unsigned int len);
void SM3_Final(unsigned char *md, SM3_CTX *ctx);
unsigned char *sm3(const unsigned char *d, unsigned int n, unsigned char *md);
/*
d: data
n: byte length
md: 32 bytes digest
*/
#ifdef __cplusplus
}
#endif
#endif
#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)))