使用SHA1和RSA与java.security.Signature vs. MessageDigest和Cipher [英] Using SHA1 and RSA with java.security.Signature vs. MessageDigest and Cipher

查看:999
本文介绍了使用SHA1和RSA与java.security.Signature vs. MessageDigest和Cipher的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解Java java.security.Signature 类的作用。如果我计算一个SHA1消息摘要,然后使用RSA加密该摘要,我得到不同的结果,要求签名类签署同样的事情:

  //生成新密钥
KeyPair keyPair = KeyPairGenerator.getInstance(RSA)。generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
String plaintext =这是正在签名的消息;

//计算签名
签名实例= Signature.getInstance(SHA1withRSA);
instance.initSign(privateKey);
instance.update((plaintext).getBytes());
byte [] signature = instance.sign();

//计算摘要
MessageDigest sha1 = MessageDigest.getInstance(SHA1);
byte [] digest = sha1.digest((plaintext).getBytes());

//加密摘要
密码加密= Cipher.getInstance(RSA);
cipher.init(Cipher.ENCRYPT_MODE,privateKey);
byte [] cryptoText = cipher.doFinal(digest);

//显示结果
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 ...

签名: 7177c74bbbb871cc0af92e30d2808ebae146f25d3fd8ba1622 ...


我必须对根据签名所做的事情有根本性的误解 - 通过它,它似乎是在一个 MessageDigest 对象上调用update,算法设置为SHA1,如我所料,然后获取摘要,然后进行加密。



Leonidas让我检查是否有不同的结果签名计划应该做我想象的。在 RFC 中定义了两种类型的签名:





其中第一个(PKCS1)是我上面描述的。它使用哈希函数创建摘要,然后使用私钥加密结果。



第二算法使用随机盐值,并且更安全,但非确定性。从上面的代码生成的签名不会改变,如果相同的键被重复使用,所以我不认为它可以是PSS。



编辑: / strong>



这是我使用的 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
}

这是为什么他们是不同的。


I'm trying to understand what the Java java.security.Signature class does. If I compute an SHA1 message digest, and then encrypt that digest using RSA, I get a different result to asking the Signature class to sign the same thing:

// 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));

Results in (for example):

Input data: This is the message being signed
Digest: 62b0a9ef15461c82766fb5bdaae9edbe4ac2e067
Cipher text: 057dc0d2f7f54acc95d3cf5cba9f944619394711003bdd12...
Signature: 7177c74bbbb871cc0af92e30d2808ebae146f25d3fd8ba1622...

I must have a fundamental misunderstanding of what Signature is doing - I've traced through it, and it appears to be calling update on a MessageDigest object, with the algorithm set to SHA1 as I would expect, then getting the digest, then doing the encryption. What's making the results differ?

EDIT:

Leonidas made me check whether the signature scheme is supposed to do what I think it does. There are two types of signature defined in the RFC:

The first of these (PKCS1) is the one I describe above. It uses a hash function to create a digest, and then encrypts the result with a private key.

The second algorithm uses a random salt value, and is more secure but non-deterministic. The signature produced from the code above does not change if the same key is used repeatedly, so I don't think it can be PSS.

EDIT:

Here's the bytes2string method I was using:

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();
}

解决方案

OK, I've worked out what's going on. I was being stupid. Leonidas is right, it's not just the hash that gets encrypted, it's the ID of the hash algorithm concatenated with the digest:

  DigestInfo ::= SEQUENCE {
      digestAlgorithm AlgorithmIdentifier,
      digest OCTET STRING
  }

Which is why they are different.

这篇关于使用SHA1和RSA与java.security.Signature vs. MessageDigest和Cipher的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