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++实现之九:算法功能与测试例子
实现完KGC密钥生成和各个算法功能部分后,可以测试一下。
使用SM9算法时只需要包含KGC.h和SM9.h两个文件,上层数据都用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();
}
将前面几篇的算法实现描述放在SM9算法实现的算法功能部分的类SM9中。
#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
#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;
}