少女祈祷中...

Java 常用加密解密算法及应用示例

摘要:在Java开发中,加密解密技术是保护数据安全的重要手段。无论是存储敏感信息(如用户密码、个人信息)还是传输加密数据,都需要用到加密算法。不同的加密算法运用的场景也不同,因此选择合适的加密解密算法也是至关重要。

一、加密算法分类

加密算法的种类繁多,主要可以归纳为以下几大类:

一、对称加密算法

定义:加密和解密使用相同密钥的加密算法。
特点:加密强度高,效率高,但密钥分发和管理较为复杂。
常见算法:
DES:一种使用对称密钥加密的块算法,由IBM公司于1975年研发,是广泛应用的早期对称加密算法之一,但由于密钥长度较短(56位),安全性已逐渐降低。
3DES:DES算法的一个更安全的变形,使用3条56位的密钥对数据进行三次加密,提高了安全性,是DES算法向AES算法过渡的算法。
AES:高级加密标准(Advanced Encryption Standard),是一种分块加密算法,用于替代原先的DES算法。AES算法由三种不同的算法组成,分别使用128、192或256位加密密钥,具有高强度、高速度和易于实现的特点。
RC4:一种流密码算法,由Ron Rivest于1987年创建,通过生成一个伪随机数流与明文进行异或运算来实现加密,具有速度快、简单易用、灵活性高以及适用范围广的特点。
其他还包括Blowfish、IDEA、RC5、RC6等算法。

二、非对称加密算法

定义:非对称加密算法是指加密和解密使用不同密钥的加密算法,通常包含公钥和私钥。公钥用于加密,私钥用于解密(或反之用于验签)。
特点:加密速度慢,但强度高,适用于密钥交换和数字签名等场景。
常见算法:
RSA:一种基于公钥加密的算法,广泛应用于SSL证书中的密钥交换和数字签名过程,助力网站实现HTTPS加密,确保网络通信安全。
ECC:基于椭圆曲线密码学的加密算法,相比于RSA算法,ECC算法提供了更高的安全性和更短的密钥长度。
其他还包括Diffie-Hellman、El Gamal、DSA(数字签名用)等算法。

三、哈希算法

定义:也叫安全散列算法、消息摘要算法、杂凑算法,是一种将任意长度的输入数据输出为固定长度数据的算法,具有单向性,即不能通过输出数据反推出输入数据。
特点:可实现数据签名、数据完整性校验等功能。
常见算法:
MD5:一种加密散列函数算法,将任意长度的信息作为输入,并转换为128位(16字节)的固定长度信息,主要用于验证文件是否被篡改。但近年来,由于其哈希值长度较短,安全性逐渐受到质疑。
SHA系列:包括SHA-1、SHA-2(SHA-224、SHA-256、SHA-384、SHA-512)等算法,其中SHA-1算法可以生成160位(20字节)散列值,而SHA-2算法则是SHA-1算法的继承者,提供了更高的安全性。SHA系列算法广泛应用于文件传输校验、代码签名证书等领域。
其他还包括MD2、MD4、HAVAL等算法,但部分算法由于安全性问题已逐渐被淘汰。
##二、加密算法实现
本文将介绍几种Java中常用的加密解密算法,并提供相应的使用示例。

对称加密算法

DES算法

DES(Data Encryption Standard)是一种古老的对称加密算法,它以64位为分组长度,密钥长度为56位,8位用于奇偶校验。
在Java中,可以使用javax.crypto.Cipher类来执行DES加密和解密。

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
import com.alibaba.fastjson.JSON;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
* DES算法加解密工具类
*/
public class DESUtil {

/**
* 生成DES密钥
*
* @return SecretKey DES密钥
* @throws NoSuchAlgorithmException 当DES算法不可用时抛出
*/
public static SecretKey generateDESKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
keyGenerator.init(56); // DES算法密钥长度为56位,这里每次调用随机都会生成新的密钥。
return keyGenerator.generateKey();
}

/**
* 生成固定DES密钥
*
* @return SecretKey DES密钥
*/
public static SecretKey generateFixDESKey() throws UnsupportedEncodingException {
// 定义一个8字节字符串key
String fixedKey = "qwerasdf";

// 使用固定的字节数组(64位)创建DES密钥
return new SecretKeySpec(fixedKey.getBytes(StandardCharsets.UTF_8), "DES");
}

/**
* 使用DES算法加密
*
* @param data 待加密的数据
* @param secretKey DES密钥
* @return 加密后的数据(Base64编码)
* @throws Exception 加密过程中的异常
*/
public static String encrypt(String data, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedData = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(encryptedData);
}

