Java案例怎么实现对称加密?

wen java案例 75

本文目录导读:

Java案例怎么实现对称加密?

  1. AES加密实现(推荐使用)
  2. 3DES加密(遗留系统兼容)
  3. 使用工具类封装
  4. 最佳实践建议
  5. 注意事项

在Java中实现对称加密通常使用javax.crypto包下的类,以下是几种常见对称加密算法的实现方法。

AES加密实现(推荐使用)

AES是目前最常用的对称加密算法,安全性高、性能好。

基础AES加密

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
public class AESEncryption {
    // AES加密,使用ECB模式(不推荐生产使用)
    public static String encryptECB(String plainText, String secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "AES");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }
    // AES解密,使用ECB模式
    public static String decryptECB(String encryptedText, String secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
        return new String(decrypted, StandardCharsets.UTF_8);
    }
    // 推荐:AES加密,使用CBC模式(更安全)
    public static String encryptCBC(String plainText, String secretKey, String iv) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }
    // 推荐:AES解密,使用CBC模式
    public static String decryptCBC(String encryptedText, String secretKey, String iv) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
        return new String(decrypted, StandardCharsets.UTF_8);
    }
    public static void main(String[] args) {
        try {
            // 使用固定密钥(16字节即128位)
            String key = "1234567890123456";  // 必须是16、24或32位
            String iv = "1234567890123456";   // IV必须16位
            String originalText = "Hello, World! 这是敏感数据";
            // ECB模式(简单但不安全,不适合块数据)
            String encryptedECB = encryptECB(originalText, key);
            String decryptedECB = decryptECB(encryptedECB, key);
            System.out.println("ECB模式:");
            System.out.println("原文: " + originalText);
            System.out.println("密文: " + encryptedECB);
            System.out.println("解密: " + decryptedECB);
            // CBC模式(推荐)
            String encryptedCBC = encryptCBC(originalText, key, iv);
            String decryptedCBC = decryptCBC(encryptedCBC, key, iv);
            System.out.println("\nCBC模式:");
            System.out.println("原文: " + originalText);
            System.out.println("密文: " + encryptedCBC);
            System.out.println("解密: " + decryptedCBC);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

自动生成密钥和IV(推荐生产使用)

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
public class AESGCMEncryption {
    private static final int AES_KEY_SIZE = 256;  // 密钥位数
    private static final int GCM_NONCE_LENGTH = 12;  // IV长度(推荐12字节)
    private static final int GCM_TAG_LENGTH = 128;   // 认证标签长度
    // 生成随机密钥
    public static SecretKey generateKey() throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(AES_KEY_SIZE);
        return keyGen.generateKey();
    }
    // AES-GCM加密(最安全的方式)
    public static String encrypt(String plainText, SecretKey key) throws Exception {
        byte[] nonce = new byte[GCM_NONCE_LENGTH];
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(nonce);
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, nonce);
        cipher.init(Cipher.ENCRYPT_MODE, key, spec);
        byte[] cipherText = cipher.doFinal(plainText.getBytes());
        // 将nonce和密文拼接
        byte[] combined = new byte[nonce.length + cipherText.length];
        System.arraycopy(nonce, 0, combined, 0, nonce.length);
        System.arraycopy(cipherText, 0, combined, nonce.length, cipherText.length);
        return Base64.getEncoder().encodeToString(combined);
    }
    // AES-GCM解密
    public static String decrypt(String encryptedData, SecretKey key) throws Exception {
        byte[] combined = Base64.getDecoder().decode(encryptedData);
        byte[] nonce = new byte[GCM_NONCE_LENGTH];
        System.arraycopy(combined, 0, nonce, 0, nonce.length);
        byte[] cipherText = new byte[combined.length - nonce.length];
        System.arraycopy(combined, nonce.length, cipherText, 0, cipherText.length);
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, nonce);
        cipher.init(Cipher.DECRYPT_MODE, key, spec);
        byte[] plainText = cipher.doFinal(cipherText);
        return new String(plainText);
    }
    public static void main(String[] args) {
        try {
            // 生成密钥
            SecretKey key = generateKey();
            String keyStr = Base64.getEncoder().encodeToString(key.getEncoded());
            System.out.println("密钥(Base64): " + keyStr);
            String originalText = "Hello, World! 这是使用AES-GCM加密的敏感数据";
            // 加密
            String encrypted = encrypt(originalText, key);
            System.out.println("原文: " + originalText);
            System.out.println("密文: " + encrypted);
            // 解密
            String decrypted = decrypt(encrypted, key);
            System.out.println("解密: " + decrypted);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3DES加密(遗留系统兼容)

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.util.Base64;
public class TripleDESEncryption {
    public static String encrypt(String plainText, String secretKey) throws Exception {
        byte[] keyBytes = secretKey.getBytes();
        DESedeKeySpec spec = new DESedeKeySpec(keyBytes);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
        javax.crypto.SecretKey key = keyFactory.generateSecret(spec);
        Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        IvParameterSpec ivSpec = new IvParameterSpec(new byte[8]); // 8字节IV
        cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
        byte[] encrypted = cipher.doFinal(plainText.getBytes());
        return Base64.getEncoder().encodeToString(encrypted);
    }
    public static String decrypt(String encryptedText, String secretKey) throws Exception {
        byte[] keyBytes = secretKey.getBytes();
        DESedeKeySpec spec = new DESedeKeySpec(keyBytes);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
        javax.crypto.SecretKey key = keyFactory.generateSecret(spec);
        Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        IvParameterSpec ivSpec = new IvParameterSpec(new byte[8]);
        cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
        return new String(decrypted);
    }
}

使用工具类封装

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
public class CryptoUtils {
    // 从密码生成固定长度的密钥
    public static SecretKeySpec generateKey(String password) throws Exception {
        MessageDigest sha = MessageDigest.getInstance("SHA-256");
        byte[] key = sha.digest(password.getBytes(StandardCharsets.UTF_8));
        return new SecretKeySpec(key, "AES");
    }
    // 简单的AES加密封装
    public static String encrypt(String plainText, String password) {
        try {
            SecretKeySpec keySpec = generateKey(password);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);
            byte[] encrypted = cipher.doFinal(plainText.getBytes());
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            throw new RuntimeException("加密失败", e);
        }
    }
    // 简单的AES解密封装
    public static String decrypt(String encryptedText, String password) {
        try {
            SecretKeySpec keySpec = generateKey(password);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
            byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
            return new String(decrypted);
        } catch (Exception e) {
            throw new RuntimeException("解密失败", e);
        }
    }
    public static void main(String[] args) {
        String password = "mySecretPassword123!";
        String data = "Hello, World!";
        String encrypted = encrypt(data, password);
        String decrypted = decrypt(encrypted, password);
        System.out.println("原文: " + data);
        System.out.println("密文: " + encrypted);
        System.out.println("解密: " + decrypted);
    }
}

最佳实践建议

// 推荐的生产环境配置
public class EncryptionConfig {
    // 常量配置
    public static final String ALGORITHM = "AES/GCM/NoPadding";  // 使用GCM模式
    public static final int KEY_SIZE = 256;                      // 256位密钥
    public static final int IV_SIZE = 12;                        // 12字节IV
    public static final int TAG_SIZE = 128;                      // 128位认证标签
    // 密钥管理(生产环境应使用密钥管理服务)
    // 1. 不要硬编码密钥
    // 2. 使用密钥存储服务(KMS)
    // 3. 定期轮换密钥
    // 4. 密钥要有过期时间
}

注意事项

  1. 密钥管理

    • 不要硬编码密钥在代码中
    • 使用密钥管理服务(如AWS KMS、Azure Key Vault)
    • 密钥定期轮换
  2. 模式选择

    • ECB模式:不适合加密块数据,相同明文生成相同密文
    • CBC模式:需要IV,每个块依赖于前一个块
    • GCM模式:推荐,提供认证和加密
  3. IV管理

    • IV必须是随机且唯一的
    • IV不需要加密,但最好与密文一起存储
    • 同一个密钥下,IV不能重复使用
  4. 编码处理

    • 密文通常使用Base64编码传输
    • 注意字符编码统一使用UTF-8
  5. 异常处理

    • 密码学操作应使用try-catch处理异常
    • 解密失败时不要泄露具体原因(防止padding oracle攻击)

推荐使用AES-GCM模式进行生产环境的对称加密,它提供了加密和认证双重保障。

抱歉,评论功能暂时关闭!