package com.nt.obs.encryption;
/**
* @author : fangcong
* @date : 2023/5/4 15:49
* @description : 类作用
**/
import org.springframework.stereotype.Service;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
@Service
public class AesEncryptionService implements IEncryptionFile {
/**
* 使用固定的密钥
*/
private static byte[] key = "MyFileSecretKey12345".getBytes();
/**
* 加密方法
* 输入inputStream,将随机盐和iv值添加到对应的加密后的inputStream中,因此无需存储对应的随机盐
*/
@Override
public InputStream encrypt(InputStream input) throws Exception {
// 生成随机盐
byte[] salt = new byte[16];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(salt);
// 创建秘钥
SecretKeySpec secretKeySpec = generateSecretKey(key, salt);
// 创建IV
byte[] iv = new byte[16];
secureRandom.nextBytes(iv);
// 初始化加密器
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
// 构造缓冲流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream);
// 写入随机盐和IV
bufferedOutputStream.write(salt);
bufferedOutputStream.write(iv);
// 执行加密操作
CipherOutputStream cipherOutputStream = new CipherOutputStream(bufferedOutputStream, cipher);
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) != -1) {
cipherOutputStream.write(buffer, 0, len);
}
cipherOutputStream.close();
// 返回加密后的输入流
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}
/**
* 对inputStream进行解密
* @param input 输入流
* @return 解密后数据
* @throws Exception
*/
@Override
public InputStream decrypt(InputStream input) throws Exception {
// 构造缓冲流
BufferedInputStream bufferedInputStream = new BufferedInputStream(input);
// 读取随机盐和IV
byte[] salt = new byte[16];
bufferedInputStream.read(salt);
byte[] iv = new byte[16];
bufferedInputStream.read(iv);
// 创建秘钥
SecretKeySpec secretKeySpec = generateSecretKey(key, salt);
// 初始化解密器
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
// 执行解密操作
CipherInputStream cipherInputStream = new CipherInputStream(bufferedInputStream, cipher);
byte[] buffer = new byte[1024];
int len;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
while ((len = cipherInputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
cipherInputStream.close();
// 返回解密后的输入流
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}
// 生成秘钥
private static SecretKeySpec generateSecretKey(byte[] key, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeySpec keySpec = new PBEKeySpec(new String(key).toCharArray(), salt, 65536, 256);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] keyBytes = secretKeyFactory.generateSecret(keySpec).getEncoded();
return new SecretKeySpec(keyBytes, "AES");
}
}
问题
该方式还是为单一加密,也就是每一个文件都是使用相同的key,即使盐不同,iv 不同,获得到了key也能够解密到所有的文件。
双重加密
每一个文件都对应着自己一个key,也就是说每一个文件自己生成一个password,这样必须破解数据库,才有可能破解文件内容。
但是这样不太放心,password应加密保存到数据库,这样就有一个主密钥,那么主密钥应该如何安全进行管理?
反思
以上写法都无法保证百分之百安全,只能提高破解的难度。