package com.example.test.security;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
public class FileSecurityUtils {
public static void main(String[] args) {
try {
encryptFile("C:\\test.txt", "password");
decryptFile("C:\\test.txt", "password");
} catch (IOException | GeneralSecurityException e) {
e.printStackTrace();
}
}
/**
* 任意选择8字节盐顺序
*/
private static final byte[] salt =
{(byte)0x43, (byte)0x76, (byte)0x95, (byte)0xc7, (byte)0x5b, (byte)0xd7, (byte)0x45, (byte)0x17};
/**
* 功能描述 : 制作密码
*
* @param pass
* 密码
* @param decryptMode
* 加密或者解密
* @return {@link Cipher}
* @author Ziyear 2021-4-21 22:20
*/
private static Cipher makeCipher(String pass, Boolean decryptMode) throws GeneralSecurityException {
// 使用KeyFactory从密码短语中导出相应的密钥:
PBEKeySpec keySpec = new PBEKeySpec(pass.toCharArray());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(keySpec);
// 从盐和任意数量的迭代中创建参数:
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 42);
// 设置密码:
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
// 将密码模式设置为解密或加密
if (decryptMode) {
cipher.init(Cipher.ENCRYPT_MODE, key, pbeParamSpec);
} else {
cipher.init(Cipher.DECRYPT_MODE, key, pbeParamSpec);
}
return cipher;
}
/**
* 功能描述 : 使用从密码短语派生的密钥将一个文件加密为第二个文件
*
* @param fileName
* 文件名
* @param pass
* 密码
* @author Ziyear 2021-4-21 22:27
*/
public static void encryptFile(String fileName, String pass) throws IOException, GeneralSecurityException {
byte[] decData;
byte[] encData;
File inFile = new File(fileName);
// Generate the cipher using pass:
Cipher cipher = FileSecurityUtils.makeCipher(pass, true);
// Read in the file:
FileInputStream inStream = new FileInputStream(inFile);
int blockSize = 8;
// Figure out how many bytes are padded
int paddedCount = blockSize - ((int)inFile.length() % blockSize);
// Figure out full size including padding
int padded = (int)inFile.length() + paddedCount;
decData = new byte[padded];
inStream.read(decData);
inStream.close();
// Write out padding bytes as per PKCS5 algorithm
for (int i = (int)inFile.length(); i < padded; ++i) {
decData[i] = (byte)paddedCount;
}
// Encrypt the file data:
encData = cipher.doFinal(decData);
// Write the encrypted data to a new file:
FileOutputStream outStream = new FileOutputStream(new File(fileName + ".encrypted"));
outStream.write(encData);
outStream.close();
}
/**
* 功能描述 : 使用派生自密码短语的密钥将一个文件解密为第二个文件
*
* @param fileName
* 文件名
* @param pass
* 密码
* @author Ziyear 2021-4-21 22:28
*/
public static void decryptFile(String fileName, String pass) throws GeneralSecurityException, IOException {
String fileExt =
fileName.substring(fileName.lastIndexOf(".") == -1 ? fileName.length() : fileName.lastIndexOf("."));
byte[] encData;
byte[] decData;
File inFile = new File(fileName + ".encrypted");
// Generate the cipher using pass:
Cipher cipher = FileSecurityUtils.makeCipher(pass, false);
// Read in the file:
FileInputStream inStream = new FileInputStream(inFile);
encData = new byte[(int)inFile.length()];
inStream.read(encData);
inStream.close();
// Decrypt the file data:
decData = cipher.doFinal(encData);
// Figure out how much padding to remove
int padCount = (int)decData[decData.length - 1];
// Naive check, will fail if plaintext file actually contained
// this at the end
// For robust check, check that padCount bytes at the end have same value
if (padCount >= 1 && padCount <= 8) {
decData = Arrays.copyOfRange(decData, 0, decData.length - padCount);
}
// Write the decrypted data to a new file:
FileOutputStream target = new FileOutputStream(new File(fileName + ".decrypted" + fileExt));
target.write(decData);
target.close();
}
}
使用密钥对文件进行加解密
最新推荐文章于 2024-08-15 14:47:41 发布