首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将SHA1和RSA与java.security.Signature和MessageDigest及密码配合使用

将SHA1和RSA与java.security.Signature和MessageDigest及密码配合使用
EN

Stack Overflow用户
提问于 2009-02-06 16:51:56
回答 7查看 107.7K关注 0票数 70

我正在尝试理解Java java.security.Signature类的作用。如果我计算一个SHA1消息摘要,然后使用RSA对摘要进行加密,则得到与要求签名类签名相同内容不同的结果:

代码语言:javascript
复制
// 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...

签名: 7177c74bbbb871cc0af92e30d2808ebae146f25d3fd8ba1622...

我肯定对签名的作用有一个根本性的误解--我跟踪过它,它似乎在MessageDigest对象上调用update,算法如我所料设置为SHA1,然后获取摘要,然后进行加密。是什么导致了结果的不同?

编辑:

Leonidas让我检查签名方案是否应该做我认为它应该做的事情。RFC中定义了两种类型的签名

first of these (PKCS1)就是我上面描述的那个。它使用哈希函数创建摘要,然后使用私钥对结果进行加密。

second algorithm使用随机的salt值,更安全,但不确定。如果重复使用相同的密钥,上面代码生成的签名不会改变,所以我不认为它可以是PSS。

编辑:

下面是我使用的bytes2string方法:

代码语言:javascript
复制
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();
}
EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2009-02-06 18:02:25

好了,我已经搞清楚是怎么回事了。Leonidas是对的,加密的不只是散列(在Cipher类方法的情况下),还有散列算法的ID和摘要:

代码语言:javascript
复制
  DigestInfo ::= SEQUENCE {
      digestAlgorithm AlgorithmIdentifier,
      digest OCTET STRING
  }

这就是为什么密码加密和签名加密是不同的。

票数 53
EN

Stack Overflow用户

发布于 2011-01-26 23:53:23

要产生相同的结果:

代码语言:javascript
复制
MessageDigest sha1 = MessageDigest.getInstance("SHA1", BOUNCY_CASTLE_PROVIDER);
byte[] digest = sha1.digest(content);
DERObjectIdentifier sha1oid_ = new DERObjectIdentifier("1.3.14.3.2.26");

AlgorithmIdentifier sha1aid_ = new AlgorithmIdentifier(sha1oid_, null);
DigestInfo di = new DigestInfo(sha1aid_, digest);

byte[] plainSig = di.getDEREncoded();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", BOUNCY_CASTLE_PROVIDER);
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] signature = cipher.doFinal(plainSig);
票数 11
EN

Stack Overflow用户

发布于 2011-06-12 17:19:56

bytes2String方法的一个稍微更有效的版本是

代码语言:javascript
复制
private static final char[] hex = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private static String byteArray2Hex(byte[] bytes) {
    StringBuilder sb = new StringBuilder(bytes.length * 2);
    for (final byte b : bytes) {
        sb.append(hex[(b & 0xF0) >> 4]);
        sb.append(hex[b & 0x0F]);
    }
    return sb.toString();
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/521101

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档