前言

接口加解密作为现代互联网应用中的重要安全机制,广泛应用于金融、电商、社交、企业服务等各个领域。通过合理的加密算法和密钥管理,能够有效保护接口传输数据的安全性,防止数据泄露和篡改。本文从接口加密设计到解密算法,从基础实现到企业级方案,系统梳理基于接口加解密的完整解决方案。

一、接口加解密架构设计

1.1 接口加解密整体架构

1.2 加解密流程架构

二、加密算法实现

2.1 AES对称加密

2.1.1 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
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
/**
* AES对称加密服务
*/
@Service
public class AESCryptoService {

private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static final String CHARSET = "UTF-8";

@Autowired
private KeyManagementService keyManagementService;

/**
* AES加密
*/
public String encrypt(String plainText, String keyId) {
try {
// 获取密钥
SecretKey secretKey = keyManagementService.getSecretKey(keyId);

// 创建Cipher实例
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);

// 加密数据
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(CHARSET));

// 获取IV
byte[] iv = cipher.getIV();

// 组合IV和加密数据
byte[] combined = new byte[iv.length + encryptedBytes.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encryptedBytes, 0, combined, iv.length, encryptedBytes.length);

// 返回Base64编码的结果
return Base64.getEncoder().encodeToString(combined);

} catch (Exception e) {
log.error("AES加密失败", e);
throw new CryptoException("AES加密失败", e);
}
}

/**
* AES解密
*/
public String decrypt(String encryptedText, String keyId) {
try {
// 获取密钥
SecretKey secretKey = keyManagementService.getSecretKey(keyId);

// Base64解码
byte[] combined = Base64.getDecoder().decode(encryptedText);

// 分离IV和加密数据
byte[] iv = new byte[16]; // AES块大小为16字节
byte[] encryptedBytes = new byte[combined.length - 16];
System.arraycopy(combined, 0, iv, 0, 16);
System.arraycopy(combined, 16, encryptedBytes, 0, encryptedBytes.length);

// 创建Cipher实例
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);

// 解密数据
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

return new String(decryptedBytes, CHARSET);

} catch (Exception e) {
log.error("AES解密失败", e);
throw new CryptoException("AES解密失败", e);
}
}

/**
* 批量加密
*/
public Map<String, String> batchEncrypt(Map<String, String> plainTexts, String keyId) {
Map<String, String> encryptedTexts = new HashMap<>();

for (Map.Entry<String, String> entry : plainTexts.entrySet()) {
try {
String encrypted = encrypt(entry.getValue(), keyId);
encryptedTexts.put(entry.getKey(), encrypted);
} catch (Exception e) {
log.error("批量加密失败: {}", entry.getKey(), e);
encryptedTexts.put(entry.getKey(), null);
}
}

return encryptedTexts;
}

/**
* 批量解密
*/
public Map<String, String> batchDecrypt(Map<String, String> encryptedTexts, String keyId) {
Map<String, String> plainTexts = new HashMap<>();

for (Map.Entry<String, String> entry : encryptedTexts.entrySet()) {
try {
String decrypted = decrypt(entry.getValue(), keyId);
plainTexts.put(entry.getKey(), decrypted);
} catch (Exception e) {
log.error("批量解密失败: {}", entry.getKey(), e);
plainTexts.put(entry.getKey(), null);
}
}

return plainTexts;
}

/**
* 生成随机密钥
*/
public String generateRandomKey() {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
keyGenerator.init(256); // 256位密钥
SecretKey secretKey = keyGenerator.generateKey();
return Base64.getEncoder().encodeToString(secretKey.getEncoded());
} catch (Exception e) {
log.error("生成随机密钥失败", e);
throw new CryptoException("生成随机密钥失败", e);
}
}
}

2.1.2 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
/**
* AES加密配置
*/
@Configuration
public class AESConfig {

@Value("${crypto.aes.key-size:256}")
private int keySize;

@Value("${crypto.aes.algorithm:AES}")
private String algorithm;

@Value("${crypto.aes.transformation:AES/CBC/PKCS5Padding}")
private String transformation;

@Value("${crypto.aes.charset:UTF-8}")
private String charset;

@Bean
public AESCryptoService aesCryptoService() {
return new AESCryptoService();
}

@Bean
public KeyGenerator aesKeyGenerator() {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
keyGenerator.init(keySize);
return keyGenerator;
} catch (Exception e) {
throw new RuntimeException("创建AES密钥生成器失败", e);
}
}
}

2.2 RSA非对称加密

2.2.1 RSA加密服务

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
/**
* RSA非对称加密服务
*/
@Service
public class RSACryptoService {

private static final String ALGORITHM = "RSA";
private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding";
private static final String CHARSET = "UTF-8";
private static final int KEY_SIZE = 2048;

@Autowired
private KeyManagementService keyManagementService;

/**
* RSA公钥加密
*/
public String encryptWithPublicKey(String plainText, String keyId) {
try {
// 获取公钥
PublicKey publicKey = keyManagementService.getPublicKey(keyId);

// 创建Cipher实例
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);

// 分段加密
byte[] plainBytes = plainText.getBytes(CHARSET);
int maxEncryptBlock = getMaxEncryptBlock(publicKey);

ByteArrayOutputStream out = new ByteArrayOutputStream();
int inputLen = plainBytes.length;
int offset = 0;

while (inputLen - offset > 0) {
byte[] cache;
if (inputLen - offset > maxEncryptBlock) {
cache = cipher.doFinal(plainBytes, offset, maxEncryptBlock);
} else {
cache = cipher.doFinal(plainBytes, offset, inputLen - offset);
}
out.write(cache, 0, cache.length);
offset += maxEncryptBlock;
}

byte[] encryptedBytes = out.toByteArray();
out.close();

return Base64.getEncoder().encodeToString(encryptedBytes);

} catch (Exception e) {
log.error("RSA公钥加密失败", e);
throw new CryptoException("RSA公钥加密失败", e);
}
}

/**
* RSA私钥解密
*/
public String decryptWithPrivateKey(String encryptedText, String keyId) {
try {
// 获取私钥
PrivateKey privateKey = keyManagementService.getPrivateKey(keyId);

// Base64解码
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);

// 创建Cipher实例
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, privateKey);

