简介
国密SM2算法并不仅仅是提供了新的曲线参数,而是在算法上对ECC进行了修改。
SM2的曲线使用了Weierstrass模型:
y
2
=
x
3
+
a
x
+
b
m
o
d
P
y^2=x^3+ax+b \mod P
y2=x3+ax+bmodP
推荐参数
p=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF
a=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC
b=28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93
n=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123
Gx=32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7
Gy=BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0
1. 前置条件
1.1 点到字符串的转换
椭圆曲线是关于x轴对称的,点和字节数据转换时,y坐标只需要获取/提供正负即可。
压缩
PC(Padding Char) = 02或03;
int nLsbY = epoint_get(epointC1, bigX, bigX);
if (0 == nLsbY)
{
PC = 2;
}
else // 1 == nLsbY
{
PC = 3;
}
S = PC || bigX;
未压缩
PC = 04
PC = 04;
S = PC || X1 || Y1;
混合形式
PC = 06或07
int nLsbY = epoint_get(epointC1, bigX, bigY);
if (0 == nLsbY)
{
PC = 6;
}
else // 1 == nLsbY
{
PC = 7;
}
S = PC || bigX || bigY;
1.2 密钥派生函数
int KDF(const uint8_t* pData
, uint32_t nData
, uint32_t nKeyBytesLen
, PFnHash pfnHash
, uint32_t nHash
, uint8_t* pOut )
{
int nRet = 0;
uint32_t nLoop = 0;
uint32_t zt = 1;
uint32_t i = 0;
uint8_t *pBuf = NULL;
uint32_t nBuf = nData + 4/*sizeof(zt)*/;
if (!pData || !pOut)
{
return 0;
}
// alloc memory
pBuf = (uint8_t *)calloc(nBuf, 1);
if(!pBuf) return 0;
memcpy(pBuf, pData, nData);
nLoop = (nKeyBytesLen + nHash - 1) / nHash; // upper(nKeyBytesLen/nHash)
for (i = 0; i < nLoop; ++i)
{
u32to8_big(&(pBuf[nData]), zt);
if (ERR_OK != pfnHash(pBuf, nBuf
, pOut + i * nHash, nHash))
{
break;
}
++zt;
}
if (i == nLoop)
{
nRet = nKeyBytesLen;
}
return nRet;
}
6. 加解密
加密流程
- 生成随机数k
- 计算点C1 = kG = (Xc1, Yc1)
- 大数库可能封装了这一步:公钥为Q, h为余因子,S=[h]Q ,若S是无穷远点,则报错并退出;
- kQ = (x2, y2)
- t=KDF(x2 ∥ y2, nMsg), 若t为全0比特串,则报错并退出
- C2 = Msg xor t
- C3 = Hash(x2 || Msg || y2)
- Cipher = C1 || C2 || C3,C1压缩方式任意。
官网加解密示例使用了未压缩的转换方式。
解密流程
- 从密文中取出C1,验证是否为曲线上的点;
- 点S=[h]C1,若S是无穷远点,则报错并退出;
- 私钥为d,dC1 = (x2, y2)
- t=KDF(x2 ∥ y2, nMsg),这一步nMsg = nCipher - nC1 - nHash
- 取出C2, Msg = C2 xor t
- 验证u = Hash(x2 ∥ Msg ∥ y2) == C3,
- 明文为Msg
实现
https://github.com/C0deStarr/CryptoImp/tree/main/pubkey/ecc
- sm2.h
- sm2.c
参考资料
国家密码管理局关于发布《SM2椭圆曲线公钥密码算法》公告(国密局公告第21号)_国家密码管理局 (sca.gov.cn)