我有一个软件做数字签名如下。
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);
我想用几行 batch/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!
最佳答案
Java 代码通过 SHA-1 哈希执行原始或教科书 RSA。这是不安全的,您应该在 Java 代码中使用 PKCS#1 v1.5 填充(用于签名生成)或 PSS。例如,PKCS#1 v1.5 是使用 Signature
类的 "SHA1withRSA"
算法字符串执行的。
虽然它不安全,但我尝试使用 -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 代码中的原始签名不同的输出。
关于java - Java/BouncyCaSTLe 签名的 OpenSSL 等价物,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28765861/