SM2和RSA加解密

Java环境下的SM2和RSA加解密工具

1. Maven导包

1
2
3
4
5
6
7
8
<dependencies>
<!-- Bouncy Castle Provider (国密算法支持) -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.78.1</version>
</dependency>
</dependencies>

2. 工具类

2.1 CryptoUtil.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
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
* CryptoUtil.java
* Cryptographic utility class
* Supports RSA and SM2 encryption/decryption algorithms
*
* @date 2025-12-08
*/
public class CryptoUtil {

static {
// 添加BouncyCastleProvider支持
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
}

/**
* RSA公钥加密
*
* @param data 待加密数据
* @param publicKey 公钥(Base64编码)
* @return 加密后的数据(Base64编码)
* @throws Exception 加密异常
*/
public static String rsaEncrypt(String data, String publicKey) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
java.security.PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encryptedData = cipher.doFinal(data.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encryptedData);
}

/**
* RSA私钥解密
*
* @param encryptedData 待解密数据(Base64编码)
* @param privateKey 私钥(Base64编码)
* @return 解密后的数据
* @throws Exception 解密异常
*/
public static String rsaDecrypt(String encryptedData, String privateKey) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
java.security.PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, priKey);
byte[] decryptedData = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
return new String(decryptedData, "UTF-8");
}

/**
* SM2公钥加密
*
* @param data 待加密数据
* @param publicKey 公钥(Base64编码)
* @return 加密后的数据(Hex编码)
* @throws Exception 加密异常
*/
public static String sm2Encrypt(String data, String publicKey) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); // SM2基于椭圆曲线,使用EC算法
java.security.PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
return GmSecurityUtil.sm2Encrypt(data, pubKey);
}

/**
* SM2私钥解密
*
* @param encryptedData 待解密数据(Hex编码)
* @param privateKey 私钥(Base64编码)
* @return 解密后的数据
* @throws Exception 解密异常
*/
public static String sm2Decrypt(String encryptedData, String privateKey) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); // SM2基于椭圆曲线,使用EC算法
java.security.PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
return GmSecurityUtil.sm2Decrypt(encryptedData, priKey);
}

/**
* 生成RSA密钥对
*
* @return KeyPair 包含公钥和私钥(Base64编码)
* @throws Exception 生成异常
*/
public static java.util.Map<String, String> generateRSAKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();

java.util.Map<String, String> result = new java.util.HashMap<>();
result.put("publicKey", Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
result.put("privateKey", Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()));

return result;
}

/**
* 生成SM2密钥对
*
* @return KeyPair 包含公钥和私钥(Base64编码)
* @throws Exception 生成异常
*/
public static java.util.Map<String, String> generateSM2KeyPair() throws Exception {
KeyPair keyPair = SM2Util.generateKeyPair();

java.util.Map<String, String> result = new java.util.HashMap<>();
result.put("publicKey", Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
result.put("privateKey", Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()));

return result;
}
}

2.2 GmSecurityUtil.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
75
76
77
78
79
80
81
82
83
84
85
86
87
import java.security.PrivateKey;
import java.security.PublicKey;

/**
* GmSecurityUtil.java
* GM cryptographic security utility class
* Provides GM algorithm operations based on complete key objects
*
* @date 2025-12-08
*/
public class GmSecurityUtil {

/**
* Sign data with SM2 private key
*
* @param data Data to be signed
* @param privateKey SM2 private key
* @return Signature result (Hex encoded)
*/
public static String sm2Sign(String data, PrivateKey privateKey) {
try {
return SM2Util.sign(data, privateKey);
} catch (Exception e) {
throw new RuntimeException("SM2签名失败", e);
}
}

/**
* Verify signature with SM2 public key
*
* @param data Original data
* @param sign Signature (Hex encoded)
* @param publicKey SM2 public key
* @return Verification result
*/
public static boolean sm2Verify(String data, String sign, PublicKey publicKey) {
try {
return SM2Util.verify(data, sign, publicKey);
} catch (Exception e) {
throw new RuntimeException("SM2验签失败", e);
}
}

/**
* Calculate SM3 digest of data
*
* @param data Data to calculate digest
* @return SM3 digest (Hex encoded)
*/
public static String sm3Digest(String data) {
try {
return SM3Util.hash(data);
} catch (Exception e) {
throw new RuntimeException("SM3摘要计算失败", e);
}
}

/**
* Encrypt data with SM2 public key
*
* @param data Data to be encrypted
* @param publicKey SM2 public key
* @return Encrypted data (Hex encoded)
*/
public static String sm2Encrypt(String data, PublicKey publicKey) {
try {
return SM2Util.encrypt(data, publicKey);
} catch (Exception e) {
throw new RuntimeException("SM2加密失败", e);
}
}

/**
* Decrypt data with SM2 private key
*
* @param encryptedData Data to be decrypted (Hex encoded)
* @param privateKey SM2 private key
* @return Decrypted data
*/
public static String sm2Decrypt(String encryptedData, PrivateKey privateKey) {
try {
return SM2Util.decrypt(encryptedData, privateKey);
} catch (Exception e) {
throw new RuntimeException("SM2解密失败", e);
}
}
}

