Creation of ECDSA public key given curve and public point?

泄露秘密 提交于 2019-12-06 04:12:55

The answer is detailed on the ECDSA wiki page, but its not readily apparent. You need to perform the following to initialize the publicKey given the curve and public point:

string pt = "2DB45A3F21889438B42C8F464C75292BACF5FDDB5DA0B492501B299CBFE92D8F"
            "DB90FC8FF4026129838B1BCAD1402CAE47FE7D8084E409A41AFCE16D63579C5F";

HexDecoder decoder;
decoder.Put((byte*)pt.data(), pt.size());
decoder.MessageEnd();

ECP::Point q;
size_t len = decoder.MaxRetrievable();
// len should be GetField().MaxElementByteLength()

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;

The program above produces the following results.

$ ./cryptopp-test.exe
Validated public key
Q.x: 2db45a3f21889438b42c8f464c75292bacf5fddb5da0b492501b299cbfe92d8fh
Q.y: db90fc8ff4026129838b1bcad1402cae47fe7d8084e409a41afce16d63579c5fh

You can't use GetField().MaxElementByteLength() because the only thing available are the x and y coordinates. Things like field size won't be available until you initialize the underlying DL_GroupParameters_EC< EC > in the public key.

As an example, the following causes a segmentation fault:

ECDSA<ECP, SHA256>::PublicKey publicKey;
unsigned int u = publicKey.GetGroupParameters().GetCurve().GetField().MaxElementByteLength();
cout << "Field element length: " << u << endl;

You can tamper with the public key to ensure a validation failure with:

q.y.Decode(decoder, len/2);
q.y++;

Here's the answer to your second question on how to use 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);
}

Calling Detach on the HexDecoder deletes the current filter, and replaces it with the new filter. In the code above, its the StringSink. You have to do it to ensure memory is not leaked.

Your message does not verify under the public key:

$ ./cryptopp-test.exe
Validated public key
Failed to verify message

You can also try to verify the ASCII message rather than the binary message, but it fails to verify too:

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;

So someone gave you the wrong message, the wrong signature or the wrong public key (or some combination).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!