Spring 前后端通信加密解密

一、为什么需要通信加密?数字化时代,信息传输安全是一件非常重要的事。HTTPS 证书的每年费用也是一笔不小的费用。如果 WEB 应用的数据传输的时候自带数据加密的话,也能适当提高 HTTP 下的数据传输安全。如何构建安全的通信加密体系成为每个开发者必须掌握的技能。本文将深入探讨 SpringBoot 前后端通信加密的完整方案。

二、加密方案技术对比

加密类型 算法示例 适用场景 性能影响
对称加密 AES、DES 大数据量加密
非对称加密 RSA、ECC 密钥交换、数字签名
哈希算法 SHA-256、MD5 数据完整性验证 极低
混合加密 RSA+AES 综合安全方案 中等

pom.xml 依赖配置

bash 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>最新</version>
    </dependency>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.70</version>
    </dependency>
</dependencies>

核心加密工具类

java 复制代码
@Slf4j
@Component
public class CryptoUtils {

    private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
    private static final int AES_KEY_SIZE = 256;
    private static final int RSA_KEY_SIZE = 2048;

    /**
     * AES加密
     */
    public String aesEncrypt(String data, String key, String iv) throws Exception {
        try {
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));

            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);

            byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            log.error("AES加密失败", e);
            throw new CryptoException("加密失败");
        }
    }

    /**
     * AES解密
     */
    public String aesDecrypt(String encryptedData, String key, String iv) throws Exception {
        try {
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));

            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);

            byte[] decodedBytes = Base64.getDecoder().decode(encryptedData);
            byte[] decryptedBytes = cipher.doFinal(decodedBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("AES解密失败", e);
            throw new CryptoException("解密失败");
        }
    }

    /**
     * RSA公钥加密
     */
    public String rsaEncrypt(String data, String publicKey) throws Exception {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(publicKey);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey pubKey = keyFactory.generatePublic(keySpec);

            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);

            byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            log.error("RSA加密失败", e);
            throw new CryptoException("RSA加密失败");
        }
    }

    /**
     * RSA私钥解密
     */
    public String rsaDecrypt(String encryptedData, String privateKey) throws Exception {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(privateKey);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey priKey = keyFactory.generatePrivate(keySpec);

            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, priKey);

            byte[] decodedBytes = Base64.getDecoder().decode(encryptedData);
            byte[] decryptedBytes = cipher.doFinal(decodedBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("RSA解密失败", e);
            throw new CryptoException("RSA解密失败");
        }
    }

    /**
     * 生成AES密钥和IV
     */
    public Map<String, String> generateAesKey() {
        try {
            KeyGenerator keyGen = KeyGenerator.getInstance("AES");
            keyGen.init(AES_KEY_SIZE);
            SecretKey secretKey = keyGen.generateKey();

            SecureRandom secureRandom = new SecureRandom();
            byte[] iv = new byte[16];
            secureRandom.nextBytes(iv);

            Map<String, String> result = new HashMap<>();
            result.put("key", Base64.getEncoder().encodeToString(secretKey.getEncoded()));
            result.put("iv", Base64.getEncoder().encodeToString(iv));

            return result;
        } catch (Exception e) {
            log.error("生成AES密钥失败", e);
            throw new CryptoException("生成密钥失败");
        }
    }

    /**
     * 自定义加密异常
     */
    public static class CryptoException extends RuntimeException {
        public CryptoException(String message) {
            super(message);
        }
    }
}

密钥管理服务实现

java 复制代码
@Service
@Slf4j
public class KeyManagerService {

    @Autowired
    private CryptoUtils cryptoUtils;

    private final Map<String, KeyPair> keyPairCache = new ConcurrentHashMap<>();
    private final Map<String, String> sessionKeys = new ConcurrentHashMap<>();

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

    /**
     * 获取客户端RSA公钥
     */
    public String getClientPublicKey(String clientId) {
        KeyPair keyPair = keyPairCache.computeIfAbsent(clientId, k -> generateRsaKeyPair());
        return Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
    }

