Crypto++:使用 PBKDF2 生成基于密码的密钥并将其与 ECDSA 一起使用从 Python 代码转换而来

问题描述

我正在尝试使用 Crypto++ 将用于密码签名的 Python 代码转换为 C++。由于我有示例代码,我认为这是一项相当简单的任务,但我在加载使用 PBKDF2 生成的私钥作为 ECDSA 的私钥时遇到了困难。但由于我不熟悉加密算法,所以我可能会错过一些东西。

Python 示例代码(取自 ErisX-REST-API-v3.3(第 9 页),您可以在此处找到:https://www.erisx.com/api-documentation/):

import​ hashlib
import​ ecdsa
from​ ecdsa.util ​ import​ sigencode_der_canonize
import​ base58

def​ ​ privateKeyFromPassword​ (authId,password):
    return​ hashlib.pbkdf2_hmac(
        hash_name=​ 'sha256'​,password=password.encode(),salt=authId.encode(),iterations=​ 100000​,dklen=​ 32​ )

def​ ​ signMessage​ (message,authId,password):
    privateKey = privateKeyFromPassword(authId,password)
    sk = ecdsa.SigningKey.from_string(privateKey,curve=ecdsa.secp256k1)
    signature = sk.sign_deterministic(
        message.encode(),sigencode=sigencode_der_canonize,hashfunc=hashlib.sha256)
    return​ base58.b58encode(signature).decode(​ 'ascii'​ )

signature = signMessage(message,password)

生成的签名是:381yXZ1tstiJroZCoFypQ19xPFus8nHqnWbJGg7oQfEA2VzocCG9ZP5erdXxM4YAkV4vcuyZBTH4g8NfYxiSHWvufPi7RGGX

这是我的 C++ 实现:

#include <iostream>

#include <cryptlib.h>
#include <pwdbased.h>
#include <sha.h>
#include <hex.h>
#include <eccrypto.h>
#include <osrng.h>
#include <asn.h>
#include <oids.h>
#include <sstream>
#include <base64.h>

int main(int n,char **args){
    std::string message = "test message";
    std::string authId = "12345";
    int iterations= 100000;
    
    // https://cryptopp.com/wiki/PKCS5_PBKDF2_HMAC
    CryptoPP::byte password[] ="abcde";
    size_t plen = strlen((const char*)password);
    CryptoPP::byte salt[] = "12345"; // authID from Python code is the salt;
    size_t slen = strlen((const char*)salt);

    CryptoPP::byte key[32]; // dklen from the Python example

    PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
    byte purpose = 0; // purpose is unused in PKCS5_PBKDF2_HMAC => 0.

    pbkdf.DeriveKey(key,sizeof(key),purpose,password,plen,salt,slen,iterations,0.0f);

    std::string result;
    std::stringstream ss_result;
    ss_result << "" << key;
    std::cout << "(Derived) key with stringstream: " << key << std::endl;
        
    /// Define a custom encoder for base58
    // Encoder
    CryptoPP::Base64Encoder encoder(new StringSink(result));
    const CryptoPP::byte ALPHABET[] = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
    AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET);
    encoder.IsolatedInitialize(params);

    // Decoder
    //int lookup[256];
    //const CryptoPP::byte ALPHABET[] = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
    //Base64Decoder::InitializeDecodingLookupArray(lookup,ALPHABET,58,false);

    //Base64Decoder decoder;
    //AlgorithmParameters params_dec = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup);
    //decoder.IsolatedInitialize(params_dec);

    encoder.Put(key,sizeof(key));
    encoder.MessageEnd();

    std::cout << "(Derived) key with base58-Encoding: " << result << std::endl;

    CryptoPP::AutoSeededRandomPool prng; //Create a random number
    CryptoPP::ECDSA<ECP,CryptoPP::SHA256>::PrivateKey privateKey;
    ECDSA<ECP,CryptoPP::SHA256>::Signer signer ( privateKey );
    signer.AccessKey().Initialize(prng,CryptoPP::ASN1::secp256k1());

    CryptoPP::StringSource ss2(result,true);
    signer.AccessKey().Load(ss2);
    
    std::string signature;
    StringSource ss1( message,true /*pump all*/,new SignerFilter( prng,signer,new HexEncoder(new StringSink(signature))
        ) // SignerFilter
    );
    std::cout << "Signature: " << (signature) << std::endl;

}

有问题的行是 signer.AccessKey().Load(ss2);因为它在我运行编译程序时抛出以下异常:“在抛出一个 'CryptoPP::BERDecodeErr' what() 实例后调用终止:BER 解码错误”。所以我的问题是:是什么导致了这个问题?来自 PBKDF2 的私钥是否与 ECDSA 的使用不兼容? 此外,ECDSA 的 Python 实现不使用 RNG 来生成密钥。我试过 CryptoPP::NullRNG() 作为参数,但这没有用。有没有办法做到这一点,还是我必须从 Crypto++-lib 自定义函数代码的最后一部分使用 StringSource 创建签名。我知道它仍然使用 HexEncoder 而不是 base58Encoder。尝试将其作为参数传递的不同版本。我也很感激这里的帮助。

非常感谢您的帮助!

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)