/**
* 使用DES算法解密
*
* @param data 加密的数据(Base64编码)
* @param secretKey DES密钥
* @return 解密后的数据
* @throws Exception 解密过程中的异常
*/
public static String decrypt(String data, SecretKey secretKey) throws Exception {
byte[] encryptedData = Base64.getDecoder().decode(data);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedData = cipher.doFinal(encryptedData);
return new String(decryptedData);
}

// 工具类不应该有公共构造器
private DESUtil() {
}

// 主方法用于测试工具类
public static void main(String[] args) {
try {
// 生成DES密钥
SecretKey secretKey = generateFixDESKey();

System.out.println(JSON.toJSONString(secretKey));

// 加密数据
String originalString = "Hello, World!";
String encryptedString = encrypt(originalString, secretKey);
System.out.println("Encrypted: " + encryptedString);

// 解密数据
String decryptedString = decrypt(encryptedString, secretKey);
System.out.println("Decrypted: " + decryptedString);
} catch (Exception e) {
e.printStackTrace();
}
}
}

AES算法

AES(Advanced Encryption Standard)是一种高级加密标准,是目前广泛使用的加密算法之一,提供多种密钥长度(如128位、192位、256位)。
在Java中,可以使用javax.crypto.Cipher类来执行AES加密和解密。

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
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class AESUtil {

// AES算法名称
private static final String AES_ALGORITHM = "AES";

/**
* 生成AES密钥
*
* @return SecretKey AES密钥
* @throws NoSuchAlgorithmException 当AES算法不可用时抛出
*/
public static SecretKey generateAESKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM);
keyGenerator.init(128); // 设置密钥长度为128位
return keyGenerator.generateKey();
}

/**
* 生成AES特定密钥
*
* @return SecretKey AES密钥
* @throws NoSuchAlgorithmException 当AES算法不可用时抛出
*/
public static SecretKey generateFixAESKey() throws NoSuchAlgorithmException {
// 定义一个16字节字符串key
String fixedKey = "qwerasdfzxcvbnml";

// 使用固定的字节数组(128位)创建DES密钥
return new SecretKeySpec(fixedKey.getBytes(StandardCharsets.UTF_8), "AES");
}

/**
* 使用AES算法加密
*
* @param data 待加密的数据
* @param secretKey AES密钥
* @return 加密后的数据(Base64编码)
* @throws Exception 加密过程中的异常
*/
public static String encrypt(String data, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedData = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(encryptedData);
}

/**
* 使用AES算法解密
*
* @param data 加密的数据(Base64编码)
* @param secretKey AES密钥
* @return 解密后的数据
* @throws Exception 解密过程中的异常
*/
public static String decrypt(String data, SecretKey secretKey) throws Exception {
byte[] encryptedData = Base64.getDecoder().decode(data);
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedData = cipher.doFinal(encryptedData);
return new String(decryptedData);
}

// 工具类不应该有公共构造器
private AESUtil() {
}

// 主方法用于测试工具类
public static void main(String[] args) {
try {
// 生成AES密钥
SecretKey secretKey = generateFixAESKey();

// 加密数据
String originalString = "Hello, World!";
String encryptedString = encrypt(originalString, secretKey);
System.out.println("Encrypted: " + encryptedString);

// 解密数据
String decryptedString = decrypt(encryptedString, secretKey);
System.out.println("Decrypted: " + decryptedString);
} catch (Exception e) {
e.printStackTrace();
}
}
}

我们也可以使用组合算法来进行进一步的加密

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
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;

public class AESUtil {

// AES密钥的key,用来生成密钥。长度可以为128,192,256
private static final String AES_KEY = "qwerasdfzxcvbnml";
// AES算法名称
private static final String AES_ALGORITHM = "AES";
/**
* 组合算法,它由三个部分组成:
* AES:这是一个对称加密算法,用于加密和解密数据。
* CBC:这是块密码的密码块链模式(Cipher Block Chaining),它使用一个初始化向量(IV)来混淆加密的数据。在CBC模式下,每个加密块都是基于前一个块的密文,这意味着如果加密了多个块,每个块的加密都会依赖于之前的加密结果。
* PKCS5Padding:这是一种填充模式,用于将明文填充到下一个加密块的大小。在AES中,每个块的大小是128位(16字节),因此PKCS5Padding会根据块的大小来填充明文,以确保明文大小总是块大小的整数倍。
* */
private static final String AES_CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";

/**
* 生成特定AES密钥
*
* @return SecretKey AES密钥
*/
public static SecretKey generateAESKey() {
// 使用固定的字节数组(128位)创建DES密钥
return new SecretKeySpec(AES_KEY.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM);
}

/**
* 生成CBC初始化向量
*
* @return AlgorithmParameterSpec CBC初始化向量
*/
public static AlgorithmParameterSpec generateIvParam() {
return new IvParameterSpec(AES_KEY.getBytes());
}

/**
* 使用AES算法加密
*
* @param data 待加密的数据
* @param secretKey AES密钥
* @return 加密后的数据(Base64编码)
* @throws Exception 加密过程中的异常
*/
public static String encrypt(String data, SecretKey secretKey, AlgorithmParameterSpec parameterSpec) throws Exception {
Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] encryptedData = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(encryptedData);
}

