跳转至

Java AES 加密解密技术详解

简介

在当今数字化时代,数据安全至关重要。AES(高级加密标准,Advanced Encryption Standard)作为一种广泛应用的对称加密算法,为数据提供了强大的保密性。Java 语言提供了丰富的库来支持 AES 加密和解密操作。本文将深入探讨 Java AES 的基础概念、使用方法、常见实践以及最佳实践,帮助读者更好地掌握这一重要的加密技术。

目录

  1. AES 基础概念
  2. Java 中 AES 的使用方法
    • 生成密钥
    • 加密操作
    • 解密操作
  3. 常见实践
    • 文件加密与解密
    • 网络数据传输加密
  4. 最佳实践
    • 密钥管理
    • 填充模式与加密模式选择
  5. 小结
  6. 参考资料

AES 基础概念

AES 是一种对称加密算法,这意味着加密和解密使用相同的密钥。它具有以下特点: - 分组加密:AES 将数据分成固定长度的块(通常为 128 位)进行加密。 - 密钥长度:支持 128 位、192 位和 256 位的密钥长度,密钥长度越长,安全性越高。 - 加密模式:常见的加密模式有 ECB(电子密码本模式)、CBC(密码块链接模式)、CTR(计数器模式)等。不同的模式具有不同的特点和适用场景。 - 填充模式:当数据长度不是分组长度的整数倍时,需要进行填充。常见的填充模式有 PKCS5Padding、PKCS7Padding 等。

Java 中 AES 的使用方法

生成密钥

在 Java 中,使用 KeyGenerator 类生成 AES 密钥。以下是生成 256 位 AES 密钥的示例代码:

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.NoSuchAlgorithmException;

public class AESKeyGenerator {
    public static SecretKey generateAESKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(256); // 设置密钥长度为 256 位
        SecretKey secretKey = keyGen.generateKey();
        return secretKey;
    }
}

加密操作

使用生成的密钥对数据进行加密。这里以 Cipher 类为例,采用 CBC 模式和 PKCS5Padding 填充模式:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

public class AESEncryption {
    public static byte[] encrypt(String plaintext, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] iv = new byte[16]; // 初始化向量长度为 16 字节
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
        byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        byte[] encryptedIVAndText = new byte[iv.length + encrypted.length];
        System.arraycopy(iv, 0, encryptedIVAndText, 0, iv.length);
        System.arraycopy(encrypted, 0, encryptedIVAndText, iv.length, encrypted.length);
        return encryptedIVAndText;
    }
}

解密操作

对加密后的数据进行解密:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class AESDecryption {
    public static String decrypt(byte[] encryptedText, SecretKey secretKey) throws Exception {
        int ivLength = 16;
        byte[] iv = new byte[ivLength];
        byte[] encrypted = new byte[encryptedText.length - ivLength];
        System.arraycopy(encryptedText, 0, iv, 0, ivLength);
        System.arraycopy(encryptedText, ivLength, encrypted, 0, encrypted.length);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        return new String(decrypted, StandardCharsets.UTF_8);
    }
}

常见实践

文件加密与解密

对文件进行加密和解密是常见的需求。以下是使用 AES 对文件进行加密和解密的示例代码:

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.io.*;

public class AESFileEncryption {
    public static void encryptFile(String inputFile, String outputFile, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] iv = new byte[16];
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);

        try (FileOutputStream fos = new FileOutputStream(outputFile);
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {
            bos.write(iv);
            try (CipherOutputStream cos = new CipherOutputStream(bos, cipher);
                 FileInputStream fis = new FileInputStream(inputFile);
                 BufferedInputStream bis = new BufferedInputStream(fis)) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = bis.read(buffer)) != -1) {
                    cos.write(buffer, 0, len);
                }
            }
        }
    }

    public static void decryptFile(String inputFile, String outputFile, SecretKey secretKey) throws Exception {
        try (FileInputStream fis = new FileInputStream(inputFile);
             BufferedInputStream bis = new BufferedInputStream(fis)) {
            byte[] iv = new byte[16];
            bis.read(iv);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);

            try (CipherInputStream cis = new CipherInputStream(bis, cipher);
                 FileOutputStream fos = new FileOutputStream(outputFile);
                 BufferedOutputStream bos = new BufferedOutputStream(fos)) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = cis.read(buffer)) != -1) {
                    bos.write(buffer, 0, len);
                }
            }
        }
    }
}

网络数据传输加密

在网络通信中,对传输的数据进行加密可以防止数据被窃取或篡改。以下是一个简单的示例,展示如何在网络传输中使用 AES 加密和解密数据:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.io.*;
import java.net.Socket;

public class AESNetworkEncryption {
    public static void sendEncryptedData(Socket socket, String data, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] iv = new byte[16];
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
        byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));

        try (OutputStream os = socket.getOutputStream();
             BufferedOutputStream bos = new BufferedOutputStream(os)) {
            bos.write(iv);
            bos.write(encryptedData);
            bos.flush();
        }
    }

    public static String receiveDecryptedData(Socket socket, SecretKey secretKey) throws Exception {
        try (InputStream is = socket.getInputStream();
             BufferedInputStream bis = new BufferedInputStream(is)) {
            byte[] iv = new byte[16];
            bis.read(iv);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = bis.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            byte[] encryptedData = baos.toByteArray();
            byte[] decryptedData = cipher.doFinal(encryptedData);
            return new String(decryptedData, StandardCharsets.UTF_8);
        }
    }
}

最佳实践

密钥管理

  • 密钥生成:使用安全的随机数生成器生成密钥,确保密钥的随机性和不可预测性。
  • 密钥存储:将密钥存储在安全的地方,如硬件安全模块(HSM)或加密的文件系统中。避免将密钥硬编码在代码中。
  • 密钥更新:定期更新密钥,以降低密钥被破解的风险。

填充模式与加密模式选择

  • 填充模式:根据具体需求选择合适的填充模式。PKCS5Padding 和 PKCS7Padding 是常用的填充模式,适用于大多数场景。
  • 加密模式:对于大多数应用,CBC 模式是一个不错的选择,它可以增加数据的保密性和完整性。CTR 模式则适用于对性能要求较高的场景。

小结

本文详细介绍了 Java 中 AES 加密解密的基础概念、使用方法、常见实践以及最佳实践。通过学习这些内容,读者可以在自己的项目中有效地使用 AES 进行数据加密,保护数据的安全性。在实际应用中,需要根据具体需求选择合适的加密模式和填充模式,并注意密钥的管理和更新。

参考资料