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算法的各个部分了,整体总共分为2个类,KGC和SM9。
KGC类中实现主密钥对和用户私钥的生成;SM9类实现各个算法功能。
在上一篇中的Parameters中定义了一个SELF_CHECK宏,表示验证SM9文档第5部分中的测试数据,这在KGC和SM9类中会用到。
本篇文章描述KGC部分的接口实现。
首先,把SM9文档中描述的一些基本功能函数提取出来,放在Base类中,KGC和SM9类都继承于此类。
Base类中主要包括以下内容:
#ifndef YY_SM9_BASE_INCLUDE_H__
#define YY_SM9_BASE_INCLUDE_H__
#pragma once
#include
#include
#include "Errors.h"
using namespace std;
#define HID_SIGN 0x01
#define HID_KEYEXCHANGE 0x02
#define HID_ENCRYPT 0x03
/**
* 一个公共基类,提供SM9的KGC部分和算法部分的公用函数、错误处理,SM9参数的初始化和释放接口.
* @author YaoYuan
*/
class Base{
protected:
Base() {}
virtual ~Base() {}
public:
/**
* 初始化SM9环境.
* 在使用SM9之前需要调用此函数初始化SM9曲线参数.
* @return true-初始化成功;false-初始化失败. 初始化失败是错误码为 SM9_ERROR_INIT_G1BASEPOINT | SM9_ERROR_INIT_G2BASEPOINT
*/
static bool init();
/**
* 释放SM9环境.
* 在使用完SM9之后需要调用此函数释放SM9曲线参数.
*/
static void release() noexcept;
protected:
/**
* 密码函数H1.
* 定义:H1(IDA||hid, N);
* @param id 用户ID
* @param hid 私钥生成函数识别符
* @return 一个big大数的字节数据
*/
static string H1(const string& id, int hid);
/**
* 密码函数H2.
* 定义:H2(M||w, N);
* @param data 输入数据
* @param w GT群元素w的字节数据
* @return 一个big大数的字节数据
*/
static string H2(const string& data, const string& w);
/**
* 密钥派生函数.
* 基于SM3实现
* @param data 数据
* @param klen 要生成的密钥的字节长度
* @return 密钥
*/
static string KDF(const string& data, int kLen);
/**
* 消息认证码函数.
* 基于SM3实现
* @param key 密钥
* @param data 数据
* @return 认证码
*/
static string MAC(const string& key, const string& data);
static bool isAllZero(const string& data) noexcept;
private:
/**
* H1和H2的共同部分.
* H1和H2两者只是输入不同,将相同部分提取为H函数。
* @return 一个big大数的字节数据
*/
static string H(const string& Z);
public:
static string getErrorMsg() noexcept { return Errors::getErrorMsg(mErrorNum); }
static int getErrorNum() noexcept { return mErrorNum; }
protected:
static bool mIsInit;
static int mErrorNum;
};
#endif
#include "Base.h"
#include
#include "Parameters.h"
#include "yy/hash/sm3/YSM3.h"
bool Base::mIsInit = false;
int Base::mErrorNum = SM9_OK;
bool Base::init()
{
if( mIsInit )
return true;
else {
bool result = Parameters::init();
if( result ) {
mIsInit = true;
} else {
mErrorNum = Parameters::getErrorNum();
throw exception(getErrorMsg().c_str());
}
return result;
}
}
void Base::release() noexcept
{
if( mIsInit ) {
Parameters::release();
mIsInit = false;
mErrorNum = SM9_OK;
}
}
std::string Base::H1(const string& id, int hid)
{
string bufferZ;
bufferZ.append(1, 0x01);
bufferZ.append(id);
bufferZ.append(1, (char)hid);
return H(bufferZ);
}
std::string Base::H2(const string& data, const string& w)
{
string bufferZ;
bufferZ.append(1, 0x02);
bufferZ.append(data);
bufferZ.append(w);
return H(bufferZ);
}
std::string Base::H(const string& Z)
{
big NSub1 = NULL;
big bha = NULL;
big tmp = NULL;
big h = NULL;
int hlen = (int)ceil((5.0*logb2(Parameters::param_N)) / 32.0);
string ha, result;
Parameters::init_big(NSub1);
Parameters::init_big(bha);
Parameters::init_big(tmp);
Parameters::init_big(h);
ha = KDF(Z, hlen);
decr(Parameters::param_N, 1, NSub1);
Parameters::cin_big(bha, ha.c_str(), ha.length());
divide(bha, NSub1, tmp);
incr(bha, 1, h);
result = Parameters::cout_big(h);
Parameters::release_big(NSub1);
Parameters::release_big(bha);
Parameters::release_big(tmp);
Parameters::release_big(h);
return result;
}
std::string Base::KDF(const string& data, int kLen)
{
int ct = 0x00000001;
int hashLength = YY::YSM3::HASH_SIZE;
int groupNum = (kLen * 8 + (hashLength * 8 - 1)) / (hashLength * 8);
unsigned char* buffer = new unsigned char[groupNum*hashLength];
YY::YSM3 sm3Digest;
string result;
for( int i = 0; i < groupNum; i++ ) {
sm3Digest.update(data.c_str(), data.length());
sm3Digest.update((ct >> 24) & 0xFF);
sm3Digest.update((ct >> 16) & 0xFF);
sm3Digest.update((ct >> 8) & 0xFF);
sm3Digest.update((ct >> 0) & 0xFF);
sm3Digest.finish();
ct++;
std::string hash = sm3Digest.getData(YY::YHashEngine::VALUE_DATA);
memcpy(buffer + i*hashLength, hash.c_str(), hashLength);
}
result = string((char*)buffer, kLen);
delete[] buffer;
return result;
}
std::string Base::MAC(const string& key, const string& data)
{
YY::YSM3 digest;
digest.update(data);
digest.update(key);
digest.finish();
return digest.getData();
}
bool Base::isAllZero(const string& data) noexcept
{
for( size_t i = 0; i < data.length(); i++ ) {
if( data.at(i) != (char)0 )
return false;
}
return true;
}
KGC的主密钥对包括公钥和私钥,且又分为签名主密钥对和加密主密钥对。我将其封装为一个MasterKeyPair类,该类只表示主密钥对,没有区分是签名主密钥对还是加密主密钥对。有需要的可以自己添加标志。
#ifndef YY_SM9_MASTERKEY_INCLUDE_H__
#define YY_SM9_MASTERKEY_INCLUDE_H__
#pragma once
#include
using namespace std;
/**
* 主密钥对.
* @author YaoYuan
*/
class MasterKeyPair {
public:
MasterKeyPair() {}
MasterKeyPair(const string& prikey, const string& pubkey) : mPrikey(prikey), mPubkey(pubkey) {}
~MasterKeyPair() {}
public:
string getPrivate() const { return mPrikey; }
string getPublic() const { return mPubkey; }
private:
string mPrikey;
string mPubkey;
};
#endif
KGC密钥生成部分主要包括以下内容:
#ifndef YY_SM9_KGC_INCLUDE_H__
#define YY_SM9_KGC_INCLUDE_H__
#pragma once
#include
#include
#include "Base.h"
#include "MasterKeyPair.h"
using namespace std;
/**
* KGC密钥中心接口类.
* 主要提供KGC的签名主密钥对和加密主密钥对的生成、用户的签名私钥和加密私钥的生成功能。
*
* SM9算法的密钥主要分为KGC的主密钥对和用户私钥。
*
* KGC主密钥对包括加密主密钥对和签名主密钥对。
* 签名主密钥对中的私钥是一个在[1,N-1]范围内的随机数;公钥是G2群的基点P2的倍点,倍数为私钥。
* 加密主密钥对中的私钥是一个在[1,N-1]范围内的随机数;公钥是G1群的基点P1的倍点,倍数为私钥。
* 主密钥对中的私钥仅用于计算用户私钥,主密钥对中的公钥由KGC公开并用在其他部分。
* 其中,签名主公钥仅用于签名和验签算法;加密主公钥用于密钥封装、加密和密钥交换中,各部分可使用不同或相同的加密主公钥。
*
* 用户私钥包括签名私钥和加密私钥。
* 签名私钥是G1群的基点P1的倍点。签名私钥仅用于签名中。
* 加密私钥是G2群的基点P2的倍点。加密私钥用于密钥解封、解密和密钥交换中,各部分可使用不同或相同的加密私钥。
*
* @author YaoYuan
*/
class KGC : public Base {
public:
/** 私钥类型. */
enum TYPE_PRIVATEKEY {
TYPE_SIGN, // 签名私钥
TYPE_ENCRYPT, // 加密私钥
TYPE_KEYEXCHANGE // 密钥交换私钥
};
private:
KGC() {}
~KGC() {}
public:
/**
* 生成签名主密钥对
*
* @throw std::exception SM9_ERROR_NOT_INIT
*/
static MasterKeyPair genSignMasterKeyPair();
/**
* 生成加密主密钥对
*
* @throw std::exception SM9_ERROR_NOT_INIT
*/
static MasterKeyPair genEncryptMasterKeyPair();
// 生成密钥交换主密钥对,就是加密主密钥对,此函数仅在验证SM9算法标准测试数据时使用;
// 因为测试数据中的加密主私钥和密钥交换主私钥要制定不同值;正式版本中将取消
static MasterKeyPair genKeyExchangeMasterKeyPair();
/**
* 用户私钥生成函数.
* 用户私钥分为签名私钥和加密私钥,密钥交换中的私钥也是加密私钥,只是生成参数中规定HID不同。
* @param masterPrivateKey KGC的主私钥
* @param id 用户ID
* @param typePrivateKey 要生成的私钥类型
* @return 返回生成的私钥;失败返回空,且错误值置为SM9_ERROR_KGC_GENPRIKEY_T1_IS_ZERO。
* @note 按照国密SM9算法标准,生成私钥失败时,是因为t1为0。此时KGC需要重新产生签名或加密主密钥对,并更新已用用户的签名或加密私钥。
* @throw std::exception SM9_ERROR_NOT_INIT | SM9_ERROR_KGC_GENPRIKEY_T1_IS_ZERO | SM9_ERROR_KGC_WRONG_PRIKEY_TYPE
*/
static string genPrivateKey(const string& masterPrivateKey, const string& id, const TYPE_PRIVATEKEY& typePrivateKey);
private:
/**
* 在G1上生成私钥时计算t2.
* t1的计算封装在t2中。
*
* @param masterPrivateKey 主私钥
* @param id 用户ID
* @param hid 私钥生成函数识别符
* @return 返回一个big大数的字节数据;失败返回空,且错误值置为SM9_ERROR_KGC_GENPRIKEY_T1_IS_ZERO。
* @note 按照国密SM9算法标准,计算t1时,如果t1为0,则KGC需要重新产生签名或加密主密钥对,并更新已用用户的签名或加密私钥。
* @throw std::exception
*/
static string T2(const string& masterPrivateKey, const string& id, int hid);
/**
* 生成用户签名私钥
* @param masterPrivateKey KGC的主私钥
* @param id 用户ID
* @return G1群的基点P1的倍点的字节数据.
*/
static string genSignPrivateKey(const string& masterPrivateKey, const string& id);
/**
* 生成用户加密私钥
* @param masterPrivateKey KGC的主私钥
* @param id 用户ID
* @param hid 私钥生成函数识别符,用以标识加密或密钥交换
* @return G2群的基点P2的倍点的字节数据.
*/
static string genEncryptPrivateKey(const string& masterPrivateKey, const string& id, int hid);
};
#endif
#include "KGC.h"
#include
#include "Errors.h"
#include "Parameters.h"
#ifdef SELF_CHECK
#include "yy/utils/YHex.h"
#endif
MasterKeyPair KGC::genSignMasterKeyPair()
{
big ks = NULL;
ecn2 Ppub;
string prikey, pubkey;
if( !mIsInit ) {
mErrorNum = SM9_ERROR_NOT_INIT;
throw exception(getErrorMsg().c_str());
}
#ifdef SELF_CHECK
string ksHex;
#endif
Parameters::init_big(ks);
Parameters::init_ecn2(Ppub);
#ifdef SELF_CHECK
ksHex = YY::YHex::hex2bin("0130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4");
Parameters::cin_big(ks, ksHex.c_str(), ksHex.length());
#else
bigrand(Parameters::param_N, ks);
#endif
ecn2_copy(&Parameters::param_P2, &Ppub);
ecn2_mul(ks, &Ppub);
prikey = Parameters::cout_big(ks);
pubkey = Parameters::cout_ecn2(Ppub);
Parameters::release_big(ks);
Parameters::release_ecn2(Ppub);
return MasterKeyPair(prikey, pubkey);
}
MasterKeyPair KGC::genEncryptMasterKeyPair()
{
big ke = NULL;
epoint *Ppube = NULL;
string prikey, pubkey;
if( !mIsInit ) {
mErrorNum = SM9_ERROR_NOT_INIT;
throw exception(getErrorMsg().c_str());
}
#ifdef SELF_CHECK
string keHex;
#endif
Parameters::init_big(ke);
Parameters::init_epoint(Ppube);
#ifdef SELF_CHECK
keHex = YY::YHex::hex2bin("01EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22");
Parameters::cin_big(ke, keHex.c_str(), keHex.length());
#else
bigrand(Parameters::param_N, ke);
#endif
ecurve_mult(ke, Parameters::param_P1, Ppube);
prikey = Parameters::cout_big(ke);
pubkey = Parameters::cout_epoint(Ppube);
Parameters::release_big(ke);
Parameters::release_epoint(Ppube);
return MasterKeyPair(prikey, pubkey);
}
MasterKeyPair KGC::genKeyExchangeMasterKeyPair()
{
big ke = NULL;
epoint *Ppube = NULL;
string prikey, pubkey;
if( !mIsInit ) {
mErrorNum = SM9_ERROR_NOT_INIT;
throw exception(getErrorMsg().c_str());
}
#ifdef SELF_CHECK
string keHex;
#endif
Parameters::init_big(ke);
Parameters::init_epoint(Ppube);
#ifdef SELF_CHECK
keHex = YY::YHex::hex2bin("02E65B0762D042F51F0D23542B13ED8CFA2E9A0E7206361E013A283905E31F");
Parameters::cin_big(ke, keHex.c_str(), keHex.length());
#else
bigrand(Parameters::param_N, ke);
#endif
ecurve_mult(ke, Parameters::param_P1, Ppube);
prikey = Parameters::cout_big(ke);
pubkey = Parameters::cout_epoint(Ppube);
Parameters::release_big(ke);
Parameters::release_epoint(Ppube);
return MasterKeyPair(prikey, pubkey);
}
std::string KGC::T2(const string& masterPrivateKey, const string& id, int hid)
{
string result;
bool hasException = true;
big h1 = NULL;
big ks = NULL;
big t1 = NULL;
big t2 = NULL;
big rem = NULL;
big zero = NULL;
#ifdef SELF_CHECK
string hashH1Hex, hashT1Hex, hashT2Hex;
#endif
string hashH1 = H1(id, hid);
#ifdef SELF_CHECK
hashH1Hex = YY::YHex::bin2Hex(hashH1);
#endif
Parameters::init_big(ks);
Parameters::init_big(h1);
Parameters::init_big(t1);
Parameters::init_big(t2);
Parameters::init_big(rem);
Parameters::init_big(zero);
Parameters::cin_big(h1, hashH1.c_str(), hashH1.length());
Parameters::cin_big(ks, masterPrivateKey.c_str(), masterPrivateKey.length());
add(h1, ks, t1); // t1=h1+ks;
if( mr_compare(t1, zero) == 0 ) {
mErrorNum = SM9_ERROR_KGC_GENPRIKEY_T1_IS_ZERO;
goto END;
}
#ifdef SELF_CHECK
hashT1Hex = YY::YHex::bin2Hex(Parameters::cout_big(t1));
#endif
xgcd(t1, Parameters::param_N, t1, t1, t1);// t1=t1^
multiply(ks, t1, t2); // t2=ks*t1^1
divide(t2, Parameters::param_N, rem); // t2 = ks*t1^1 mod N
result = Parameters::cout_big(t2);
#ifdef SELF_CHECK
hashT2Hex = YY::YHex::bin2Hex(Parameters::cout_big(t2));
#endif
hasException = false;
END:
Parameters::release_big(h1);
Parameters::release_big(ks);
Parameters::release_big(t1);
Parameters::release_big(t2);
Parameters::release_big(rem);
Parameters::release_big(zero);
if( hasException ) {
throw exception(Errors::getErrorMsg(mErrorNum).c_str());
}
return result;
}
std::string KGC::genSignPrivateKey(const string& masterPrivateKey, const string& id)
{
big t2 = NULL;
epoint *dsa = NULL;
string result;
string sT2;
Parameters::init_big(t2);
Parameters::init_epoint(dsa);
sT2 = T2(masterPrivateKey, id, HID_SIGN);
if( sT2.empty() )
goto END;
Parameters::cin_big(t2, sT2.c_str(), sT2.length());
ecurve_mult(t2, Parameters::param_P1, dsa);
result = Parameters::cout_epoint(dsa);
END:
Parameters::release_big(t2);
Parameters::release_epoint(dsa);
return result;
}
std::string KGC::genEncryptPrivateKey(const string& masterPrivateKey, const string& id, int hid)
{
big t2 = NULL;
ecn2 de;
string result;
string sT2;
Parameters::init_big(t2);
Parameters::init_ecn2(de);
sT2 = T2(masterPrivateKey, id, hid);
if( sT2.empty() )
goto END;
Parameters::cin_big(t2, sT2.c_str(), sT2.length());
ecn2_copy(&Parameters::param_P2, &de);
ecn2_mul(t2, &de);
result = Parameters::cout_ecn2(de);
END:
Parameters::release_big(t2);
Parameters::release_ecn2(de);
return result;
}
std::string KGC::genPrivateKey(const string& masterPrivateKey, const string& id, const TYPE_PRIVATEKEY& typePrivateKey)
{
if( !mIsInit ) {
mErrorNum = SM9_ERROR_NOT_INIT;
throw exception(getErrorMsg().c_str());
}
if( typePrivateKey == TYPE_PRIVATEKEY::TYPE_SIGN ) {
return genSignPrivateKey(masterPrivateKey, id);
} else if( typePrivateKey == TYPE_PRIVATEKEY::TYPE_ENCRYPT ) {
return genEncryptPrivateKey(masterPrivateKey, id, HID_ENCRYPT);
} else if( typePrivateKey == TYPE_PRIVATEKEY::TYPE_KEYEXCHANGE ) {
return genEncryptPrivateKey(masterPrivateKey, id, HID_KEYEXCHANGE);
} else {
mErrorNum = SM9_ERROR_KGC_WRONG_PRIKEY_TYPE;
throw exception(getErrorMsg().c_str());
}
}