    /**
     * 获取服务端RSA私钥(用于解密客户端发送的AES密钥)
     */
    public PrivateKey getServerPrivateKey(String clientId) {
        KeyPair keyPair = keyPairCache.get(clientId);
        if (keyPair == null) {
            throw new IllegalArgumentException("未找到客户端密钥对");
        }
        return keyPair.getPrivate();
    }

    /**
     * 存储会话AES密钥
     */
    public void storeSessionKey(String sessionId, String aesKey, String aesIv) {
        String combinedKey = aesKey + ":" + aesIv;
        sessionKeys.put(sessionId, combinedKey);
    }

    /**
     * 获取会话AES密钥
     */
    public Map<String, String> getSessionKey(String sessionId) {
        String combinedKey = sessionKeys.get(sessionId);
        if (combinedKey == null) {
            throw new IllegalArgumentException("会话密钥不存在或已过期");
        }

        String[] parts = combinedKey.split(":");
        Map<String, String> result = new HashMap<>();
        result.put("key", parts[0]);
        result.put("iv", parts[1]);

        return result;
    }

    /**
     * 清理过期会话密钥
     */
    @Scheduled(fixedRate = 300000) // 每5分钟清理一次
    public void cleanExpiredKeys() {
        long currentTime = System.currentTimeMillis();
        // 实现密钥过期清理逻辑
        log.info("执行密钥清理任务");
    }
}

加密请求体封装

java 复制代码
@Data
public class EncryptedRequest {
    /**
     * 加密的AES密钥(使用RSA公钥加密)
     */
    private String encryptedKey;

    /**
     * 加密的业务数据(使用AES加密)
     */
    private String encryptedData;

    /**
     * 会话ID
     */
    private String sessionId;

    /**
     * 时间戳(防重放攻击)
     */
    private Long timestamp;

    /**
     * 签名(数据完整性验证)
     */
    private String signature;
}

@Data
public class EncryptedResponse {
    /**
     * 加密的响应数据
     */
    private String encryptedData;

    /**
     * 响应状态码
     */
    private String code;

    /**
     * 响应消息
     */
    private String message;

    /**
     * 时间戳
     */
    private Long timestamp;
}

加解密切面实现

java 复制代码
@Aspect
@Component
@Slf4j
public class CryptoAspect {

    @Autowired
    private CryptoUtils cryptoUtils;

    @Autowired
    private KeyManagerService keyManagerService;

