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++实现之九:算法功能与测试例子
根据算法描述,定义接口函数:
/**
* 密钥封装
*
* @param masterPublicKey 加密主公钥
* @param prikey 用户ID
* @param klen 密钥字节长度
* @return 密钥封装值
* @throw std::exception SM9_ERROR_NOT_INIT | SM9_ERROR_CALC_RATE
*/
static KeyEncapsulation keyEncap(const string& masterPublicKey, const string& id, int klen);
SM9密钥封装结果包括密钥本身K和密钥密文C两个部分,对此,也简单将其封装为一个类。
#ifndef YY_SM9_KEYENCAP_INCLUDE_H__
#define YY_SM9_KEYENCAP_INCLUDE_H__
#pragma once
#include
using namespace std;
/**
* 密钥封装结果值类,包括密钥K和封装值C.
* @author YaoYuan
*/
class KeyEncapsulation {
public:
KeyEncapsulation() {}
KeyEncapsulation(const string& k, const string& c) {
mK = k;
mC = c;
}
~KeyEncapsulation() {}
public:
string getK() const { return mK; }
string getC() const { return mC; }
private:
string mK;
string mC;
};
#endif
按照密钥封装流程,实现密钥封装算法:
KeyEncapsulation SM9::keyEncap(const string& masterPublicKey, const string& id, int klen)
{
KeyEncapsulation keyEncapsulation;
bool hasException = true;
big h1 = NULL;
big r = NULL;
epoint *Ppube = NULL;
epoint *QB = NULL;
epoint *C = NULL;
ZZN12 g;
ZZN12 w;
string sC, sW, bufferZ, sK, hashH1;
#ifdef SELF_CHECK
string hashH1Hex, QBHex, rHex, CHex, gHex, wHex;
#endif
if( !mIsInit ) {
mErrorNum = SM9_ERROR_NOT_INIT;
throw exception(getErrorMsg().c_str());
}
Parameters::init_big(h1);
Parameters::init_epoint(Ppube);
Parameters::init_epoint(QB);
Parameters::init_epoint(C);
Parameters::init_big(r);
hashH1 = KGC::H1(id, HID_ENCRYPT);
Parameters::cin_big(h1, hashH1.c_str(), hashH1.length());
Parameters::cin_epoint(Ppube, masterPublicKey.c_str());
#ifdef SELF_CHECK
hashH1Hex = YY::YHex::bin2Hex(hashH1);
#endif
// Step1 : QB=[H1(IDB||hid, N)]P1+Ppub-e
ecurve_mult(h1, Parameters::param_P1, QB);
ecurve_add(Ppube, QB);
#ifdef SELF_CHECK
QBHex = YY::YHex::bin2hex(Parameters::cout_epoint(QB));
#endif
while( true ) {
#ifdef SELF_CHECK
rHex = YY::YHex::hex2bin("74015F8489C01EF4270456F9E6475BFB602BDE7F33FD482AB4E3684A6722");
Parameters::cin_big(r, rHex.c_str(), rHex.length());
#else
// Step2: generate r
bigrand(Parameters::param_N, r);
#endif
// Step3 : C=[r]QB
ecurve_mult(r, QB, C);
sC = Parameters::cout_epoint(C);
#ifdef SELF_CHECK
CHex = YY::YHex::bin2Hex(sC);
#endif
// Step4 : g=e(Ppub-e, P2)
if( !ZZN12::calcRatePairing(g, Parameters::param_P2, Ppube, Parameters::param_t, Parameters::norm_X) ) {
mErrorNum = SM9_ERROR_CALC_RATE;
goto END;
}
#ifdef SELF_CHECK
gHex = YY::YHex::bin2Hex(g.toByteArray());
#endif
// Step5 : calculate w=g^r
w = g.pow(r);
sW = w.toByteArray();
#ifdef SELF_CHECK
wHex = YY::YHex::bin2Hex(sW);
#endif
// Step6 : K = KDF(C || w || IDB, klen)
bufferZ.append(sC);
bufferZ.append(sW);
bufferZ.append(id);
sK = KGC::KDF(bufferZ, klen);
if( !isAllZero(sK) )
break;
}
// Step7 : output (K,C)
keyEncapsulation = KeyEncapsulation(sK, sC);
hasException = false;
END:
Parameters::release_big(h1);
Parameters::release_big(r);
Parameters::release_epoint(Ppube);
Parameters::release_epoint(QB);
Parameters::release_epoint(C);
if( hasException ) {
throw exception(getErrorMsg().c_str());
}
return keyEncapsulation;
}
根据算法描述,定义接口函数:
/**
* 密钥解封
*
* @param prikey 用户加密私钥
* @param C 密钥封装值中的C
* @param prikey 用户ID
* @param klen 密钥字节长度
* @return 密钥
* @throw std::exception SM9_ERROR_NOT_INIT | SM9_ERROR_CALC_RATE | SM9_ERROR_DECAP_C_NOT_ON_G1 | SM9_ERROR_DECAP_K_IS_ZERO
*/
static string keyDecap(const string& prikey, const string& C, const string& id, int klen);
需要注意的是,密钥解封时的密钥长度应该和密钥封装时的一致。
std::string SM9::keyDecap(const string& prikey, const string& C, const string& id, int klen)
{
bool hasException = true;
string sK, sKi, sW, bufferZ;
epoint* bC = NULL;
ecn2 de;
ZZN12 w;
#ifdef SELF_CHECK
string wHex;
#endif
if( !mIsInit ) {
mErrorNum = SM9_ERROR_NOT_INIT;
throw exception(getErrorMsg().c_str());
}
Parameters::init_epoint(bC);
Parameters::init_ecn2(de);
// Step1 : check if C is on G1
Parameters::cin_epoint(bC, C.c_str());
if( !Parameters::isPointOnG1(bC) ) {
mErrorNum = SM9_ERROR_DECAP_C_NOT_ON_G1;
goto END;
}
// Step2 : w=e(c,de)
Parameters::cin_ecn2_byte128(de, prikey.c_str());
if( !ZZN12::calcRatePairing(w, de, bC, Parameters::param_t, Parameters::norm_X) ) {
mErrorNum = SM9_ERROR_CALC_RATE;
goto END;
}
sW = w.toByteArray();
#ifdef SELF_CHECK
wHex = YY::YHex::bin2Hex(sW);
#endif
// Step3 : K=KDF(C||w||IDB, klen)
bufferZ.append(C);
bufferZ.append(sW);
bufferZ.append(id);
sKi = KGC::KDF(bufferZ, klen);
if( isAllZero(sKi) ) {
mErrorNum = SM9_ERROR_DECAP_K_IS_ZERO;
goto END;
}
// Step4 : output K
sK = sKi;
hasException = false;
END:
Parameters::release_epoint(bC);
Parameters::release_ecn2(de);
if( hasException ) {
throw exception(getErrorMsg().c_str());
}
return sK;
}