加密与签名技术之对称加密算法

123 阅读14分钟

概述

对称加密算法使用相同的密钥进行加密和解密操作。这类算法速度快、效率高,适合加密大量数据。

目录

  1. AES (Advanced Encryption Standard)
  2. DES (Data Encryption Standard)
  3. 3DES (Triple DES)
  4. Blowfish
  5. Twofish
  6. ChaCha20
  7. SM4 (国密算法)
  8. 加密模式
  9. 性能对比

AES (Advanced Encryption Standard)

原理

AES是一种分组密码算法,使用128位固定块大小,密钥长度可以是128、192或256位。它基于Substitution-Permutation Network (SPN)结构。

核心操作:

  • SubBytes: 使用S-box进行字节替换
  • ShiftRows: 行移位操作
  • MixColumns: 列混合操作(最后一轮除外)
  • AddRoundKey: 与轮密钥异或

技术规格

属性
块大小128位 (16字节)
密钥长度128/192/256位
轮数10/12/14轮 (对应密钥长度)
安全级别非常高
状态NIST标准,广泛使用

应用场景

  1. 数据存储加密:文件系统、数据库字段加密
  2. 网络传输:TLS/SSL协议中的对称加密部分
  3. 磁盘加密:BitLocker、FileVault等
  4. 无线通信:WPA2/WPA3
  5. VPN:IPSec、OpenVPN

性能影响

  • 加密/解密速度:非常快(现代CPU通常有硬件加速)
  • 内存占用:低(约128字节状态)
  • CPU使用率:低(硬件加速时几乎无影响)
  • 吞吐量:可达到GB/s级别(取决于实现和硬件)

Java实现示例

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
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 AESExample {
    
    /**
     * AES-256-GCM加密示例(推荐模式)
     * GCM提供加密和认证,防止篡改
     */
    public static String encryptGCM(String plaintext, SecretKey key) throws Exception {
        // 生成随机IV (12字节用于GCM)
        byte[] iv = new byte[12];
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);
        
        // 创建GCM参数(标签长度128位)
        GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
        
        // 初始化加密器
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, key, gcmSpec);
        
        // 执行加密
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        
        // 将IV和密文组合(IV长度12字节)
        byte[] encrypted = new byte[12 + ciphertext.length];
        System.arraycopy(iv, 0, encrypted, 0, 12);
        System.arraycopy(ciphertext, 0, encrypted, 12, ciphertext.length);
        
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    /**
     * AES-256-GCM解密示例
     */
    public static String decryptGCM(String encryptedData, SecretKey key) throws Exception {
        byte[] encrypted = Base64.getDecoder().decode(encryptedData);
        
        // 提取IV和密文
        byte[] iv = new byte[12];
        System.arraycopy(encrypted, 0, iv, 0, 12);
        byte[] ciphertext = new byte[encrypted.length - 12];
        System.arraycopy(encrypted, 12, ciphertext, 0, ciphertext.length);
        
        // 创建GCM参数
        GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
        
        // 初始化解密器
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, key, gcmSpec);
        
        // 执行解密
        byte[] plaintext = cipher.doFinal(ciphertext);
        return new String(plaintext, StandardCharsets.UTF_8);
    }
    
    /**
     * AES-CBC加密示例(兼容模式)
     */
    public static String encryptCBC(String plaintext, SecretKey key) throws Exception {
        // 生成随机IV (16字节用于CBC)
        byte[] iv = new byte[16];
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);
        
        // 初始化加密器(使用PKCS5Padding)
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        
        // 执行加密
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        
        // 将IV和密文组合
        byte[] encrypted = new byte[16 + ciphertext.length];
        System.arraycopy(iv, 0, encrypted, 0, 16);
        System.arraycopy(ciphertext, 0, encrypted, 16, ciphertext.length);
        
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    /**
     * AES-CBC解密示例
     */
    public static String decryptCBC(String encryptedData, SecretKey key) throws Exception {
        byte[] encrypted = Base64.getDecoder().decode(encryptedData);
        
        // 提取IV和密文
        byte[] iv = new byte[16];
        System.arraycopy(encrypted, 0, iv, 0, 16);
        byte[] ciphertext = new byte[encrypted.length - 16];
        System.arraycopy(encrypted, 16, ciphertext, 0, ciphertext.length);
        
        // 初始化解密器
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        
        // 执行解密
        byte[] plaintext = cipher.doFinal(ciphertext);
        return new String(plaintext, StandardCharsets.UTF_8);
    }
    
    /**
     * 生成AES密钥
     */
    public static SecretKey generateKey(int keySize) throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(keySize); // 128, 192, 或 256
        return keyGenerator.generateKey();
    }
    
    /**
     * 从字节数组创建密钥
     */
    public static SecretKey createKeyFromBytes(byte[] keyBytes) {
        return new SecretKeySpec(keyBytes, "AES");
    }
    
    /**
     * 完整使用示例
     */
    public static void main(String[] args) throws Exception {
        // 生成256位密钥
        SecretKey key = generateKey(256);
        
        String originalText = "这是要加密的敏感数据";
        
        // 使用GCM模式(推荐)
        System.out.println("=== AES-GCM模式 ===");
        String encryptedGCM = encryptGCM(originalText, key);
        System.out.println("加密后: " + encryptedGCM);
        String decryptedGCM = decryptGCM(encryptedGCM, key);
        System.out.println("解密后: " + decryptedGCM);
        
        // 使用CBC模式
        System.out.println("\n=== AES-CBC模式 ===");
        String encryptedCBC = encryptCBC(originalText, key);
        System.out.println("加密后: " + encryptedCBC);
        String decryptedCBC = decryptCBC(encryptedCBC, key);
        System.out.println("解密后: " + decryptedCBC);
    }
}

