国密SM9算法C++实现之四:基本功能函数与KGC接口的实现

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++实现之四:基本功能函数与KGC接口的实现

文章目录

  • 国密SM9算法C++实现之四:基本功能函数与KGC接口的实现
    • @[toc]
    • Base类
      • Base.h
      • Base.cpp
    • 主密钥对
      • MasterKeyPair.h
    • KGC密钥生成
      • KGC.h
      • KGC.cpp

在有了上篇文章描述的底层支持后,可以开始实现SM9算法的各个部分了,整体总共分为2个类,KGC和SM9。
KGC类中实现主密钥对和用户私钥的生成;SM9类实现各个算法功能。
在上一篇中的Parameters中定义了一个SELF_CHECK宏,表示验证SM9文档第5部分中的测试数据,这在KGC和SM9类中会用到。

本篇文章描述KGC部分的接口实现。

Base类

首先,把SM9文档中描述的一些基本功能函数提取出来,放在Base类中,KGC和SM9类都继承于此类。
Base类中主要包括以下内容:

  • init():初始化SM9环境,在使用SM9之前需要调用此函数初始化SM9曲线参数,否则将抛出SM9_ERROR_NOT_INIT
  • release():释放SM9环境,在使用完SM9之后需要调用此函数释放SM9曲线参数
  • H1函数:密码函数H1(IDA||hid, N)
  • H2函数:密码函数H2(M||w, N)
  • KDF函数:密钥派生函数
  • MAC函数:消息认证码函数,在加密解密中用到
  • 错误消息值获取函数

Base.h


#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

Base.cpp


#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类,该类只表示主密钥对,没有区分是签名主密钥对还是加密主密钥对。有需要的可以自己添加标志。

MasterKeyPair.h


#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密钥生成

KGC密钥生成部分主要包括以下内容:

  • TYPE_PRIVATEKEY:用户私钥类型。根据SM9文档的描述,KGC生成用户私钥和算法部分需要使用一个HID,即密钥生成函数标识符,其定义为:01表示签名私钥;02表示密钥交换的私钥;03表示密钥解封和解密的私钥。此处,将其定义为enum枚举类。
  • genSignMasterKeyPair():生成签名主密钥对。
  • genEncryptMasterKeyPai():生成加密主密钥对。
  • genKeyExchangeMasterKeyPair():生成密钥交换用的主密钥对,因为要对SM9文档第5部分中的测试数据进行验证,所以添加了此函数。该函数就是**genEncryptMasterKeyPai()**的一个copy。不需要验证就可以删除掉。
  • T2()函数:把私钥生成部分的T2提取出来单独作为一个函数。

KGC.h


#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

KGC.cpp


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

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