需求
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:源碼見附件