2.3 SM2Util.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
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
* SM2Util.java
* SM2 cryptographic algorithm utility class
* Provides SM2 signature, verification, encryption, decryption and other functions
*
* @date 2025-12-08
*/
public class SM2Util {

private static final String ALGORITHM_NAME = "SM2";

static {
// Add BouncyCastleProvider support
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
}

/**
* Generate SM2 key pair
*
* @return KeyPair SM2 key pair
* @throws GeneralSecurityException Security exception
*/
public static KeyPair generateKeyPair() throws GeneralSecurityException {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
keyPairGenerator.initialize(256, new SecureRandom()); // SM2 standard recommends 256 bits
return keyPairGenerator.generateKeyPair();
} catch (Exception e) {
throw new GeneralSecurityException("Failed to generate SM2 key pair", e);
}
}

/**
* Sign data with private key
*
* @param data Data to be signed
* @param privateKey Private key
* @return Signature result (Hex encoded)
* @throws GeneralSecurityException Security exception
*/
public static String sign(byte[] data, PrivateKey privateKey) throws GeneralSecurityException {
try {
Signature signer = Signature.getInstance("SM3withSM2", BouncyCastleProvider.PROVIDER_NAME);
signer.initSign(privateKey);
signer.update(data);
byte[] signature = signer.sign();
return Hex.toHexString(signature);
} catch (Exception e) {
throw new GeneralSecurityException("SM2 signature failed", e);
}
}

/**
* Sign string data with private key
*
* @param data String data to be signed
* @param privateKey Private key
* @return Signature result (Hex encoded)
* @throws GeneralSecurityException Security exception
*/
public static String sign(String data, PrivateKey privateKey) throws GeneralSecurityException {
return sign(data.getBytes(), privateKey);
}

/**
* Verify signature with public key
*
* @param data Original data
* @param sign Signature (Hex encoded)
* @param publicKey Public key
* @return Verification result
* @throws GeneralSecurityException Security exception
*/
public static boolean verify(byte[] data, String sign, PublicKey publicKey) throws GeneralSecurityException {
try {
Signature verifier = Signature.getInstance("SM3withSM2", BouncyCastleProvider.PROVIDER_NAME);
verifier.initVerify(publicKey);
verifier.update(data);
byte[] signature = Hex.decode(sign);
return verifier.verify(signature);
} catch (Exception e) {
throw new GeneralSecurityException("SM2 signature verification failed", e);
}
}

/**
* Verify string data signature with public key
*
* @param data Original string data
* @param sign Signature (Hex encoded)
* @param publicKey Public key
* @return Verification result
* @throws GeneralSecurityException Security exception
*/
public static boolean verify(String data, String sign, PublicKey publicKey) throws GeneralSecurityException {
return verify(data.getBytes(), sign, publicKey);
}

/**
* Create public key from Base64 encoded byte array
*
* @param encoded Base64 encoded public key byte array
* @return PublicKey Public key object
* @throws GeneralSecurityException Security exception
*/
public static PublicKey decodePublicKey(byte[] encoded) throws GeneralSecurityException {
try {
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
return keyFactory.generatePublic(keySpec);
} catch (Exception e) {
throw new GeneralSecurityException("Failed to decode public key", e);
}
}

/**
* Create private key from Base64 encoded byte array
*
* @param encoded Base64 encoded private key byte array
* @return PrivateKey Private key object
* @throws GeneralSecurityException Security exception
*/
public static PrivateKey decodePrivateKey(byte[] encoded) throws GeneralSecurityException {
try {
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
return keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
throw new GeneralSecurityException("Failed to decode private key", e);
}
}

/**
* Encrypt data with SM2 public key
*
* @param data Data to be encrypted
* @param publicKey SM2 public key
* @return Encrypted data (Hex encoded)
* @throws GeneralSecurityException Security exception
*/
public static String encrypt(byte[] data, PublicKey publicKey) throws GeneralSecurityException {
try {
// Use BouncyCastle library for SM2 encryption via Cipher
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("SM2", "BC");
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(data);
return org.bouncycastle.util.encoders.Hex.toHexString(encryptedBytes);
} catch (Exception e) {
throw new GeneralSecurityException("SM2 encryption failed", e);
}
}

/**
* Encrypt string data with SM2 public key
*
* @param data String data to be encrypted
* @param publicKey SM2 public key
* @return Encrypted data (Hex encoded)
* @throws GeneralSecurityException Security exception
*/
public static String encrypt(String data, PublicKey publicKey) throws GeneralSecurityException {
return encrypt(data.getBytes(StandardCharsets.UTF_8), publicKey);
}

/**
* Decrypt data with SM2 private key
*
* @param data Data to be decrypted (Hex encoded)
* @param privateKey SM2 private key
* @return Decrypted data
* @throws GeneralSecurityException Security exception
*/
public static byte[] decrypt(byte[] data, PrivateKey privateKey) throws GeneralSecurityException {
try {
// Use BouncyCastle library for SM2 decryption via Cipher
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("SM2", "BC");
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
} catch (Exception e) {
throw new GeneralSecurityException("SM2 decryption failed", e);
}
}

