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等硬件加密设备

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

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

相关推荐
松仔log1 小时前
JetPack——Paging3+Room
android·java·zoom
㳺三才人子6 小时前
初探 Flask
后端·python·flask·html
星栈独行6 小时前
我在 Rust 全栈项目里用 JWT 做无状态认证
开发语言·后端·rust·前端框架·开源·github·web
Lei活在当下6 小时前
先用起来,再理解,关于协程Coroutine应该知道的事
android·java·jvm
Java爱好狂.6 小时前
Java程序员体系化学习路线(2026最新版)
java·后端·java面试·java架构师·java程序员·java八股文·java学习路线
陈随易7 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
tongluowan0077 小时前
以ReentrantLock为例解释AQS的工作流程
java·模板方法模式·aqs·reentrantlock
装不满的克莱因瓶7 小时前
SpringBoot 如何将 lib 目录中jar包打包进最终的jar包里面
spring boot·后端·maven·jar·mvn
ltl8 小时前
Transformer 原论文实验结果:为什么 28.4 BLEU 足以改写路线图
后端
身如柳絮随风扬8 小时前
Java 项目打包与部署完全指南:JAR vs WAR,从构建到运行
java·firefox·jar