I want to generate a RSA-SHA256 signature in Java, but I can't get it to produce the same signature as with OpenSSL on the console.
This is what I did with OpenSSL (following this tutorial):
Generate key pair:
openssl genrsa -out private.pem 1024
Extract public key:
openssl rsa -in private.pem -out public.pem -outform PEM -pubout
Create hash of data:
echo 'data to sign' > data.txt
openssl dgst -sha256 < data.txt > hash
The generated hash file starts with (stdin)=
what I removed by hand (first forgot to mention it, thanks mata).
Sign hash:
openssl rsautl -sign -inkey private.pem -keyform PEM -in hash > signature
To reproduce the results in Java I first converted the private key from PEM to DER:
openssl pkcs8 -topk8 -inform PEM -outform DER -in private.pem -nocrypt > private.der
Now I wrote this Java class to generate the same signature:
public class RSATest {
public static void main(String[] args) throws IOException,
NoSuchAlgorithmException, InvalidKeySpecException,
InvalidKeyException, SignatureException {
byte[] encodedPrivateKey = readFile("private.der");
byte[] content = readFile("data.txt");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory
.generatePrivate(keySpec);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(content);
byte[] signatureBytes = signature.sign();
FileOutputStream fos = new FileOutputStream("signature-java");
fos.write(signatureBytes);
fos.close();
}
private static byte[] readFile(String filename) throws IOException {
File file = new File(filename);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
file));
byte[] bytes = new byte[(int) file.length()];
bis.read(bytes);
bis.close();
return bytes;
}
}
Unfortunately the results are not the same, so I think I must have done something wrong, but I can't figure out what. Can someone of you help me to find the bug?
produces something like:
notice the
(stdin)=
'? you don't want that to be part of your hash, if you need to create a digest, use the-binary
option.try using this to sign your data:
This does everything you need.
edit - a little more explanations:
let's create a digest and show it
now we take this digest and sign int using
rsautl
:now let's sign the same file using
dgst
directly:So what's different here? To see that, we can verify the signature and show the raw output. Both files do contain the digest, but the metadata and padding is different:
To see this more clearly, we can try to use the
-asn1parse
flag, which won't work for the first signature, but for the second it shows the correct structure of the signature: