杰瑞科技汇

Java加密有哪些常用方法?

为了让你能快速上手,我将从以下几个方面进行详细说明:

Java加密有哪些常用方法?-图1
(图片来源网络,侵删)
  1. 核心概念:了解加密的基本术语。
  2. 对称加密:使用同一个密钥进行加密和解密(AES 是最常用的)。
  3. 非对称加密:使用公钥和私钥(RSA 是最常用的)。
  4. 混合加密:结合对称和非对称加密的优点(HTTPS 的原理)。
  5. 完整示例代码:提供一个可以直接运行的 AES 加密解密示例。
  6. 最佳实践与注意事项:避免常见的安全陷阱。

核心概念

在深入代码之前,先理解几个关键术语:

  • 加密算法:定义了如何将明文转换为密文的数学规则,AES, DES, RSA。
  • 密钥:一个用于加密和解密的秘密字符串或数字。密钥管理是加密中最重要也最困难的部分。
  • 对称加密:加密和解密使用同一个密钥,优点是速度快,适合加密大量数据;缺点是密钥分发困难。
    • 常见算法:AES (Advanced Encryption Standard), DES (已不安全), 3DES。
  • 非对称加密:使用一对密钥:公钥私钥
    • 公钥可以自由分发,用它加密的数据只能用对应的私钥解密。
    • 私钥必须严格保密,用它签名的数据可以用对应的公钥验证。
    • 优点是解决了密钥分发问题;缺点是速度慢,不适合加密大量数据。
    • 常见算法:RSA, ECC (Elliptic Curve Cryptography)。
  • 填充:现代加密算法要求数据长度是特定块大小的整数倍,填充(如 PKCS5Padding)就是在数据末尾添加一些字节以满足这个要求。
  • 初始化向量:在对称加密中,IV 是一个随机数,用于确保即使加密相同的数据,每次生成的密文也不同,从而增加安全性。
  • :在哈希或密码加密时,盐是一个随机值,与密码混合后一起进行哈希/加密,目的是防止彩虹表攻击。

对称加密示例 (AES)

AES 是目前最流行的对称加密算法,我们将使用 AES-128-CBC 模式(最常用的组合之一)进行演示。

关键步骤:

  1. 生成密钥:从一个密码或随机字节生成一个固定长度的密钥。
  2. 生成 IV:生成一个随机初始化向量。
  3. 加密:使用密钥和 IV 对数据进行加密。
  4. 解密:使用相同的密钥和 IV 对密文进行解密。

