基于ECDSA公私钥实现的"非对称加解密"方案(带源码)

需求

ECDSA(elliptic curve digital signature algorithm) 椭圆曲线数字签名算法是区块链应用常用的签名算法(例如比特币,腾讯的trustsql等),这个算法具有速度快,强度高,签名短等特点。这个算法适合用于签名,但是在openssl库里找不到对应的加解密方案。

在工作中遇到这样的需求,区块链用户(客户端)本身已经拥有了ECDSA的公私钥,现在服务端想基于客户端的ECDSA公私钥实现加密内容传输(非对称加密)。

通过研究,发现可以通过以下组合的方式来实现基于ECDSA公私钥的非对称加解密。

封装

首先总共封装了三个函数:生成公私钥,公钥加密私钥解密,一目了然。

//生成ECDSA公私钥(16进制编码)
int ECDSA_GenKeyBase16(std::string &sPrikeyB16, std::string &sPubkeyB16);
//使用公钥加密
int ECDSA_Encode(const std::string &sPlaintext, const std::string &sPubkeyB16, std::string &sCiphertext);
//使用私钥加密
int ECDSA_Decode(const std::string &sCiphertext, const std::string &sPrikeyB16, std::string &sPlaintext);
 

 流程和原理

第一步:客户端生成公私钥

首先客户端本地调用ECHDS_GenKeyBase16函数生成16进制编码的ECDSA私钥CliPriKeyB16和ECDSA公钥CliPubKeyB16,然后将公钥CliPubKeyB16上传到服务端。

int ECDSA_GenKeyBase16(std::string &sPrikeyB16, std::string &sPubkeyB16);

第二步:服务端加密

服务端调用加密函数ECDSA_Encode,输入明文Splaintext和客户端上传的公钥CliPubKeyB16,输出密文sCiphertext。

int ECDSA_Encode(const std::string &sPlaintext, const std::string &sPubkeyB16,std::string &sCiphertext);

输出的密文sCiphertext结构如下图所示:

 

报文分成四个部分:
第一部分(secure_head_t):存储的是一个结构体的二进制信息,长度是32字节,结构体如下描述

typedef struct 
{
    uint64_t key_len;     //秘钥协商的随机key
    uint64_t hmac_len;    //hmac长度
    uint64_t orig_len;    //原始明文长度
    uint64_t body_len;    //密文长度
} secure_head_t;

 实际上结构体里面存储了第二,三,四部分的报文长度(字节)。同时还保存了原始明文(sPlaintext)的长度。

第二部分(key):服务端随机生成ECDSA私钥SerPriKeyB16和对应公钥SerPubKeyB16,把SerPubKeyB16做编码转换存储为key。

第三部分(body):对明文信息sPlaintext进行AES对称加密后得到body,body的生成过程如下
1,使用ECDH秘钥协商,输入参数:a)客户端的公钥CliPubKeyB16;b)服务端私钥SerPriKeyB16。输出参数:协商出一个结果envelope_key(64字节)。

2,用envelope_key的前32个字节作为AES对称秘钥, 对sPlaintext加密得到body。

第四部分(hmac):校验信息,生成过程如下:

1,使用envelope_key的后32个字节作为HMAC算法的秘钥,对body计算得出hmac值(后续作校验用)。

第三步:客户端解密

客户端从服务商得到sCiphertext后,根据私钥CliPriKeyB16调用ECDSA_decode函数进行解密

int ECDSA_Decode(const std::string &sCiphertext, const std::string &sPrikeyB16,std::string &sPlaintext);

解密过程如下:

1,通过第一部分的secure_head_t计算长度,分别得到二,三,四部分的key,body和hmac。

2,使用ECDH秘钥协商,输入参数:a)客户端私钥CliPriKeyB16;b)服务端公钥(通过透传过来的key换算得来)。输出参数:协商出一个结果envelope_key(64字节),envelope_key等价于第二步生成的envelope_key。

3,使用envelope_key的后32个字节作为HMAC算法的秘钥,对body计算得出hmac`值,比较hmac`是否等于hmac,如果不等于说明数据已经被损坏,如果等於则跳到第4步。

4,用envelope_key的前32个字节作为AES对称秘钥,对body解密得到明文sPlaintext。

ps:源码见附件

发布了6 篇原创文章 · 获赞 5 · 访问量 2454
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章