// 分段解密
int maxDecryptBlock = getMaxDecryptBlock(privateKey);

ByteArrayOutputStream out = new ByteArrayOutputStream();
int inputLen = encryptedBytes.length;
int offset = 0;

while (inputLen - offset > 0) {
byte[] cache;
if (inputLen - offset > maxDecryptBlock) {
cache = cipher.doFinal(encryptedBytes, offset, maxDecryptBlock);
} else {
cache = cipher.doFinal(encryptedBytes, offset, inputLen - offset);
}
out.write(cache, 0, cache.length);
offset += maxDecryptBlock;
}

byte[] decryptedBytes = out.toByteArray();
out.close();

return new String(decryptedBytes, CHARSET);

} catch (Exception e) {
log.error("RSA私钥解密失败", e);
throw new CryptoException("RSA私钥解密失败", e);
}
}

/**
* RSA私钥签名
*/
public String signWithPrivateKey(String data, String keyId) {
try {
// 获取私钥
PrivateKey privateKey = keyManagementService.getPrivateKey(keyId);

// 创建签名实例
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data.getBytes(CHARSET));

// 生成签名
byte[] signBytes = signature.sign();

return Base64.getEncoder().encodeToString(signBytes);

} catch (Exception e) {
log.error("RSA私钥签名失败", e);
throw new CryptoException("RSA私钥签名失败", e);
}
}

/**
* RSA公钥验签
*/
public boolean verifyWithPublicKey(String data, String signature, String keyId) {
try {
// 获取公钥
PublicKey publicKey = keyManagementService.getPublicKey(keyId);

// 创建签名实例
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
sig.update(data.getBytes(CHARSET));

// 验证签名
byte[] signatureBytes = Base64.getDecoder().decode(signature);
return sig.verify(signatureBytes);

} catch (Exception e) {
log.error("RSA公钥验签失败", e);
return false;
}
}

/**
* 生成RSA密钥对
*/
public KeyPair generateKeyPair() {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(KEY_SIZE);
return keyPairGenerator.generateKeyPair();
} catch (Exception e) {
log.error("生成RSA密钥对失败", e);
throw new CryptoException("生成RSA密钥对失败", e);
}
}

/**
* 获取最大加密块大小
*/
private int getMaxEncryptBlock(PublicKey publicKey) {
return ((RSAPublicKey) publicKey).getModulus().bitLength() / 8 - 11;
}

/**
* 获取最大解密块大小
*/
private int getMaxDecryptBlock(PrivateKey privateKey) {
return ((RSAPrivateKey) privateKey).getModulus().bitLength() / 8;
}
}

2.3 SM4国密加密

2.3.1 SM4加密服务

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
/**
* SM4国密加密服务
*/
@Service
public class SM4CryptoService {

private static final String ALGORITHM = "SM4";
private static final String TRANSFORMATION = "SM4/CBC/PKCS5Padding";
private static final String CHARSET = "UTF-8";
private static final int KEY_LENGTH = 16; // 128位

@Autowired
private KeyManagementService keyManagementService;

/**
* SM4加密
*/
public String encrypt(String plainText, String keyId) {
try {
// 获取密钥
SecretKey secretKey = keyManagementService.getSM4Key(keyId);

// 创建Cipher实例
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);

// 加密数据
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(CHARSET));

// 获取IV
byte[] iv = cipher.getIV();

// 组合IV和加密数据
byte[] combined = new byte[iv.length + encryptedBytes.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encryptedBytes, 0, combined, iv.length, encryptedBytes.length);

// 返回Base64编码的结果
return Base64.getEncoder().encodeToString(combined);

} catch (Exception e) {
log.error("SM4加密失败", e);
throw new CryptoException("SM4加密失败", e);
}
}

/**
* SM4解密
*/
public String decrypt(String encryptedText, String keyId) {
try {
// 获取密钥
SecretKey secretKey = keyManagementService.getSM4Key(keyId);

// Base64解码
byte[] combined = Base64.getDecoder().decode(encryptedText);

// 分离IV和加密数据
byte[] iv = new byte[16]; // SM4块大小为16字节
byte[] encryptedBytes = new byte[combined.length - 16];
System.arraycopy(combined, 0, iv, 0, 16);
System.arraycopy(combined, 16, encryptedBytes, 0, encryptedBytes.length);

// 创建Cipher实例
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);

// 解密数据
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

return new String(decryptedBytes, CHARSET);

} catch (Exception e) {
log.error("SM4解密失败", e);
throw new CryptoException("SM4解密失败", e);
}
}

/**
* 生成SM4密钥
*/
public String generateSM4Key() {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
keyGenerator.init(128); // 128位密钥
SecretKey secretKey = keyGenerator.generateKey();
return Base64.getEncoder().encodeToString(secretKey.getEncoded());
} catch (Exception e) {
log.error("生成SM4密钥失败", e);
throw new CryptoException("生成SM4密钥失败", e);
}
}

/**
* 从字符串创建SM4密钥
*/
public SecretKey createSM4KeyFromString(String keyString) {
try {
byte[] keyBytes = Base64.getDecoder().decode(keyString);
return new SecretKeySpec(keyBytes, ALGORITHM);
} catch (Exception e) {
log.error("从字符串创建SM4密钥失败", e);
throw new CryptoException("从字符串创建SM4密钥失败", e);
}
}
}

三、密钥管理服务

3.1 密钥管理服务实现

3.1.1 密钥管理服务

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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/**
* 密钥管理服务
*/
@Service
public class KeyManagementService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Autowired
private KeyRepository keyRepository;

private final String KEY_PREFIX = "crypto_key:";
private final String KEY_CACHE_PREFIX = "key_cache:";

