AES 属于对称加密算法,即加密和解密使用相同的密钥。这意味着通信双方在进行数据传输之前,需要先共享密钥,然后使用该密钥对数据进行加密和解密操作。
特点
- 安全性高:AES 具有很高的安全性,能够抵御多种已知的攻击方式,如差分攻击、线性攻击等。在合理的密钥长度下,破解 AES 加密的难度极大。
- 效率高:AES 算法在软件和硬件上都能高效实现。它的运算速度快,能够满足大多数应用场景对加密和解密速度的要求。
- 灵活性强:AES 算法具有良好的灵活性,支持不同的块大小和密钥长度,可以根据具体的应用需求进行选择。
应用场景
- 数据加密:用于对敏感数据进行加密存储和传输,如银行账户信息、用户密码、企业机密文件等,以保护数据的机密性和完整性。
- 网络通信:在网络通信中,AES 常用于加密传输的数据,如 SSL/TLS 协议中就使用 AES 来加密客户端和服务器之间的通信数据,防止数据被窃取或篡改。
- 数字版权管理:在数字内容的保护中,AES 可以用于加密数字媒体文件,如音乐、视频、电子书等,以防止未经授权的复制和传播。
一、AES工具类
先准备好一个springboot项目
(1)初始化 AES 加密器或解密器
/**
* 初始化 AES 加密器或解密器
*
* @param password 用于生成密钥的密码字符串
* @param cipherMode 加密模式(如 Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE)
* @return 初始化好的 Cipher 对象,如果初始化失败则返回 null
*/
public static Cipher initAESCipher(String password, int cipherMode) {
Cipher cipher = null;
try {
// 调用 getKey 方法根据传入的密码生成 AES 密钥
SecretKey key = getKey(password);
// 获取 AES 加密算法的 Cipher 实例,使用 ECB 模式和 PKCS5 填充方式
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// 使用生成的密钥和指定的加密模式初始化 Cipher 对象
cipher.init(cipherMode, key);
} catch (Exception e) {
// 若初始化过程中出现异常,打印异常堆栈信息
e.printStackTrace();
}
return cipher;
}
/**
* 根据传入的密码生成 AES-128 密钥
*
* @param password 用于生成密钥的密码字符串
* @return 生成的 AES 密钥对象
*/
private static SecretKey getKey(String password) {
// 初始化一个长度为 16 字节的字节数组,用于存储 AES-128 所需的密钥
byte[] key = new byte[16];
try {
// 获取 SHA-256 哈希算法的实例
MessageDigest sha = MessageDigest.getInstance("SHA-256");
// 对传入的密码字符串进行 SHA-256 哈希处理,得到一个长度为 32 字节的哈希值
byte[] keyBytes = sha.digest(password.getBytes());
// 将哈希值的前 16 个字节复制到 key 数组中,作为 AES-128 密钥
System.arraycopy(keyBytes, 0, key, 0, key.length);
// 使用 key 数组创建一个 AES 密钥对象
return new SecretKeySpec(key, "AES");
} catch (NoSuchAlgorithmException e) {
// 若系统不支持 SHA-256 算法,抛出运行时异常
throw new RuntimeException("Error generating key", e);
}
}
(2)设置加密和解密公共方法
/**
* AES 文件加密
* @param inputStream 输入文件流,即待加密的文件对应的输入流
* @param outputStream 输出文件流,加密后的文件将通过此输出流输出
* @return 加密操作是否成功,成功返回 true,失败返回 false
*/
public static boolean encryptFile(InputStream inputStream, OutputStream outputStream) {
CipherOutputStream cipherOutputStream = null;
BufferedInputStream bufferedInputStream = null;
try {
// 初始化 AES 加密器,调用 initAESCipher 方法,传入密钥和加密模式
Cipher cipher = initAESCipher(KEY, Cipher.ENCRYPT_MODE);
// 创建 CipherOutputStream 对象,将输出流和加密器关联,用于对输出数据进行加密
cipherOutputStream = new CipherOutputStream(outputStream, cipher);
// 创建 BufferedInputStream 对象,用于缓冲输入流,提高读取效率
bufferedInputStream = new BufferedInputStream(inputStream);
// 定义一个字节数组作为缓冲区,用于存储每次从输入流中读取的数据
byte[] buffer = new byte[1024];
int bufferLength;
// 从输入流中读取数据,每次读取的数据长度存储在 bufferLength 中,当读取到文件末尾时返回 -1
while ((bufferLength = bufferedInputStream.read(buffer)) != -1) {
// 将读取到的数据写入到加密输出流中,完成加密操作
cipherOutputStream.write(buffer, 0, bufferLength);
}
// 关闭输入流
bufferedInputStream.close();
// 关闭加密输出流
cipherOutputStream.close();
} catch (IOException e) {
// 若发生 IO 异常,打印异常堆栈信息
e.printStackTrace();
// 返回加密失败
return false;
}
// 若没有异常发生,返回加密成功
return true;
}
/**
* AES 文件解密
* @param inputStream 输入文件流,即待解密的加密文件对应的输入流
* @param responseOutputStream 输出文件流,解密后的文件将通过此输出流输出
*/
public static void decryptFile(InputStream inputStream, OutputStream responseOutputStream) {
try {
// 初始化 AES 解密器,调用 initAESCipher 方法,传入密钥和解密模式
Cipher cipher = initAESCipher(KEY, Cipher.DECRYPT_MODE);
// 创建 CipherInputStream 对象,将输入流和解密器关联,用于对输入数据进行解密
inputStream = new CipherInputStream(inputStream, cipher);
int bufferLength;
// 定义一个字节数组作为缓冲区,用于存储每次从解密输入流中读取的数据
byte[] buffer = new byte[1024];
// 从解密输入流中读取数据,每次读取的数据长度存储在 bufferLength 中,当读取到文件末尾时返回 -1
while ((bufferLength = inputStream.read(buffer)) != -1) {
// 将解密后的数据写入到输出流中
responseOutputStream.write(buffer, 0, bufferLength);
}
// 关闭输入流
inputStream.close();
// 关闭输出流
responseOutputStream.close();
} catch (IOException e) {
// 若发生 IO 异常,打印异常堆栈信息
e.printStackTrace();
}
}
二、控制层
(1)准备控制层接口
/**
* 文件加密
*/
@PostMapping("/encryptFile")
public Result encryptFile(MultipartFile file, HttpServletResponse response) throws IOException {
// 保存到指定位置
File encryptFile = new File("D:\\xhj\\文件\\xhj\\文件\\AES\\加密文件\\"+file.getOriginalFilename());
AESFileUtil.encryptFile(file.getInputStream(), new FileOutputStream(encryptFile));
// 通过响应体返回加密好的文件流
// AESFileUtil.encryptFile(file.getInputStream(), response.getOutputStream());
return Result.ok();
}
/**
* 文件解密
*/
@PostMapping("/decryptFile")
public Result decryptFile(MultipartFile file, HttpServletResponse response) throws IOException {
// 保存到指定位置
File decryptFile = new File("D:\\xhj\\文件\\xhj\\文件\\AES\\解密文件\\"+file.getOriginalFilename());
AESFileUtil.decryptFile(file.getInputStream(), new FileOutputStream(decryptFile));
// 通过响应体返回加密好的文件流
// AESFileUtil.decryptFile(file.getInputStream(), response.getOutputStream());
return Result.ok();
}
代码中有两种返回方式,一种是直接保存到指定位置,一种是直接通过响应体返回流,可以根据实际使用进行调整
(2)准备测试文件
随便准备一个文件用来测试,我这边就用word文档进行测试
(3)apifox接口测试
测试文件加密
找到你加密之后文件保存的文件位置打开文件,因为加密了,所以可能会出现文件打不开或者文件内容乱码的情况
测试文件解密
把刚才加密的文件进行解密
同样的找到解密之后文件保存的文件位置打开文件,可以正确的看到文件内容
总结
文件加密有很多种方式,比如对称加密、非对称加密、哈希加密以及其他特殊加密方式等等等,这次我使用的是对称加密里面的一种AES加密,大家可以选择自己需要的加密方式进行加解密,基本上都是用加密算法根据密钥对数据进行分块加密,当然了,肯定没有我说的那么简单,底层算法还是非常的复杂的,不是目前的我能接触的。但是基本流程都是通过密钥和加密算法对你的明文进行处理之后得到你想要的密文