密钥对制作

KeyPair 是java中的秘钥对,可以获取公私钥信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 生成密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
//keyPairGenerator.initialize(2048, JCAUtil.getSecureRandom());
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();

//或者这样

RSAKeyPairGenerator rsaKeyPairGenerator = new RSAKeyPairGenerator();

SecureRandom random = SecureRandom.getInstanceStrong();
//SecureRandom randomSecureRandom.getInstance("SHA1PRNG");

rsaKeyPairGenerator.initialize(2048, random);
KeyPair keyPair1 = rsaKeyPairGenerator.generateKeyPair();

其中,在获取SecureRandom时可以选择随机算法SHA1PRNG/NativePRNG/NativePRNGBlocking/DRBG/AES128CounterMode
java使用时可以默认选择SecureRandom.getInstanceStrong()系统自行选择

(1) SHA1PRNG
描述:基于 SHA1 的伪随机数生成器(PRNG),性能较高但安全性较弱。
适用场景:非高安全需求的场景(如测试或简单加密)。
注意:SHA1 已被证明存在碰撞漏洞,不建议用于高安全场景。
(2) NativePRNG
描述:直接调用操作系统底层的随机数生成器(如 Linux 的 /dev/urandom 或 Windows 的 CryptGenRandom)。
优点:高安全性,直接依赖操作系统提供的随机性。
适用场景:需要强加密安全性的场景(如密钥生成、SSL/TLS)。
注意:
在 Linux/macOS 上,NativePRNG 使用 /dev/urandom。
在 Windows 上,使用 CryptGenRandom API。
可能需要指定后缀(如 NativePRNGBlocking 或 NativePRNGNonBlocking,具体见下文)。
(3) NativePRNGBlocking
描述:与 NativePRNG 类似,但会阻塞直到获取足够的熵(更安全但可能较慢)。
适用场景:需要最高安全性的场景(如生成密钥对)。
(4) DRBG
描述:基于 NIST 标准的 DRBG(Deterministic Random Bit Generator)算法。
优点:符合 FIPS 标准,安全性高。
适用场景:符合 FIPS 要求的环境(如美国政府项目)。
注意:需要启用 FIPS 模式(通过 JVM 参数 -Dcom.sun.security.enableFIPS=true)。
(5) AES128CounterMode
描述:基于 AES 的计数器模式生成随机数。
优点:性能较好且安全性较高。
适用场景:需要平衡安全性和性能的场景。

证书制作

bouncycastle 制作

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.asn1.x500.X500Name;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.math.BigInteger;
import java.util.Date;

/**
* 2025/04/18
*
* @author kewen
* @since 1.0.0
*/
public class CertificateGenerator {
static {
Security.addProvider(new BouncyCastleProvider());
}

@Data
@Accessors(chain = true)
static class CertificateInfo {
private String subject;
private String issuer;
private String serial;
private Date notBefore;
private Date notAfter;
private String signatureAlgorithm = "SHA256withRSA";
}

public static void main(String[] args) throws Exception {
CertificateInfo certificateInfo = new CertificateInfo();
certificateInfo.setSubject("CN=John Doe, OU=Engineering, O=MyCompany, C=US")
.setIssuer("CN=John Doe, OU=Engineering, O=MyCompany, C=US")
.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24))
.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 365)))
;

generate(certificateInfo);
}

public static void generate(CertificateInfo certificateInfo) throws Exception {
// 生成密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();

// 定义证书主体和颁发者(自签名)
X500Name subject = new X500Name(certificateInfo.getSubject());
// 自签名证书
X500Name issuer = new X500Name(certificateInfo.getIssuer());

// 证书参数
BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
Date notBefore = certificateInfo.getNotBefore();
Date notAfter = certificateInfo.getNotAfter();

// 签名算法
ContentSigner signer = new JcaContentSignerBuilder(certificateInfo.getSignatureAlgorithm()).build(keyPair.getPrivate());

// 构建证书
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(
issuer,
serial,
notBefore,
notAfter,
subject,
keyPair.getPublic()
);

// 生成最终证书
X509Certificate x509Certificate = new JcaX509CertificateConverter()
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
.getCertificate(certBuilder.build(signer));

System.out.println("Certificate generated successfully!");
x509Certificate.verify(keyPair.getPublic());
byte[] encoded = x509Certificate.getEncoded();

String privateKeyBase64 = Base64.encodeBase64String(keyPair.getPrivate().getEncoded());
String publicKeyBase64 = Base64.encodeBase64String(keyPair.getPublic().getEncoded());

String strCertData = StringUtils.newStringUtf8(Base64
.encodeBase64Chunked(encoded));
System.out.println("strCertData: " + strCertData);
System.out.println("privateKeyBase64: " + privateKeyBase64);
System.out.println("publicKeyBase64: " + publicKeyBase64);

System.out.println("x509Certificate: " + x509Certificate);
System.out.println("x509Certificate.getPublicKey(): " + x509Certificate.getPublicKey());
}

}

Java内置的方法制作

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

import java.math.BigInteger;
import java.security.*;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.Date;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
import sun.security.x509.*;

import javax.security.auth.x500.X500PrivateCredential;

/**
* 2025/04/18
*
* @author kewen
* @since 1.0.0
*/
public class CertificateJavaSecurity {

public static void main(String[] args) throws Exception {
// 生成RSA密钥对
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();

// 创建X.509证书
X509CertInfo x509CertInfo = new X509CertInfo();

// 设置版本号
x509CertInfo.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));

// 设置序列号
BigInteger serialNumber = new BigInteger(Long.toString(System.currentTimeMillis()));
x509CertInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(serialNumber));

// 设置算法
x509CertInfo.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(AlgorithmId.get("RSA")));

// 设置公钥
x509CertInfo.set(X509CertInfo.KEY, new CertificateX509Key(keyPair.getPublic()));

// 设置主体名
X500Name owner = new X500Name("CN=MyUser,O=MyOrg,L=MyCity,C=MY");
x509CertInfo.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));

// 设置颁发者名
X500Name issuer = new X500Name("CN=MyCA,O=MyOrg,L=MyCity,C=MY");
x509CertInfo.set(X509CertInfo.ISSUER, new CertificateIssuerName(issuer));

// 设置有效期
Date notBefore = Date.from(Instant.now().minusSeconds(5 * 60 * 60));
Date notAfter = Date.from(Instant.now().plusSeconds(5 * 60 * 60));
x509CertInfo.set(X509CertInfo.VALIDITY, new CertificateValidity(notBefore, notAfter));


// 创建最终的X.509证书
X509Certificate x509Certificate = new X509CertImpl(x509CertInfo);
// 验证证书
x509Certificate.verify(publicKey);

X500PrivateCredential x500PrivateCredential = new X500PrivateCredential(x509Certificate, keyPair.getPrivate());

byte[] encoded = x509Certificate.getEncoded();
String strCertData = StringUtils.newStringUtf8(Base64
.encodeBase64Chunked(encoded));

// 输出证书信息
System.out.println(x509Certificate.toString());
}
}