给出曲线和公共点的ECDSA公钥的创建?

时间:2014-12-05 12:15:11

标签: c++ hex crypto++ ecdsa

我正在努力从公钥的字符串表示创建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我在这里问了一个与私钥有关的类似问题Creation of ECDSA private key given curve and private exponent?

2 个答案:

答案 0 :(得分:1)

答案详见ECDSA wiki page,但不是很明显。给定曲线和公共点,您需要执行以下操作来初始化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);

是一种kludge。这是您要使用的值,而不是SHA256::DIGESTSIZE

GetField().MaxElementByteLength()

但是您无法使用它,因为唯一可用的是xy坐标。在初始化公钥中的基础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++;

答案 1 :(得分:0)

以下是关于如何使用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;

所以有人给了你错误的信息,错误的签名或错误的公钥(或某种组合)。