    /**
     * 请求解密切面
     */
    @Around("@annotation(DecryptRequest)")
    public Object decryptRequest(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();

        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof EncryptedRequest) {
                args[i] = decryptRequestBody((EncryptedRequest) args[i]);
            }
        }

        return joinPoint.proceed(args);
    }

    /**
     * 响应加密切面
     */
    @Around("@annotation(EncryptResponse)")
    public Object encryptResponse(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed();

        if (result instanceof ResponseEntity) {
            ResponseEntity<?> responseEntity = (ResponseEntity<?>) result;
            if (responseEntity.getBody() instanceof EncryptedResponse) {
                return result; // 已经是加密响应,无需再次处理
            }

            // 加密响应体
            Object body = responseEntity.getBody();
            HttpServletRequest request = ((ServletRequestAttributes) 
                RequestContextHolder.currentRequestAttributes()).getRequest();

            String sessionId = request.getHeader("X-Session-Id");
            EncryptedResponse encryptedResponse = encryptResponseBody(body, sessionId);

            return new ResponseEntity<>(encryptedResponse, responseEntity.getHeaders(), 
                                      responseEntity.getStatusCode());
        }

        return result;
    }

    /**
     * 解密请求体
     */
    private EncryptedRequest decryptRequestBody(EncryptedRequest encryptedRequest) {
        try {
            // 验证时间戳(防重放攻击)
            validateTimestamp(encryptedRequest.getTimestamp());

            // 获取会话密钥
            Map<String, String> sessionKey = keyManagerService
                .getSessionKey(encryptedRequest.getSessionId());

            // 解密AES密钥(使用RSA私钥)
            String encryptedKey = encryptedRequest.getEncryptedKey();
            String privateKeyStr = Base64.getEncoder().encodeToString(
                keyManagerService.getServerPrivateKey(encryptedRequest.getSessionId())
                    .getEncoded());

            String decryptedAesKey = cryptoUtils.rsaDecrypt(encryptedKey, privateKeyStr);

            // 解密业务数据
            String decryptedData = cryptoUtils.aesDecrypt(
                encryptedRequest.getEncryptedData(),
                decryptedAesKey,
                sessionKey.get("iv")
            );

            // 验证签名
            validateSignature(decryptedData, encryptedRequest.getSignature(), 
                            decryptedAesKey);

            // 将解密后的数据设置回请求对象
            encryptedRequest.setEncryptedData(decryptedData);

            return encryptedRequest;

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

    /**
     * 加密响应体
     */
    private EncryptedResponse encryptResponseBody(Object body, String sessionId) {
        try {
            String jsonData = objectToJson(body);

            Map<String, String> sessionKey = keyManagerService.getSessionKey(sessionId);

            String encryptedData = cryptoUtils.aesEncrypt(
                jsonData,
                sessionKey.get("key"),
                sessionKey.get("iv")
            );

            EncryptedResponse response = new EncryptedResponse();
            response.setEncryptedData(encryptedData);
            response.setCode("200");
            response.setMessage("成功");
            response.setTimestamp(System.currentTimeMillis());

            return response;

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

    /**
     * 验证时间戳(防重放攻击)
     */
    private void validateTimestamp(Long timestamp) {
        long currentTime = System.currentTimeMillis();
        long timeDiff = Math.abs(currentTime - timestamp);

        // 允许5分钟的时间偏差
        if (timeDiff > 5 * 60 * 1000) {
            throw new CryptoUtils.CryptoException("请求已过期");
        }
    }

    /**
     * 验证签名
     */
    private void validateSignature(String data, String signature, String key) {
        try {
            // 使用HMAC-SHA256验证签名
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
            sha256_HMAC.init(secret_key);

            String computedSignature = Base64.getEncoder().encodeToString(
                sha256_HMAC.doFinal(data.getBytes()));

            if (!computedSignature.equals(signature)) {
                throw new CryptoUtils.CryptoException("签名验证失败");
            }
        } catch (Exception e) {
            throw new CryptoUtils.CryptoException("签名验证异常");
        }
    }

    private String objectToJson(Object obj) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(obj);
    }
}

/**
 * 自定义注解:解密请求
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DecryptRequest {
}

/**
 * 自定义注解:加密响应
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptResponse {
}

加密API控制器

java 复制代码
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/api/secure")
public class SecureApiController {
    private final KeyManagerService keyManagerService;
    private final CryptoUtils cryptoUtils;

    /**
     * 获取RSA公钥(用于前端加密AES密钥)
     */
    @GetMapping("/public-key")
    public ResponseEntity<Map<String, String>> getPublicKey(
            @RequestParam String clientId) {

        String publicKey = keyManagerService.getClientPublicKey(clientId);

        // 生成AES密钥对
        Map<String, String> aesKeys = cryptoUtils.generateAesKey();

        // 存储会话密钥
        String sessionId = generateSessionId();
        keyManagerService.storeSessionKey(sessionId, 
            aesKeys.get("key"), aesKeys.get("iv"));

        Map<String, String> response = new HashMap<>();
        response.put("publicKey", publicKey);
        response.put("sessionId", sessionId);
        response.put("aesIv", aesKeys.get("iv"));

        return ResponseEntity.ok(response);
    }

    /**
     * 加密数据提交接口
     */
    @PostMapping("/submit")
    @DecryptRequest
    @EncryptResponse
    public ResponseEntity<UserData> submitData(
            @RequestBody EncryptedRequest encryptedRequest,
            HttpServletRequest request) {

        try {
            // 这里encryptedRequest的encryptedData字段已经被AOP解密为原始JSON字符串
            String decryptedData = encryptedRequest.getEncryptedData();

            ObjectMapper mapper = new ObjectMapper();
            UserData userData = mapper.readValue(decryptedData, UserData.class);

            // 处理业务逻辑
            log.info("接收到用户数据: {}", userData);

            // 返回处理结果(会被AOP自动加密)
            return ResponseEntity.ok(userData);

        } catch (Exception e) {
            log.error("处理加密数据失败", e);
            throw new CryptoUtils.CryptoException("数据处理失败");
        }
    }

    /**
     * 批量数据加密接口
     */
    @PostMapping("/batch")
    @DecryptRequest
    @EncryptResponse
    public ResponseEntity<BatchResult> processBatch(
            @RequestBody EncryptedRequest encryptedRequest) {

        try {
            String decryptedData = encryptedRequest.getEncryptedData();
            ObjectMapper mapper = new ObjectMapper();
            BatchRequest batchRequest = mapper.readValue(decryptedData, BatchRequest.class);

            // 处理批量数据
            BatchResult result = processBatchData(batchRequest);

            return ResponseEntity.ok(result);

        } catch (Exception e) {
            log.error("批量处理失败", e);
            throw new CryptoUtils.CryptoException("批量处理失败");
        }
    }

    private String generateSessionId() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    // 业务数据类
    @Data
    public static class UserData {
        private String username;
        private String email;
        private String phone;
        private Map<String, Object> additionalInfo;
    }

    @Data
    public static class BatchRequest {
        private List<UserData> items;
        private String operation;
    }

    @Data
    public static class BatchResult {
        private int successCount;
        private int failureCount;
        private List<String> errors;
    }

    private BatchResult processBatchData(BatchRequest request) {
        // 实现批量处理逻辑
        BatchResult result = new BatchResult();
        result.setSuccessCount(request.getItems().size());
        result.setFailureCount(0);
        result.setErrors(new ArrayList<>());
        return result;
    }
}

三、前端加密实现

  1. JavaScript加密工具
bash 复制代码
class CryptoClient {
    constructor() {
        this.sessionId = null;
        this.aesIv = null;
        this.publicKey = null;
    }

    /**
     * 初始化加密客户端
     */
    async initialize(clientId) {
        try {
            const response = await fetch(`/api/secure/public-key?clientId=${clientId}`);
            const data = await response.json();

            this.sessionId = data.sessionId;
            this.aesIv = data.aesIv;
            this.publicKey = data.publicKey;

            return true;
        } catch (error) {
            console.error('初始化加密客户端失败:', error);
            return false;
        }
    }

    /**
     * 生成AES密钥
     */
    generateAesKey() {
        const randomBytes = new Uint8Array(32);
        window.crypto.getRandomValues(randomBytes);
        return btoa(String.fromCharCode(...randomBytes));
    }

    /**
     * RSA加密
     */
    async rsaEncrypt(data, publicKey) {
        // 使用jsencrypt库进行RSA加密
        const encrypt = new JSEncrypt();
        encrypt.setPublicKey(publicKey);
        return encrypt.encrypt(data);
    }

    /**
     * AES加密
     */
    async aesEncrypt(data, key, iv) {
        const encoder = new TextEncoder();
        const keyData = encoder.encode(key);
        const ivData = encoder.encode(iv);
        const dataBuffer = encoder.encode(data);

        const cryptoKey = await window.crypto.subtle.importKey(
            'raw',
            keyData,
            { name: 'AES-CBC' },
            false,
            ['encrypt']
        );

        const encrypted = await window.crypto.subtle.encrypt(
            {
                name: 'AES-CBC',
                iv: ivData
            },
            cryptoKey,
            dataBuffer
        );

        return btoa(String.fromCharCode(...new Uint8Array(encrypted)));
    }

    /**
     * 生成HMAC签名
     */
    async generateSignature(data, key) {
        const encoder = new TextEncoder();
        const keyData = encoder.encode(key);
        const dataBuffer = encoder.encode(data);

        const cryptoKey = await window.crypto.subtle.importKey(
            'raw',
            keyData,
            { name: 'HMAC', hash: 'SHA-256' },
            false,
            ['sign']
        );

        const signature = await window.crypto.subtle.sign(
            'HMAC',
            cryptoKey,
            dataBuffer
        );

        return btoa(String.fromCharCode(...new Uint8Array(signature)));
    }

    /**
     * 发送加密请求
     */
    async sendEncryptedRequest(url, data) {
        if (!this.sessionId || !this.publicKey) {
            throw new Error('加密客户端未初始化');
        }

        try {
            // 生成AES密钥
            const aesKey = this.generateAesKey();

            // 加密AES密钥(使用RSA公钥)
            const encryptedKey = await this.rsaEncrypt(aesKey, this.publicKey);

            // 加密业务数据(使用AES)
            const jsonData = JSON.stringify(data);
            const encryptedData = await this.aesEncrypt(jsonData, aesKey, this.aesIv);

            // 生成签名
            const signature = await this.generateSignature(jsonData, aesKey);

            // 构建加密请求
            const encryptedRequest = {
                encryptedKey: encryptedKey,
                encryptedData: encryptedData,
                sessionId: this.sessionId,
                timestamp: Date.now(),
                signature: signature
            };

            // 发送请求
            const response = await fetch(url, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-Session-Id': this.sessionId
                },
                body: JSON.stringify(encryptedRequest)
            });

            return await response.json();

        } catch (error) {
            console.error('发送加密请求失败:', error);
            throw error;
        }
    }
}

