【问题标题】:Creation of ECDSA public key given curve and public point?给定曲线和公共点创建 ECDSA 公钥?
【发布时间】:2015-02-03 14:40:12
【问题描述】:

我正在努力从公钥的字符串表示创建 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?问了一个与私钥有关的类似问题

【问题讨论】:

    标签: c++ hex crypto++ ecdsa


    【解决方案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();
    // 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;
    

    上面的程序产生以下结果。

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

    您不能使用GetField().MaxElementByteLength(),因为唯一可用的是xy 坐标。在您初始化公钥中的底层 DL_GroupParameters_EC&lt; EC &gt; 之前,字段大小等内容将不可用。

    例如,以下导致分段错误:

    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++;
    

    【讨论】:

    【解决方案2】:

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

    HexDecoder 上调用Detach 会删除当前过滤器,并将其替换为新过滤器。在上面的代码中,它是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;
    

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

    【讨论】:

    • 这非常有效。我已经更新了上面示例中的密钥,并且消息验证正常。再次感谢您的所有帮助
    • 我也可以使用它来获取 ECDSA 签名的 r 和 s 值吗?如果是,我该怎么做?
    • 我知道这是一个老问题,但是,你最终设法得到了 r 和 s 吗?
    猜你喜欢
    • 2015-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-06
    相关资源
    最近更新 更多