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:源码见附件
作者:zhengluohai1