一、椭圆曲线密码算法
椭圆曲线密码编码学(ECC)是一种理论性很强的学科。后来随着计算科学和密码学的发展,被应用到了公钥密码体制这个领域中。椭圆曲线密码体制最早是由Kobiliz和Millr于185年提出的,是迄今为止安全性最高的一种算法,它的安全性是基于有限域椭圆曲线离散对数(Eliptic Curve Discrete Logarithm Problem,ECDLP)的难解性,是目前公认的3种安全有效的公钥密码体制之一另外2种分别是基于大整数分解问题(nteger Factorization Problem,IFP)的公钥密码体制和基于有限域离散对数问题(Discrete Logarithm Problem,DLP)的公钥密码体制。ECDLP比DLP更难处理.这使得椭圆曲线密码体制采用较短的密钥就可以达到与有限域上使用较长的密钥所达的安全性。椭圆曲线的安全性除了依赖于ECC上离散对数的分解难度,还依赖于曲线的选择。因此建立椭圆曲线密码体制的首要问题就是产生可以抵御所有已有算法攻击的椭圆曲线。
SM2是国家密码管理局组织制定并提出的椭圆曲线密码算法标准。关于其具体算法内容及国标内容可以参考:在线预览|GB/T 32918.1-2016
二、密钥对生成大致流程
输入:一个有效的Fq(包含q个元素的有限域,q=p且p为大于3的素数或q=2^m)上椭圆系统参数的集合。
基于椭圆曲线的密码系统有7个主要域参数T=(q,a,b,FR,G,n,h):
q代表有限域GF(q),其中q为p或2m(p为素数),相应的有限域分别为素域和二进制域;
a,b是椭圆曲线方程的系数;
FR为曲线的方程,如素域GF(q)上的曲线方程为y^2=x^3+ax+b,二进制域GF(2^m)上的曲线方程为y^2+xy=x^3+a^2x+b;G为基点;
G为基点;
n为大素数并且等于基点G的阶6,椭圆曲线系统中最主要的参数是n,因此椭圆曲线的密钥长度就定义为n的长度;
h是n的余因子,其为一个小整数且h=#E(Fq)/n;
输出:与椭圆系统参数相关的密钥对(d,P),d为私钥,P为公钥
1)初始化椭圆系统
2)产生随机整数d∈[1,n-2]
3)以G为基点,计算P(Xp,Yp)=[d]G(椭圆曲线上点G的d倍点),可用多种方法如:加减法、滑动窗法等计算
4)输出(d,P),d为私钥,P为公钥
注:以上所有计算都可以借助库函数实现
三、代码实现
我采用的是C实现,使用的是miracl库
输入的参数可参考:
- struct FPECC
- {
- char* p;
- char* a;
- char* b;
- char* n; //G的阶
- char* x; //g=(x,y)
- char* y;
- };
-
- struct FPECC Ecc256 =
- {
- "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",
- "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
- "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
- "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
- "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
- "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0",
- };
若想使用其他参数可参考 http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=3EE2FD47B962578070541ED468497C5B中的附录C
- /**
- * @brief 生成SM2公私钥对
- * @param wx: 公钥的X坐标,不足32字节在前面加0x00
- * @param wxlen: wx的字节数,32
- * @param wy: 公钥的Y坐标,不足32字节在前面加0x00
- * @param wylen: wy的字节数,32
- * @param privkey: 私钥,不足32字节在前面加0x00
- * @param privkeylen: privkey的字节数,32
- * @retval void
- */
- void sm2_keygen(unsigned char* wx, int* wxlen, unsigned char* wy, int* wylen, unsigned char* privkey, int* privkeylen)
- {
- struct FPECC *cfig = &Ecc256;
- epoint* g, * pB;
- big a, b, p, n, x, y, key1;
- miracl* mip = mirsys(20, 0); //初始化大数系统
- mip->IOBASE = 16; //输入为16进制数改为大数
-
- p = mirvar(0); //将大数字符串转换成大数,这里是16进制的字符串转换大数
- 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、wy,长度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();
- }