/**
* 获取AES密钥
*/
public SecretKey getSecretKey(String keyId) {
try {
// 先从缓存获取
String cacheKey = KEY_CACHE_PREFIX + "aes:" + keyId;
SecretKey cachedKey = (SecretKey) redisTemplate.opsForValue().get(cacheKey);
if (cachedKey != null) {
return cachedKey;
}

// 从数据库获取
CryptoKey cryptoKey = keyRepository.findByKeyId(keyId);
if (cryptoKey == null) {
throw new KeyNotFoundException("密钥不存在: " + keyId);
}

// 检查密钥状态
if (cryptoKey.getStatus() != KeyStatus.ACTIVE) {
throw new KeyException("密钥已失效: " + keyId);
}

// 检查密钥过期时间
if (cryptoKey.getExpireTime() != null && System.currentTimeMillis() > cryptoKey.getExpireTime()) {
throw new KeyException("密钥已过期: " + keyId);
}

// 创建SecretKey
byte[] keyBytes = Base64.getDecoder().decode(cryptoKey.getKeyValue());
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");

// 缓存密钥
redisTemplate.opsForValue().set(cacheKey, secretKey, Duration.ofMinutes(30));

return secretKey;

} catch (Exception e) {
log.error("获取AES密钥失败: {}", keyId, e);
throw new KeyException("获取AES密钥失败", e);
}
}

/**
* 获取RSA公钥
*/
public PublicKey getPublicKey(String keyId) {
try {
// 先从缓存获取
String cacheKey = KEY_CACHE_PREFIX + "rsa_public:" + keyId;
PublicKey cachedKey = (PublicKey) redisTemplate.opsForValue().get(cacheKey);
if (cachedKey != null) {
return cachedKey;
}

// 从数据库获取
CryptoKey cryptoKey = keyRepository.findByKeyId(keyId);
if (cryptoKey == null) {
throw new KeyNotFoundException("密钥不存在: " + keyId);
}

// 检查密钥状态
if (cryptoKey.getStatus() != KeyStatus.ACTIVE) {
throw new KeyException("密钥已失效: " + keyId);
}

// 创建PublicKey
byte[] keyBytes = Base64.getDecoder().decode(cryptoKey.getPublicKey());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);

// 缓存密钥
redisTemplate.opsForValue().set(cacheKey, publicKey, Duration.ofMinutes(30));

return publicKey;

} catch (Exception e) {
log.error("获取RSA公钥失败: {}", keyId, e);
throw new KeyException("获取RSA公钥失败", e);
}
}

/**
* 获取RSA私钥
*/
public PrivateKey getPrivateKey(String keyId) {
try {
// 先从缓存获取
String cacheKey = KEY_CACHE_PREFIX + "rsa_private:" + keyId;
PrivateKey cachedKey = (PrivateKey) redisTemplate.opsForValue().get(cacheKey);
if (cachedKey != null) {
return cachedKey;
}

// 从数据库获取
CryptoKey cryptoKey = keyRepository.findByKeyId(keyId);
if (cryptoKey == null) {
throw new KeyNotFoundException("密钥不存在: " + keyId);
}

// 检查密钥状态
if (cryptoKey.getStatus() != KeyStatus.ACTIVE) {
throw new KeyException("密钥已失效: " + keyId);
}

// 创建PrivateKey
byte[] keyBytes = Base64.getDecoder().decode(cryptoKey.getPrivateKey());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

// 缓存密钥
redisTemplate.opsForValue().set(cacheKey, privateKey, Duration.ofMinutes(30));

return privateKey;

} catch (Exception e) {
log.error("获取RSA私钥失败: {}", keyId, e);
throw new KeyException("获取RSA私钥失败", e);
}
}

/**
* 获取SM4密钥
*/
public SecretKey getSM4Key(String keyId) {
try {
// 先从缓存获取
String cacheKey = KEY_CACHE_PREFIX + "sm4:" + keyId;
SecretKey cachedKey = (SecretKey) redisTemplate.opsForValue().get(cacheKey);
if (cachedKey != null) {
return cachedKey;
}

// 从数据库获取
CryptoKey cryptoKey = keyRepository.findByKeyId(keyId);
if (cryptoKey == null) {
throw new KeyNotFoundException("密钥不存在: " + keyId);
}

// 检查密钥状态
if (cryptoKey.getStatus() != KeyStatus.ACTIVE) {
throw new KeyException("密钥已失效: " + keyId);
}

// 创建SecretKey
byte[] keyBytes = Base64.getDecoder().decode(cryptoKey.getKeyValue());
SecretKey secretKey = new SecretKeySpec(keyBytes, "SM4");

// 缓存密钥
redisTemplate.opsForValue().set(cacheKey, secretKey, Duration.ofMinutes(30));

return secretKey;

} catch (Exception e) {
log.error("获取SM4密钥失败: {}", keyId, e);
throw new KeyException("获取SM4密钥失败", e);
}
}

/**
* 创建密钥
*/
public CryptoKey createKey(KeyType keyType, String keyName, String description) {
try {
CryptoKey cryptoKey = new CryptoKey();
cryptoKey.setKeyId(UUID.randomUUID().toString());
cryptoKey.setKeyName(keyName);
cryptoKey.setKeyType(keyType);
cryptoKey.setDescription(description);
cryptoKey.setStatus(KeyStatus.ACTIVE);
cryptoKey.setCreateTime(System.currentTimeMillis());
cryptoKey.setExpireTime(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000L); // 1年过期

// 根据密钥类型生成密钥
switch (keyType) {
case AES:
String aesKey = generateAESKey();
cryptoKey.setKeyValue(aesKey);
break;
case RSA:
KeyPair keyPair = generateRSAKeyPair();
cryptoKey.setPublicKey(Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
cryptoKey.setPrivateKey(Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()));
break;
case SM4:
String sm4Key = generateSM4Key();
cryptoKey.setKeyValue(sm4Key);
break;
default:
throw new KeyException("不支持的密钥类型: " + keyType);
}

// 保存到数据库
keyRepository.save(cryptoKey);

return cryptoKey;

} catch (Exception e) {
log.error("创建密钥失败", e);
throw new KeyException("创建密钥失败", e);
}
}

