Signing a hash

335 views
Skip to first unread message

Magnus J

unread,
Feb 17, 2011, 11:48:48 AM2/17/11
to Crypto++ Users
Hi,

How do I go about using RSA for signing an already calculated hash?

I've found the PK_Signer method Sign() but how do I get my hash into a
PK_MessageAccumulator?

Is there another or even correct way of doing this that I'm missing?

Jeffrey Walton

unread,
Feb 17, 2011, 12:10:05 PM2/17/11
to Crypto++ Users
I'm not sure that it incorrect - maybe just non-standard??? Its
probably easiest to call the RSA decrypt function on the cipher text
(i.e., the hash) yourself. http://www.cryptopp.com/wiki/Raw_rsa

Jeff

Geoff Beier

unread,
Feb 17, 2011, 12:12:22 PM2/17/11
to Magnus J, Crypto++ Users
There may be a better approach than this, but what I did was create a
new class derived from CryptoPP::HashTransformation. This new class
gets created with an already-calculated digest buffer. It has an empty
Update() method and implements TruncatedFinal(), DigestSize() and
TruncatedVerify() exactly as you'd think.

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.

Geoff Beier

unread,
Feb 17, 2011, 12:18:11 PM2/17/11
to Jeffrey Walton, Crypto++ Users
On Thu, Feb 17, 2011 at 12:10, Jeffrey Walton <nolo...@gmail.com> wrote:
>
>
> I'm not sure that it incorrect - maybe just non-standard??? Its
> probably easiest to call the RSA decrypt function on the cipher text
> (i.e., the hash) yourself. http://www.cryptopp.com/wiki/Raw_rsa
>

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

Jeffrey Walton

unread,
Feb 17, 2011, 12:31:07 PM2/17/11
to Crypto++ Users


On Feb 17, 12:18 pm, Geoff Beier <geoffbe...@gmail.com> wrote:
> On Thu, Feb 17, 2011 at 12:10, Jeffrey Walton <noloa...@gmail.com> wrote:
>
> > I'm not sure that it incorrect - maybe just non-standard??? Its
> > probably easiest to call the RSA decrypt function on the cipher text
> > (i.e., the hash) yourself.http://www.cryptopp.com/wiki/Raw_rsa
>
> 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.
Agreed. I don't recall seeing that advisory.

When the collisions were engineered using the extra data, what digest
was in play? MD2 or MD5? I would be surprised if someone could do it
with SHA-1, and bet against it with near certainty when using SHA-2 or
Whirlpool.

Geoff Beier

unread,
Feb 17, 2011, 12:38:01 PM2/17/11
to Jeffrey Walton, Crypto++ Users
On Thu, Feb 17, 2011 at 12:31, Jeffrey Walton <nolo...@gmail.com> wrote:
>
> When the collisions were engineered using the extra data, what digest
> was in play? MD2 or MD5? I would be surprised if someone could do it
> with SHA-1, and bet against it with near certainty when using SHA-2 or
> Whirlpool.
>

SHA-1. Here's a good explanation of the mechanics:
http://www.mail-archive.com/crypto...@metzdowd.com/msg06537.html


Geoff

Jeffrey Walton

unread,
Feb 17, 2011, 1:12:15 PM2/17/11
to Crypto++ Users


On Feb 17, 12:38 pm, Geoff Beier <geoffbe...@gmail.com> wrote:
> On Thu, Feb 17, 2011 at 12:31, Jeffrey Walton <noloa...@gmail.com> wrote:
>
> > When the collisions were engineered using the extra data, what digest
> > was in play? MD2 or MD5? I would be surprised if someone could do it
> > with SHA-1, and bet against it with near certainty when using SHA-2 or
> > Whirlpool.
>
> SHA-1. Here's a good explanation of the mechanics:
> http://www.mail-archive.com/cryptogra...@metzdowd.com/msg06537.html
OK, thanks. I updated the page with a note on signing keys, exponents
of 3, and the US-Cert advisory.

Jeff

Magnus J

unread,
Feb 21, 2011, 9:03:05 AM2/21/11
to Crypto++ Users
Thank you.

> 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>.

This part gets me a bit perplex though. I still don't see how you get
the hash into the message accumulator. The PK_MessageAccumulatorImpl
objectholder looks very protected.

Geoff Beier

unread,
Feb 21, 2011, 11:06:33 AM2/21/11
to Magnus J, Crypto++ Users

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

Message has been deleted

Roman Pasechnik

unread,
Jun 11, 2013, 4:00:50 AM6/11/13
to cryptop...@googlegroups.com, Magnus J
Signing with prehashed SHA1:

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

Понеділок, 21 лютого 2011 р. 18:06:33 UTC+2 користувач Geoff Beier написав:
Message has been deleted

Mattias Hird

unread,
Jun 11, 2013, 10:03:32 AM6/11/13
to cryptop...@googlegroups.com
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;
Reply all
Reply to author
Forward
0 new messages