Я новичок в 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;
}
Этот код генерирует следующую ошибку в Visual Studio, когда я пытаюсь сделать privateKey.load (…)
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, но этот «трюк», похоже, не работает в этом случае.
DLLTest.exe: исключение Microsoft C ++: CryptoPP :: BERDecodeErr …
У вас есть личный показатель, и не закрытый ключ Так что вы должны не вызов Load
в теме. Это вызывает Crypto ++ BERDecodeErr
исключение.
Ответ подробно изложен на ECDSA вики-страница, но это не совсем очевидно. Вам нужно выполнить следующее для инициализации privateKey
учитывая кривую и показатель степени:
string exp = "E4A6CFB431471CFCAE491FD566D19C87082CF9FA7722D7FA24B2B3F5669DBEFB";
exp.insert(0, "0x");
Integer x(exp.c_str());
privateKey.Initialize(ASN1::secp256r1(), x);
Предшественник "0x"
обеспечивает Integer
Класс будет правильно анализировать строку ASCII. Вы также можете добавить "h"
символ строки. Вы можете увидеть код синтаксического анализа для Integer
класс в Integer.cpp вокруг линии 2960 в 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
используя его Decode (BufferedTransformation &bt, size_t inputLen, Signedness=UNSIGNED)
метод.
А вот еще один способ использования HexDecoder
(Crypto ++ порой так же плох, как языки сценариев:) …
string exp = "E4A6CFB431471CFCAE491FD566D19C87082CF9FA7722D7FA24B2B3F5669DBEFB";
StringSource ss(exp, true /*punpAll*/, new HexDecoder);
Integer x;
x.Decode(ss, ss.MaxRetrievable());
privateKey.Initialize(ASN1::secp256r1(), x);
После инициализации ключа вы должны проверить его:
bool result = privateKey.Validate( prng, 3 );
if( !result ) { /* Handle error */ }
Это выведет двоичные данные:
cout << signature.data() << endl;
Если вы хотите что-то печатное / читабельное, запустите его через Crypto ++ HexEncoder.
для других, ищущих это позже
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;
}