代码示例:

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.security.SecureRandom;
import.util.Base64;
public class AesEncryptionUtil {
    // AES 加密算法
    private static final String ALGORITHM = "AES";
    // 加密模式与填充方式
    private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
    // 密钥长度 (128, 192, 256)
    private static final int KEY_SIZE = 128;
    /**
     * 生成 AES 密钥
     */
    public static SecretKey generateKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
        keyGenerator.init(KEY_SIZE);
        return keyGenerator.generateKey();
    }
    /**
     * 从字符串生成密钥 (注意:实际应用中,密码应该更复杂,并使用密钥派生函数如 PBKDF2)
     */
    public static SecretKey getKeyFromString(String keyStr) {
        byte[] keyBytes = keyStr.getBytes(StandardCharsets.UTF_8);
        // 确保密钥长度符合要求 (AES-128 需要 16字节, AES-256 需要 32字节)
        byte[] finalKeyBytes = new byte[KEY_SIZE / 8];
        System.arraycopy(keyBytes, 0, finalKeyBytes, 0, Math.min(keyBytes.length, finalKeyBytes.length));
        return new SecretKeySpec(finalKeyBytes, ALGORITHM);
    }
    /**
     * 生成初始化向量
     */
    public static IvParameterSpec generateIv() {
        byte[] iv = new byte[16]; // AES block size is 16 bytes
        new SecureRandom().nextBytes(iv);
        return new IvParameterSpec(iv);
    }
    /**
     * 加密
     */
    public static String encrypt(String input, SecretKey key, IvParameterSpec iv) throws Exception {
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);
        byte[] cipherBytes = cipher.doFinal(input.getBytes(StandardCharsets.UTF_8));
        // 使用 Base64 编码,方便存储和传输
        return Base64.getEncoder().encodeToString(cipherBytes);
    }
    /**
     * 解密
     */
    public static String decrypt(String cipherText, SecretKey key, IvParameterSpec iv) throws Exception {
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        byte decipheredBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText));
        return new String(decipheredBytes, StandardCharsets.UTF_8);
    }
    public static void main(String[] args) {
        try {
            String originalString = "这是一个需要加密的秘密信息!";
            // --- 方式一:生成随机密钥 ---
            SecretKey secretKey = generateKey();
            IvParameterSpec ivParameterSpec = generateIv();
            System.out.println("原始字符串: " + originalString);
            System.out.println("使用的密钥 (Base64): " + Base64.getEncoder().encodeToString(secretKey.getEncoded()));
            System.out.println("使用的 IV (Base64): " + Base64.getEncoder().encodeToString(ivParameterSpec.getIV()));
            String encryptedString = encrypt(originalString, secretKey, ivParameterSpec);
            System.out.println("加密后 (Base64): " + encryptedString);
            String decryptedString = decrypt(encryptedString, secretKey, ivParameterSpec);
            System.out.println("解密后: " + decryptedString);
            System.out.println("---------------------------------");
            // --- 方式二:从字符串密码生成密钥 ---
            String password = "mySecretPassword123"; // 实际应用中应更复杂
            SecretKey keyFromPassword = getKeyFromString(password);
            IvParameterSpec ivForPassword = generateIv();
            System.out.println("\n从密码生成密钥");
            System.out.println("原始字符串: " + originalString);
            System.out.println("使用的密码: " + password);
            System.out.println("使用的 IV (Base64): " + Base64.getEncoder().encodeToString(ivForPassword.getIV()));
            String encryptedWithPassword = encrypt(originalString, keyFromPassword, ivForPassword);
            System.out.println("加密后 (Base64): " + encryptedWithPassword);
            String decryptedWithPassword = decrypt(encryptedWithPassword, keyFromPassword, ivForPassword);
            System.out.println("解密后: " + decryptedWithPassword);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

非对称加密示例 (RSA)

RSA 通常用于加密少量数据,比如对称加密的密钥,或者数字签名。

关键步骤:

  1. 生成密钥对:生成一个公钥和一个私钥。
  2. 公钥加密:使用公钥加密数据(或对称密钥)。
  3. 私钥解密:使用私钥解密数据(或对称密钥)。

代码示例:

import javax.crypto.Cipher;
import java.security.*;
import java.util.Base64;
public class RsaEncryptionUtil {
    private static final String ALGORITHM = "RSA";
    /**
     * 生成 RSA 密钥对
     */
    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
        keyPairGenerator.initialize(2048); // 密钥长度,至少 2048
        return keyPairGenerator.generateKeyPair();
    }
    /**
     * 公钥加密
     */
    public static String encrypt(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] cipherBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(cipherBytes);
    }
    /**
     * 私钥解密
     */
    public static String decrypt(String data, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decipheredBytes = cipher.doFinal(Base64.getDecoder().decode(data));
        return new String(decipheredBytes, StandardCharsets.UTF_8);
    }
    public static void main(String[] args) {
        try {
            String originalString = "用 RSA 加密一条短消息";
            // 1. 生成密钥对
            KeyPair keyPair = generateKeyPair();
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();
            System.out.println("原始字符串: " + originalString);
            System.out.println("公钥 (Base64):\n" + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
            System.out.println("私钥 (Base64):\n" + Base64.getEncoder().encodeToString(privateKey.getEncoded()));
            // 2. 使用公钥加密
            String encryptedString = encrypt(originalString, publicKey);
            System.out.println("\n加密后 (Base64): " + encryptedString);
            // 3. 使用私钥解密
            String decryptedString = decrypt(encryptedString, privateKey);
            System.out.println("解密后: " + decryptedString);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

混合加密 (Hybrid Encryption)

这是实际应用中最常见的模式,完美结合了对称和非对称加密的优点。HTTPS/TLS 协议就是使用这个原理

Java加密有哪些常用方法?-图2
(图片来源网络,侵删)

流程:

  1. 发送方
    • 生成一个临时的、对称的会话密钥(AES 密钥)。
    • 使用接收方的公钥对这个会话密钥进行非对称加密
    • 使用这个会话密钥对要传输的大量数据进行对称加密
    • 将加密后的会话密钥和加密后的数据一起发送给接收方。
  2. 接收方
    • 使用自己的私钥解密出会话密钥。
    • 使用这个会话密钥解密出原始数据。

优点

  • 安全:利用非对称加密安全地传输对称密钥,再利用对称加密高效地传输数据。
  • 高效:数据传输使用快速的对对称加密。

最佳实践与注意事项

  1. 不要自己实现加密算法:使用 Java 标准库或信誉良好的第三方库(如 Bouncy Castle),自己实现极易出错。
  2. 密钥管理是重中之重
    • 不要硬编码密钥在代码里,密钥应该从安全的地方加载,如环境变量、密钥管理服务 (KMS, 如 AWS KMS, HashiCorp Vault) 或专门的硬件安全模块 (HSM)。
    • 对称密钥和非对称密钥的私钥都需要严格保护。
  3. 选择合适的算法和模式
    • AES 是对称加密的首选。
    • RSA 是非对称加密的首选(用于加密少量数据或签名)。
    • 使用像 AES/GCM/NoPadding (GCM 模式同时提供加密和认证) 或 AES/CBC/PKCS5Padding 这样的模式。
    • 避免使用 ECB 模式,因为它不能隐藏数据模式,非常不安全。
  4. 使用安全的随机数生成器:IV 和盐必须使用 java.security.SecureRandom 来生成,而不是 Math.random()
  5. 处理异常:加密操作可能因为各种原因抛出异常(如无效的密钥、错误的填充),必须妥善处理。
  6. 考虑使用 javax.crypto.CipherInputStreamCipherOutputStream:当你需要加密/解密大文件(如视频、数据库备份)时,使用流可以避免将整个文件加载到内存中,提高性能和稳定性。

希望这份详细的指南能帮助你理解和使用 Java 进行加密!

分享:
扫描分享到社交APP
上一篇
下一篇