我是cryptopp的新手,并且在为ECDSA签名创建私钥方面已经挣扎了一段时间。
我有一个十六进制编码的私有指数E4A6CFB431471CFCAE491FD566D19C87082CF9FA7722D7FA24B2B3F5669DBEFB
。它存储为字符串。
我想用它来使用ECDSA对文本块进行签名。我的代码看起来有点像这样
string Sig::genSignature(const string& privKeyIn, const string& messageIn)
{
AutoSeededRandomPool prng;
ECDSA<ECP, SHA256>::PrivateKey privateKey;
privateKey.AccessGroupParameters().Initialize(ASN1::secp256r1());
privateKey.Load(StringSource(privKeyIn, true, NULL).Ref());
ECDSA<ECP, SHA256>::Signer signer(privateKey);
// Determine maximum size, allocate a string with that size
size_t siglen = signer.MaxSignatureLength();
string signature(siglen, 0x00);
// Sign, and trim signature to actual size
siglen = signer.SignMessage(prng, (const byte *) messageIn.data(), (size_t) messageIn.length(), (byte*)signature.data());
signature.resize(siglen);
cout << signature.data() << endl;
return signature;
}
当我尝试执行privateKey.load(...)时,此代码在Visual Studio中生成以下错误
First-chance exception at 0x7693C42D in DLLTest.exe: Microsoft C++ exception: CryptoPP::BERDecodeErr at memory location 0x0033EEA8.
Unhandled exception at 0x7693C42D in DLLTest.exe: Microsoft C++ exception: CryptoPP::BERDecodeErr at memory location 0x0033EEA8.
我猜我做的事情有点愚蠢......任何帮助都会很棒???
PS我在使用ECDH进行GMAC生成方面遇到了类似的问题,但通过将密钥保存为SECByteBlock来解决这个问题,但这种“技巧”在这种情况下似乎无效。
答案 0 :(得分:2)
DLLTest.exe:Microsoft C ++异常:CryptoPP :: BERDecodeErr ...
您有一个私人指数,不一个私钥。所以你应该不在上面调用Load
。这导致了Crypto ++ BERDecodeErr
异常。
答案详见ECDSA wiki page,但不是很明显。在给定曲线和指数::
的情况下,您需要执行以下操作来初始化privateKey
string exp = "E4A6CFB431471CFCAE491FD566D19C87082CF9FA7722D7FA24B2B3F5669DBEFB";
exp.insert(0, "0x");
Integer x(exp.c_str());
privateKey.Initialize(ASN1::secp256r1(), x);
预先"0x"
确保Integer
类将正确解析ASCII字符串。您还可以在字符串中附加"h"
个字符。您可以在Integer
函数的2960行左右Integer.cpp看到StringToInteger
类的解析代码。
这是另一种做同样事情的方法:
string exp = "E4A6CFB431471CFCAE491FD566D19C87082CF9FA7722D7FA24B2B3F5669DBEFB";
HexDecoder decoder;
decoder.Put((byte*)exp.data(), exp.size());
decoder.MessageEnd();
Integer x;
x.Decode(decoder, decoder.MaxRetrievable());
privateKey.Initialize(ASN1::secp256r1(), x);
HexDecoder
将为您执行ASCII到二进制转换。然后,HexDecoder
使用Integer
方法使用string exp = "E4A6CFB431471CFCAE491FD566D19C87082CF9FA7722D7FA24B2B3F5669DBEFB";
StringSource ss(exp, true /*punpAll*/, new HexDecoder);
Integer x;
x.Decode(ss, ss.MaxRetrievable());
privateKey.Initialize(ASN1::secp256r1(), x);
占用的缓冲区。
以下是另一种使用Decode (BufferedTransformation &bt, size_t inputLen, Signedness=UNSIGNED)
的方法(Crypto ++有时和脚本语言一样糟糕:):
bool result = privateKey.Validate( prng, 3 );
if( !result ) { /* Handle error */ }
初始化密钥后,您应该对其进行验证:
cout << signature.data() << endl;
这将输出二进制数据:
{{1}}
如果您想要可打印/可读的内容,请通过Crypto ++ HexDecoder
运行它。
答案 1 :(得分:0)
其他人稍后会这样做
string genSignature(const string& privKeyIn, const string& messageIn)
{
CryptoPP::Integer secretNumber(genSecretNumber(privKeyIn, messageIn));
AutoSeededRandomPool secretNumberGenerator;
if (encryptBase::debug)
{
cout << "secret number: " << secretNumber << endl;
}
SecByteBlock message(convertHexStrToSecByteBlock(messageIn));
ECDSA<ECP, SHA256>::PrivateKey privateKey;
string exp(privKeyIn);
exp.insert(0, "0x");
Integer x(exp.c_str());
privateKey.Initialize(ASN1::secp256r1(), x);
AutoSeededRandomPool prng;
if (!privateKey.Validate(prng, 3))
{
cout << "unable to verify key" << endl;
return "failed to verify key";
}
ECDSA<ECP, SHA256>::Signer signer(privateKey);
size_t siglen = signer.MaxSignatureLength();
string signature(siglen, 0x00);
siglen = signer.SignMessage(secretNumberGenerator, message.BytePtr(), message.size(), (byte*)signature.data());
signature.resize(siglen);
string encoded;
HexEncoder encoder;
encoder.Put((byte *) signature.data(), signature.size());
encoder.MessageEnd();
word64 size = encoder.MaxRetrievable();
if (size)
{
encoded.resize(size);
encoder.Get((byte*)encoded.data(), encoded.size());
}
return encoded;
}