/**
* 轮换密钥
*/
public CryptoKey rotateKey(String keyId) {
try {
// 获取原密钥
CryptoKey oldKey = keyRepository.findByKeyId(keyId);
if (oldKey == null) {
throw new KeyNotFoundException("密钥不存在: " + keyId);
}

// 创建新密钥
CryptoKey newKey = new CryptoKey();
newKey.setKeyId(UUID.randomUUID().toString());
newKey.setKeyName(oldKey.getKeyName() + "_rotated");
newKey.setKeyType(oldKey.getKeyType());
newKey.setDescription(oldKey.getDescription() + " (轮换)");
newKey.setStatus(KeyStatus.ACTIVE);
newKey.setCreateTime(System.currentTimeMillis());
newKey.setExpireTime(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000L);

// 生成新密钥
switch (oldKey.getKeyType()) {
case AES:
String aesKey = generateAESKey();
newKey.setKeyValue(aesKey);
break;
case RSA:
KeyPair keyPair = generateRSAKeyPair();
newKey.setPublicKey(Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
newKey.setPrivateKey(Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()));
break;
case SM4:
String sm4Key = generateSM4Key();
newKey.setKeyValue(sm4Key);
break;
}

// 保存新密钥
keyRepository.save(newKey);

// 标记原密钥为已轮换
oldKey.setStatus(KeyStatus.ROTATED);
oldKey.setRotateTime(System.currentTimeMillis());
oldKey.setRotatedToKeyId(newKey.getKeyId());
keyRepository.save(oldKey);

// 清除缓存
clearKeyCache(keyId);

return newKey;

} catch (Exception e) {
log.error("轮换密钥失败: {}", keyId, e);
throw new KeyException("轮换密钥失败", e);
}
}

/**
* 生成AES密钥
*/
private String generateAESKey() {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
SecretKey secretKey = keyGenerator.generateKey();
return Base64.getEncoder().encodeToString(secretKey.getEncoded());
} catch (Exception e) {
throw new KeyException("生成AES密钥失败", e);
}
}

/**
* 生成RSA密钥对
*/
private KeyPair generateRSAKeyPair() {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
return keyPairGenerator.generateKeyPair();
} catch (Exception e) {
throw new KeyException("生成RSA密钥对失败", e);
}
}

/**
* 生成SM4密钥
*/
private String generateSM4Key() {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("SM4");
keyGenerator.init(128);
SecretKey secretKey = keyGenerator.generateKey();
return Base64.getEncoder().encodeToString(secretKey.getEncoded());
} catch (Exception e) {
throw new KeyException("生成SM4密钥失败", e);
}
}

/**
* 清除密钥缓存
*/
private void clearKeyCache(String keyId) {
try {
String[] cacheKeys = {
KEY_CACHE_PREFIX + "aes:" + keyId,
KEY_CACHE_PREFIX + "rsa_public:" + keyId,
KEY_CACHE_PREFIX + "rsa_private:" + keyId,
KEY_CACHE_PREFIX + "sm4:" + keyId
};

redisTemplate.delete(Arrays.asList(cacheKeys));
} catch (Exception e) {
log.error("清除密钥缓存失败: {}", keyId, e);
}
}
}

四、接口加解密拦截器

4.1 请求解密拦截器

4.1.1 请求解密拦截器

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
/**
* 请求解密拦截器
*/
@Component
public class RequestDecryptInterceptor implements HandlerInterceptor {

@Autowired
private AESCryptoService aesCryptoService;

@Autowired
private RSACryptoService rsaCryptoService;

@Autowired
private KeyManagementService keyManagementService;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
try {
// 检查是否需要解密
if (!needDecrypt(request)) {
return true;
}

// 获取加密数据
String encryptedData = getEncryptedData(request);
if (StringUtils.isEmpty(encryptedData)) {
throw new CryptoException("加密数据为空");
}

// 获取密钥ID
String keyId = getKeyId(request);
if (StringUtils.isEmpty(keyId)) {
throw new CryptoException("密钥ID为空");
}

// 解密数据
String decryptedData = decryptData(encryptedData, keyId, request);

// 验证签名
if (!verifySignature(decryptedData, request)) {
throw new CryptoException("签名验证失败");
}

// 将解密后的数据放入请求属性
request.setAttribute("decryptedData", decryptedData);

return true;

} catch (Exception e) {
log.error("请求解密失败", e);
response.setStatus(HttpStatus.BAD_REQUEST.value());
response.getWriter().write("{\"code\":400,\"message\":\"请求解密失败\"}");
return false;
}
}

/**
* 检查是否需要解密
*/
private boolean needDecrypt(HttpServletRequest request) {
String encryptHeader = request.getHeader("X-Encrypt");
return "true".equalsIgnoreCase(encryptHeader);
}

/**
* 获取加密数据
*/
private String getEncryptedData(HttpServletRequest request) {
// 优先从请求体获取
String encryptedData = request.getParameter("encryptedData");
if (StringUtils.isNotEmpty(encryptedData)) {
return encryptedData;
}

// 从请求头获取
encryptedData = request.getHeader("X-Encrypted-Data");
if (StringUtils.isNotEmpty(encryptedData)) {
return encryptedData;
}

// 从请求体读取
try {
String body = getRequestBody(request);
if (StringUtils.isNotEmpty(body)) {
JSONObject jsonObject = JSON.parseObject(body);
return jsonObject.getString("encryptedData");
}
} catch (Exception e) {
log.error("读取请求体失败", e);
}

return null;
}

/**
* 获取密钥ID
*/
private String getKeyId(HttpServletRequest request) {
String keyId = request.getHeader("X-Key-Id");
if (StringUtils.isNotEmpty(keyId)) {
return keyId;
}

keyId = request.getParameter("keyId");
if (StringUtils.isNotEmpty(keyId)) {
return keyId;
}

return "default"; // 默认密钥ID
}

/**
* 解密数据
*/
private String decryptData(String encryptedData, String keyId, HttpServletRequest request) {
String encryptType = request.getHeader("X-Encrypt-Type");

switch (encryptType) {
case "AES":
return aesCryptoService.decrypt(encryptedData, keyId);
case "RSA":
return rsaCryptoService.decryptWithPrivateKey(encryptedData, keyId);
case "SM4":
return sm4CryptoService.decrypt(encryptedData, keyId);
default:
return aesCryptoService.decrypt(encryptedData, keyId);
}
}

/**
* 验证签名
*/
private boolean verifySignature(String data, HttpServletRequest request) {
String signature = request.getHeader("X-Signature");
if (StringUtils.isEmpty(signature)) {
return true; // 没有签名则跳过验证
}

String keyId = getKeyId(request);
return rsaCryptoService.verifyWithPublicKey(data, signature, keyId);
}

