使用OpenSSL签名的邮件;无法使用Android Java验证 [英] Signed message using OpenSSL; can't verify with Android Java
问题描述
我使用SHA256和RSA在我的Ubuntu机器上使用OpenSSL签署一条消息。
我的目标是使用Android的Java在Android上验证此消息。
I'm using SHA256 and RSA to sign a message on my Ubuntu machine using OpenSSL. My goal is to verify this message on Android using Android's Java.
在ubuntu上使用了以下命令:
Following commands were used on ubuntu:
openssl genrsa -out private.pem 1024
openssl rsa -in private.pem -out public.pem -outform PEM -pubout
echo 'foobar' > data.txt
openssl dgst -sha256 < data.txt > hash
openssl rsautl -sign -inkey private.pem -keyform PEM -in hash > signature
openssl rsa -in private_key.pem -pubout -outform DER -out public_key.der
openssl enc -base64 -in signature -out base64_signature
我现在已经创建了密钥,签名了消息,为公钥创建了一个.der文件,该文件应该能够在Java中访问,并使用Base64编码消息。
然后我将.der公钥放在我的设备上,并成功加载到PublicKey类中。
I have now created keys, signed the message, created a .der file for the public key that should be able to be accessed in Java and encoded the message with Base64. I then place the .der public key on my device and successfully load the key into the class PublicKey.
此方法用于验证消息:
public static boolean verify(PublicKey publicKey,String data,String verification){
java.security.Signature sig;
try {
sig = java.security.Signature.getInstance("SHA256WithRSA");
sig.initVerify(publicKey);
try {
sig.update(verification.getBytes());
} catch (Exception e) {
...
}
if (!sig.verify(Base64.decode(data, Base64.DEFAULT))) {
return false;
}
return true;
}
catch ....
return false;
}
调用方法时的参数:
verify(PublicKey, Base64 encoded data in a String that is to be verified, "foobar");
显然验证失败,但我不明白为什么。我猜它必须用编码(?)做一些事情。
Obviously the verification fails, but I can't understand why. I'm guessing it has to do something with the encoding(?).
更新!
所以我设法将 Base64.decode(data,Base64.DEFAULT))
的结果写入文件,并使用hexeditor将其与原始签名文件进行比较。完全不同!
Update!
So I managed to write the results of Base64.decode(data, Base64.DEFAULT))
to a file and compare it with the original signature file using a hexeditor. Completely different!
推荐答案
Java生成并期望以略微不同的形式接收签名。消息的哈希必须在DER中编码,然后用PKCS#1填充,然后仅使用私钥进行签名。 Openssl有一个命令(因为它实际上是一个标准过程)。而不是
Java produces and expects to receive signatures in slightly different form. Hash of the message must be encoded in DER, then padded with PKCS#1 and only then signed with private key. And Openssl has a command for that (because it's actually a standard procedure). Instead of
openssl dgst -sha256 < data.txt > hash
openssl rsautl -sign -inkey private.pem -keyform PEM -in hash > signature
你
openssl dgst -sha256 -binary -sign private.pem data.txt > signature
另请注意:
- 您的
data.txt
包含换行符,不要忘记它字符串验证
li>
-
sig.update(verification.getBytes())
应明确指明一个字符集 - 同一个字符集,用于填充data.txt
文件,例如:sig.update(verification.getBytes(UTF-8))
- your
data.txt
contains a newline, don't forget it inString verification
variable sig.update(verification.getBytes())
should explicitly indicate a charset - the same charset, that was used to fill thedata.txt
file, for example:sig.update(verification.getBytes("UTF-8"))
其余的命令/代码似乎没问题。
The rest of your commands/code seems OK.
UPD - 回答@GilCol有关差异:
UPD - to answer @GilCol about the differences:
两个签名消息(PKCS#1)的填充都相同。但是消息是不同的。
The padding is the same for both signed messages (PKCS#1). But the messages are different.
当您使用 openssl dgst -sha256< data.txt> hash
, hash
将包含(取决于openssl版本):
When you use openssl dgst -sha256 < data.txt > hash
, hash
will contain (depending on openssl version):
(stdin)= aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f
或
aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f
它是您将使用 openssl rsautl -sign ...
签署的消息。我们可以看到 openssl rsautl -verify ...
:
It is just plain text and it is the message you will sign using openssl rsautl -sign ...
. We can see that with openssl rsautl -verify ...
:
# raw message as-is - we can see the 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 00 61 ...............a #
00c0 - 65 63 30 37 30 36 34 35-66 65 35 33 65 65 33 62 ec070645fe53ee3b #
00d0 - 33 37 36 33 30 35 39 33-37 36 31 33 34 66 30 35 3763059376134f05 # your plain-text message
00e0 - 38 63 63 33 33 37 32 34-37 63 39 37 38 61 64 64 8cc337247c978add #
00f0 - 31 37 38 62 36 63 63 64-66 62 30 30 31 39 66 0a 178b6ccdfb0019f. # we can even see newline char (0a) at the end
# strip the padding
$ openssl rsautl -in signature -pubin -inkey public.pem -verify -pkcs -hexdump
0000 - 61 65 63 30 37 30 36 34-35 66 65 35 33 65 65 33 aec070645fe53ee3
0010 - 62 33 37 36 33 30 35 39-33 37 36 31 33 34 66 30 b3763059376134f0
0020 - 35 38 63 63 33 33 37 32-34 37 63 39 37 38 61 64 58cc337247c978ad
0030 - 64 31 37 38 62 36 63 63-64 66 62 30 30 31 39 66 d178b6ccdfb0019f
0040 - 0a .
如果使用 openssl dgst -sha256 -binary< data.txt> hash
以二进制(纯)形式获得散列,然后对其进行签名,结果会更好,但仍然不正确:
If you use openssl dgst -sha256 -binary < data.txt > hash
to get hash in binary (pure) 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. # the hash - now in binary form
00f0 - 58 cc 33 72 47 c9 78 ad-d1 78 b6 cc df b0 01 9f X.3rG.x..x...... #
# strip the padding
$ openssl rsautl -in signature -pubin -inkey public.pem -verify -pkcs -hexdump
0000 - ae c0 70 64 5f e5 3e e3-b3 76 30 59 37 61 34 f0 ..pd_.>..v0Y7a4. # just the hash, nothing else
0010 - 58 cc 33 72 47 c9 78 ad-d1 78 b6 cc df b0 01 9f X.3rG.x..x...... #
但是当你使用 openssl dgst -sha256 -sign ...
,消息是不同的 - 它现在是消息摘要(哈希)的标准ASN.1结构。让我们看看:
But when you use openssl dgst -sha256 -sign ...
, the message is different - it's now a standard ASN.1 structure for message digests (hashes). Let's see:
# 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 #
00d0 - 0d 06 09 60 86 48 01 65-03 04 02 01 05 00 04 20 ...`.H.e....... # the message - it's different
00e0 - ae c0 70 64 5f e5 3e e3-b3 76 30 59 37 61 34 f0 ..pd_.>..v0Y7a4. # <- we can see the hash (in binary form) starting at this line
00f0 - 58 cc 33 72 47 c9 78 ad-d1 78 b6 cc df b0 01 9f X.3rG.x..x...... #
# strip the padding
$ openssl rsautl -in signature -pubin -inkey public.pem -verify -pkcs -hexdump
0000 - 30 31 30 0d 06 09 60 86-48 01 65 03 04 02 01 05 010...`.H.e.....
0010 - 00 04 20 ae c0 70 64 5f-e5 3e e3 b3 76 30 59 37 .. ..pd_.>..v0Y7
0020 - 61 34 f0 58 cc 33 72 47-c9 78 ad d1 78 b6 cc df a4.X.3rG.x..x...
0030 - b0 01 9f ...
# parse the message and show the underlying ASN.1 structure
$ openssl rsautl -in signature -pubin -inkey public.pem -verify -pkcs -asn1parse
0:d=0 hl=2 l= 49 cons: SEQUENCE
2:d=1 hl=2 l= 13 cons: SEQUENCE
4:d=2 hl=2 l= 9 prim: OBJECT :sha256 # type of hash
15:d=2 hl=2 l= 0 prim: NULL
17:d=1 hl=2 l= 32 prim: OCTET STRING
0000 - ae c0 70 64 5f e5 3e e3-b3 76 30 59 37 61 34 f0 ..pd_.>..v0Y7a4. # the hash in binary form
0010 - 58 cc 33 72 47 c9 78 ad-d1 78 b6 cc df b0 01 9f X.3rG.x..x...... # and no extra newline chars
正如你所看到的,只有最后的签名
文件具有正确的ASN.1结构,前两个只是一些任意消息,用RSA私钥签名。
As you can see, only the last signature
file had proper ASN.1 structure, previous two were just "some arbitrary" messages, signed with RSA private key.
这篇关于使用OpenSSL签名的邮件;无法使用Android Java验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!