Then I have a factory function that takes the digest buffer and length
as parameters and returns a pointer to a newly allocated
CryptoPP::PK_MessageAccumulatorImpl<MyExternalDigestHashTransformation>.
That then gets fed to InputSignature() on a PK_Verifier or Sign() on a
PK_Signer. It's worth remembering that in the former case you own your
PK_MessageAccumulator and in the latter the PK_Signer takes ownership.
I don't think this is a particularly good way to use the library, but
it was the shortest path I could find to doing this in a
digest-agnostic fashion without inviting serious errors.
Geoff
> --
> You received this message because you are subscribed to the "Crypto++ Users" Google Group.
> To unsubscribe, send an email to cryptopp-user...@googlegroups.com.
> More information about Crypto++ and this group is available at http://www.cryptopp.com.
Be *very* careful if you do this. It's an approach that invites
serious, security-relevant errors. It sounds easy when you describe
it, but I've seen extremely smart developers get this wrong in ways
that led to acceptance of forged signatures. MFSA 2006-60[1] is a good
public example of a prominent case.
It also marries your code pretty tightly to RSA, which may or may not
be an issue for you.
Geoff
[1] http://www.mozilla.org/security/announce/2006/mfsa2006-60.html
SHA-1. Here's a good explanation of the mechanics:
http://www.mail-archive.com/crypto...@metzdowd.com/msg06537.html
Geoff
It's kind of a dirty trick, but the only way I could find to wire this
in without subclassing for each digest I wanted. (If anyone knows a
cleaner way to accomplish this, I'd love to hear. I can confirm that
this works, though :-) )
Here's the relevant code from my factory:
http://cryptopp.pastebin.com/d0DHqaqF
Then when signing, the basic flow is
PK_Signer * signer = 0; // set up signer for the algorithm you need
PKIFCryptoPPErrorsAccumulator * ed = NewEDAccumulator(pHashData,nHashDataLen);
signer->Sign(rng, ed, pSignature);
And when verifying it's
PK_Verifier * verifier = 0; // set up verifier for the algorithm you need
PKIFCryptoPPExternalDigestAccumulator * ed =
NewEDAccumulator(pHashData,nHashDataLen);
verifier->InputSignature(*ed,pSignature,nSignatureLen);
bool verified = verifier->Verify(ed);
HTH,
Geoff
template <typename Hash> class Prehashed : public HashTransformation { public: enum { DIGESTSIZE = Hash::DIGESTSIZE }; static const char * CRYPTOPP_API StaticAlgorithmName() {return Hash::StaticAlgorithmName();} virtual void Update(const byte *input, size_t length) { m_prehashed += SecByteBlock(input, length); } virtual unsigned int DigestSize() const { return m_prehashed.size(); } virtual void TruncatedFinal(byte *digest, size_t digestSize) { memcpy(digest, m_prehashed.data(), digestSize); } private: SecByteBlock m_prehashed; }; template<> const byte PKCS_DigestDecoration<Prehashed<SHA1> >::decoration[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14}; template<> const unsigned int PKCS_DigestDecoration<Prehashed<SHA1> >::length = sizeof(PKCS_DigestDecoration<Prehashed<SHA1>>::decoration); // Signer object RSASS<PKCS1v15, Prehashed<SHA1> >::Signer signer(privateKey); // Verifier object RSASS<PKCS1v15, Prehashed<SHA1> >::Verifier verifier(publicKey);
It is easier to just pad your pre-hashed data manually according to PKCS#1 and then do a raw encrypt with the private key:CryptoPP::RSA::PrivateKey mPrivateKey; //Generate as necessary length = mPrivateKey.GetModulus().ByteCount(); byte tmp[length]; Pad(tmp, length, inData, inLength); //Pad the data CryptoPP::Integer m(tmp, length); //Encode the message CryptoPP::Integer c = mPrivateKey.ApplyFunction(m); // Calculate c CryptoPP::Integer cInv = mPrivateKey.CalculateInverse(rng, c); //Inverse c for (int i = 0; i < cInv.ByteCount() ; i++) tmp[i] = cInv.GetByte(i); outData = tmp;