/**
* 使用AES算法解密
*
* @param data 加密的数据(Base64编码)
* @param secretKey AES密钥
* @return 解密后的数据
* @throws Exception 解密过程中的异常
*/
public static String decrypt(String data, SecretKey secretKey, AlgorithmParameterSpec parameterSpec) throws Exception {
byte[] encryptedData = Base64.getDecoder().decode(data);
Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_PADDING);
cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);
byte[] decryptedData = cipher.doFinal(encryptedData);
return new String(decryptedData);
}

// 工具类不应该有公共构造器
private AESUtil2() {
}

// 主方法用于测试工具类
public static void main(String[] args) {
try {
// 生成AES密钥
SecretKey secretKey = generateAESKey();
// 生成CBC初始化向量
AlgorithmParameterSpec ivParam = generateIvParam();

// 加密数据
String originalString = "Hello, World!";
String encryptedString = encrypt(originalString, secretKey, ivParam);
System.out.println("Encrypted: " + encryptedString);

// 解密数据
String decryptedString = decrypt(encryptedString, secretKey, ivParam);
System.out.println("Decrypted: " + decryptedString);
} catch (Exception e) {
e.printStackTrace();
}
}
}

非对称加密算法

RSA算法

RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,它包含公钥和私钥。公钥用于加密,私钥用于解密。
Java的KeyPairGenerator和Cipher类可以用来生成密钥对和执行加密解密操作。

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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
* Rsa算法工具类
* */
public class RSAUtil {

//签名算法名称
private static final String RSA_KEY_ALGORITHM = "RSA";

//标准签名算法名称
private static final String RSA_SIGNATURE_ALGORITHM = "SHA1withRSA";
private static final String RSA2_SIGNATURE_ALGORITHM = "SHA256withRSA";

//RSA密钥长度,默认密钥长度是1024,密钥长度必须是64的倍数,在512到65536位之间,不管是RSA还是RSA2长度推荐使用2048
private static final int KEY_SIZE = 2048;

/**
* 生成密钥对
*
* @return 返回包含公私钥的map
*/
public static Map<String, String> generateKey() {
KeyPairGenerator keygen;
try {
keygen = KeyPairGenerator.getInstance(RSA_KEY_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("RSA初始化密钥出现错误,算法异常");
}
SecureRandom secrand = new SecureRandom();
//初始化随机产生器
secrand.setSeed("Alian".getBytes());
//初始化密钥生成器
keygen.initialize(KEY_SIZE, secrand);
KeyPair keyPair = keygen.genKeyPair();
//获取公钥并转成base64编码
byte[] pub_key = keyPair.getPublic().getEncoded();
String publicKeyStr = Base64.getEncoder().encodeToString(pub_key);
//获取私钥并转成base64编码
byte[] pri_key = keyPair.getPrivate().getEncoded();
String privateKeyStr = Base64.getEncoder().encodeToString(pri_key);
//创建一个Map返回结果
Map<String, String> keyPairMap = new HashMap<>();
keyPairMap.put("publicKeyStr", publicKeyStr);
keyPairMap.put("privateKeyStr", privateKeyStr);
return keyPairMap;
}

/**
* 公钥加密(用于数据加密)
*
* @param data 加密前的字符串
* @param publicKeyStr base64编码后的公钥
* @return base64编码后的字符串
* @throws Exception
*/
public static String encryptByPublicKey(String data, String publicKeyStr) throws Exception {
//Java原生base64解码
byte[] pubKey = Base64.getDecoder().decode(publicKeyStr);
//创建X509编码密钥规范
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//根据X509编码密钥规范产生公钥对象
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
//根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//用公钥初始化此Cipher对象(加密模式)
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
//对数据加密
byte[] encrypt = cipher.doFinal(data.getBytes());
//返回base64编码后的字符串
return Base64.getEncoder().encodeToString(encrypt);
}

/**
* 私钥解密(用于数据解密)
*
* @param data 解密前的字符串
* @param privateKeyStr 私钥
* @return 解密后的字符串
* @throws Exception
*/
public static String decryptByPrivateKey(String data, String privateKeyStr) throws Exception {
//Java原生base64解码
byte[] priKey = Base64.getDecoder().decode(privateKeyStr);
//创建PKCS8编码密钥规范
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//根据PKCS8编码密钥规范产生私钥对象
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
//根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//用私钥初始化此Cipher对象(解密模式)
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//对数据解密
byte[] decrypt = cipher.doFinal(Base64.getDecoder().decode(data));
//返回字符串
return new String(decrypt);
}

/**
* 私钥加密(用于数据签名)
*
* @param data 加密前的字符串
* @param privateKeyStr base64编码后的私钥
* @return base64编码后后的字符串
* @throws Exception
*/
public static String encryptByPrivateKey(String data, String privateKeyStr) throws Exception {
//Java原生base64解码
byte[] priKey = Base64.getDecoder().decode(privateKeyStr);
//创建PKCS8编码密钥规范
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//根据PKCS8编码密钥规范产生私钥对象
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
//根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//用私钥初始化此Cipher对象(加密模式)
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
//对数据加密
byte[] encrypt = cipher.doFinal(data.getBytes());
//返回base64编码后的字符串
return Base64.getEncoder().encodeToString(encrypt);
}

/**
* 公钥解密(用于数据验签)
*
* @param data 解密前的字符串
* @param publicKeyStr base64编码后的公钥
* @return 解密后的字符串
* @throws Exception
*/
public static String decryptByPublicKey(String data, String publicKeyStr) throws Exception {
//Java原生base64解码
byte[] pubKey = Base64.getDecoder().decode(publicKeyStr);
//创建X509编码密钥规范
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//根据X509编码密钥规范产生公钥对象
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
//根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//用公钥初始化此Cipher对象(解密模式)
cipher.init(Cipher.DECRYPT_MODE, publicKey);
//对数据解密
byte[] decrypt = cipher.doFinal(Base64.getDecoder().decode(data));
//返回字符串
return new String(decrypt);
}

/**
* RSA签名
*
* @param data 待签名数据
* @param priKey 私钥
* @param signType RSA或RSA2
* @return 签名
* @throws Exception
*/
public static String sign(byte[] data, byte[] priKey, String signType) throws Exception {
//创建PKCS8编码密钥规范
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//根据PKCS8编码密钥规范产生私钥对象
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
//标准签名算法名称(RSA还是RSA2)
String algorithm = RSA_KEY_ALGORITHM.equals(signType) ? RSA_SIGNATURE_ALGORITHM : RSA2_SIGNATURE_ALGORITHM;
//用指定算法产生签名对象Signature
Signature signature = Signature.getInstance(algorithm);
//用私钥初始化签名对象Signature
signature.initSign(privateKey);
//将待签名的数据传送给签名对象(须在初始化之后)
signature.update(data);
//返回签名结果字节数组
byte[] sign = signature.sign();
//返回Base64编码后的字符串
return Base64.getEncoder().encodeToString(sign);
}

/**
* RSA校验数字签名
*
* @param data 待校验数据
* @param sign 数字签名
* @param pubKey 公钥
* @param signType RSA或RSA2
* @return boolean 校验成功返回true,失败返回false
*/
public static boolean verify(byte[] data, byte[] sign, byte[] pubKey, String signType) throws Exception {
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
//创建X509编码密钥规范
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
//根据X509编码密钥规范产生公钥对象
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
//标准签名算法名称(RSA还是RSA2)
String algorithm = RSA_KEY_ALGORITHM.equals(signType) ? RSA_SIGNATURE_ALGORITHM : RSA2_SIGNATURE_ALGORITHM;
//用指定算法产生签名对象Signature
Signature signature = Signature.getInstance(algorithm);
//用公钥初始化签名对象,用于验证签名
signature.initVerify(publicKey);
//更新签名内容
signature.update(data);
//得到验证结果
return signature.verify(sign);
}

public static void main(String[] args) throws Exception {
Map<String, String> keyMap = RSAUtil2.generateKey();
String publicKeyStr = keyMap.get("publicKeyStr");
String privateKeyStr = keyMap.get("privateKeyStr");
System.out.println("-----------------生成的公钥和私钥------------------------------");
System.out.println("获取到的公钥:" + publicKeyStr);
System.out.println("获取到的私钥:" + privateKeyStr);
// 待加密数据
String data = "tranSeq=1920542585&amount=100&payType=wechat";
// 公钥加密
System.out.println("-----------------加密和解密------------------------------");
System.out.println("待加密的数据:" + data);
String encrypt = RSAUtil2.encryptByPublicKey(data, publicKeyStr);
System.out.println("加密后数据:" + encrypt);
// 私钥解密
String decrypt = RSAUtil2.decryptByPrivateKey(encrypt, privateKeyStr);
System.out.println("解密后数据:" + decrypt);

// 数字签名
System.out.println("待签名的数据:" + data);
String sign = RSAUtil2.sign(data.getBytes(), Base64.getDecoder().decode(privateKeyStr), "RSA");
System.out.println("数字签名结果:" + sign);
boolean verify = RSAUtil2.verify(data.getBytes(), Base64.getDecoder().decode(sign), Base64.getDecoder().decode(publicKeyStr), "RSA");
System.out.println("数字签名验证结果:" + verify);

}
}

使用RSA进行加密和解密时,由于RSA算法的性能问题,通常不直接用于加密大量数据,而是用于加密对称加密算法的密钥(如AES密钥),然后使用该对称密钥加密实际数据。

注意事项:

密钥对的生成、存储和传输需要特别小心,以避免私钥泄露。
在实际应用中,密钥对可能需要持久化存储到文件系统或数据库中,但应确保存储的安全性。
加密和解密过程中,数据编码(如getBytes())应使用统一的字符集(如UTF-8),以避免乱码问题。

哈希算法

MD5算法

MD5(Message-Digest Algorithm 5)是一种常用的哈希算法,它可以接受任意长度的输入(信息),并输出一个128位的哈希值,通常以32位十六进制数表示。

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
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Util {

/**
* 获取字符串的MD5哈希值
*
* @param data 输入字符串
* @return 32位十六进制MD5哈希值
* @throws NoSuchAlgorithmException 当MD5算法不可用时抛出
*/
public static String getMD5(String data) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(data.getBytes());
byte[] digest = md.digest();
return bytesToHex(digest);
}

/**
* 将字节数组转换为十六进制字符串
*
* @param bytes 字节数组
* @return 十六进制字符串
*/
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}