/**
* 获取请求体
*/
private String getRequestBody(HttpServletRequest request) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
return stringBuilder.toString();
}
}

4.2 响应加密拦截器

4.2.1 响应加密拦截器

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
/**
* 响应加密拦截器
*/
@Component
public class ResponseEncryptInterceptor implements HandlerInterceptor {

@Autowired
private AESCryptoService aesCryptoService;

@Autowired
private RSACryptoService rsaCryptoService;

@Autowired
private SM4CryptoService sm4CryptoService;

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 在postHandle中处理响应加密
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
try {
// 检查是否需要加密
if (!needEncrypt(request)) {
return;
}

// 获取响应数据
String responseData = getResponseData(response);
if (StringUtils.isEmpty(responseData)) {
return;
}

// 获取密钥ID
String keyId = getKeyId(request);

// 加密数据
String encryptedData = encryptData(responseData, keyId, request);

// 生成签名
String signature = generateSignature(encryptedData, keyId, request);

// 设置响应头
response.setHeader("X-Encrypt", "true");
response.setHeader("X-Encrypt-Type", getEncryptType(request));
response.setHeader("X-Key-Id", keyId);
response.setHeader("X-Signature", signature);

// 设置响应体
JSONObject responseJson = new JSONObject();
responseJson.put("encryptedData", encryptedData);
responseJson.put("timestamp", System.currentTimeMillis());

response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(responseJson.toJSONString());

} catch (Exception e) {
log.error("响应加密失败", e);
}
}

/**
* 检查是否需要加密
*/
private boolean needEncrypt(HttpServletRequest request) {
String encryptHeader = request.getHeader("X-Encrypt");
return "true".equalsIgnoreCase(encryptHeader);
}

/**
* 获取响应数据
*/
private String getResponseData(HttpServletResponse response) {
// 这里需要从响应中获取数据
// 实际实现中可能需要使用ResponseBodyAdvice或自定义ResponseWrapper
return null;
}

/**
* 获取密钥ID
*/
private String getKeyId(HttpServletRequest request) {
String keyId = request.getHeader("X-Key-Id");
if (StringUtils.isNotEmpty(keyId)) {
return keyId;
}

return "default"; // 默认密钥ID
}

/**
* 加密数据
*/
private String encryptData(String data, String keyId, HttpServletRequest request) {
String encryptType = request.getHeader("X-Encrypt-Type");

switch (encryptType) {
case "AES":
return aesCryptoService.encrypt(data, keyId);
case "RSA":
return rsaCryptoService.encryptWithPublicKey(data, keyId);
case "SM4":
return sm4CryptoService.encrypt(data, keyId);
default:
return aesCryptoService.encrypt(data, keyId);
}
}

/**
* 生成签名
*/
private String generateSignature(String data, String keyId, HttpServletRequest request) {
return rsaCryptoService.signWithPrivateKey(data, keyId);
}

/**
* 获取加密类型
*/
private String getEncryptType(HttpServletRequest request) {
String encryptType = request.getHeader("X-Encrypt-Type");
return StringUtils.isNotEmpty(encryptType) ? encryptType : "AES";
}
}

4.3 响应体加密处理器

4.3.1 响应体加密处理器

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
/**
* 响应体加密处理器
*/
@ControllerAdvice
public class ResponseEncryptAdvice implements ResponseBodyAdvice<Object> {

@Autowired
private AESCryptoService aesCryptoService;

@Autowired
private RSACryptoService rsaCryptoService;

@Autowired
private SM4CryptoService sm4CryptoService;

@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}

@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {

try {
// 检查是否需要加密
if (!needEncrypt(request)) {
return body;
}

// 获取密钥ID
String keyId = getKeyId(request);

// 将响应体转换为JSON字符串
String responseData = JSON.toJSONString(body);

// 加密数据
String encryptedData = encryptData(responseData, keyId, request);

// 生成签名
String signature = generateSignature(encryptedData, keyId, request);

// 设置响应头
response.getHeaders().add("X-Encrypt", "true");
response.getHeaders().add("X-Encrypt-Type", getEncryptType(request));
response.getHeaders().add("X-Key-Id", keyId);
response.getHeaders().add("X-Signature", signature);

// 构建加密响应
EncryptedResponse encryptedResponse = new EncryptedResponse();
encryptedResponse.setEncryptedData(encryptedData);
encryptedResponse.setTimestamp(System.currentTimeMillis());
encryptedResponse.setKeyId(keyId);

return encryptedResponse;

} catch (Exception e) {
log.error("响应体加密失败", e);
return body;
}
}

/**
* 检查是否需要加密
*/
private boolean needEncrypt(ServerHttpRequest request) {
String encryptHeader = request.getHeaders().getFirst("X-Encrypt");
return "true".equalsIgnoreCase(encryptHeader);
}

/**
* 获取密钥ID
*/
private String getKeyId(ServerHttpRequest request) {
String keyId = request.getHeaders().getFirst("X-Key-Id");
return StringUtils.isNotEmpty(keyId) ? keyId : "default";
}

/**
* 加密数据
*/
private String encryptData(String data, String keyId, ServerHttpRequest request) {
String encryptType = request.getHeaders().getFirst("X-Encrypt-Type");

switch (encryptType) {
case "AES":
return aesCryptoService.encrypt(data, keyId);
case "RSA":
return rsaCryptoService.encryptWithPublicKey(data, keyId);
case "SM4":
return sm4CryptoService.encrypt(data, keyId);
default:
return aesCryptoService.encrypt(data, keyId);
}
}

/**
* 生成签名
*/
private String generateSignature(String data, String keyId, ServerHttpRequest request) {
return rsaCryptoService.signWithPrivateKey(data, keyId);
}

/**
* 获取加密类型
*/
private String getEncryptType(ServerHttpRequest request) {
String encryptType = request.getHeaders().getFirst("X-Encrypt-Type");
return StringUtils.isNotEmpty(encryptType) ? encryptType : "AES";
}
}

五、企业级加解密应用

5.1 金融接口加解密

