Создание закрытого ключа ECDSA с учетом кривой и частного показателя?

Я новичок в 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, но этот «трюк», похоже, не работает в этом случае.


person gizmo    schedule 01.12.2014    source источник
comment
У меня была аналогичная проблема с использованием ECDH для генерации GMAC... - Мне не ясно, где находится пересечение между ECDH и GMAC. Вы можете запросить проверку кода на Code Review Stack Exchange.   -  person jww    schedule 01.12.2014
comment
ECDH используется при создании общего секрета, который затем используется для создания ключа AES, который я использую для GMAC gen.   -  person gizmo    schedule 05.12.2014


Ответы (2)


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.

person jww    schedule 01.12.2014
comment
Спасибо за ответ!! это сработало. Я опубликую свой окончательный код для других. Мне было интересно, не могли бы вы помочь с аналогичным вопросом, касающимся открытых ключей? stackoverflow.com/questions/27315687/ - person gizmo; 05.12.2014
comment
@jww, если бы это была строка закрытого ключа вместо строки экспоненты закрытого ключа, то как сгенерировать закрытый ключ? Я разместил свой вопрос здесь stackoverflow.com/questions/30860777/. Пожалуйста, ответьте. - person SandeepAggarwal; 16.06.2015

для других, которые ищут это позже

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;
}
person gizmo    schedule 05.12.2014
comment
Вам не нужен secretNumberGenerator, так как у вас есть prng. Вы можете использовать HexEncoder encoder(new StringSink(encoded)) и удалить код, чтобы получить значение в шестнадцатеричном коде. HexEncoder поместит результат в строку из-за прикрепленного StringSink. Вам все равно нужно позвонить encoder.MessageEnd(). - person jww; 07.12.2014
comment
спасибо за предложения .. Я скоро обновлю код. приведенный выше код не является окончательной версией, так как в «настоящем» приложении секретный номер не является случайным. Он использует пользовательский класс для возврата предварительно вычисленного значения. - person gizmo; 08.12.2014