安全建议

推荐:

  • 使用AES-256-GCM进行新项目开发
  • 使用随机IV,每次加密都不同
  • 安全存储密钥

避免:

  • 使用ECB模式(不安全)
  • 重复使用相同的IV
  • 使用弱密钥(建议使用KeyGenerator)

DES (Data Encryption Standard)

原理

DES使用56位密钥(加上8位奇偶校验位)和64位块大小,基于Feistel网络结构。现已不安全,不应在新项目中使用。

技术规格

属性
块大小64位 (8字节)
密钥长度56位 (实际64位,8位校验)
轮数16轮
安全级别已不安全 ⚠️
状态已废弃,不应使用

应用场景

已不建议使用,仅用于:

  • 学习目的
  • 兼容遗留系统(需要迁移)

性能影响

  • 加密/解密速度:中等(硬件支持但已过时)
  • 内存占用:低
  • CPU使用率:中等
  • 吞吐量:远低于AES

Java实现示例

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
​
public class DESExample {
    
    /**
     * DES加密示例(仅用于演示,不建议使用)
     */
    public static String encrypt(String plaintext, SecretKey key) throws Exception {
        byte[] iv = new byte[8]; // DES使用8字节IV
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);
        
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        
        byte[] encrypted = new byte[8 + ciphertext.length];
        System.arraycopy(iv, 0, encrypted, 0, 8);
        System.arraycopy(ciphertext, 0, encrypted, 8, ciphertext.length);
        
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    public static SecretKey generateKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
        return keyGenerator.generateKey();
    }
    
    public static void main(String[] args) throws Exception {
        System.out.println("⚠️ 警告: DES已不安全,仅用于演示");
        SecretKey key = generateKey();
        String encrypted = encrypt("测试数据", key);
        System.out.println("加密结果: " + encrypted);
    }
}

安全建议

⚠️ 强烈建议:

  • 不要在新项目中使用DES
  • 迁移到AES-256
  • 如需兼容,考虑3DES作为临时方案

3DES (Triple DES)