5.1.1 金融接口加解密服务

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
/**
* 金融接口加解密服务
*/
@Service
public class FinancialCryptoService {

@Autowired
private AESCryptoService aesCryptoService;

@Autowired
private RSACryptoService rsaCryptoService;

@Autowired
private KeyManagementService keyManagementService;

private final String FINANCIAL_KEY_PREFIX = "financial:";

/**
* 加密金融数据
*/
public FinancialEncryptedData encryptFinancialData(FinancialData financialData, String clientId) {
try {
// 获取客户端密钥
String keyId = FINANCIAL_KEY_PREFIX + clientId;

// 将金融数据转换为JSON
String jsonData = JSON.toJSONString(financialData);

// 使用AES加密数据
String encryptedData = aesCryptoService.encrypt(jsonData, keyId);

// 使用RSA签名
String signature = rsaCryptoService.signWithPrivateKey(encryptedData, keyId);

// 构建加密响应
FinancialEncryptedData encryptedResponse = new FinancialEncryptedData();
encryptedResponse.setEncryptedData(encryptedData);
encryptedResponse.setSignature(signature);
encryptedResponse.setTimestamp(System.currentTimeMillis());
encryptedResponse.setClientId(clientId);
encryptedResponse.setKeyId(keyId);

return encryptedResponse;

} catch (Exception e) {
log.error("加密金融数据失败", e);
throw new FinancialCryptoException("加密金融数据失败", e);
}
}

/**
* 解密金融数据
*/
public FinancialData decryptFinancialData(FinancialEncryptedData encryptedData) {
try {
String keyId = encryptedData.getKeyId();
String encryptedText = encryptedData.getEncryptedData();
String signature = encryptedData.getSignature();

// 验证签名
if (!rsaCryptoService.verifyWithPublicKey(encryptedText, signature, keyId)) {
throw new FinancialCryptoException("签名验证失败");
}

// 验证时间戳
long currentTime = System.currentTimeMillis();
long dataTime = encryptedData.getTimestamp();
if (Math.abs(currentTime - dataTime) > 5 * 60 * 1000) { // 5分钟
throw new FinancialCryptoException("数据已过期");
}

// 解密数据
String decryptedData = aesCryptoService.decrypt(encryptedText, keyId);

// 转换为金融数据对象
return JSON.parseObject(decryptedData, FinancialData.class);

} catch (Exception e) {
log.error("解密金融数据失败", e);
throw new FinancialCryptoException("解密金融数据失败", e);
}
}

/**
* 加密交易数据
*/
public TransactionEncryptedData encryptTransactionData(TransactionData transactionData, String merchantId) {
try {
// 获取商户密钥
String keyId = FINANCIAL_KEY_PREFIX + "merchant:" + merchantId;

// 添加交易ID和时间戳
transactionData.setTransactionId(UUID.randomUUID().toString());
transactionData.setTimestamp(System.currentTimeMillis());

// 将交易数据转换为JSON
String jsonData = JSON.toJSONString(transactionData);

// 使用AES加密数据
String encryptedData = aesCryptoService.encrypt(jsonData, keyId);

// 使用RSA签名
String signature = rsaCryptoService.signWithPrivateKey(encryptedData, keyId);

// 构建加密响应
TransactionEncryptedData encryptedResponse = new TransactionEncryptedData();
encryptedResponse.setEncryptedData(encryptedData);
encryptedResponse.setSignature(signature);
encryptedResponse.setTimestamp(System.currentTimeMillis());
encryptedResponse.setMerchantId(merchantId);
encryptedResponse.setKeyId(keyId);

return encryptedResponse;

} catch (Exception e) {
log.error("加密交易数据失败", e);
throw new FinancialCryptoException("加密交易数据失败", e);
}
}

/**
* 解密交易数据
*/
public TransactionData decryptTransactionData(TransactionEncryptedData encryptedData) {
try {
String keyId = encryptedData.getKeyId();
String encryptedText = encryptedData.getEncryptedData();
String signature = encryptedData.getSignature();

// 验证签名
if (!rsaCryptoService.verifyWithPublicKey(encryptedText, signature, keyId)) {
throw new FinancialCryptoException("签名验证失败");
}

// 验证时间戳
long currentTime = System.currentTimeMillis();
long dataTime = encryptedData.getTimestamp();
if (Math.abs(currentTime - dataTime) > 2 * 60 * 1000) { // 2分钟
throw new FinancialCryptoException("交易数据已过期");
}

// 解密数据
String decryptedData = aesCryptoService.decrypt(encryptedText, keyId);

// 转换为交易数据对象
return JSON.parseObject(decryptedData, TransactionData.class);

} catch (Exception e) {
log.error("解密交易数据失败", e);
throw new FinancialCryptoException("解密交易数据失败", e);
}
}
}

5.2 电商接口加解密