// 使用示例
const cryptoClient = new CryptoClient();

// 初始化
cryptoClient.initialize('web-client').then(success => {
    if (success) {
        console.log('加密客户端初始化成功');
    }
});

// 发送加密数据
async function submitUserData(userData) {
    try {
        const response = await cryptoClient.sendEncryptedRequest(
            '/api/secure/submit',
            userData
        );

        console.log('加密响应:', response);
        // 这里response.encryptedData需要在前端解密
        return response;
    } catch (error) {
        console.error('提交数据失败:', error);
    }
}

防重放攻击机制

bash 复制代码
@Component
public class ReplayAttackDefender {

    private final Set<String> usedNonces = Collections.synchronizedSet(new HashSet<>());
    private final long maxTimeWindow = 5 * 60 * 1000; // 5分钟

    /**
     * 验证请求唯一性
     */
    public boolean validateRequest(String nonce, long timestamp) {
        // 检查时间窗口
        long currentTime = System.currentTimeMillis();
        if (Math.abs(currentTime - timestamp) > maxTimeWindow) {
            return false;
        }

        // 检查nonce唯一性
        if (usedNonces.contains(nonce)) {
            return false;
        }

        // 添加nonce到已使用集合
        usedNonces.add(nonce);

        // 清理过期nonce
        cleanExpiredNonces();

        return true;
    }

