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++实现之八:密钥交换算法

文章目录

  • 国密SM9算法C++实现之八:密钥交换算法
    • @[toc]
    • 密钥交换算法流程
      • 密钥交换结果值
      • 密钥协商初始化:keyExchange_init
      • 临时密钥对:TempKeyPair
      • KeyAgreement .h
      • 接口描述
      • 密钥交换算法实现

密钥交换算法流程

SM9标准文档中描述的密钥交换算法流程如下所示:

其流程图为:

密钥交换结果值

SM9密钥交换结果包括两个可选的哈希验证值和一个共享密钥值,,对此,也简单将其封装为一个类。

密钥协商初始化:keyExchange_init

根据算法描述和算法流程图,可以看到,在密钥交换的第1步~第3部中,需要产生一个[1,N-1]范围内的随机数,并计算G1群上的倍点,可以个过程理解为生成G1群上的一对公私钥,私钥就是随机数,公钥就是倍点,点是通过主公钥和G1的几点P1运算后得到的,倍数就是私钥。
同时,在A4和B7中,需要将公钥发送给对方。因此,此处将前3步提取出来,作为密钥交换的初始化部分,这个接口命名为keyExchange_init

临时密钥对:TempKeyPair

keyExchange_init密钥协商初始化的结果是产生了一对G1上的临时公私钥,将其封装为TempKeyPair,并放在密钥交换结果值之中。

KeyAgreement .h

#ifndef YY_SM9_KEYAGREEMENT_INCLUDE_H__
#define YY_SM9_KEYAGREEMENT_INCLUDE_H__#pragma once#include <string>
using namespace std;/**
* 密钥交换结果值类,包括两个hash验证值和共享密钥.
* @author YaoYuan
*/
class KeyAgreement {
public:KeyAgreement() {}KeyAgreement(const string& shareKey, const string& hashA2, const string& hashB1) {mShareKey = shareKey;mHashA2 = hashA2;mHashB1 = hashB1;}~KeyAgreement() {}public:string getShareKey() {return mShareKey;}string getHashA2() {return mHashA2;}string getHashB1() {return mHashB1;}private:/** 共享密钥. */string mShareKey;/** 选项S_A或者S_2. */string mHashA2;/** 选项S_B或者S_1. */string mHashB1;
};/**
* 密钥交换中的临时密钥对,是群G1上的一对公私钥.
* @author YaoYuan
*/
class TempKeyPair {
public:TempKeyPair() {};TempKeyPair(const string& prikey, const string& pubkey) : mPrikey(prikey), mPubkey(pubkey) { }public:string getPrivate() const { return mPrikey; }string getPublic() const { return mPubkey; }private:string mPrikey;string mPubkey;
};#endif

接口描述

