OpenSSL等效于Java / BouncyCastle签名

时间:2015-02-27 13:06:02

标签: java openssl bouncycastle

我有一个软件如下进行数字签名。

    MessageDigest md = MessageDigest.getInstance("SHA1", "BC");
    Cipher cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");
    cipher.init(Cipher.ENCRYPT_MODE, privateKey);
    byte[] hash = md.digest("message".getBytes());
    byte[] signature = cipher.doFinal(hash);

我想用批量/ openssl的某些行替换它,但是无法再现这个签名。基本上它是SHA1和RSA的组合,并不是那么糟糕。我想知道为什么散列和加密是分开的。两种方式使用openssl执行此操作会导致不同的签名(忽略格式):

openssl dgst -sha1 -binary msg.txt > hash
openssl rsautl -sign -inkey priv.pem -in hash -hexdump

openssl dgst -sha1 -sign priv.pem -hex < msg.txt

所以我缺少了一些东西......

更新:

感谢您的评论!当然,这个Java代码不是正确签名的方式,但验证的代码不在我手中,我的目标是创建一个可以验证的签名。不过,我会提出改变整个事情的建议。

但我终于设法重现了签名。我自己不回答这个问题,因为我想要一个合适的openssl解决方案。所以这就是我得到的:

上面的Java代码填充!哈希代码预填充零字节,长度为256!

4 个答案:

答案 0 :(得分:2)

Java代码通过SHA-1哈希执行原始或教科书RSA。这不安全,您应该在Java代码中使用PKCS#1 v1.5填充(用于签名生成)或PSS。例如,PKCS#1 v1.5使用"SHA1withRSA"类的Signature算法字符串执行。

虽然它不安全但我尝试使用-raw参数复制Java代码的结果,但由于在OpenSSL代码中进行了检查,这失败了:

$ openssl rsautl -encrypt -raw -inkey priv.pem -in hash -hexdump
RSA operation error
3077884104:error:0406B07A:rsa routines:RSA_padding_add_none:data too small for key size:rsa_none.c:76:

所以OpenSSL不会让你犯这个错误。顺便说一句,我也尝试过签名,结果相同。

默认情况下,OpenSSL使用PKCS#1 v1.5填充(用于签名)进行签名生成,使用PKCS#1 v1.5填充(用于加密)进行加密。这将生成与Java代码中的原始签名不同的输出。

答案 1 :(得分:1)

到目前为止,我找到的最佳解决方案是使用236个零字节(填充)和另一个临时文件(哈希)进行手动填充。

COPY padding hash
openssl dgst -sha1 -binary msg.txt >>hash
openssl pkeyutl -sign -in hash -inkey priv.pem -out signature -pkeyopt rsa_padding_mode:none

我尝试使用openssl dgst代替并指定各种填充方案,但没有成功。我假设openssl不支持这种填充方案,并怀疑它是标准的。

答案 2 :(得分:0)

您的msg.txt的内容很可能与您在Java源代码中散列的"message"不同。我在linux上尝试了你的样本,得到了这个:

# echo message > msg.txt
# xxd msg.txt
0000000: 6d65 7373 6167 650a                      message.

您会注意到字符串末尾的其他换行符(0x0a)。

一旦你修剪了它:

# dd if=msg.txt of=msg2.txt bs=1 count=7
# xxd msg2.txt
0000000: 6d65 7373 6167 65                        message

您将获得与Java代码相同的校验和。

就RSA而言,一旦获得相同的源数据,就没有理由不起作用。

答案 3 :(得分:0)

  

cipher.init(Cipher.ENCRYPT_MODE,privateKey);

我很确定这不太正确。

没有“使用私钥加密”这样的操作。在较高级别,当您创建签名时,您将散列和填充作为密文的实例进行签名。然后,您“使用私钥解密”以获得签名。

如果您真的想“使用私钥加密”,那么您应该调查带有恢复的签名方案。这可能是你最接近“使用私钥加密”的原因。

您应该使用Java内置的签名方案之一,尤其是在尝试与OpenSSL命令行实用程序互操作时。例如,请参阅Java Tutorial » Security » RSA algorithm

否则,请查看RSASignature的Sun来源。它们直接与BigIntegers一起使用并执行取幂,尝试“使用私钥加密”。例如,请参阅Sun的RSASignature classcrtCrypt method