原理

3DES是对DES的增强,通过三次DES加密来提高安全性。使用2个或3个56位密钥。

加密模式:

  • EEE: E(K₁, E(K₂, E(K₁, P)))
  • EDE: E(K₁, D(K₂, E(K₁, P))) - 最常用

技术规格

属性
块大小64位 (8字节)
有效密钥长度112位 (2-key) 或 168位 (3-key)
安全级别中等(已逐渐淘汰)
状态遗留系统使用,新项目不推荐

应用场景

  1. 遗留系统兼容:需要与旧系统交互
  2. 金融系统迁移期:从DES迁移到AES的过渡方案
  3. 嵌入式系统:资源受限但需要中等安全性

性能影响

  • 加密/解密速度:慢(3倍DES操作)
  • 内存占用:低
  • CPU使用率:高(比AES慢3倍以上)
  • 吞吐量:远低于AES

Java实现示例

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
​
public class TripleDESExample {
    
    /**
     * 3DES加密示例
     */
    public static String encrypt(String plaintext, SecretKey key) throws Exception {
        byte[] iv = new byte[8]; // 3DES使用8字节IV
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);
        
        Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        
        byte[] encrypted = new byte[8 + ciphertext.length];
        System.arraycopy(iv, 0, encrypted, 0, 8);
        System.arraycopy(ciphertext, 0, encrypted, 8, ciphertext.length);
        
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    /**
     * 3DES解密示例
     */
    public static String decrypt(String encryptedData, SecretKey key) throws Exception {
        byte[] encrypted = Base64.getDecoder().decode(encryptedData);
        
        byte[] iv = new byte[8];
        System.arraycopy(encrypted, 0, iv, 0, 8);
        byte[] ciphertext = new byte[encrypted.length - 8];
        System.arraycopy(encrypted, 8, ciphertext, 0, ciphertext.length);
        
        Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        
        byte[] plaintext = cipher.doFinal(ciphertext);
        return new String(plaintext, StandardCharsets.UTF_8);
    }
    
    public static SecretKey generateKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
        keyGenerator.init(168); // 168位密钥(3-key 3DES)
        return keyGenerator.generateKey();
    }
    
    public static void main(String[] args) throws Exception {
        System.out.println("⚠️ 注意: 3DES性能较差,建议迁移到AES");
        SecretKey key = generateKey();
        String original = "测试数据";
        String encrypted = encrypt(original, key);
        System.out.println("加密后: " + encrypted);
        String decrypted = decrypt(encrypted, key);
        System.out.println("解密后: " + decrypted);
    }
}

安全建议

⚠️ 建议:

  • 仅在需要兼容遗留系统时使用
  • 优先考虑迁移到AES
  • 使用168位密钥(3-key模式)

Blowfish

原理

Blowfish是由Bruce Schneier设计的对称分组密码算法,使用可变长度密钥(32-448位)和64位块大小。基于Feistel网络。

技术规格

属性
块大小64位 (8字节)
密钥长度32-448位(通常128或256位)
轮数16轮
安全级别中等(块大小较小)
状态仍在使用但不如AES流行

应用场景

  1. 文件加密工具:某些加密软件
  2. 数据库加密:部分数据库系统
  3. 游戏和娱乐软件:DRM系统

性能影响

  • 加密/解密速度:快(无专利,实现简单)
  • 内存占用:中等(需要S-box)
  • CPU使用率:中等
  • 吞吐量:高于DES但低于AES

Java实现示例

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
​
public class BlowfishExample {
    