    /**
     * 清理过期nonce
     */
    @Scheduled(fixedRate = 60000) // 每分钟清理一次
    public void cleanExpiredNonces() {
        // 实现清理逻辑
    }
}

性能优化配置

bash 复制代码
@Configuration
@EnableAsync
public class CryptoConfig {

    @Bean
    public ThreadPoolTaskExecutor cryptoExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(50);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("crypto-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    @Bean
    public CacheManager keyCacheManager() {
        return new ConcurrentMapCacheManager("rsaKeys", "sessionKeys");
    }
}

测试方法

bash 复制代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.*;

@SpringBootApplication
@Slf4j
public class CryptoServiceTest {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(CryptoServiceTest.class, args);
        
        try {
            testAesEncryption(context);
            testFullWorkflow(context);
            log.info("所有测试通过!");
        } catch (Exception e) {
            log.error("测试失败", e);
        } finally {
            context.close();
        }
    }

    static void testAesEncryption(ConfigurableApplicationContext context) throws Exception {
        CryptoUtils cryptoUtils = context.getBean(CryptoUtils.class);
        
        String originalText = "这是一段需要加密的敏感数据";
        Map<String, String> keys = cryptoUtils.generateAesKey();

        String encrypted = cryptoUtils.aesEncrypt(originalText, 
            keys.get("key"), keys.get("iv"));
        String decrypted = cryptoUtils.aesDecrypt(encrypted, 
            keys.get("key"), keys.get("iv"));

        if (!originalText.equals(decrypted)) {
            throw new RuntimeException("AES加密测试失败");
        }
        log.info("AES加密测试通过");
    }

