Java produces and expects to receive signatures in a slightly different form. The message hash must be encoded in DER, then supplemented by PKCS # 1 and only then signed with the private key. And Openssl has a command for this (because it is actually a standard procedure). Instead
openssl dgst -sha256 < data.txt > hash openssl rsautl -sign -inkey private.pem -keyform PEM -in hash > signature
you do
openssl dgst -sha256 -binary -sign private.pem data.txt > signature
Also note:
- your
data.txt contains a new line, do not forget about it in the variable String verification sig.update(verification.getBytes()) must explicitly indicate the encoding - the same encoding used to populate the data.txt file, for example: sig.update(verification.getBytes("UTF-8"))
The rest of your commands / code looks fine.
UPD - reply to @GilCol about the differences:
The indentation is the same for both signed messages (PKCS # 1). But the messages are different.
When you use openssl dgst -sha256 < data.txt > hash , hash will contain (depending on the version of openssl):
(stdin)= aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f
or
aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f
This is just text, and you will sign this message with openssl rsautl -sign ... We can see that with openssl rsautl -verify ... :
If you use openssl dgst -sha256 -binary < data.txt > hash to get the hash in binary (clean) form, and then sign it, the result will be better, but still not right:
# raw message as-is - we can see the same padding $ openssl rsautl -in signature -pubin -inkey public.pem -verify -raw -hexdump 0000 - 00 01 ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0010 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0020 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0030 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0040 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0050 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0060 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0070 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0080 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0090 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 00a0 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 00b0 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 00c0 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 00d0 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff 00 ................ 00e0 - ae c0 70 64 5f e5 3e e3-b3 76 30 59 37 61 34 f0 ..pd_.>..v0Y7a4.
But when you use openssl dgst -sha256 -sign ... , the message is different - it is now the standard ASN.1 structure for message digests (hashes). Let's get a look:
# raw message as-is - we can see the same padding $ openssl rsautl -in signature -pubin -inkey public.pem -verify -raw -hexdump 0000 - 00 01 ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0010 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0020 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0030 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0040 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0050 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0060 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0070 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0080 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 0090 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 00a0 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 00b0 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ 00c0 - ff ff ff ff ff ff ff ff-ff ff ff ff 00 30 31 30 .............010
As you can see, only the last signature file had the correct ASN.1 structure, the previous two were just βarbitraryβ messages signed with the RSA private key.