// 工具类不应该有公共构造器
private MD5Util() {
}

// 主方法用于测试工具类
public static void main(String[] args) {
try {
String originalString = "Hello, World!";
String md5String = MD5Util.getMD5(originalString);
System.out.println("Original: " + originalString);
System.out.println("MD5 Hash: " + md5String);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}

SHA-1算法

SHA-1(Secure Hash Algorithm 1)是一种加密哈希函数,它接收一个输入(信息)并输出一个160位的哈希值,通常以40位十六进制数表示。

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
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SHA1Util {

/**
* 获取字符串的SHA-1哈希值
*
* @param data 输入字符串
* @return 40位十六进制SHA-1哈希值
* @throws NoSuchAlgorithmException 当SHA-1算法不可用时抛出
*/
public static String getSHA1(String data) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(data.getBytes());
byte[] digest = md.digest();
return bytesToHex(digest);
}

/**
* 将字节数组转换为十六进制字符串
*
* @param bytes 字节数组
* @return 十六进制字符串
*/
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}

// 工具类不应该有公共构造器
private SHA1Util() {
}

// 主方法用于测试工具类
public static void main(String[] args) {
try {
String originalString = "Hello, World!";
String sha1String = SHA1Util.getSHA1(originalString);
System.out.println("Original: " + originalString);
System.out.println("SHA-1 Hash: " + sha1String);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}

SHA-256算法

它生成数据的固定长度(如256位)摘要,用于验证数据的完整性。

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
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SHA256Util {

/**
* 获取字符串的SHA-256哈希值
*
* @param data 输入字符串
* @return 64位十六进制SHA-256哈希值
* @throws NoSuchAlgorithmException 当SHA-256算法不可用时抛出
*/
public static String getSHA256(String data) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(data.getBytes());
byte[] digest = md.digest();
return bytesToHex(digest);
}

/**
* 将字节数组转换为十六进制字符串
*
* @param bytes 字节数组
* @return 十六进制字符串
*/
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}

// 工具类不应该有公共构造器
private SHA256Util() {
}

// 主方法用于测试工具类
public static void main(String[] args) {
try {
String originalString = "Hello, World!";
String sha256String = SHA256Util.getSHA256(originalString);
System.out.println("Original: " + originalString);
System.out.println("SHA-256 Hash: " + sha256String);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}