Java 数字签名算法

数字签名算法可以看成是带秘钥的消息摘要算法,用于验证数据完整性、认证数据来源,并起到抗否认的作用。遵循私钥加签,公钥验签的规则,数字签名算法是非对称加密算法和消息摘要算法的结合体。数字签名算法主要包括RSA和DSA。这节记录下这两种算法在JDK8下的实现。

数字签名加签验签流程分为以下几步:

  1. A在本地构建秘钥对,并将公钥发布给B;
  2. A使用私钥对数据进行签名;
  3. A发送签名和数据给B;
  4. B使用公钥对签名和数据进行验签。

RSA

RSA数字签名算法主要分为MD系列和SHA系列两大类。MD系列主要包括MD2withRSA和MD5withRSA共2种数字签名算法;SHA系列主要包括SHA1withRSA、SHA224withRSA、SHA256withRSA、SHA384withRSA和SHA512withRSA共5种数字签名算法。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import org.junit.Test;

import java.security.*;
import java.util.Base64;

public class RsaSignatureDemo {

@Test
public void test() throws Exception {
String value = "mrbird's blog";
// 非对称加密算法
String algorithm = "RSA";
// 签名算法,RSA+SHA
String signAlgorithm = "SHA256withRSA";

// ----- 公私钥生成 --------
// 实例化秘钥对生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
// 初始化,秘钥长度512~16384位,64倍数
keyPairGenerator.initialize(512);
// 生成秘钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 公钥
PublicKey publicKey = keyPair.getPublic();
System.out.println("RSA公钥: " + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
// 私钥
PrivateKey privateKey = keyPair.getPrivate();
System.out.println("RSA私钥: " + Base64.getEncoder().encodeToString(privateKey.getEncoded()));

// ----- 私钥加签 ---------
// 获取签名对象
Signature signature = Signature.getInstance(signAlgorithm);
signature.initSign(privateKey);
signature.update(value.getBytes());
byte[] sign = signature.sign();
System.out.println("签名值: " + Base64.getEncoder().encodeToString(sign));

// ----- 公钥验签 ---------
signature.initVerify(publicKey);
signature.update(value.getBytes());
System.out.println("验签结果: " + signature.verify(sign));

}
}

秘钥对生成过程和上篇RSA介绍的无异,主要关注加签和验签操作即可,程序输出如下:

1
2
3
4
RSA公钥: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKTTlw+zyhGzmTmhT5w9vEP1ejOcVfM2rHbz8jUae7InAh42R9ZaYUk1c3q0uqmTv8xKOnszU/vrdV52zoFM+OMCAwEAAQ==
RSA私钥: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEApNOXD7PKEbOZOaFPnD28Q/V6M5xV8zasdvPyNRp7sicCHjZH1lphSTVzerS6qZO/zEo6ezNT++t1XnbOgUz44wIDAQABAkBsZQXz+p2J1J2Qq8fqDSNxYc8Sf956SttSgw0m5Rqxxiw10cgHt67uocu3qK6UeMuJuaOiN3YT48kvFp6Joc75AiEA4L7R1zDWcOdWf2BE/k3yxJ4Uv0vbIZ9vWLuJGBR3xK0CIQC7v5f2fcedBWbJ/kR7CvbFE91ivM55dvWZMe/JrjXVzwIgFUn+FqRJq+g+CVLVNkGr/XP8AyLsXwL7SSx6kA1gSwECIHysAn4VEftr/dC+Pr0yD6HYyhbp53XzD6214lQbkfYzAiB1b2wNi0Y3N+D/OIrGUHlwgA0vkX82NP3V8qMDmRbCTQ==
签名值: HVN5WkhND0hy/xY43h8r3+AVt6oxMSv1Ug/Y+bv1tGxw4ePQtIgzFwK0lQQbhIlwts2d2STwQBews4dXCfEMmA==
验签结果: true

需要注意的是不同签名算法需要的秘钥长度最小值不同,大伙可以自己试试。

DSA

DSA算法与RSA算法都是数字证书中不可或缺的两种算法。两者不同的是,DSA算法仅包含数字签名算法,使用DSA算法的数字证书无法进行加密通信,而RSA算法既包含加密/解密算法,同时兼有数字签名算法。

JDK8支持SHA1withDSA、SHA224withDSA、SHA256withDSA、SHA384withDSA和SHA512withDSA这五种DSA数字签名算法。

代码示例(只需将上面的例子算法替换下就好,并且注意秘钥的长度范围):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import org.junit.Test;

import java.security.*;
import java.util.Base64;

public class RsaSignatureDemo {

@Test
public void test() throws Exception {
String value = "mrbird's blog";
// 非对称加密算法
String algorithm = "DSA";
// 签名算法,DSA+SHA
String signAlgorithm = "SHA224withDSA";

// ----- 公私钥生成 --------
// 实例化秘钥对生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
// 初始化,秘钥长度512~1024位,64倍数
keyPairGenerator.initialize(1024);
// 生成秘钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 公钥
PublicKey publicKey = keyPair.getPublic();
System.out.println("DSA公钥: " + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
// 私钥
PrivateKey privateKey = keyPair.getPrivate();
System.out.println("DSA私钥: " + Base64.getEncoder().encodeToString(privateKey.getEncoded()));

// ----- 私钥加签 ---------
// 获取签名对象
Signature signature = Signature.getInstance(signAlgorithm);
signature.initSign(privateKey);
signature.update(value.getBytes());
byte[] sign = signature.sign();
System.out.println("签名值: " + Base64.getEncoder().encodeToString(sign));

// ----- 公钥验签 ---------
signature.initVerify(publicKey);
signature.update(value.getBytes());
System.out.println("验签结果: " + signature.verify(sign));

}
}

运行结果如下:

1
2
3
4
DSA公钥: MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAcW0aiebAWi5M18Lu6QS/1OoHbtw2I7kyivwExbNAZpWR9I9sNIwE1T0a491t1oqRV1cdBHyd9jiJqFwfLG6k5QidasXTgGYSsSZqFBebP5nrF5q3RtkosoHeHVKDnShQf5b36NK53CpCRfLayk2e5inu7CCCo+a58piAMiF3c+k=
DSA私钥: MIIBTAIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFwIVAIv03r5wR+DolDC5bGFOqQ2vuHlo
签名值: MCwCFBRba/HI5/tLt+exzpgvLoq5mAwaAhQvaVv4dbGFNtMpcI4ZeqjgAGeGyg==
验签结果: true

请作者喝瓶肥宅水🥤

0