5.2.1 电商接口加解密服务

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
/**
* 电商接口加解密服务
*/
@Service
public class EcommerceCryptoService {

@Autowired
private AESCryptoService aesCryptoService;

@Autowired
private SM4CryptoService sm4CryptoService;

@Autowired
private KeyManagementService keyManagementService;

private final String ECOMMERCE_KEY_PREFIX = "ecommerce:";

/**
* 加密用户数据
*/
public UserEncryptedData encryptUserData(UserData userData, String userId) {
try {
// 获取用户密钥
String keyId = ECOMMERCE_KEY_PREFIX + "user:" + userId;

// 敏感数据脱敏
UserData maskedData = maskSensitiveData(userData);

// 将用户数据转换为JSON
String jsonData = JSON.toJSONString(maskedData);

// 使用AES加密数据
String encryptedData = aesCryptoService.encrypt(jsonData, keyId);

// 构建加密响应
UserEncryptedData encryptedResponse = new UserEncryptedData();
encryptedResponse.setEncryptedData(encryptedData);
encryptedResponse.setTimestamp(System.currentTimeMillis());
encryptedResponse.setUserId(userId);
encryptedResponse.setKeyId(keyId);

return encryptedResponse;

} catch (Exception e) {
log.error("加密用户数据失败", e);
throw new EcommerceCryptoException("加密用户数据失败", e);
}
}

/**
* 解密用户数据
*/
public UserData decryptUserData(UserEncryptedData encryptedData) {
try {
String keyId = encryptedData.getKeyId();
String encryptedText = encryptedData.getEncryptedData();

// 验证时间戳
long currentTime = System.currentTimeMillis();
long dataTime = encryptedData.getTimestamp();
if (Math.abs(currentTime - dataTime) > 10 * 60 * 1000) { // 10分钟
throw new EcommerceCryptoException("用户数据已过期");
}

// 解密数据
String decryptedData = aesCryptoService.decrypt(encryptedText, keyId);

// 转换为用户数据对象
return JSON.parseObject(decryptedData, UserData.class);

} catch (Exception e) {
log.error("解密用户数据失败", e);
throw new EcommerceCryptoException("解密用户数据失败", e);
}
}

/**
* 加密订单数据
*/
public OrderEncryptedData encryptOrderData(OrderData orderData, String merchantId) {
try {
// 获取商户密钥
String keyId = ECOMMERCE_KEY_PREFIX + "merchant:" + merchantId;

// 添加订单ID和时间戳
orderData.setOrderId(UUID.randomUUID().toString());
orderData.setTimestamp(System.currentTimeMillis());

// 将订单数据转换为JSON
String jsonData = JSON.toJSONString(orderData);

// 使用SM4加密数据(国密算法)
String encryptedData = sm4CryptoService.encrypt(jsonData, keyId);

// 构建加密响应
OrderEncryptedData encryptedResponse = new OrderEncryptedData();
encryptedResponse.setEncryptedData(encryptedData);
encryptedResponse.setTimestamp(System.currentTimeMillis());
encryptedResponse.setMerchantId(merchantId);
encryptedResponse.setKeyId(keyId);

return encryptedResponse;

} catch (Exception e) {
log.error("加密订单数据失败", e);
throw new EcommerceCryptoException("加密订单数据失败", e);
}
}

/**
* 解密订单数据
*/
public OrderData decryptOrderData(OrderEncryptedData encryptedData) {
try {
String keyId = encryptedData.getKeyId();
String encryptedText = encryptedData.getEncryptedData();

// 验证时间戳
long currentTime = System.currentTimeMillis();
long dataTime = encryptedData.getTimestamp();
if (Math.abs(currentTime - dataTime) > 30 * 60 * 1000) { // 30分钟
throw new EcommerceCryptoException("订单数据已过期");
}

// 解密数据
String decryptedData = sm4CryptoService.decrypt(encryptedText, keyId);

// 转换为订单数据对象
return JSON.parseObject(decryptedData, OrderData.class);

} catch (Exception e) {
log.error("解密订单数据失败", e);
throw new EcommerceCryptoException("解密订单数据失败", e);
}
}

/**
* 敏感数据脱敏
*/
private UserData maskSensitiveData(UserData userData) {
UserData maskedData = new UserData();
maskedData.setUserId(userData.getUserId());
maskedData.setUsername(userData.getUsername());
maskedData.setEmail(maskEmail(userData.getEmail()));
maskedData.setPhone(maskPhone(userData.getPhone()));
maskedData.setAddress(maskAddress(userData.getAddress()));
return maskedData;
}

/**
* 邮箱脱敏
*/
private String maskEmail(String email) {
if (StringUtils.isEmpty(email)) {
return email;
}

int atIndex = email.indexOf("@");
if (atIndex <= 0) {
return email;
}

String username = email.substring(0, atIndex);
String domain = email.substring(atIndex);

if (username.length() <= 2) {
return username + domain;
}

return username.substring(0, 2) + "***" + domain;
}

/**
* 手机号脱敏
*/
private String maskPhone(String phone) {
if (StringUtils.isEmpty(phone) || phone.length() < 7) {
return phone;
}

return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4);
}

/**
* 地址脱敏
*/
private String maskAddress(String address) {
if (StringUtils.isEmpty(address) || address.length() < 6) {
return address;
}

return address.substring(0, 3) + "***" + address.substring(address.length() - 3);
}
}

六、性能优化与监控

6.1 性能优化

6.1.1 加解密性能优化

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
/**
* 加解密性能优化服务
*/
@Service
public class CryptoPerformanceOptimizationService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Autowired
private CaffeineCache localCache;

private final String CRYPTO_CACHE_PREFIX = "crypto_cache:";

/**
* 缓存加密结果
*/
public String encryptWithCache(String plainText, String keyId, String encryptType) {
String cacheKey = CRYPTO_CACHE_PREFIX + "encrypt:" + encryptType + ":" + keyId + ":" + DigestUtil.md5Hex(plainText);

// 1. 尝试从本地缓存获取
String cachedResult = (String) localCache.getIfPresent(cacheKey);
if (cachedResult != null) {
return cachedResult;
}

// 2. 从Redis获取
String redisCacheKey = "redis_cache:" + cacheKey;
String redisResult = (String) redisTemplate.opsForValue().get(redisCacheKey);
if (redisResult != null) {
localCache.put(cacheKey, redisResult);
return redisResult;
}

// 3. 执行加密
String encryptedResult = performEncryption(plainText, keyId, encryptType);

// 4. 写入缓存
localCache.put(cacheKey, encryptedResult);
redisTemplate.opsForValue().set(redisCacheKey, encryptedResult, Duration.ofMinutes(10));

return encryptedResult;
}

/**
* 批量加密优化
*/
public Map<String, String> batchEncryptOptimized(Map<String, String> plainTexts, String keyId, String encryptType) {
Map<String, String> encryptedTexts = new HashMap<>();

// 使用并行流处理
plainTexts.entrySet().parallelStream().forEach(entry -> {
try {
String encrypted = encryptWithCache(entry.getValue(), keyId, encryptType);
encryptedTexts.put(entry.getKey(), encrypted);
} catch (Exception e) {
log.error("批量加密失败: {}", entry.getKey(), e);
encryptedTexts.put(entry.getKey(), null);
}
});

return encryptedTexts;
}

/**
* 预热加密缓存
*/
@PostConstruct
public void warmupEncryptionCache() {
// 预热常用数据的加密结果
List<String> commonData = getCommonData();
String defaultKeyId = "default";

for (String data : commonData) {
try {
encryptWithCache(data, defaultKeyId, "AES");
} catch (Exception e) {
log.error("预热加密缓存失败", e);
}
}
}

