国密SM9算法C++实现之五:签名验签算法

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++实现之九:算法功能与测试例子

国密SM9算法C++实现之五:签名验签算法

文章目录

  • 国密SM9算法C++实现之五:签名验签算法
    • @[toc]
    • 签名算法流程
      • 签名值
        • Signature.h
      • 签名算法实现
    • 验签算法流程
      • 验签算法实现

实现完KGC部分后,可以开始实现SM9算法部分。本篇描述签名验签算法的实现。

签名算法流程

SM9标准文档中描述的签名算法流程如下所示:

国密SM9算法C++实现之五:签名验签算法_第1张图片

其流程图为:
国密SM9算法C++实现之五:签名验签算法_第2张图片

根据算法描述,定义接口函数:

	/** 
	* 签名
	* 
	* @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两个部分,对此,也简单将其封装为一个类。

Signature.h


#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;
}

验签算法流程

SM9标准文档中描述的验签算法流程如下所示:
国密SM9算法C++实现之五:签名验签算法_第3张图片
其流程为:
国密SM9算法C++实现之五:签名验签算法_第4张图片

根据算法描述,定义接口函数:

	/**
	* 验签
	*
	* @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获取错误信息。

你可能感兴趣的:(程序设计)