关键词:
某电信安信息安全数学基础实验要求实现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)))
sm2椭圆曲线公钥密码算法
...其中的原理 国家密码管理局于2010年12月17日发布了SM2椭圆曲线公钥密码算法,并要求为对现有基于RSA算法的电子认证系统、密钥管理系统、应用系统进行升级改造。关于算法标准,请参见《国家密码管理局公告(第21号)》... 查看详情
003国密算法【技术】
...非对称加密算法(公钥算法),加密强度为256位,是一种椭圆曲线算法。公钥密码学与其他密码学完全不同,使用这种方法的加密系统,不仅公开加密算法本身,也公开了加密用的密钥。公钥密码系统与只使用一个密钥的对称传... 查看详情
sm2国密ssl证书为https加密提速
...是我国自主设计的公钥密码算法。SM2基于更加安全先进的椭圆曲线密码机制,在国际标准的ECC椭圆曲线密码理论基础上进行改进而来,其加密强 查看详情
sm系列国密算法(转)
...应用领域(包括国家政务通、警务通等重要领域)。2SM2椭圆曲线公钥密码算法SM2算法就是ECC椭圆曲线密码机制,但在签名、密钥交换方面不同于ECDSA、ECDH等国际标准,而是采取了更为安全的机制。另外,SM2推荐了一条256位的曲... 查看详情
密码学系列-国密sm2为什么不支持恢复公钥(代码片段)
...,EOS之类的公链代码底层密码库替换成国密库,因为它们的椭圆曲线验签采用的都是recover模式,而非verify模式.verify模式:输入签名,消息摘要,公钥;输出是否是该公钥对应的私钥做的签名recover模式:输入签名,消息摘要,recoverid;输出签名... 查看详情
密码学系列-国密sm2为什么不支持恢复公钥(代码片段)
...,EOS之类的公链代码底层密码库替换成国密库,因为它们的椭圆曲线验签采用的都是recover模式,而非verify模式.verify模式:输入签名,消息摘要,公钥;输出是否是该公钥对应的私钥做的签名recover模式:输入签名,消息摘要,recoverid;输出签名... 查看详情
椭圆曲线密码学(代码片段)
椭圆曲线密码学是下一代的公钥密码学,它比之前的公钥密码学系统例如RSA和Diffe-Hellman在安全性方面有显著提高。椭圆曲线密码学是目前被广泛使用的最强大的密码学算法之一,但是真正理解其工作原理的开发者并不多... 查看详情
椭圆曲线密码学ecc
??椭圆曲线密码学(Ellipticcurvecryptography),简称ECC,是一种建立公开密钥加密的算法,也就是非对称加密。类似的还有RSA,ElGamal算法等。ECC被公认为在给定密钥长度下最安全的加密算法。比特币中的公私钥生成以及签名算法ECDSA... 查看详情
信息安全工程师笔记-国产密码算法(国密)概念
国产密码算法国产密码算法有SM1分组密码算法、SM2椭圆曲线公钥密码算法、SM3密码杂凑算法、SM4分组算法、SM9标识密码算法。算法名称算法特征描述SM1对称加密,分组长度和密钥长度都为128比特SM2非对称加密,用于公钥... 查看详情
2017-2018-220179216《网络攻防与实践》sm234算法
国密商用算法是指国密SM系列算法,包括基于椭圆曲线的非对称公钥密码SM2算法、密码杂凑SM3算法、分组密码SM4算法,还有只以IP核形式提供的非公开算法流程的对称密码SM1算法等。国密即国家密码局认定的国产密码算法。主要... 查看详情
libsecp256k1比特币密码算法开源库(代码片段)
2021SC@SDUSClibsecp256k1代码分析综述有限域GaloisField椭圆曲线EllipticCurves椭圆曲线几何加法椭圆曲线标量乘法从本篇开始我将开始分析libsecp256k1中的代码。本开源库可以实现:私钥经标量乘法生成公钥;私钥签名(ECDSA... 查看详情
密码学——公钥密码体系之背包算法1(代码片段)
...解难解性(RSA)离散对数难解性(ElGamal)椭圆曲线离散对数难解性(ECC)1.背包算法本次介绍的并不是以上三种类型的公钥密码 查看详情
centos7编译安装openssl1.1.1支持国密标准(代码片段)
OpenSSL项目新版本增加了中国SM2/SM3/SM4算法的支持:SM2椭圆曲线:https://github.com/openssl/openssl/pull/4793SM3哈希摘要:https://github.com/openssl/openssl/pull/4616SM4对称加密:https://github.com/openssl/openssl/pull/4552参考:中国×××制定的商业密码算法标准《G... 查看详情
国密算法介绍
...。2010年底,国家密码管理局公布了我国自主研制的“椭圆曲线公钥密码算法”(SM2算法)。为保障重要经济系统密码应用安全,国家密码管理局于2011年发布了《关于做好公钥密码算法升级工作的通知》,要求... 查看详情
国密算法介绍
...。2010年底,国家密码管理局公布了我国自主研制的“椭圆曲线公钥密码算法”(SM2算法)。为保障重要经济系统密码应用安全,国家密码管理局于2011年发布了《关于做好公钥密码算法升级工作的通知》,要求... 查看详情
算法2_非对称加密算法之ecdsa(椭圆曲线数字签名算法)(代码片段)
ECDSA(椭圆曲线数字签名算法)AES(高级加密标准):=>对称加密对业务数据进行加密,防止他人可以看见ECDSA(椭圆曲线数字签名算法):=>非对称加密算法(公钥和私钥)验证数据的真实性,防止业务数据被篡改SHA(安全哈希算法)... 查看详情
国密算法
...RSA2048位高,但运算速度快于RSA。国家密码管理局公布的公钥算法,其加密强度为256位SM3消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。SM4无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度... 查看详情
椭圆曲线算法:简单介绍(代码片段)
椭圆曲线首先:什么是椭圆曲线,WolframMathWorld提供了出色而完整的定义。但是对于我们的目标,椭圆曲线将简单表示为方程式所描述的点集:y^2=x^3+ax+b其中4a^3+27b^2!=0需要排除特殊曲线。上面的等式是椭圆曲线的Weierstrass范式。... 查看详情