How to make “MessageDigest SHA-1 and Signature NONEwithRSA” equivalent to “Signature SHA1withRSA ”



I am interested in applying a SHA-1 hash with RSA signature to some data, but I need to do it in two steps – apply hash first and then sign the data. The Signature.sign() function appears to create a more complex (ASN.1?) data structure that is ultimately signed (see this question). How can I make the two equivalent without using any external libraries like BouncyCastle?

Apply hash and sign in single step with Signature:

PrivateKey privatekey = (PrivateKey) keyStore.getKey(alias, null);
...
sig = Signature.getInstance("SHA1withRSA", "SunMSCAPI");
sig.initSign(privatekey);
sig.update(data_to_sign);
byte[] bSignedData_CAPISHA1_CAPIRSA = sig.sign();

Apply hash via MessageDigest, then sign with Signature:

PrivateKey privatekey = (PrivateKey) keyStore.getKey(alias, null);
...
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
byte[] data_to_sign = sha1.digest(bdataToSign);
Signature sig = Signature.getInstance("NONEwithRSA", "SunMSCAPI");
sig.initSign(privatekey);
sig.update(data_to_sign);
byte[] bSignedData_JAVASHA1_CAPIRSA = sig.sign();
...

I am looking for the following equivalency:

bSignedData_JAVASHA1_CAPIRSA == bSignedData_CAPISHA1_CAPIRSA

My ultimate goal is to create the hash and then sign with a PKCS11 token, but I require the signed data to be the same format as legacy data for verification purposes.

Answer

I was able to solve this by doing the following:

  1. The data to be signed needed to be formatted correctly in a DigestInfo DER-encoded byte array. The Signature SHA1withRSA takes care of this for you, but if you want to accomplish it in a two-step process, you need to create your own DigestInfo. I ended up copying a very minimal amount of ASN.1 classes from BouncyCastle into my project to accomplish this, despite my desire not to use a third party lib.

  2. If you try to use the Cipher API to encrypt the DigestInfo, the PKCS1 padding will be random and not appropriate for a digital signature. I needed static padding.

  3. The Signature.getInstance(“NONEwithRSA”, “SunMSCAPI”) rejects the DER-encoded DigestInfo format, and will return an error if you try to sign that data. But, since I ultimately wanted to use the PKCS11 API to generate the signature, I ended up signing the DER-encoded DigestInfo with the PKCS11 C_SignInit and C_Sign functions.

To summarize, what worked for me was:

  1. generate the SHA-1 hash of the data to sign using the Java MessageDigest API
  2. generated a DigestInfo DER-encoded ASN.1 object with the SHA-1 hash and SHA-1 OID embedded in the object.
  3. signed the DigestInfo using the PKCS11 C_Sign function from a third party library.

The following links were most helpful in solving my problem:

Oracle Forums: SHA1withRSA – how to do that in 2 steps?

StackOverflow: Using SHA1 and RSA with java.security.Signature vs. MessageDigest and Cipher



Source: stackoverflow