c++ - 使用 ECDSA 或 DSA 对预先计算的哈希进行签名

标签 c++ digital-signature crypto++

我正在研究 Crypto++ 签名者并使用以下直接来自 wiki 的代码:

ECDSA<ECP, SHA256>::PrivateKey privateKey;
const Integer D(string("8964e19c5ae38669db3047f6b460863f5dc6c4510d3427e33545caf9527aafcf").c_str());
privateKey.Initialize(CryptoPP::ASN1::secp256r1(), D);
if (!privateKey.Validate(rng, 3)) {
    cerr << "ECDSA privateKey key validation failed after setting private parameter." << endl;
    return 1;
}

ECDSA<ECP,SHA256>::Signer signer(privateKey);
StringSource ss1(message, true,
    new SignerFilter(rng, signer,
        new HexEncoder(new StringSink(signature), false)
    ) // SignerFilter
); // StringSource
int slen = signature.length() / 2;
// since it's IEEE P1363 format to display r and s:
cout << signature.substr(0, slen) << "\n"
     << signature.substr(slen, slen) << endl;

现在,我想知道如何覆盖那里的 SHA256 以直接指定要传递给签名算法的摘要值。

我已经深入研究了 wikidoxygen documentation , 但没有成功。起初我以为可能是 NullHash可以在那里提供帮助,但根据消息来源,它实际上只是零散列。我也对 PK_MessageAccumulator 抱有希望但它似乎没有像我预期的那样工作。

那么,是否有某种我完全错过的继承自 HashTransformation 类的“身份”函数?
如果不是,您将如何构建类似允许指定要直接签名的摘要的东西?

最佳答案

H(M)=M might work. Would it be possible to feed such a custom HashTransformation to the ECDSA<ECP,H>::Signer?

是的。该程序如下。它提供了一个 IdentityHash将输入复制到输出的类。它需要一个模板参数来指定散列大小。

但是要小心。消息在散列后被格式化。我们真正拥有的是to_sign = MF(H(M)) .

$ cat test.cxx
#include "cryptlib.h"
#include "secblock.h"
#include "eccrypto.h"
#include "osrng.h"
#include "oids.h"
#include "hex.h"

#include <iostream>
#include <string>

using namespace CryptoPP;

template <unsigned int HASH_SIZE = 32>
class IdentityHash : public HashTransformation
{
public:
    CRYPTOPP_CONSTANT(DIGESTSIZE = HASH_SIZE)
    static const char * StaticAlgorithmName()
    {
        return "IdentityHash";
    }

    IdentityHash() : m_digest(HASH_SIZE), m_idx(0) {}

    virtual unsigned int DigestSize() const
    {
        return DIGESTSIZE;
    }

    virtual void Update(const byte *input, size_t length)
    {
        size_t s = STDMIN(STDMIN<size_t>(DIGESTSIZE, length),
                                         DIGESTSIZE - m_idx);    
        if (s)
            ::memcpy(&m_digest[m_idx], input, s);
        m_idx += s;
    }

    virtual void TruncatedFinal(byte *digest, size_t digestSize)
    {
        if (m_idx != DIGESTSIZE)
            throw Exception(Exception::OTHER_ERROR, "Input size must be " + IntToString(DIGESTSIZE));

        ThrowIfInvalidTruncatedSize(digestSize);

        if (digest)
            ::memcpy(digest, m_digest, digestSize);

        m_idx = 0;
    }

private:
    SecByteBlock m_digest;
    size_t m_idx;
};

int main(int argc, char* argv[])
{
    AutoSeededRandomPool prng;

    ECDSA<ECP, IdentityHash<32> >::PrivateKey privateKey;
    privateKey.Initialize(prng, ASN1::secp256r1());

    std::string message;
    message.resize(IdentityHash<32>::DIGESTSIZE);
    ::memset(&message[0], 0xAA, message.size());

    ECDSA<ECP, IdentityHash<32> >::Signer signer(privateKey);
    std::string signature;

    StringSource ss(message, true,
                        new SignerFilter(prng, signer,
                            new HexEncoder(new StringSink(signature))
                        ) // SignerFilter
                    ); // StringSource

    std::cout << "Signature: " << signature << std::endl;

    return 0;
}

我知道它会编译并生成输出。我不知道它是否是正确的输出:

skylake:cryptopp$ g++ test.cxx ./libcryptopp.a -o test.exe
skylake:cryptopp$ ./test.exe
Signature: cafb8fca487c7d5023fbc76ccf96f107f72a07fecca77254e8845a2c8f2ed0ee8b50b
8ee0702beb7572eaa30c8d250a7b082c79f2f02e58ccfb97d7091755e91

你可以测试IdentityHash与以下。类(class)IdentityHash与前面的示例没有变化。 main功能做到了。

$ cat test.cxx
#include "cryptlib.h"
#include "secblock.h"

#include <iostream>
#include <string>

using namespace CryptoPP;

template <unsigned int HASH_SIZE = 32>
class IdentityHash : public HashTransformation
{
public:
    CRYPTOPP_CONSTANT(DIGESTSIZE = HASH_SIZE)
    static const char * StaticAlgorithmName()
    {
        return "IdentityHash";
    }

    IdentityHash() : m_digest(HASH_SIZE), m_idx(0) {}

    virtual unsigned int DigestSize() const
    {
        return DIGESTSIZE;
    }

    virtual void Update(const byte *input, size_t length)
    {
        size_t s = STDMIN(STDMIN<size_t>(DIGESTSIZE, length),
                                         DIGESTSIZE - m_idx);    
        if (s)
            ::memcpy(&m_digest[m_idx], input, s);
        m_idx += s;
    }

    virtual void TruncatedFinal(byte *digest, size_t digestSize)
    {
        if (m_idx != DIGESTSIZE)
            throw Exception(Exception::OTHER_ERROR, "Input size must be " + IntToString(DIGESTSIZE));

        ThrowIfInvalidTruncatedSize(digestSize);

        if (digest)
            ::memcpy(digest, m_digest, digestSize);

        m_idx = 0;
    }

private:
    SecByteBlock m_digest;
    size_t m_idx;
};

int main(int argc, char* argv[])
{
    std::string message;
    message.resize(IdentityHash<32>::DIGESTSIZE);
    ::memset(&message[0], 'A', message.size());

    IdentityHash<32> hash;
    hash.Update((const byte*)message.data(), message.size());

    std::string digest(32, 0);
    hash.TruncatedFinal((byte*)digest.data(), digest.size());

    std::cout << "Message: " << message << std::endl;
    std::cout << " Digest: " << digest << std::endl;

    return 0;
}

它产生:

skylake:cryptopp$ g++ test.cxx ./libcryptopp.a -o test.exe
skylake:cryptopp$ ./test.exe
Message: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 Digest: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

关于c++ - 使用 ECDSA 或 DSA 对预先计算的哈希进行签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45186660/

相关文章:

c++ - 非静态成员函数的无效使用

c++ - 没有对象参数特化的模板函数

c++ - 为什么这个针对给定挑战的解决方案不起作用?

c++ - Qt错误:expected primary-expression before ')' token

ssl - 使用 openssl smime 进行数据验证失败

java - 为特定 XML 元素/节点创建数字签名时引用 URI 错误

java - 使用用户签名在服务器文档上签署 PDF

gcc - 使用Cygwin x86_64构建Crypto++ 5.6.2

c++ - 将公钥与 Crypto++ 的 ECDH 类配合使用

c++ - FileStore::OpenErr 在内存位置 0x012FED64