    public static String encrypt(String plaintext, SecretKey key) throws Exception {
        byte[] iv = new byte[8]; // Blowfish使用8字节IV
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);
        
        Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        
        byte[] encrypted = new byte[8 + ciphertext.length];
        System.arraycopy(iv, 0, encrypted, 0, 8);
        System.arraycopy(ciphertext, 0, encrypted, 8, ciphertext.length);
        
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    public static String decrypt(String encryptedData, SecretKey key) throws Exception {
        byte[] encrypted = Base64.getDecoder().decode(encryptedData);
        
        byte[] iv = new byte[8];
        System.arraycopy(encrypted, 0, iv, 0, 8);
        byte[] ciphertext = new byte[encrypted.length - 8];
        System.arraycopy(encrypted, 8, ciphertext, 0, ciphertext.length);
        
        Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        
        byte[] plaintext = cipher.doFinal(ciphertext);
        return new String(plaintext, StandardCharsets.UTF_8);
    }
    
    public static SecretKey generateKey(int keySize) throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
        keyGenerator.init(keySize); // 32-448位
        return keyGenerator.generateKey();
    }
    
    public static void main(String[] args) throws Exception {
        SecretKey key = generateKey(128);
        String original = "测试数据";
        String encrypted = encrypt(original, key);
        System.out.println("加密后: " + encrypted);
        String decrypted = decrypt(encrypted, key);
        System.out.println("解密后: " + decrypted);
    }
}

安全建议

⚠️ 注意:

  • 块大小较小(64位),不适合加密大文件
  • 建议使用256位密钥
  • 新项目优先考虑AES

Twofish

原理

Twofish是AES竞赛的决赛算法之一,使用128位块大小和128、192或256位密钥。虽然没有被选为AES标准,但安全性很高。

技术规格

属性
块大小128位 (16字节)
密钥长度128/192/256位
轮数16轮
安全级别高(与AES相当)
状态无专利,开源使用

应用场景

  1. TrueCrypt/VeraCrypt:磁盘加密工具
  2. PGP加密:某些版本的PGP
  3. 需要无专利算法的场景

性能影响

  • 加密/解密速度:快(软件实现,无硬件加速)
  • 内存占用:中等
  • CPU使用率:中等
  • 吞吐量:接近AES(软件实现时)

Java实现示例

// 注意:Java标准库不包含Twofish
// 需要使用BouncyCastle等第三方库import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.security.SecureRandom;
import java.util.Base64;
​
public class TwofishExample {
    
    static {
        // 添加BouncyCastle提供者
        Security.addProvider(new BouncyCastleProvider());
    }
    
    public static String encrypt(String plaintext, SecretKey key) throws Exception {
        byte[] iv = new byte[16]; // Twofish使用16字节IV
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);
        
        Cipher cipher = Cipher.getInstance("Twofish/CBC/PKCS5Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        
        byte[] encrypted = new byte[16 + ciphertext.length];
        System.arraycopy(iv, 0, encrypted, 0, 16);
        System.arraycopy(ciphertext, 0, encrypted, 16, ciphertext.length);
        
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    public static SecretKey generateKey(int keySize) throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("Twofish", "BC");
        keyGenerator.init(keySize);
        return keyGenerator.generateKey();
    }
    
    public static void main(String[] args) throws Exception {
        SecretKey key = generateKey(256);
        String original = "测试数据";
        String encrypted = encrypt(original, key);
        System.out.println("加密后: " + encrypted);
    }
}

安全建议

适合场景:

  • 需要无专利算法
  • 磁盘加密等特定应用
  • 新项目建议使用AES(更广泛支持)

ChaCha20

原理

ChaCha20是Daniel J. Bernstein设计的流密码算法,使用256位密钥和96位nonce。它是Salsa20的改进版本,适合软件实现。

技术规格

属性
密钥长度256位
Nonce长度96位 (12字节)
块大小512位 (流密码)
轮数20轮
安全级别
状态IETF标准,广泛使用

应用场景

  1. TLS/SSL:Google Chrome等浏览器的TLS实现
  2. VPN:WireGuard协议使用ChaCha20-Poly1305
  3. 移动设备:无硬件AES加速时性能更好
  4. 实时通信:低延迟要求

