2017-07-19 52 views
3

我與加密+簽名者玩弄和使用下面的代碼,徑直出了維基的預先計算哈希:簽訂ECDSA或DSA

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類繼承的「身份」功能,我完全錯過了?
如果不是,你會如何去建設類似的東西,允許指定摘要直接簽名?

+0

爲了什麼它的價值,這是圖書館的一個非常討厭的區域。我幫助切入了RFC 6979,確定性簽名。組件之間有如此多的交互(比如消息累加器,格式化程序和簽名函數),所以我把事情做得很乾淨整潔。對我來說這是非常痛苦的事情(當談到Crypto ++時,我的門檻很高)。 – jww

+0

@jww其實我試圖做的是_simply_簽名/驗證**預計算**哈希。我不知道你是否知道[EdDSA](https://tools.ietf.org/html/rfc8032)及其變體名爲PureEdDSA。然後,您可以將EdDSA簡單描述爲PureEdDSA對散列消息H(M)的應用。以同樣的方式,我試圖用「純粹的」ECDSA簽名一個預先計算的散列,我將其作爲輸入接收。所以我在想也許HashTransformation什麼也不做,並輸出消息:H(M)= M可能工作。將這種自定義HashTransformation提供給ECDSA ::簽名者有可能嗎? – Lery

回答

3

H(M)=M可能工作。是否有可能將這種定製HashTransformation添加到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有以下幾點。類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 
+0

謝謝,我會明天嘗試第一件事,讓你知道它是如何工作的。我對你提到的MF函數有點困惑,是指根據Sec1v2的4.1.3節將散列轉換爲整數的方式? – Lery

+0

精彩,它完美的工作,並與OpenSSL,mbedTLS和Go互操作!您是否以另一個HashTransformation爲例?我試圖從SHA3開始,但是無法圍繞所有基於模板的編程打包。與我在Crypto ++代碼中看到的其他散列相比,您的版本非常整齊。 – Lery

+0

絕妙的主意,謝謝。 – Lery