我试图了解Java java.security.Signature 类的作用。如果我计算一个SHA1消息摘要,然后使用RSA加密该摘要,则得到的结果与要求 Signature 类对同一事物进行签名的结果不同:
// Generate new key KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); String plaintext = "This is the message being signed"; // Compute signature Signature instance = Signature.getInstance("SHA1withRSA"); instance.initSign(privateKey); instance.update((plaintext).getBytes()); byte[] signature = instance.sign(); // Compute digest MessageDigest sha1 = MessageDigest.getInstance("SHA1"); byte[] digest = sha1.digest((plaintext).getBytes()); // Encrypt digest Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); byte[] cipherText = cipher.doFinal(digest); // Display results System.out.println("Input data: " + plaintext); System.out.println("Digest: " + bytes2String(digest)); System.out.println("Cipher text: " + bytes2String(cipherText)); System.out.println("Signature: " + bytes2String(signature));
结果(例如):
输入数据:这是正在签名的消息 摘要:62b0a9ef15461c82766fb5bdaae9edbe4ac2e067 密码文本:057dc0d2f7f54acc95d3cf5cba9f944619394711003bdd12 … 签名:7177c74bbbb871cc0af92e30d2808ebae146f22d3 …
我必须对 Signature 所做的事情有一个基本的误解-我已经对其进行了跟踪,并且它似乎正在对 MessageDigest 对象调用update ,将算法设置为我期望的SHA1,然后获取摘要,然后执行加密。是什么使结果有所不同?
编辑:
列奥尼达斯(Leonidas)让我检查了签名方案是否应该执行我认为的功能。RFC中定义了两种类型的签名:
其中的第一个(PKCS1)是我上面描述的。它使用哈希函数创建摘要,然后使用私钥对结果进行加密。
所述第二算法使用随机盐值,并且是更安全的,但非确定性。如果重复使用相同的密钥,则由上面的代码产生的签名不会更改,因此我认为它可能不是PSS。
这是bytes2string我使用的方法:
bytes2string
private static String bytes2String(byte[] bytes) { StringBuilder string = new StringBuilder(); for (byte b : bytes) { String hexString = Integer.toHexString(0x00FF & b); string.append(hexString.length() == 1 ? "0" + hexString : hexString); } return string.toString(); }
好的,我已经解决了问题。我很傻 Leonidas是正确的,不仅仅是加密的哈希值,还有与摘要连接在一起的哈希算法的ID:
DigestInfo ::= SEQUENCE { digestAlgorithm AlgorithmIdentifier, digest OCTET STRING }
这就是为什么它们不同的原因。