/**
* 清理过期缓存
*/
@Scheduled(fixedRate = 300000) // 5分钟
public void cleanupExpiredCache() {
// 清理本地缓存
localCache.cleanUp();

// 清理Redis过期缓存
cleanupRedisExpiredCache();
}

/**
* 执行加密
*/
private String performEncryption(String plainText, String keyId, String encryptType) {
// 根据加密类型执行相应的加密
switch (encryptType) {
case "AES":
return aesCryptoService.encrypt(plainText, keyId);
case "RSA":
return rsaCryptoService.encryptWithPublicKey(plainText, keyId);
case "SM4":
return sm4CryptoService.encrypt(plainText, keyId);
default:
return aesCryptoService.encrypt(plainText, keyId);
}
}

/**
* 获取常用数据
*/
private List<String> getCommonData() {
return Arrays.asList(
"{\"code\":200,\"message\":\"success\"}",
"{\"code\":400,\"message\":\"bad request\"}",
"{\"code\":500,\"message\":\"internal server error\"}"
);
}

/**
* 清理Redis过期缓存
*/
private void cleanupRedisExpiredCache() {
try {
Set<String> cacheKeys = redisTemplate.keys("redis_cache:" + CRYPTO_CACHE_PREFIX + "*");

for (String key : cacheKeys) {
Long ttl = redisTemplate.getExpire(key);
if (ttl != null && ttl <= 0) {
redisTemplate.delete(key);
}
}
} catch (Exception e) {
log.error("清理Redis过期缓存失败", e);
}
}
}

6.2 监控告警

6.2.1 监控指标

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
/**
* 加解密监控指标
*/
@Component
public class CryptoMetrics {

private final MeterRegistry meterRegistry;

public CryptoMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}

/**
* 记录加密操作
*/
public void recordEncryption(String encryptType) {
Counter.builder("crypto.encryption.count")
.description("加密操作次数")
.tag("type", encryptType)
.register(meterRegistry)
.increment();
}

/**
* 记录解密操作
*/
public void recordDecryption(String encryptType) {
Counter.builder("crypto.decryption.count")
.description("解密操作次数")
.tag("type", encryptType)
.register(meterRegistry)
.increment();
}

/**
* 记录加密失败
*/
public void recordEncryptionFailure(String encryptType) {
Counter.builder("crypto.encryption.failure.count")
.description("加密失败次数")
.tag("type", encryptType)
.register(meterRegistry)
.increment();
}

/**
* 记录解密失败
*/
public void recordDecryptionFailure(String encryptType) {
Counter.builder("crypto.decryption.failure.count")
.description("解密失败次数")
.tag("type", encryptType)
.register(meterRegistry)
.increment();
}

/**
* 记录加密响应时间
*/
public void recordEncryptionResponseTime(String encryptType, long duration) {
Timer.builder("crypto.encryption.response.time")
.description("加密响应时间")
.tag("type", encryptType)
.register(meterRegistry)
.record(duration, TimeUnit.MILLISECONDS);
}

/**
* 记录解密响应时间
*/
public void recordDecryptionResponseTime(String encryptType, long duration) {
Timer.builder("crypto.decryption.response.time")
.description("解密响应时间")
.tag("type", encryptType)
.register(meterRegistry)
.record(duration, TimeUnit.MILLISECONDS);
}

/**
* 记录密钥使用次数
*/
public void recordKeyUsage(String keyId, String keyType) {
Counter.builder("crypto.key.usage.count")
.description("密钥使用次数")
.tag("key_id", keyId)
.tag("key_type", keyType)
.register(meterRegistry)
.increment();
}
}

6.2.2 告警规则

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
# prometheus-rules.yml
groups:
- name: crypto_alerts
rules:
- alert: HighCryptoFailureRate
expr: rate(crypto_encryption_failure_count[5m]) / rate(crypto_encryption_count[5m] + crypto_encryption_failure_count[5m]) > 0.1
for: 2m
labels:
severity: warning
annotations:
summary: "加密失败率过高"
description: "加密失败率超过10%,当前值: {{ $value }}"

- alert: HighDecryptionFailureRate
expr: rate(crypto_decryption_failure_count[5m]) / rate(crypto_decryption_count[5m] + crypto_decryption_failure_count[5m]) > 0.1
for: 2m
labels:
severity: warning
annotations:
summary: "解密失败率过高"
description: "解密失败率超过10%,当前值: {{ $value }}"

- alert: HighCryptoResponseTime
expr: crypto_encryption_response_time{quantile="0.95"} > 1000
for: 2m
labels:
severity: warning
annotations:
summary: "加密响应时间过长"
description: "加密响应时间P95超过1秒,当前值: {{ $value }}ms"

- alert: HighDecryptionResponseTime
expr: crypto_decryption_response_time{quantile="0.95"} > 1000
for: 2m
labels:
severity: warning
annotations:
summary: "解密响应时间过长"
description: "解密响应时间P95超过1秒,当前值: {{ $value }}ms"

七、总结

接口加解密作为现代互联网应用中的重要安全机制,通过合理的加密算法和密钥管理,能够有效保护接口传输数据的安全性。本文从接口加密设计到解密算法,从基础实现到企业级方案,系统梳理了基于接口加解密的完整解决方案。

7.1 关键要点

  1. 算法选择:AES、RSA、SM4等加密算法各有特点,需要根据场景选择合适的算法
  2. 密钥管理:密钥的生成、分发、轮换、销毁是加解密系统的核心
  3. 性能优化:通过缓存、批量处理等手段提高加解密性能
  4. 安全控制:签名验证、时间戳验证、访问控制等安全机制
  5. 监控告警:建立完善的监控体系,及时发现和处理问题

7.2 最佳实践

  1. 算法选择:根据数据敏感性和性能要求选择合适的加密算法
  2. 密钥管理:建立完善的密钥生命周期管理体系
  3. 性能优化:使用缓存和批量处理提高加解密性能
  4. 安全控制:实施多重安全验证机制
  5. 监控告警:建立完善的监控体系,确保系统稳定运行

通过以上措施,可以构建一个安全、高效、可扩展的接口加解密系统,为企业的各种业务场景提供数据安全保障。