Я борюсь с созданием открытого ключа ECDSA из строкового представления открытого ключа, т.е.
string devicePublicKey("86FB5EB3CA0507226BE7197058B9EC041D3A3758D9D9C91902ACA3391F4E58AEF13AFF63CC4EF68942B9B94904DC1B890EDBEABD16B992110624968E894E560E");
ранее я обнаружил, что мне нужно добавить префикс «04» к этому ключу, поэтому не уверен, требуется ли это на этот раз?
Я пытаюсь сгенерировать его для проверки подписи
string ecs04b2ExpSignature("0199E984CEC75DDCA7F1DDF6E53E2E67352A2BE38A4B66F8ED596606FAB983FF300CAA76DE88CED9D563A5C03E8F3A7C000780F3F2061C611E9AA0B18B460D77");
где данные для подписи
string ecs04b2SigningData("020000000000000001FFFFFFFFFFFFFFFE123456789ABCDEF000B3DA2000000100000300000003030003000300");
Мой грубый код сейчас выглядит так
SecByteBlock message(convertHexStrToSecByteBlock(messageIn));
SecByteBlock signature(convertHexStrToSecByteBlock(signatureIn));
ECDSA<ECP, SHA256>::PublicKey publicKey;
string inPublicKey("04");
inPublicKey.append(pubKeyIn);
SecByteBlock pubKey = encryptBase::convertHexStrToSecByteBlock(inPublicKey);ECP::Point p;
publicKey.AccessGroupParameters().Initialize(CryptoPP::ASN1::secp256r1());
publicKey.GetGroupParameters().GetCurve().DecodePoint(p, pubKey, publicKey.GetGroupParameters().GetCurve().EncodedPointSize(true));
publicKey.SetPublicElement(p);
//ByteQueue qt;
//qt.Put((byte*)exp.c_str(),(size_t)exp.size());
AutoSeededRandomPool prng;
bool result = publicKey.Validate(prng, 3);
if (result)
{
// Load public key (in ByteQueue, X509 format)
ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
bool result = verifier.VerifyMessage(message.data(), messageIn.size(), signature.data(), signature.size());
if (result)
cout << "Verified signature on message" << endl;
else
cerr << "Failed to verify signature on message" << endl;
}
else
{
cout << "Failed to validate key" << endl;
}
это нарезать вместе, поэтому не будет строить. Любая помощь будет отличной
PS Я задал похожий вопрос, касающийся секретных ключей здесь Создание закрытого ключа ECDSA с учетом кривой и частного показателя?
Ответ подробно изложен на ECDSA вики-страница, но это не совсем очевидно. Вам нужно выполнить следующее для инициализации publicKey
учитывая кривую и публичную точку:
string pt = "2DB45A3F21889438B42C8F464C75292BACF5FDDB5DA0B492501B299CBFE92D8F""DB90FC8FF4026129838B1BCAD1402CAE47FE7D8084E409A41AFCE16D63579C5F";
HexDecoder decoder;
decoder.Put((byte*)pt.data(), pt.size());
decoder.MessageEnd();
ECP::Point q;
size_t len = decoder.MaxRetrievable();
assert(len == SHA256::DIGESTSIZE * 2);
q.identity = false;
q.x.Decode(decoder, len/2);
q.y.Decode(decoder, len/2);
ECDSA<ECP, SHA256>::PublicKey publicKey;
publicKey.Initialize(ASN1::secp256r1(), q);
bool result = publicKey.Validate( prng, 3 );
if( result )
{
cout << "Validated public key" << endl;
}
else
{
cerr << "Failed to validate public key" << endl;
exit(1);
}
const ECP::Point& qq = publicKey.GetPublicElement();
cout << "Q.x: " << std::hex << qq.x << endl;
cout << "Q.y: " << std::hex << qq.y << endl;
Программа выше дает следующие результаты.
$ ./cryptopp-test.exe
Validated public key
Q.x: 2db45a3f21889438b42c8f464c75292bacf5fddb5da0b492501b299cbfe92d8fh
Q.y: db90fc8ff4026129838b1bcad1402cae47fe7d8084e409a41afce16d63579c5fh
Тест:
assert(len == SHA256::DIGESTSIZE * 2);
это своего рода клудж. Это значение, которое вы хотите использовать вместо SHA256::DIGESTSIZE
:
GetField().MaxElementByteLength()
Но вы не можете использовать его, потому что единственная доступная вещь x
а также y
координаты. Такие вещи, как размер поля не будут доступны, пока вы не инициализируете DL_GroupParameters_EC< EC >
в открытом ключе.
Например, следующее вызывает ошибку сегментации:
ECDSA<ECP, SHA256>::PublicKey publicKey;
unsigned int u = publicKey.GetGroupParameters().GetCurve().GetField().MaxElementByteLength();
cout << "Field element length: " << u << endl;
Вы можете вмешаться с открытым ключом, чтобы гарантировать ошибку проверки с:
q.y.Decode(decoder, len/2);
q.y++;
Вот ответ на ваш второй вопрос о том, как использовать VerifyMessage
:
...
publicKey.Initialize(ASN1::secp256r1(), q);
string msg = "020000000000000001FFFFFFFFFFFFFFFE123456789ABCDEF000B3DA2000000100000300000003030003000300";
string sig = "0199E984CEC75DDCA7F1DDF6E53E2E67352A2BE38A4B66F8ED596606FAB983FF300CAA76DE88CED9D563A5C03E8F3A7C000780F3F2061C611E9AA0B18B460D77";
string mm, ss;
decoder.Detach(new StringSink(mm));
decoder.Put((byte*)msg.data(), msg.size());
decoder.MessageEnd();
decoder.Detach(new StringSink(ss));
decoder.Put((byte*)sig.data(), sig.size());
decoder.MessageEnd();
ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
result = verifier.VerifyMessage((byte*)mm.data(), mm.size(), (byte*)ss.data(), ss.size());
if( result )
{
cout << "Verified message" << endl;
}
else
{
cerr << "Failed to verify message" << endl;
exit(1);
}
призвание Detach
на HexDecoder
удаляет текущий фильтр и заменяет его новым фильтром. В приведенном выше коде это StringSink
, Вы должны сделать это, чтобы память не просочилась.
Ваше сообщение не проверяется под открытым ключом:
$ ./cryptopp-test.exe
Validated public key
Failed to verify message
Вы также можете попытаться проверить сообщение ASCII, а не двоичное сообщение, но оно также не может проверить:
decoder.Attach(new StringSink(mm));
decoder.Put((byte*)msg.data(), msg.size());
decoder.MessageEnd();
// Swap in the ASCII message for the binary message
mm = msg;
Таким образом, кто-то дал вам неправильное сообщение, неправильную подпись или неправильный открытый ключ (или некоторую комбинацию).