/**
* Decrypt data with SM2 private key
*
* @param data Data to be decrypted (Hex encoded)
* @param privateKey SM2 private key
* @return Decrypted string data
* @throws GeneralSecurityException Security exception
*/
public static String decrypt(String data, PrivateKey privateKey) throws GeneralSecurityException {
byte[] decryptedBytes = decrypt(org.bouncycastle.util.encoders.Hex.decode(data), privateKey);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
}

2.4 SM3Util.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
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import java.nio.charset.StandardCharsets;
import java.security.Security;

/**
* SM3Util.java
* SM3国密算法工具类
* 提供SM3摘要计算功能
*
* @date 2025-12-08
*/
public class SM3Util {

static {
// 添加BouncyCastleProvider支持
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
}

/**
* 计算数据的SM3摘要
*
* @param data 待计算摘要的数据
* @return SM3摘要(Hex编码)
*/
public static String hash(byte[] data) {
SM3Digest digest = new SM3Digest();
digest.update(data, 0, data.length);
byte[] hash = new byte[digest.getDigestSize()];
digest.doFinal(hash, 0);
return Hex.toHexString(hash);
}

/**
* 计算字符串的SM3摘要
*
* @param data 待计算摘要的字符串
* @return SM3摘要(Hex编码)
*/
public static String hash(String data) {
return hash(data.getBytes(StandardCharsets.UTF_8));
}
}

3. 测试函数

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
105
106
107
108
import org.utils.CryptoUtil;

public class Main {
public static void main(String[] args) {
try {
System.out.println("=== 开始完整测试CryptoUtil类 ===");

// 测试RSA功能
System.out.println("1. 测试RSA密钥生成和加解密:");
testRSA();

// 测试SM2功能
System.out.println("\n2. 测试SM2密钥生成:");
testSM2KeyGeneration();

// 测试SM2加解密功能
System.out.println("\n3. 测试SM2加解密:");
testSM2EncryptionDecryption();

System.out.println("\n=== 完整测试完成 ===");
} catch (Exception e) {
System.err.println("测试过程中发生异常: " + e.getMessage());
e.printStackTrace();
}
}


private static void testRSA() {
try {
// 生成RSA密钥对
java.util.Map<String, String> rsaKeyPair = CryptoUtil.generateRSAKeyPair();
String publicKey = rsaKeyPair.get("publicKey");
String privateKey = rsaKeyPair.get("privateKey");
System.out.println(" RSA公钥长度: " + publicKey.length());
System.out.println(" RSA私钥长度: " + privateKey.length());

// 测试数据
String originalData = "Hello, RSA Encryption!";

// 加密
String encrypted = CryptoUtil.rsaEncrypt(originalData, publicKey);
System.out.println(" RSA加密完成");

// 解密
String decrypted = CryptoUtil.rsaDecrypt(encrypted, privateKey);
System.out.println(" RSA解密完成");

// 验证
if (originalData.equals(decrypted)) {
System.out.println(" ✅ RSA加解密测试通过!");
} else {
System.out.println(" ❌ RSA加解密测试失败!");
}
} catch (Exception e) {
System.err.println(" RSA测试异常: " + e.getMessage());
e.printStackTrace();
}
}

private static void testSM2KeyGeneration() {
try {
// 生成SM2密钥对
java.util.Map<String, String> sm2KeyPair = CryptoUtil.generateSM2KeyPair();
String publicKey = sm2KeyPair.get("publicKey");
String privateKey = sm2KeyPair.get("privateKey");

System.out.println(" SM2公钥长度: " + publicKey.length());
System.out.println(" SM2私钥长度: " + privateKey.length());

System.out.println(" ✅ SM2密钥生成测试通过!");
} catch (Exception e) {
System.err.println(" SM2密钥生成测试异常: " + e.getMessage());
e.printStackTrace();
}
}

private static void testSM2EncryptionDecryption() {
try {
// 生成SM2密钥对
java.util.Map<String, String> sm2KeyPair = CryptoUtil.generateSM2KeyPair();
String publicKey = sm2KeyPair.get("publicKey");
String privateKey = sm2KeyPair.get("privateKey");

// 测试数据
String originalData = "Hello, SM2 Encryption 测试!";

System.out.println(" 原始数据: " + originalData);

// 使用公钥加密
String encrypted = CryptoUtil.sm2Encrypt(originalData, publicKey);
System.out.println(" SM2加密后数据长度: " + encrypted.length());

// 使用私钥解密
String decrypted = CryptoUtil.sm2Decrypt(encrypted, privateKey);
System.out.println(" SM2解密后数据: " + decrypted);

// 验证
if (originalData.equals(decrypted)) {
System.out.println(" ✅ SM2加解密测试通过!");
} else {
System.out.println(" ❌ SM2加解密测试失败!");
}
} catch (Exception e) {
System.err.println(" SM2加解密测试异常: " + e.getMessage());
e.printStackTrace();
}
}
}