SM9算法C++实现系列目录:
基于JPBC的SM9算法的java实现与测试
国密SM9算法C++实现之0:源码下载地址
国密SM9算法C++实现之一:算法简介
国密SM9算法C++实现之二:测试工具
国密SM9算法C++实现之三:椭圆曲线接口、参数初始化
国密SM9算法C++实现之四:基本功能函数与KGC接口的实现
国密SM9算法C++实现之五:签名验签算法
国密SM9算法C++实现之六:密钥封装解封算法
国密SM9算法C++实现之七:加密解密算法
国密SM9算法C++实现之八:密钥交换算法
国密SM9算法C++实现之九:算法功能与测试例子
实现完KGC部分后,可以开始实现SM9算法部分。本篇描述签名验签算法的实现。
SM9标准文档中描述的签名算法流程如下所示:
根据算法描述,定义接口函数:
/**
* 签名
*
* @param masterPublicKey 签名主公钥
* @param prikey 用户签名私钥
* @param data 待签数据
* @return 签名值
* @throw std::exception SM9_ERROR_NOT_INIT | SM9_ERROR_CALC_RATE
*/
static Signature sign(const string& masterPublicKey, const string& prikey, const string& data);
SM9签名结果包括h和S两个部分,对此,也简单将其封装为一个类。
#ifndef YY_SM9_SIGNATURE_INCLUDE_H__
#define YY_SM9_SIGNATURE_INCLUDE_H__
#pragma once
#include
using namespace std;
/**
* 签名值.
* @author YaoYuan
*/
class Signature {
public:
Signature() {}
Signature(const string& h, const string& s) {
mH = h;
mS = s;
}
~Signature() {}
public:
string getH() const { return mH; }
string getS() const { return mS; }
private:
string mH;
string mS;
};
#endif
按照签名流程,实现签名算法:
Signature SM9::sign(const string& masterPublicKey, const string& prikey, const string& data)
{
Signature signature;
bool hasException = true;
string h, s, sw;
ecn2 Ppubs;
epoint* dsa = NULL;
epoint* S = NULL;
ZZN12 g;
ZZN12 w;
big h2 = NULL;
big r = NULL;
big l = NULL;
big tmp = NULL;
big zero = NULL;
#ifdef SELF_CHECK
string gHex, rHex, wHex, h2Hex;
#endif
if( !mIsInit ) {
mErrorNum = SM9_ERROR_NOT_INIT;
throw exception(getErrorMsg().c_str());
}
Parameters::init_ecn2(Ppubs);
Parameters::init_big(h2);
Parameters::init_big(r);
Parameters::init_big(l);
Parameters::init_big(tmp);
Parameters::init_big(zero);
Parameters::init_epoint(dsa);
Parameters::init_epoint(S);
// Step1 : g = e(P1, Ppub-s)
Parameters::cin_ecn2_byte128(Ppubs, masterPublicKey.c_str());
if( !ZZN12::calcRatePairing(g, Ppubs, Parameters::param_P1, Parameters::param_t, Parameters::norm_X) ) {
mErrorNum = SM9_ERROR_CALC_RATE;
goto END;
}
#ifdef SELF_CHECK
gHex = YY::YHex::bin2Hex(g.toByteArray());
#endif
while( true ) {
#ifdef SELF_CHECK
rHex = YY::YHex::hex2bin("033C8616B06704813203DFD00965022ED15975C662337AED648835DC4B1CBE");
Parameters::cin_big(r, rHex.c_str(), rHex.length());
#else
// Step2: generate r
bigrand(Parameters::param_N, r);
#endif
// Step3 : calculate w=g^r
w = g.pow(r);
sw = w.toByteArray();
#ifdef SELF_CHECK
wHex = YY::YHex::bin2Hex(sw);
#endif
// Step4 : calculate h=H2(M||w,N)
h = KGC::H2(data, sw);
Parameters::cin_big(h2, h.c_str(), h.length());
#ifdef SELF_CHECK
h2Hex = YY::YHex::bin2Hex(h);
#endif
// Step5 : l=(r-h)mod N
subtract(r, h2, l);
divide(l, Parameters::param_N, tmp);
while( mr_compare(l, zero) < 0 )
add(l, Parameters::param_N, l);
if( mr_compare(l, zero) != 0 )
break;
}
// Step6 : S=[l]dSA=(xS,yS)
Parameters::cin_epoint(dsa, prikey.c_str());
ecurve_mult(l, dsa, S);
s = Parameters::cout_epoint(S);
// Step7 : signature=(h,s)
signature = Signature(h, s);
hasException = false;
END:
Parameters::release_epoint(dsa);
Parameters::release_epoint(S);
Parameters::release_ecn2(Ppubs);
Parameters::release_big(h2);
Parameters::release_big(r);
Parameters::release_big(l);
Parameters::release_big(tmp);
Parameters::release_big(zero);
if( hasException ) {
throw exception(getErrorMsg().c_str());
}
return signature;
}
根据算法描述,定义接口函数:
/**
* 验签
*
* @param masterPublicKey 签名主公钥
* @param prikey 用户ID
* @param signature 签名值
* @param data 待签数据
* @return true-验签成功;false-验签失败
* @throw std::exception SM9_ERROR_NOT_INIT | SM9_ERROR_CALC_RATE |
* SM9_ERROR_VERIFY_H_OUTRANGE | SM9_ERROR_VERIFY_S_NOT_ON_G1 | SM9_ERROR_VERIFY_H_VERIFY_FAILED
*/
static bool verify(const string& masterPublicKey, const string& id, const Signature& signature, const string& data);
接口中没有必要提供hid,对于验签算法来说,这是确定的。
bool SM9::verify(const string& masterPublicKey, const string& id, const Signature& signature, const string& data)
{
bool result = false;
bool hasException = true;
big NSub1 = NULL;
big one = NULL;
big h = NULL;
epoint* S = NULL;
ecn2 Ppubs;
ecn2 P;
ZZN12 g;
ZZN12 t;
ZZN12 u;
ZZN12 w;
big h1 = NULL;
string sH1, sH2, sw, sH, sS;
if( !mIsInit ) {
mErrorNum = SM9_ERROR_NOT_INIT;
throw exception(getErrorMsg().c_str());
}
sH = signature.getH();
sS = signature.getS();
#ifdef SELF_CHECK
string gHex, rHex, h1Hex, tHex, pHex, uHex, wHex;
#endif
Parameters::init_big(NSub1);
Parameters::init_big(one);
Parameters::init_big(h);
Parameters::init_epoint(S);
Parameters::init_ecn2(Ppubs);
Parameters::init_ecn2(P);
Parameters::init_big(h1);
// Step1 : check if h in the range [1, N-1]
decr(Parameters::param_N, 1, NSub1);
convert(1, one);
Parameters::cin_big(h, sH.c_str(), sH.length());
if( (mr_compare(h, one) < 0) | (mr_compare(h, NSub1) > 0) ) {
mErrorNum = SM9_ERROR_VERIFY_H_OUTRANGE;
goto END;
}
// Step2 : check if S is on G1
Parameters::cin_epoint(S, sS.c_str());
if( !Parameters::isPointOnG1(S) ) {
mErrorNum = SM9_ERROR_VERIFY_S_NOT_ON_G1;
goto END;
}
// Step3 : g = e(P1, Ppub-s)
Parameters::cin_ecn2_byte128(Ppubs, masterPublicKey.c_str());
if( !ZZN12::calcRatePairing(g, Ppubs, Parameters::param_P1, Parameters::param_t, Parameters::norm_X) ) {
mErrorNum = SM9_ERROR_CALC_RATE;
goto END;
}
#ifdef SELF_CHECK
gHex = YY::YHex::bin2Hex(g.toByteArray());
#endif
// Step4 : calculate t=g^h
t = g.pow(h);
#ifdef SELF_CHECK
tHex = YY::YHex::bin2Hex(t.toByteArray());
#endif
// Step5 : calculate h1=H1(IDA||hid,N)
sH1 = KGC::H1(id, HID_SIGN);
Parameters::cin_big(h1, sH1.c_str(), sH1.length());
#ifdef SELF_CHECK
h1Hex = YY::YHex::bin2Hex(sH1);
#endif
// Step6 : P=[h1]P2+Ppubs
ecn2_copy(&Parameters::param_P2, &P);
ecn2_mul(h1, &P);
ecn2_add(&Ppubs, &P);
#ifdef SELF_CHECK
pHex = YY::YHex::bin2Hex(Parameters::cout_ecn2(P));
#endif
// Step7 : u=e(S,P)
if( !ZZN12::calcRatePairing(u, P, S, Parameters::param_t, Parameters::norm_X) ) {
mErrorNum = SM9_ERROR_CALC_RATE;
goto END;
}
#ifdef SELF_CHECK
uHex = YY::YHex::bin2Hex(u.toByteArray());
#endif
// Step8 : w=u*t
w = u.mul(t);
sw = w.toByteArray();
#ifdef SELF_CHECK
wHex = YY::YHex::bin2Hex(sw);
#endif
// Step9 : h2=H2(M||w,N)
sH2 = KGC::H2(data, sw);
if( sH2.compare(sH) == 0 ) {
result = true;
} else {
mErrorNum = SM9_ERROR_VERIFY_H_VERIFY_FAILED;
}
hasException = false;
END:
Parameters::release_big(NSub1);
Parameters::release_big(one);
Parameters::release_big(h);
Parameters::release_epoint(S);
Parameters::release_ecn2(Ppubs);
Parameters::release_ecn2(P);
Parameters::release_big(h1);
if( hasException ) {
throw exception(getErrorMsg().c_str());
}
return result;
}
由于验签函数返回类型是bool,因此验签失败后,可以通过getErrorMsg获取错误信息。