国密SM 9アルゴリズムC++実現の九:アルゴリズム機能とテスト例

29962 ワード

SM 9アルゴリズムC++実装シリーズ目次:
  • JPBCのSM 9アルゴリズムに基づくjava実装とテスト
  • 国密SM 9アルゴリズムC++実現の0:ソースコードダウンロードアドレス
  • 国密SM 9アルゴリズムC++実現の一つ:アルゴリズム概要
  • 国密SM 9アルゴリズムC++実現の二:テストツール
  • 国密SM 9アルゴリズムC++実現の三:楕円曲線インタフェース、パラメータ初期化
  • 国密SM 9アルゴリズムC++実装の4:基本機能関数とKGCインタフェースの実装
  • 国密SM 9アルゴリズムC++実現の5:署名チェックアルゴリズム
  • 国密SM 9アルゴリズムC++実現の六:鍵パッケージ解封アルゴリズム
  • 国密SM 9アルゴリズムC++実現の七:暗号解読アルゴリズム
  • 国密SM 9アルゴリズムC++実現の8:鍵交換アルゴリズム
  • 国密SM 9アルゴリズムC++実現の九:アルゴリズム機能とテスト例
  • 国密SM 9アルゴリズムC++実現の九:アルゴリズム機能とテスト例
    文書ディレクトリ
  • 国密SM 9アルゴリズムC++実現の九:アルゴリズム機能とテスト例
  • @[toc]
  • 試験例
  • アルゴリズム機能部実装
  • SM9.h
  • SM9.cpp

  • テスト例
    KGC鍵生成と各アルゴリズム機能部を実装した後,テストすることができる.SM 9アルゴリズムを使用する場合はKGCのみを含める必要がある.hとSM 9.h 2つのファイルは、上位データがstd::stringで格納され、下位層のデータ構造には関与しません.
    
    #include "yy/utils/YHex.h"
    #include "yy/sm9/SM9.h"
    #include "yy/sm9/KGC.h"
    
    void test() {
    	try {
    		bool initOK = SM9::init(); // or KGC::init();
    		if( !initOK ) {
    			AfxMessageBox(_T("init sm9 parameters failed"));
    		} else
    		{
    			// Test sign and verify
    			MasterKeyPair signMasterKey = KGC::genSignMasterKeyPair();
    			string signMasterPrikeyHex = YY::YHex::bin2hex(signMasterKey.getPrivate());
    			string signMasterPubkeyHex = YY::YHex::bin2hex(signMasterKey.getPublic());
    
    			string id = "Alice";
    			string prikey = KGC::genPrivateKey(signMasterKey.getPrivate(), id, KGC::TYPE_PRIVATEKEY::TYPE_SIGN);
    			string prikeyHex = YY::YHex::bin2Hex(prikey);
    
    			string dataSign = "Chinese IBS standard";
    			Signature signature = SM9::sign(signMasterKey.getPublic(), prikey, dataSign);
    			string signatureHHex = YY::YHex::bin2Hex(signature.getH());
    			string signatureSHex = YY::YHex::bin2Hex(signature.getS());
    
    			bool isVerifyOK = SM9::verify(signMasterKey.getPublic(), id, signature, dataSign);
    			if( !isVerifyOK ) {
    				AfxMessageBox(_T("Verify signature failed."));
    			}
    
    
    			// Test key encap and decap, encrypt and decrypt
    			string dataEncrypt = "Chinese IBE standard";
    			MasterKeyPair encryptMasterKeyPair = KGC::genEncryptMasterKeyPair();
    			string encryptMasterPrikeyHex = YY::YHex::bin2hex(encryptMasterKeyPair.getPrivate());
    			string encryptMasterPubkeyHex = YY::YHex::bin2hex(encryptMasterKeyPair.getPublic());
    
    			string idKeyEncap = "Bob";
    			int klen = 32;
    			KeyEncapsulation keyEncapsulation = SM9::keyEncap(encryptMasterKeyPair.getPublic(), idKeyEncap, klen);
    			string keyEncapsulationKHex = YY::YHex::bin2Hex(keyEncapsulation.getK());
    			string keyEncapsulationCHex = YY::YHex::bin2Hex(keyEncapsulation.getC());
    
    			string encryptPrikey = KGC::genPrivateKey(encryptMasterKeyPair.getPrivate(), idKeyEncap, KGC::TYPE_PRIVATEKEY::TYPE_ENCRYPT);
    			string encryptPrikeyHex = YY::YHex::bin2Hex(encryptPrikey);
    			string sK = SM9::keyDecap(encryptPrikey, keyEncapsulation.getC(), idKeyEncap, klen);
    			string skHex = YY::YHex::bin2Hex(sK);
    
    			bool isBaseBlockCipher = true;
    			Cipher cipher1 = SM9::encrypt(encryptMasterKeyPair.getPublic(), idKeyEncap, dataEncrypt, isBaseBlockCipher, klen);
    			string cipher1Hex = YY::YHex::bin2Hex(cipher1.toByteArray());
    			string plain1 = SM9::decrypt(cipher1, encryptPrikey, idKeyEncap, isBaseBlockCipher, klen);
    			string plain1Hex = YY::YHex::bin2Hex(plain1);
    
    			isBaseBlockCipher = false;
    			Cipher cipher2 = SM9::encrypt(encryptMasterKeyPair.getPublic(), idKeyEncap, dataEncrypt, isBaseBlockCipher, klen);
    			string cipher2Hex = YY::YHex::bin2Hex(cipher2.toByteArray());
    			string plain2 = SM9::decrypt(cipher2, encryptPrikey, idKeyEncap, isBaseBlockCipher, klen);
    			string plain2Hex = YY::YHex::bin2Hex(plain2);
    
    
    			// Test key exchange
    			string idA = "Alice";
    			string idB = "Bob";
    			klen = 16;
    			MasterKeyPair keyExchangeMasterKeyPair = KGC::genKeyExchangeMasterKeyPair();
    			string keyExchangeMasterPrikeyHex = YY::YHex::bin2hex(keyExchangeMasterKeyPair.getPrivate());
    			string keyExchangeMasterPubkeyHex = YY::YHex::bin2hex(keyExchangeMasterKeyPair.getPublic());
    
    			string prikeyA= KGC::genPrivateKey(keyExchangeMasterKeyPair.getPrivate(), idA, KGC::TYPE_PRIVATEKEY::TYPE_KEYEXCHANGE);
    			string prikeyAHex= YY::YHex::bin2Hex(prikeyA );
    
    			string prikeyB = KGC::genPrivateKey(keyExchangeMasterKeyPair.getPrivate(), idB, KGC::TYPE_PRIVATEKEY::TYPE_KEYEXCHANGE);
    			string prikeyBHex = YY::YHex::bin2Hex(prikeyB);
    
    
    			TempKeyPair tempKeyPairA = SM9::keyExchange_init(keyExchangeMasterKeyPair.getPublic(), idB);
    			TempKeyPair tempKeyPairB = SM9::keyExchange_init(keyExchangeMasterKeyPair.getPublic(), idA);
    
    			string tempPubkeyAHex = YY::YHex::bin2Hex(tempKeyPairA.getPublic());
    			string tempPrikeyAHex= YY::YHex::bin2Hex(tempKeyPairA.getPrivate());
    			string tempPubkeyBHex = YY::YHex::bin2Hex(tempKeyPairB.getPublic());
    			string tempPrikeyBHex = YY::YHex::bin2Hex(tempKeyPairB.getPrivate());
    
    			KeyAgreement keyAgreementB = SM9::keyExchange(keyExchangeMasterKeyPair.getPublic(), false, idB, idA, prikeyB, tempKeyPairB, tempKeyPairA.getPublic(), klen);
    			string SBHex = YY::YHex::bin2Hex(keyAgreementB.getHashB1());
    			string S2Hex = YY::YHex::bin2Hex(keyAgreementB.getHashA2());
    			string sharekeyB = YY::YHex::bin2Hex(keyAgreementB.getShareKey());
    
    			KeyAgreement keyAgreementA = SM9::keyExchange(keyExchangeMasterKeyPair.getPublic(), true, idA, idB, prikeyA, tempKeyPairA, tempKeyPairB.getPublic(), klen);
    			string S1Hex = YY::YHex::bin2Hex(keyAgreementA.getHashB1());
    			string SAHex = YY::YHex::bin2Hex(keyAgreementA.getHashA2());
    			string sharekeyA = YY::YHex::bin2Hex(keyAgreementA.getShareKey());
    			if( S1Hex == SBHex && S2Hex == SAHex ) {
    				AfxMessageBox(_T("key exchange success."));
    			} else {
    				AfxMessageBox(_T("key exchange failed."));
    			}
    		}
    	} catch( std::exception& e ) {
    		AfxMessageBox(e.what());
    	}
    
    	SM9::release(); // or KGC::release();
    }
    

    アルゴリズム機能部分実装
    前述のアルゴリズム実装記述は、SM 9アルゴリズム実装のアルゴリズム機能部分のクラスSM 9に含まれる.
    SM9.h
    
    #ifndef YY_SM9_SM9_INCLUDE_H__
    #define YY_SM9_SM9_INCLUDE_H__
    
    #pragma once
    
    #include 
    #include 
    #include "Base.h"
    #include "MasterKeyPair.h"
    #include "Cipher.h"
    #include "Signature.h"
    #include "KeyAgreement.h"
    #include "KeyEncapsulation.h"
    
    using namespace std;
    
    
    /** 
    * SM9      ,        、        、      、      .
    * @author YaoYuan
    */
    class SM9 : public Base {
    private:
    	SM9();
    	~SM9();
    
    public:
    	/** 
    	*   
    	* 
    	* @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);
    
    	/**
    	*   
    	*
    	* @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);
    
    
    	/**
    	*     
    	*
    	* @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);
    
    	/**
    	*     
    	*
    	* @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);
    
    
    	/**
    	*   
    	*
    	* @param masterPublicKey      
    	* @param id   ID
    	* @param data      
    	* @param isBaseBlockCipher          :true-    ;false-  KDF     
    	* @param macKeyLen MAC         ,    MAC             。     32  
    	* @return    
    	* @throw std::exception SM9_ERROR_NOT_INIT | SM9_ERROR_CALC_RATE
    	*/
    	static Cipher encrypt(const string& masterPublicKey, const string& id, const string& data, bool isBaseBlockCipher, int macKeyLen);
    
    	/**
    	*   
    	*
    	* @param cipher    
    	* @param prikey     
    	* @param id   ID
    	* @param isBaseBlockCipher          :true-    ;false-  KDF     
    	* @param macKeyLen MAC         ,    MAC             。     32  
    	* @return     
    	* @throw std::exception SM9_ERROR_NOT_INIT | SM9_ERROR_CALC_RATE | 
    	* SM9_ERROR_DECRYPT_C1_NOT_ON_G1 | SM9_ERROR_DECRYPT_K1_IS_ZERO | SM9_ERROR_DECRYPT_C3_VERIFY_FAILED
    	*/
    	static string decrypt(const Cipher& cipher, const string& prikey, const string& id, bool isBaseBlockCipher, int macKeyLen);
    
    	/**
    	*       1:   
    	*
    	* @param masterPublicKey      
    	* @param othId   ID
    	* @return      
    	* @throw std::exception SM9_ERROR_NOT_INIT
    	*/
    	static TempKeyPair keyExchange_init(const string& masterPublicKey, const string& othId);
    
    
    	/**
    	*       2:      
    	*
    	* @param masterPublicKey      
    	* @param isSponsor true-   ;false-   
    	* @param myId   ID
    	* @param othId   ID
    	* @param myTempKeyPair        
    	* @param othTempPubkey       
    	* @param klen             
    	* @return      
    	* @throw std::exception SM9_ERROR_NOT_INIT | SM9_ERROR_CALC_RATE | SM9_ERROR_KEYEXCHANGE_R_NOT_ON_G1
    	*/
    	static KeyAgreement keyExchange(const string& masterPublicKey, bool isSponsor, const string& myId, const string& othId, 
    									const string& myPrikey, const TempKeyPair& myTempKeyPair, const string& othTempPubkey, int klen);
    };
    
    #endif
    

    SM9.cpp
    
    #include "SM9.h"
    #include "Errors.h"
    #include "Parameters.h"
    #include "KGC.h"
    #include "zzn12.h"
    
    #include "yy/crypto/symmetric/provider/YCipher.h"
    #include "yy/hash/sm3/YSM3.h"
    
    #ifdef SELF_CHECK
    #include "yy/utils/YHex.h"
    #endif
    
    
    SM9::SM9()
    {
    
    }
    
    SM9::~SM9()
    {
    
    }
    
    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;
    }
    
    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;
    }
    
    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;
    }
    
    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;
    }
    
    Cipher SM9::encrypt(const string& masterPublicKey, const string& id, const string& data, bool isBaseBlockCipher, int macKeyLen)
    {
    	Cipher cipher;
    	bool hasException = true;
    	big h1 = NULL;
    	big r = NULL;
    	epoint *Ppube = NULL;
    	epoint *QB = NULL;
    	epoint *C1 = NULL;
    	ZZN12 g;
    	ZZN12 w;
    	string sC1, sC2, sC3, sW, bufferZ, sK, sK1, sK2, tmp, hashH1;
    	int klen = 0;
    	int k1len = 16; // key length for sm4
    	int k2len = macKeyLen;
    
    #ifdef SELF_CHECK
    	string hashH1Hex, QBHex, rHex, C1Hex, C2Hex, C3Hex, gHex, wHex, K1Hex, K2Hex;
    #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(C1);
    	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("AAC0541779C8FC45E3E2CB25C12B5D2576B2129AE8BB5EE2CBE5EC9E785C");
    		Parameters::cin_big(r, rHex.c_str(), rHex.length());
    #else
    		// Step2: generate r
    		bigrand(Parameters::param_N, r);
    #endif
    
    		// Step3 : C1=[r]QB
    		ecurve_mult(r, QB, C1);
    		sC1 = Parameters::cout_epoint(C1);
    
    #ifdef SELF_CHECK
    		C1Hex = YY::YHex::bin2Hex(sC1);
    #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_1 : K = KDF(C1 || w || IDB, klen)
    		if( isBaseBlockCipher ) {
    			klen = k1len + k2len;
    		} else {
    			klen = data.length() + k2len;
    		}
    
    		bufferZ.append(sC1);
    		bufferZ.append(sW);
    		bufferZ.append(id);
    		sK = KGC::KDF(bufferZ, klen);
    
    		sK1 = string(sK, 0, sK.length()-k2len);
    		sK2 = string(sK, sK1.length(), sK.length()-sK1.length());
    
    #ifdef SELF_CHECK
    		K1Hex = YY::YHex::bin2Hex(sK1);
    		K2Hex = YY::YHex::bin2Hex(sK2);
    #endif
    
    		if( !isAllZero(sK1) )
    			break;
    	}
    	
    	// Step6_2
    	if( isBaseBlockCipher ) {
    		// C2=Enc(K1,M)
    		YY::YCipher sm4Cipher = YY::YCipher(YY::YCipher::SM4, YY::YCipher::ECB, YY::YCipher::PKCS5Padding);
    		sm4Cipher.init(YY::YCipher::ENCRYPT, sK1);
    		sC2 = sm4Cipher.update(data);
    		tmp = sm4Cipher.doFinal();
    		sC2.append(tmp);
    	} else {
    		// C2=M^K1
    		for( int i = 0; i < data.length(); i++ ) {
    			sC2.append(1, data[i] ^ sK1[i]);
    		}
    	}
    	
    	// Step7 : C3=MAC(K2,C2)
    	sC3 = MAC(sK2, sC2);
    
    #ifdef SELF_CHECK
    	C2Hex = YY::YHex::bin2Hex(sC2);
    	C3Hex = YY::YHex::bin2Hex(sC3);
    #endif
    
    	// Step8 : C=C1|C3|C2
    	cipher = Cipher(sC1, sC2, sC3);
    	hasException = false;
    
    END:
    	Parameters::release_big(h1);
    	Parameters::release_big(r);
    	Parameters::release_epoint(Ppube);
    	Parameters::release_epoint(QB);
    	Parameters::release_epoint(C1);
    
    	if( hasException ) {
    		throw exception(getErrorMsg().c_str());
    	}
    	return cipher;
    }
    
    std::string SM9::decrypt(const Cipher& cipher, const string& prikey, const string& id, bool isBaseBlockCipher, int macKeyLen)
    {
    	bool hasException = true;
    	string result, sC1, sC2, sC3, sK1, sK2, sK, sW, bufferZ, tmp, u, M;
    	epoint* C1 = NULL;
    	ecn2 de;
    	ZZN12 w;
    	YY::YSM3 sm3Digest;
    	int klen = 0;
    	int k1len = 16; // key length for sm4
    	int k2len = macKeyLen;
    
    #ifdef SELF_CHECK
    	string wHex, K1Hex, K2Hex, uHex, MHex;
    #endif
    
    	if( !mIsInit ) {
    		mErrorNum = SM9_ERROR_NOT_INIT;
    		throw exception(getErrorMsg().c_str());
    	}
    
    	sC1 = cipher.getC1();
    	sC2 = cipher.getC2();
    	sC3 = cipher.getC3();
    	Parameters::init_epoint(C1);
    	Parameters::init_ecn2(de);
    	
    	// Step1 : check if C1 is on G1
    	Parameters::cin_epoint(C1, sC1.c_str());
    	if( !Parameters::isPointOnG1(C1) ) {
    		mErrorNum = SM9_ERROR_DECRYPT_C1_NOT_ON_G1;
    		goto END;
    	}
    
    	// Step2 : w=e(c,de)
    	Parameters::cin_ecn2_byte128(de, prikey.c_str());
    	if( !ZZN12::calcRatePairing(w, de, C1, 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_1 : K = KDF(C1 || w || IDB, klen)
    	if( isBaseBlockCipher ) {
    		klen = k1len + k2len;
    	} else {
    		klen = sC2.length() + k2len;
    	}
    
    	bufferZ.append(sC1);
    	bufferZ.append(sW);
    	bufferZ.append(id);
    	sK = KGC::KDF(bufferZ, klen);
    
    	sK1 = string(sK, 0, sK.length() - k2len);
    	sK2 = string(sK, sK1.length(), sK.length() - sK1.length());
    
    #ifdef SELF_CHECK
    	K1Hex = YY::YHex::bin2Hex(sK1);
    	K2Hex = YY::YHex::bin2Hex(sK2);
    #endif
    
    	if( isAllZero(sK1) ) {
    		mErrorNum = SM9_ERROR_DECRYPT_K1_IS_ZERO;
    		goto END;
    	}
    
    	// Step3_2
    	if( isBaseBlockCipher ) {
    		// M=Dec(K1,C2)
    		YY::YCipher sm4Cipher = YY::YCipher(YY::YCipher::SM4, YY::YCipher::ECB, YY::YCipher::PKCS5Padding);
    		sm4Cipher.init(YY::YCipher::DECRYPT, sK1);
    		M = sm4Cipher.update(sC2);
    		tmp = sm4Cipher.doFinal();
    		M.append(tmp);
    	} else {
    		// M=C2^K1
    		for( int i = 0; i < sC2.length(); i++ ) {
    			M.append(1, sC2[i] ^ sK1[i]);
    		}
    	}
    
    	// Step4 : u=MAC(K2,C2)
    	u = MAC(sK2, sC2);
    	if( u.compare(sC3) != 0 ) {
    		mErrorNum = SM9_ERROR_DECRYPT_C3_VERIFY_FAILED;
    		goto END;
    	}
    
    #ifdef SELF_CHECK
    	MHex = YY::YHex::bin2Hex(M);
    	uHex = YY::YHex::bin2Hex(u);
    #endif
    
    	// Step5
    	result = M;
    	hasException = false;
    
    END:
    	Parameters::release_epoint(C1);
    	Parameters::release_ecn2(de);
    
    	if( hasException ) {
    		throw exception(getErrorMsg().c_str());
    	}
    	return result;
    }
    
    TempKeyPair SM9::keyExchange_init(const string& masterPublicKey, const string& othId)
    {
    	string sR, sr, hashH1, sg, sg3, sg0, bufferZ;
    	big h1 = NULL;
    	big r = NULL;
    	epoint *Ppube = NULL;
    	epoint *Qoth = NULL;
    	epoint *R = NULL;
    
    #ifdef SELF_CHECK
    	string H1Hex, QothHex, rHex, RHex, gHex, g3Hex, g0Hex;
    #endif
    
    	if( !mIsInit ) {
    		mErrorNum = SM9_ERROR_NOT_INIT;
    		throw exception(getErrorMsg().c_str());
    	}
    
    	Parameters::init_big(h1);
    	Parameters::init_big(r);
    	Parameters::init_epoint(Qoth);
    	Parameters::init_epoint(Ppube);
    	Parameters::init_epoint(R);
    
    	hashH1 = KGC::H1(othId, HID_KEYEXCHANGE);
    	Parameters::cin_big(h1, hashH1.c_str(), hashH1.length());
    	Parameters::cin_epoint(Ppube, masterPublicKey.c_str());
    
    #ifdef SELF_CHECK
    	H1Hex = YY::YHex::bin2Hex(hashH1);
    #endif
    
    	// Step1 : QB =[H1(IDB||hid, N)]P1 +Ppub-e or QA = [H1(IDA || hid, N)]P1 + Ppub-e
    	ecurve_mult(h1, Parameters::param_P1, Qoth);
    	ecurve_add(Ppube, Qoth);
    
    #ifdef SELF_CHECK
    	QothHex = YY::YHex::bin2hex(Parameters::cout_epoint(Qoth));
    #endif
    
    #ifdef SELF_CHECK
    	if( othId=="Bob" )
    		rHex = YY::YHex::hex2bin("5879DD1D51E175946F23B1B41E93BA31C584AE59A426EC1046A4D03B06C8");
    	else
    		rHex = YY::YHex::hex2bin("018B98C44BEF9F8537FB7D071B2C928B3BC65BD3D69E1EEE213564905634FE");
    	Parameters::cin_big(r, rHex.c_str(), rHex.length());
    #else
    	// Step2: generate r
    	bigrand(Parameters::param_N, r);
    #endif
    
    	// Step3 : RA = [rA]QB or RB= [rB]QA
    	ecurve_mult(r, Qoth, R);
    	sr = Parameters::cout_big(r);
    	sR = Parameters::cout_epoint(R);
    
    	Parameters::release_big(h1);
    	Parameters::release_big(r);
    	Parameters::release_epoint(Qoth);
    	Parameters::release_epoint(Ppube);
    	Parameters::release_epoint(R);
    
    	return TempKeyPair(sr, sR);
    }
    
    KeyAgreement SM9::keyExchange(const string& masterPublicKey, bool isSponsor, const string& myId, const string& othId, 
    							  const string& myPrikey, const TempKeyPair& myTempKeyPair, const string& othTempPubkey, int klen)
    {
    	KeyAgreement keyAgreement;
    	bool hasException = true;
    	string sKey, sg1, sg2, sg3, bufferZ, bufferTmp, srmy, sRmy, sRoth, SB1, SA2, tmp;
    	epoint *Ppube = NULL;
    	epoint *Qoth = NULL;
    	epoint *Rmy = NULL;
    	epoint *Roth = NULL;
    	big rmy = NULL;
    	ZZN12 g1;
    	ZZN12 g2;
    	ZZN12 g3;
    	ZZN12 gtmp;
    	ecn2 de;
    	YY::YSM3 sm3Digest;
    
    #ifdef SELF_CHECK
    	string g1Hex, g2Hex, g3Hex;
    #endif
    
    	if( !mIsInit ) {
    		mErrorNum = SM9_ERROR_NOT_INIT;
    		throw exception(getErrorMsg().c_str());
    	}
    
    	Parameters::init_epoint(Qoth);
    	Parameters::init_epoint(Ppube);
    	Parameters::init_epoint(Rmy);
    	Parameters::init_epoint(Roth);
    	Parameters::init_big(rmy);
    	Parameters::init_ecn2(de);
    
    	srmy = myTempKeyPair.getPrivate();
    	sRmy = myTempKeyPair.getPublic();
    	Parameters::cin_big(rmy, srmy.c_str(), srmy.length());
    	Parameters::cin_epoint(Rmy, sRmy.c_str());
    	sRoth = othTempPubkey;
    	Parameters::cin_epoint(Roth, sRoth.c_str());
    
    	// check R is on G1
    	if( !Parameters::isPointOnG1(Roth) ) {
    		mErrorNum = SM9_ERROR_KEYEXCHANGE_R_NOT_ON_G1;
    		goto END;
    	}
    
    	// StepA5_B4: g=e(Ppub-e,P2)^r
    	Parameters::cin_epoint(Ppube, masterPublicKey.c_str());
    	if( !ZZN12::calcRatePairing(gtmp, Parameters::param_P2, Ppube, Parameters::param_t, Parameters::norm_X) ) {
    		mErrorNum = SM9_ERROR_CALC_RATE;
    		goto END;
    	}
    	if( isSponsor )
    		g1 = gtmp.pow(rmy);
    	else
    		g2 = gtmp.pow(rmy);
    
    	// g=e(Roth,de)
    	Parameters::cin_ecn2_byte128(de, myPrikey.c_str());
    	if( !ZZN12::calcRatePairing(gtmp, de, Roth, Parameters::param_t, Parameters::norm_X) ) {
    		mErrorNum = SM9_ERROR_CALC_RATE;
    		goto END;
    	}
    	if( isSponsor )
    		g2 = gtmp;
    	else
    		g1 = gtmp;
    
    	// g3=g^r
    	if( isSponsor )
    		g3 = g2.pow(rmy);
    	else
    		g3 = g1.pow(rmy);
    
    	sg1 = g1.toByteArray();
    	sg2 = g2.toByteArray();
    	sg3 = g3.toByteArray();
    
    #ifdef SELF_CHECK
    	g1Hex = YY::YHex::bin2Hex(sg1);
    	g2Hex = YY::YHex::bin2Hex(sg2);
    	g3Hex = YY::YHex::bin2Hex(sg3);
    #endif
    
    	// Step6 : S1 or SB
    	bufferTmp.resize(0);
    	if( isSponsor ) {
    		bufferTmp.append(myId);
    		bufferTmp.append(othId);
    		bufferTmp.append(sRmy);
    		bufferTmp.append(sRoth);
    	} else {
    		bufferTmp.append(othId);
    		bufferTmp.append(myId);
    		bufferTmp.append(sRoth);
    		bufferTmp.append(sRmy);
    	}
    
    	bufferZ.resize(0);
    	bufferZ.append(sg2);
    	bufferZ.append(sg3);
    
    	bufferZ.append(bufferTmp);
    	sm3Digest.update(bufferZ);
    	sm3Digest.finish();
    	tmp = sm3Digest.getData();
    
    	bufferZ.resize(0);
    	bufferZ.append(1, (char)0x82);
    	bufferZ.append(sg1);
    	bufferZ.append(tmp);
    	sm3Digest.update(bufferZ);
    	sm3Digest.finish();
    	SB1 = sm3Digest.getData();
    
    	// StepA8_B7 : SA or S2
    	bufferZ[0] = (char)0x83;
    	sm3Digest.update(bufferZ);
    	sm3Digest.finish();
    	SA2 = sm3Digest.getData();
    
    	// StepA7_B5 : SKA or SKB
    	bufferZ.resize(0);
    	bufferZ.append(bufferTmp);
    	bufferZ.append(sg1);
    	bufferZ.append(sg2);
    	bufferZ.append(sg3);
    	sKey = KGC::KDF(bufferZ, klen);
    
    	keyAgreement = KeyAgreement(sKey, SA2, SB1);
    	hasException = false;
    
    END:
    	Parameters::release_epoint(Qoth);
    	Parameters::release_epoint(Ppube);
    	Parameters::release_epoint(Rmy);
    	Parameters::release_epoint(Roth);
    	Parameters::release_big(rmy);
    	Parameters::release_ecn2(de);
    
    	if( hasException ) {
    		throw exception(getErrorMsg().c_str());
    	}
    	return keyAgreement;
    }