性能影响

  • 加密/解密速度:非常快(软件实现时)
  • 内存占用:低
  • CPU使用率:低(纯软件实现高效)
  • 吞吐量:在无硬件加速时优于AES

Java实现示例

import javax.crypto.Cipher;
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 ChaCha20Example {
    
    /**
     * ChaCha20加密(需要Java 11+)
     */
    public static String encrypt(String plaintext, SecretKeySpec key) throws Exception {
        // 生成随机nonce (12字节)
        byte[] nonce = new byte[12];
        SecureRandom random = new SecureRandom();
        random.nextBytes(nonce);
        
        // 创建ChaCha20参数(使用12字节nonce)
        IvParameterSpec ivSpec = new IvParameterSpec(nonce);
        
        // 初始化加密器
        Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305");
        cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
        
        // 执行加密(Poly1305自动提供认证)
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        
        // 将nonce和密文组合
        byte[] encrypted = new byte[12 + ciphertext.length];
        System.arraycopy(nonce, 0, encrypted, 0, 12);
        System.arraycopy(ciphertext, 0, encrypted, 12, ciphertext.length);
        
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    /**
     * ChaCha20解密
     */
    public static String decrypt(String encryptedData, SecretKeySpec key) throws Exception {
        byte[] encrypted = Base64.getDecoder().decode(encryptedData);
        
        // 提取nonce和密文
        byte[] nonce = new byte[12];
        System.arraycopy(encrypted, 0, nonce, 0, 12);
        byte[] ciphertext = new byte[encrypted.length - 12];
        System.arraycopy(encrypted, 12, ciphertext, 0, ciphertext.length);
        
        IvParameterSpec ivSpec = new IvParameterSpec(nonce);
        
        Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305");
        cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
        
        byte[] plaintext = cipher.doFinal(ciphertext);
        return new String(plaintext, StandardCharsets.UTF_8);
    }
    
    /**
     * 从字节数组创建密钥
     */
    public static SecretKeySpec createKey(byte[] keyBytes) {
        return new SecretKeySpec(keyBytes, "ChaCha20");
    }
    
    public static void main(String[] args) throws Exception {
        // 生成256位密钥
        byte[] keyBytes = new byte[32];
        SecureRandom random = new SecureRandom();
        random.nextBytes(keyBytes);
        SecretKeySpec key = createKey(keyBytes);
        
        String original = "这是要加密的数据";
        String encrypted = encrypt(original, key);
        System.out.println("加密后: " + encrypted);
        String decrypted = decrypt(encrypted, key);
        System.out.println("解密后: " + decrypted);
    }
}

安全建议

推荐:

  • 移动设备或无AES硬件加速场景
  • 需要低延迟的应用
  • 与Poly1305结合使用(ChaCha20-Poly1305)

SM4 (国密算法)

原理

SM4是中国国家密码管理局发布的商用密码算法,使用128位密钥和128位块大小,基于Feistel网络结构。

技术规格

属性
块大小128位 (16字节)
密钥长度128位
轮数32轮
安全级别高(国密标准)
状态中国标准,国内广泛使用

应用场景

  1. 政府系统:符合国家密码管理要求
  2. 金融行业:国内银行、支付系统
  3. 国产化替代:信创项目
  4. 密码合规:需要符合国密标准

性能影响

  • 加密/解密速度:快(与AES相当)
  • 内存占用:低
  • CPU使用率:中等
  • 吞吐量:与AES-128相当

Java实现示例

// 需要国密算法库支持,如BouncyCastle的国密扩展
// 或使用国产密码库
​
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.security.SecureRandom;
import java.util.Base64;
​
public class SM4Example {
    
    static {
        Security.addProvider(new BouncyCastleProvider());
    }
    
    /**
     * SM4加密(CBC模式)
     */
    public static String encrypt(String plaintext, SecretKey key) throws Exception {
        byte[] iv = new byte[16]; // SM4使用16字节IV
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);
        
        Cipher cipher = Cipher.getInstance("SM4/CBC/PKCS5Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        
        byte[] encrypted = new byte[16 + ciphertext.length];
        System.arraycopy(iv, 0, encrypted, 0, 16);
        System.arraycopy(ciphertext, 0, encrypted, 16, ciphertext.length);
        
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    /**
     * SM4解密
     */
    public static String decrypt(String encryptedData, SecretKey key) throws Exception {
        byte[] encrypted = Base64.getDecoder().decode(encryptedData);
        
        byte[] iv = new byte[16];
        System.arraycopy(encrypted, 0, iv, 0, 16);
        byte[] ciphertext = new byte[encrypted.length - 16];
        System.arraycopy(encrypted, 16, ciphertext, 0, ciphertext.length);
        
        Cipher cipher = Cipher.getInstance("SM4/CBC/PKCS5Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        
        byte[] plaintext = cipher.doFinal(ciphertext);
        return new String(plaintext, StandardCharsets.UTF_8);
    }
    
    public static SecretKey generateKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("SM4", "BC");
        return keyGenerator.generateKey();
    }
    
    public static void main(String[] args) throws Exception {
        SecretKey key = generateKey();
        String original = "测试数据";
        String encrypted = encrypt(original, key);
        System.out.println("加密后: " + encrypted);
        String decrypted = decrypt(encrypted, key);
        System.out.println("解密后: " + decrypted);
    }
}

安全建议

适用场景:

  • 需要符合国密标准
  • 政府、金融等敏感行业
  • 国产化项目

⚠️ 注意:

  • 需要专门的国密算法库支持
  • 国际兼容性较差

加密模式

CBC (Cipher Block Chaining)

原理: 每个明文块与前一个密文块异或后再加密。

特点:

  • 需要IV(初始化向量)
  • 串行处理,无法并行
  • 填充攻击风险

Java示例:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

GCM (Galois/Counter Mode)

原理: CTR模式的变体,同时提供加密和认证。

特点:

  • 认证加密(AEAD)
  • 可以并行加密
  • 防止篡改

Java示例:

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);

CTR (Counter Mode)

原理: 使用计数器生成密钥流,与明文异或。

特点:

  • 流密码模式
  • 可并行
  • 需要nonce

Java示例:

Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

ECB (Electronic Codebook)

原理: 直接加密每个块,不依赖其他块。

特点:

  • ⚠️ 不安全,不推荐使用
  • 相同明文产生相同密文
  • 无IV需求

性能对比

算法性能对比表

算法密钥长度速度(软件)硬件加速推荐度
AES-256256位广泛支持⭐⭐⭐⭐⭐
ChaCha20256位非常快⭐⭐⭐⭐⭐
AES-128128位广泛支持⭐⭐⭐⭐
SM4128位有限⭐⭐⭐⭐
Blowfish128-448位中等⭐⭐⭐
3DES168位有限⭐⭐
DES56位中等有限

性能优化建议

  1. 使用硬件加速:AES在支持AES-NI的CPU上性能大幅提升
  2. 选择合适的模式:GCM模式可并行,性能更好
  3. 避免ECB模式:安全性差且性能无优势
  4. 密钥管理:密钥生成和存储不影响加密性能,但影响安全性

总结

推荐选择

现代应用:

  • 首选:AES-256-GCM(通用场景)
  • 备选:ChaCha20-Poly1305(移动/无硬件加速)

特殊需求:

  • 国密合规:SM4
  • 遗留系统:3DES(过渡方案)

不推荐:

  • ❌ DES(已不安全)
  • ❌ ECB模式(不安全)
  • ❌ 弱密钥长度(<128位)

选择决策树

需要加密?
├─ 需要国密合规?→ SM4
├─ 有硬件AES加速?→ AES-256-GCM
├─ 无硬件加速/移动设备?→ ChaCha20-Poly1305
└─ 遗留系统兼容?→ 3DES(尽快迁移)