失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 国密SM9算法C++实现之七:加密解密算法

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

时间:2018-12-29 11:48:12

相关推荐

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

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]加密算法流程加密结果值Cipher.h加密算法实现解密算法流程解密算法实现

加密算法流程

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

其流程图为:

根据算法描述,定义接口函数:

/*** 加密** @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);

对于加密和解密算法中的明文加密方法,这里定义isBaseBlockCipher参数来指示;同时,加解密算法中有两个长度,一个是用分组密码加密时的K1_len,因为使用的是SM4,所以是固定的16字节;另一个是K2_len,这个是MAC函数的密钥长度。按照MAC函数定义来说,这个长度是可以变的,但最好不小于MAC函数中的哈希函数的哈希值长度,这里因为使用的是SM3,所以默认是32字节。此处提供一个macKeyLen参数表示此K2_len长度,可以根据需要去掉该参数。

加密结果值

SM9加密结果内部包括C1、C2和C3三个部分,对此,也简单将其封装为一个类。这个封装是可取的,可以方便解密时的数据提取。

Cipher.h

#ifndef YY_SM9_CIPHER_INCLUDE_H__#define YY_SM9_CIPHER_INCLUDE_H__#pragma once#include <string>using namespace std;/*** 加密值,封装了加密结果,包括C1、C2、C3.* @author YaoYuan*/class Cipher {public:Cipher() {}Cipher(const string& C1, const string& C2, const string& C3) {mC1 = C1;mC2 = C2;mC3 = C3;}~Cipher() {}public:string getC1() const { return mC1; }string getC2() const { return mC2; }string getC3() const { return mC3; }/*** 加密数据结构构造函数.* @param cipherData 加密数据,可由{@link #toByteArray()}获得*/static Cipher fromByteArray(const string& cipherData) {string C1 = string(cipherData, 0, 64);string C3 = string(cipherData, 64, 32);string C2 = string(cipherData, 64 + 32, cipherData.length() - 96);return Cipher(C1, C2, C3);}string toByteArray() {return mC1 + mC3 + mC2;}private:string mC1;string mC2;string mC3;};#endif

加密算法实现

按照加密流程,实现加密算法:

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 sm4int k2len = macKeyLen;#ifdef SELF_CHECKstring hashH1Hex, QBHex, rHex, C1Hex, C2Hex, C3Hex, gHex, wHex, K1Hex, K2Hex;#endifif( !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_CHECKhashH1Hex = YY::YHex::bin2Hex(hashH1);#endif// Step1 : QB=[H1(IDB||hid, N)]P1+Ppub-eecurve_mult(h1, Parameters::param_P1, QB);ecurve_add(Ppube, QB);#ifdef SELF_CHECKQBHex = YY::YHex::bin2hex(Parameters::cout_epoint(QB));#endifwhile( true ) {#ifdef SELF_CHECKrHex = YY::YHex::hex2bin("AAC0541779C8FC45E3E2CB25C12B5D2576B2129AE8BB5EE2CBE5EC9E785C");Parameters::cin_big(r, rHex.c_str(), rHex.length());#else// Step2: generate rbigrand(Parameters::param_N, r);#endif// Step3 : C1=[r]QBecurve_mult(r, QB, C1);sC1 = Parameters::cout_epoint(C1);#ifdef SELF_CHECKC1Hex = 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_CHECKgHex = YY::YHex::bin2Hex(g.toByteArray());#endif// Step5 : calculate w=g^rw = g.pow(r);sW = w.toByteArray();#ifdef SELF_CHECKwHex = 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_CHECKK1Hex = YY::YHex::bin2Hex(sK1);K2Hex = YY::YHex::bin2Hex(sK2);#endifif( !isAllZero(sK1) )break;}// Step6_2if( 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^K1for( 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_CHECKC2Hex = YY::YHex::bin2Hex(sC2);C3Hex = YY::YHex::bin2Hex(sC3);#endif// Step8 : C=C1|C3|C2cipher = 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;}

解密算法流程

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

其流程为:

根据算法描述,定义接口函数:

/*** 解密** @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);

这里的后两个参数在使用时应该和加密时保持一致。

解密算法实现

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 sm4int k2len = macKeyLen;#ifdef SELF_CHECKstring wHex, K1Hex, K2Hex, uHex, MHex;#endifif( !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 G1Parameters::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_CHECKwHex = 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_CHECKK1Hex = YY::YHex::bin2Hex(sK1);K2Hex = YY::YHex::bin2Hex(sK2);#endifif( isAllZero(sK1) ) {mErrorNum = SM9_ERROR_DECRYPT_K1_IS_ZERO;goto END;}// Step3_2if( 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^K1for( int i = 0; i < sC2.length(); i++ ) {M.append(1, sC2[i] ^ sK1[i]);}}// Step4 : u=MAC(K2,C2)u = MAC(sK2, sC2);if( pare(sC3) != 0 ) {mErrorNum = SM9_ERROR_DECRYPT_C3_VERIFY_FAILED;goto END;}#ifdef SELF_CHECKMHex = YY::YHex::bin2Hex(M);uHex = YY::YHex::bin2Hex(u);#endif// Step5result = M;hasException = false;END:Parameters::release_epoint(C1);Parameters::release_ecn2(de);if( hasException ) {throw exception(getErrorMsg().c_str());}return result;}

如果觉得《国密SM9算法C++实现之七:加密解密算法》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。