    static void testFullWorkflow(ConfigurableApplicationContext context) throws Exception {
        CryptoUtils cryptoUtils = context.getBean(CryptoUtils.class);
        KeyManagerService keyManagerService = context.getBean(KeyManagerService.class);

        // 模拟完整加密流程
        String clientId = "test-client";
        String originalData = "{\"username\":\"test\",\"password\":\"123456\"}";

        // 获取公钥
        String publicKey = keyManagerService.getClientPublicKey(clientId);

        // 生成AES密钥
        Map<String, String> aesKeys = cryptoUtils.generateAesKey();
        String sessionId = UUID.randomUUID().toString();
        keyManagerService.storeSessionKey(sessionId, 
            aesKeys.get("key"), aesKeys.get("iv"));

        // 加密AES密钥
        String encryptedKey = cryptoUtils.rsaEncrypt(aesKeys.get("key"), publicKey);

        // 加密数据
        String encryptedData = cryptoUtils.aesEncrypt(originalData, 
            aesKeys.get("key"), aesKeys.get("iv"));

        // 解密流程
        String decryptedKey = cryptoUtils.rsaDecrypt(encryptedKey, 
            Base64.getEncoder().encodeToString(
                keyManagerService.getServerPrivateKey(sessionId).getEncoded()));

        String decryptedData = cryptoUtils.aesDecrypt(encryptedData, 
            decryptedKey, aesKeys.get("iv"));

        if (!originalData.equals(decryptedData)) {
            throw new RuntimeException("完整加密流程测试失败");
        }
        log.info("完整加密流程测试通过");
    }
}

一、方案优势

安全性高:采用RSA+AES混合加密,兼顾安全性和性能

易于集成:通过注解和AOP实现,业务代码无侵入

扩展性强:模块化设计,便于扩展新的加密算法

生产就绪:包含防重放攻击、密钥管理等企业级特性

二、性能考虑

使用缓存减少密钥生成开销

异步处理加解密操作

合理的连接池和线程池配置

三、未来扩展

国密算法支持:集成SM2、SM4等国密算法

硬件安全模块:支持HSM等硬件加密设备

量子安全:提前布局抗量子加密算法

零信任架构:集成零信任安全理念

相关推荐
武子康3 小时前
Java-144 深入浅出 MongoDB BSON详解:MongoDB核心存储格式与JSON的区别与应用场景
java·开发语言·数据库·mongodb·性能优化·json·bjson
聪明的笨猪猪3 小时前
Java Spring “事务” 面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
徐小夕3 小时前
花了4个月时间,我写了一款支持AI的协同Word文档编辑器
前端·vue.js·后端
云飞云共享云桌面3 小时前
东莞精密机械制造工厂如何10个SolidWorks共用一台服务器资源
java·运维·服务器·网络·数据库·电脑·制造
毕设源码-赖学姐4 小时前
【开题答辩全过程】以 网络药店管理系统为例,包含答辩的问题和答案
java·eclipse
努力也学不会java4 小时前
【Java并发】揭秘Lock体系 -- 深入理解ReentrantReadWriteLock
java·开发语言·python·机器学习
埃泽漫笔4 小时前
消息队列延迟与过期问题的实战解决
java·mq
花花无缺4 小时前
资源泄露问题
java·后端·http
爱敲代码的TOM4 小时前
深入剖析Java通信架构下的三种IO模式2
java·开发语言·架构