根据上面的描述,定义两个接口函数:

 /*** 密钥交换步骤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);

需要注意的是,密钥交换初始化时使用的对方的ID。
因为密钥交换的发起方和响应方的算法流程是一样的,因此将其封装为一个函数,只是在传入参数是需要区别一下己方和对方。

密钥交换算法实现

按照密钥交换流程,实现密钥交换算法:


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_CHECKstring H1Hex, QothHex, rHex, RHex, gHex, g3Hex, g0Hex;
#endifif( !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_CHECKH1Hex = YY::YHex::bin2Hex(hashH1);
#endif// Step1 : QB =[H1(IDB||hid, N)]P1 +Ppub-e or QA = [H1(IDA || hid, N)]P1 + Ppub-eecurve_mult(h1, Parameters::param_P1, Qoth);ecurve_add(Ppube, Qoth);#ifdef SELF_CHECKQothHex = YY::YHex::bin2hex(Parameters::cout_epoint(Qoth));
#endif#ifdef SELF_CHECKif( othId=="Bob" )rHex = YY::YHex::hex2bin("5879DD1D51E175946F23B1B41E93BA31C584AE59A426EC1046A4D03B06C8");elserHex = YY::YHex::hex2bin("018B98C44BEF9F8537FB7D071B2C928B3BC65BD3D69E1EEE213564905634FE");Parameters::cin_big(r, rHex.c_str(), rHex.length());
#else// Step2: generate rbigrand(Parameters::param_N, r);
#endif// Step3 : RA = [rA]QB or RB= [rB]QAecurve_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_CHECKstring g1Hex, g2Hex, g3Hex;
#endifif( !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 G1if( !Parameters::isPointOnG1(Roth) ) {mErrorNum = SM9_ERROR_KEYEXCHANGE_R_NOT_ON_G1;goto END;}// StepA5_B4: g=e(Ppub-e,P2)^rParameters::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);elseg2 = 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;elseg1 = gtmp;// g3=g^rif( isSponsor )g3 = g2.pow(rmy);elseg3 = g1.pow(rmy);sg1 = g1.toByteArray();sg2 = g2.toByteArray();sg3 = g3.toByteArray();#ifdef SELF_CHECKg1Hex = YY::YHex::bin2Hex(sg1);g2Hex = YY::YHex::bin2Hex(sg2);g3Hex = YY::YHex::bin2Hex(sg3);
#endif// Step6 : S1 or SBbufferTmp.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 S2bufferZ[0] = (char)0x83;sm3Digest.update(bufferZ);sm3Digest.finish();SA2 = sm3Digest.getData();// StepA7_B5 : SKA or SKBbufferZ.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;
}

总结算法实现,实际的密钥交换流程为:

  1. 首先发起方需要知道响应方的ID,然后发起方用响应方的ID调用keyExchange_init,生成一对临时密钥对,并将其中的公钥和自己的ID告知响应方。
  2. 响应方用发起方的ID调用keyExchange_init,生成一对临时密钥对。响应方用发起方的临时公钥、发起方的ID和自己的参数调用keyExchange,计算出哈希选项和共享密钥。然后响应方将自己的临时公钥和哈希选项告知发起方。
  3. 发起方用响应方的临时公钥和自己的参数调用keyExchange,计算出哈希选项和共享密钥。然后和响应方的哈希选项进行对比,以决定成败与否。当然,双方的哈希选项的验证可以按照SM9标准文档的描述进行。

国密SM9算法C++实现之八:密钥交换算法相关推荐

  1. 国密SM9算法C++实现之一:算法简介

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  2. 国密SM9算法C++实现之七:加密解密算法

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  3. 国密SM9算法C++实现之九:算法功能与测试例子

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  4. 国密SM9算法C++实现之五:签名验签算法

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  5. 国密SM9算法C++实现之六:密钥封装解封算法

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  6. 国密SM9算法C++实现之三:椭圆曲线接口、参数初始化

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

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

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  8. 国密SM9系列算法验证工具

    国密局SM9算法验证工具:SM9签名.SM9加解密.SM9秘钥交换.SM9秘钥封装.中间步骤计算-

  9. 国密SM9算法C++实现:算法功能与测试例子

    测试例子 实现完KGC密钥生成和各个算法功能部分后,可以测试一下.  使用SM9算法时只需要包含KGC.h和SM9.h两个文件,上层数据都用std::string储存,不涉及到底层数据结构. #inc ...

最新文章

  1. windows下多版本python安装与pip安装和pip使用 吐血总结
  2. 高效使用Vector
  3. Spring JDBC-事务方法嵌套调用解读
  4. java jaspersoft,Jaspersoft Studio
  5. SharePoint 2013:解决添加域名后每次都需要登录的问题
  6. C++ class和struct的区别
  7. java定时器与ThreadLocal编程陷阱
  8. 任务栏图标变成白色怎么办
  9. 百度关键词搜索量查询,百度,谷歌关键词查询工具
  10. 移动端统计分析工具Firebase、AppsFlyer、Adjust、Flurry、Tap stream、Kochava 、branch不完全对比分析
  11. 大学计算机专业的同学是怎么学习的?
  12. This is probably not a problem with npm. There is likely additional logging output above.
  13. Onvif协议PTZ服务规范(一)PTZ Service Specification
  14. Java虚拟机--Java虚拟机栈
  15. Python生成英文大小写和数字的随机数
  16. java linux 读取文件内容_java访问Linux服务器读取文件
  17. 1.8-20:反反复复
  18. 外挂制作之思路总结和基址与偏移量
  19. 【MathType】彻底解决公式大小与文章文字大小不统一(含字体的字号与磅(pt)和像素(px)之间的换算关系)
  20. dbd mysql dbi_MySQL的DBI/DBD简明安装手册

热门文章

  1. 这是我见过最完美的“docker学习宝典”,阿里云高工熬夜手写,服!
  2. 计算机时代杂志,计算机时代杂志
  3. ML机器学习算法(一): 基于逻辑回归的分类预测
  4. 用starUML画的软工课设:外卖点餐管理系统
  5. oracle数据库scn是什么
  6. SpringBoot中Web容器配置和调优
  7. matlab改consolas字体+微软雅黑的完美解决方法
  8. 斐波那契尾递归函数java_尾递归实现斐波那契数列
  9. linux的多进程等待,等待进程结束wait()和waitpid()函数
  10. QFN封装工艺,QFN封装制程