Merge pull request 'dev文件加解密操作' (#1) from dev into main
Reviewed-on: #1
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>top.gtb520.java.gnu</groupId>
|
<groupId>top.gtb520.java.gnu</groupId>
|
||||||
<artifactId>gnu_java_utils_library</artifactId>
|
<artifactId>gnu_java_utils_library</artifactId>
|
||||||
<version>1.3-SNAPSHOT</version>
|
<version>1.4-SNAPSHOT</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>25</maven.compiler.source>
|
<maven.compiler.source>25</maven.compiler.source>
|
||||||
|
|||||||
@@ -2,6 +2,13 @@ package top.gtb520.java.gnu.java.utils.library;
|
|||||||
|
|
||||||
import top.gtb520.java.gnu.java.utils.library.utils.print.ColorNameEnum;
|
import top.gtb520.java.gnu.java.utils.library.utils.print.ColorNameEnum;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static top.gtb520.java.gnu.java.utils.library.utils.file.CreateFile.BinFileType;
|
||||||
|
import static top.gtb520.java.gnu.java.utils.library.utils.file.EncryptionAndDecryption.EncryptionType;
|
||||||
|
|
||||||
|
|
||||||
public interface main {
|
public interface main {
|
||||||
// 压缩包操作相关接口与方法
|
// 压缩包操作相关接口与方法
|
||||||
interface compress {
|
interface compress {
|
||||||
@@ -127,4 +134,31 @@ public interface main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 文件操作接口与方法
|
||||||
|
interface file {
|
||||||
|
interface CreateFile {
|
||||||
|
// 创建文件,创建空白文件,异步IO
|
||||||
|
static File NewFile(String FileName, boolean isBin, BinFileType binFileType) {
|
||||||
|
return top.gtb520.java.gnu.java.utils.library.utils.file.CreateFile.NewFile(FileName, isBin, binFileType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 以字节流方式保存文件,异步IO
|
||||||
|
static boolean StreamSaveFile(File file, Path TargePath, String FileName) {
|
||||||
|
return top.gtb520.java.gnu.java.utils.library.utils.file.CreateFile.StreamSaveFile(file, TargePath, FileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件加解密操作
|
||||||
|
interface EncryptionAndDecryption {
|
||||||
|
// 文件加密
|
||||||
|
static File FileEncrypt(File file, EncryptionType type, Path keyPath) throws Exception {
|
||||||
|
return top.gtb520.java.gnu.java.utils.library.utils.file.EncryptionAndDecryption.EncryptionFile(file, type, keyPath);
|
||||||
|
}
|
||||||
|
// 文件解密
|
||||||
|
static File DecryptionFile(File file, EncryptionType type, File keyfile) throws Exception {
|
||||||
|
return top.gtb520.java.gnu.java.utils.library.utils.file.EncryptionAndDecryption.DecryptionFile(file, type, keyfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package top.gtb520.java.gnu.java.utils.library.utils.file;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
// 创建文件
|
||||||
|
public class CreateFile {
|
||||||
|
/***
|
||||||
|
* 创建文件,创建空白文件
|
||||||
|
* isBin为True时创建一个空白的二进制文件,否则创建一个空白的普通文件
|
||||||
|
* 异步IO操作
|
||||||
|
*
|
||||||
|
* @param FileName 文件名
|
||||||
|
* @param isBin 是否二进制文件
|
||||||
|
* @param binFileType 二进制文件类型,如果是普通文件则不需要设置次值,将其设置为null即可,
|
||||||
|
* 参考isBin参数,isBin参数为False则此参数设置为null
|
||||||
|
*
|
||||||
|
* @return 文件
|
||||||
|
*/
|
||||||
|
public static File NewFile(String FileName, boolean isBin, BinFileType binFileType) {
|
||||||
|
File TargetFile = null;
|
||||||
|
byte[] BufferByte = new byte[1024];
|
||||||
|
|
||||||
|
try {
|
||||||
|
TargetFile = new File(FileName);
|
||||||
|
if (TargetFile.createNewFile()) {
|
||||||
|
if (isBin && binFileType != null) {
|
||||||
|
// 根据二进制文件类型写入文件头标识
|
||||||
|
byte[] header = switch (binFileType) {
|
||||||
|
case ELF -> new byte[]{0x7F, 'E', 'L', 'F'};
|
||||||
|
case PE -> new byte[]{'M', 'Z'};
|
||||||
|
};
|
||||||
|
try (OutputStream os = Files.newOutputStream(TargetFile.toPath(),
|
||||||
|
StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
|
||||||
|
os.write(header);
|
||||||
|
os.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
TargetFile = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TargetFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 以字节流方式保存文件
|
||||||
|
* 异步IO操作
|
||||||
|
*
|
||||||
|
* @param file 文件
|
||||||
|
* @param TargePath 目标路径
|
||||||
|
* @param FileName 文件名
|
||||||
|
*
|
||||||
|
* @return 是否保存成功,True为保存成功,False为保存失败
|
||||||
|
*/
|
||||||
|
public static boolean StreamSaveFile(File file, Path TargePath, String FileName) {
|
||||||
|
try {
|
||||||
|
Path targetFile = TargePath.resolve(FileName);
|
||||||
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
|
try (OutputStream os = Files.newOutputStream(targetFile,
|
||||||
|
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int bytesRead;
|
||||||
|
try (var is = Files.newInputStream(file.toPath())) {
|
||||||
|
while ((bytesRead = is.read(buffer)) != -1) {
|
||||||
|
os.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os.flush();
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}).get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BinFileType {
|
||||||
|
ELF, PE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
package top.gtb520.java.gnu.java.utils.library.utils.file;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import javax.crypto.BadPaddingException;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
import javax.crypto.KeyGenerator;
|
||||||
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
|
||||||
|
public class EncryptionAndDecryption {
|
||||||
|
/***
|
||||||
|
* 文件加密
|
||||||
|
* 异步执行加密操作
|
||||||
|
* 加密后覆盖原文件,不添加额外后缀
|
||||||
|
* 密钥保存到 keyPath 目录下,密钥名为 原文件名.key
|
||||||
|
*
|
||||||
|
* @param file 文件
|
||||||
|
* @param type 加密类型
|
||||||
|
* @param keyPath 密钥文件目录路径,密钥名为 文件名.key
|
||||||
|
* @return 加密后的文件(原文件),失败时返回 null
|
||||||
|
*/
|
||||||
|
public static File EncryptionFile(File file, EncryptionType type, Path keyPath) {
|
||||||
|
File TargetFile = null;
|
||||||
|
|
||||||
|
if (file == null || !file.exists() || !file.isFile()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (keyPath == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
TargetFile = CompletableFuture.supplyAsync(() -> {
|
||||||
|
try {
|
||||||
|
// 读取原文件内容
|
||||||
|
byte[] plainBytes = Files.readAllBytes(file.toPath());
|
||||||
|
|
||||||
|
// 根据加密类型生成对称密钥
|
||||||
|
SecretKey secretKey = generateSecretKey(type);
|
||||||
|
byte[] encryptedBytes = encryptBytes(plainBytes, secretKey, type);
|
||||||
|
|
||||||
|
// 将密钥写入 keyPath 目录,密钥名为 文件名.key
|
||||||
|
Files.createDirectories(keyPath);
|
||||||
|
String keyFileName = file.getName() + ".key";
|
||||||
|
Path keyFilePath = keyPath.resolve(keyFileName);
|
||||||
|
try (OutputStream kos = Files.newOutputStream(keyFilePath,
|
||||||
|
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
|
||||||
|
kos.write(secretKey.getEncoded());
|
||||||
|
kos.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加密后覆盖写回原文件
|
||||||
|
try (OutputStream os = Files.newOutputStream(file.toPath(),
|
||||||
|
StandardOpenOption.TRUNCATE_EXISTING)) {
|
||||||
|
os.write(encryptedBytes);
|
||||||
|
os.flush();
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
TargetFile = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TargetFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 生成对称密钥
|
||||||
|
*
|
||||||
|
* @param type 加密类型
|
||||||
|
* @return 对称密钥
|
||||||
|
*/
|
||||||
|
private static SecretKey generateSecretKey(EncryptionType type) throws NoSuchAlgorithmException {
|
||||||
|
String algorithm = switch (type) {
|
||||||
|
case AES -> "AES";
|
||||||
|
case DES -> "DES";
|
||||||
|
case RSA -> "AES"; // RSA 为非对称加密,此处用 AES 做对称加密替代
|
||||||
|
};
|
||||||
|
KeyGenerator keyGen = KeyGenerator.getInstance(algorithm);
|
||||||
|
int keySize = switch (type) {
|
||||||
|
case AES -> 128;
|
||||||
|
case DES -> 56;
|
||||||
|
case RSA -> 128;
|
||||||
|
};
|
||||||
|
keyGen.init(keySize);
|
||||||
|
return keyGen.generateKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 对字节数据进行加密
|
||||||
|
*
|
||||||
|
* @param data 原始数据
|
||||||
|
* @param key 密钥
|
||||||
|
* @param type 加密类型
|
||||||
|
* @return 加密后的数据
|
||||||
|
*/
|
||||||
|
private static byte[] encryptBytes(byte[] data, SecretKey key, EncryptionType type)
|
||||||
|
throws NoSuchAlgorithmException, NoSuchPaddingException,
|
||||||
|
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
|
||||||
|
String algorithm = switch (type) {
|
||||||
|
case AES -> "AES/ECB/PKCS5Padding";
|
||||||
|
case DES -> "DES/ECB/PKCS5Padding";
|
||||||
|
case RSA -> "AES/ECB/PKCS5Padding";
|
||||||
|
};
|
||||||
|
Cipher cipher = Cipher.getInstance(algorithm);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||||
|
return cipher.doFinal(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 文件解密
|
||||||
|
* 异步执行解密操作
|
||||||
|
* 解密后覆盖写回原文件,不添加额外后缀
|
||||||
|
*
|
||||||
|
* @param file 加密文件
|
||||||
|
* @param type 加密类型,须与加密时一致
|
||||||
|
* @param keyfile 密钥文件,从中读取解密密钥
|
||||||
|
* @return 解密后的文件(原文件),失败时返回 null
|
||||||
|
*/
|
||||||
|
public static File DecryptionFile(File file, EncryptionType type, File keyfile) {
|
||||||
|
File TargetFile = null;
|
||||||
|
|
||||||
|
if (file == null || !file.exists() || !file.isFile()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (keyfile == null || !keyfile.exists() || !keyfile.isFile()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
TargetFile = CompletableFuture.supplyAsync(() -> {
|
||||||
|
try {
|
||||||
|
// 从密钥文件读取密钥
|
||||||
|
byte[] keyBytes = Files.readAllBytes(keyfile.toPath());
|
||||||
|
String algorithm = switch (type) {
|
||||||
|
case AES -> "AES";
|
||||||
|
case DES -> "DES";
|
||||||
|
case RSA -> "AES";
|
||||||
|
};
|
||||||
|
SecretKey secretKey = new javax.crypto.spec.SecretKeySpec(keyBytes, algorithm);
|
||||||
|
|
||||||
|
// 读取加密文件内容
|
||||||
|
byte[] encryptedBytes = Files.readAllBytes(file.toPath());
|
||||||
|
|
||||||
|
// 解密
|
||||||
|
byte[] decryptedBytes = decryptBytes(encryptedBytes, secretKey, type);
|
||||||
|
|
||||||
|
// 解密后覆盖写回原文件
|
||||||
|
try (OutputStream os = Files.newOutputStream(file.toPath(),
|
||||||
|
StandardOpenOption.TRUNCATE_EXISTING)) {
|
||||||
|
os.write(decryptedBytes);
|
||||||
|
os.flush();
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
TargetFile = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TargetFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 对字节数据进行解密
|
||||||
|
*
|
||||||
|
* @param data 加密数据
|
||||||
|
* @param key 密钥
|
||||||
|
* @param type 加密类型
|
||||||
|
* @return 解密后的数据
|
||||||
|
*/
|
||||||
|
private static byte[] decryptBytes(byte[] data, SecretKey key, EncryptionType type)
|
||||||
|
throws NoSuchAlgorithmException, NoSuchPaddingException,
|
||||||
|
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
|
||||||
|
String algorithm = switch (type) {
|
||||||
|
case AES -> "AES/ECB/PKCS5Padding";
|
||||||
|
case DES -> "DES/ECB/PKCS5Padding";
|
||||||
|
case RSA -> "AES/ECB/PKCS5Padding";
|
||||||
|
};
|
||||||
|
Cipher cipher = Cipher.getInstance(algorithm);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, key);
|
||||||
|
return cipher.doFinal(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EncryptionType {
|
||||||
|
AES, DES, RSA;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package top.gtb520.java.gnu.java.utils.library;
|
|||||||
|
|
||||||
public class version {
|
public class version {
|
||||||
// 项目的版本信息,不代表实时运行环境
|
// 项目的版本信息,不代表实时运行环境
|
||||||
public static final String VERSION = "1.3";
|
public static final String VERSION = "1.4";
|
||||||
public static final String JAVA_VERSION = "25";
|
public static final String JAVA_VERSION = "25";
|
||||||
public static final String OpenJDK_VERSION = "25.0.0.0.1";
|
public static final String OpenJDK_VERSION = "25.0.0.0.1";
|
||||||
public static final String OpenJDK_Runtime_Environment = "25.0.0.0.1+36-GA";
|
public static final String OpenJDK_Runtime_Environment = "25.0.0.0.1+36-GA";
|
||||||
|
|||||||
206
src/test/java/EncryptionAndDecryptionTest.java
Normal file
206
src/test/java/EncryptionAndDecryptionTest.java
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import top.gtb520.java.gnu.java.utils.library.utils.file.EncryptionAndDecryption;
|
||||||
|
import top.gtb520.java.gnu.java.utils.library.utils.file.EncryptionAndDecryption.EncryptionType;
|
||||||
|
|
||||||
|
public class EncryptionAndDecryptionTest {
|
||||||
|
|
||||||
|
static int passCount = 0;
|
||||||
|
static int failCount = 0;
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
System.out.println("========== EncryptionAndDecryption 测试开始 ==========");
|
||||||
|
|
||||||
|
// 正常场景:AES 加密/解密
|
||||||
|
testEncryptDecryptAES();
|
||||||
|
// 正常场景:DES 加密/解密
|
||||||
|
testEncryptDecryptDES();
|
||||||
|
// 正常场景:RSA 加密/解密
|
||||||
|
testEncryptDecryptRSA();
|
||||||
|
// 正常场景:验证密钥文件生成
|
||||||
|
testKeyFileGenerated();
|
||||||
|
// 正常场景:加密后文件内容发生变化
|
||||||
|
testFileContentChangedAfterEncrypt();
|
||||||
|
|
||||||
|
// 异常场景:file 为 null
|
||||||
|
testNullFile();
|
||||||
|
// 异常场景:keyPath 为 null
|
||||||
|
testNullKeyPath();
|
||||||
|
// 异常场景:keyfile 为 null(解密)
|
||||||
|
testNullKeyFile();
|
||||||
|
// 异常场景:文件不存在
|
||||||
|
testFileNotExist();
|
||||||
|
// 异常场景:密钥文件不存在(解密)
|
||||||
|
testKeyFileNotExist();
|
||||||
|
|
||||||
|
System.out.println("========== 测试结果 ==========");
|
||||||
|
System.out.println("通过: " + passCount);
|
||||||
|
System.out.println("失败: " + failCount);
|
||||||
|
System.out.println("总计: " + (passCount + failCount));
|
||||||
|
|
||||||
|
if (failCount > 0) {
|
||||||
|
System.out.println("存在失败的测试用例!");
|
||||||
|
System.exit(1);
|
||||||
|
} else {
|
||||||
|
System.out.println("全部测试通过!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建临时测试文件并写入测试内容
|
||||||
|
*/
|
||||||
|
static File createTempFile(String prefix) throws Exception {
|
||||||
|
Path tempDir = Files.createTempDirectory("enc_test_");
|
||||||
|
File tempFile = tempDir.resolve(prefix + ".txt").toFile();
|
||||||
|
Files.writeString(tempFile.toPath(), "Hello, EncryptionAndDecryption Test! 测试内容123");
|
||||||
|
return tempFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建临时密钥目录
|
||||||
|
*/
|
||||||
|
static Path createTempKeyPath() throws Exception {
|
||||||
|
return Files.createTempDirectory("enc_key_");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertEquals(Object expected, Object actual, String testName) {
|
||||||
|
if (expected == null && actual == null) {
|
||||||
|
passCount++;
|
||||||
|
System.out.println("[PASS] " + testName);
|
||||||
|
} else if (expected != null && expected.equals(actual)) {
|
||||||
|
passCount++;
|
||||||
|
System.out.println("[PASS] " + testName);
|
||||||
|
} else {
|
||||||
|
failCount++;
|
||||||
|
System.out.println("[FAIL] " + testName + " | 期望: " + expected + ", 实际: " + actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertTrue(boolean condition, String testName) {
|
||||||
|
if (condition) {
|
||||||
|
passCount++;
|
||||||
|
System.out.println("[PASS] " + testName);
|
||||||
|
} else {
|
||||||
|
failCount++;
|
||||||
|
System.out.println("[FAIL] " + testName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 正常场景 ====================
|
||||||
|
|
||||||
|
static void testEncryptDecryptAES() throws Exception {
|
||||||
|
String testName = "AES 加密后解密,内容还原";
|
||||||
|
File file = createTempFile("aes_test");
|
||||||
|
Path keyPath = createTempKeyPath();
|
||||||
|
String originalContent = Files.readString(file.toPath());
|
||||||
|
|
||||||
|
File encrypted = EncryptionAndDecryption.EncryptionFile(file, EncryptionType.AES, keyPath);
|
||||||
|
assertTrue(encrypted != null, testName + " - 加密返回非null");
|
||||||
|
|
||||||
|
File keyFile = keyPath.resolve(file.getName() + ".key").toFile();
|
||||||
|
File decrypted = EncryptionAndDecryption.DecryptionFile(file, EncryptionType.AES, keyFile);
|
||||||
|
assertTrue(decrypted != null, testName + " - 解密返回非null");
|
||||||
|
|
||||||
|
String decryptedContent = Files.readString(file.toPath());
|
||||||
|
assertEquals(originalContent, decryptedContent, testName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testEncryptDecryptDES() throws Exception {
|
||||||
|
String testName = "DES 加密后解密,内容还原";
|
||||||
|
File file = createTempFile("des_test");
|
||||||
|
Path keyPath = createTempKeyPath();
|
||||||
|
String originalContent = Files.readString(file.toPath());
|
||||||
|
|
||||||
|
File encrypted = EncryptionAndDecryption.EncryptionFile(file, EncryptionType.DES, keyPath);
|
||||||
|
assertTrue(encrypted != null, testName + " - 加密返回非null");
|
||||||
|
|
||||||
|
File keyFile = keyPath.resolve(file.getName() + ".key").toFile();
|
||||||
|
File decrypted = EncryptionAndDecryption.DecryptionFile(file, EncryptionType.DES, keyFile);
|
||||||
|
assertTrue(decrypted != null, testName + " - 解密返回非null");
|
||||||
|
|
||||||
|
String decryptedContent = Files.readString(file.toPath());
|
||||||
|
assertEquals(originalContent, decryptedContent, testName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testEncryptDecryptRSA() throws Exception {
|
||||||
|
String testName = "RSA 加密后解密,内容还原";
|
||||||
|
File file = createTempFile("rsa_test");
|
||||||
|
Path keyPath = createTempKeyPath();
|
||||||
|
String originalContent = Files.readString(file.toPath());
|
||||||
|
|
||||||
|
File encrypted = EncryptionAndDecryption.EncryptionFile(file, EncryptionType.RSA, keyPath);
|
||||||
|
assertTrue(encrypted != null, testName + " - 加密返回非null");
|
||||||
|
|
||||||
|
File keyFile = keyPath.resolve(file.getName() + ".key").toFile();
|
||||||
|
File decrypted = EncryptionAndDecryption.DecryptionFile(file, EncryptionType.RSA, keyFile);
|
||||||
|
assertTrue(decrypted != null, testName + " - 解密返回非null");
|
||||||
|
|
||||||
|
String decryptedContent = Files.readString(file.toPath());
|
||||||
|
assertEquals(originalContent, decryptedContent, testName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testKeyFileGenerated() throws Exception {
|
||||||
|
String testName = "加密后密钥文件正确生成";
|
||||||
|
File file = createTempFile("key_test");
|
||||||
|
Path keyPath = createTempKeyPath();
|
||||||
|
|
||||||
|
EncryptionAndDecryption.EncryptionFile(file, EncryptionType.AES, keyPath);
|
||||||
|
|
||||||
|
File keyFile = keyPath.resolve(file.getName() + ".key").toFile();
|
||||||
|
assertTrue(keyFile.exists(), testName + " - 密钥文件存在");
|
||||||
|
assertTrue(keyFile.length() > 0, testName + " - 密钥文件非空");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testFileContentChangedAfterEncrypt() throws Exception {
|
||||||
|
String testName = "加密后文件内容与原文不同";
|
||||||
|
File file = createTempFile("content_test");
|
||||||
|
Path keyPath = createTempKeyPath();
|
||||||
|
byte[] originalBytes = Files.readAllBytes(file.toPath());
|
||||||
|
|
||||||
|
EncryptionAndDecryption.EncryptionFile(file, EncryptionType.AES, keyPath);
|
||||||
|
|
||||||
|
byte[] encryptedBytes = Files.readAllBytes(file.toPath());
|
||||||
|
assertTrue(!java.util.Arrays.equals(originalBytes, encryptedBytes), testName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 异常场景 ====================
|
||||||
|
|
||||||
|
static void testNullFile() throws Exception {
|
||||||
|
String testName = "file 为 null 时加密返回 null";
|
||||||
|
Path keyPath = createTempKeyPath();
|
||||||
|
File result = EncryptionAndDecryption.EncryptionFile(null, EncryptionType.AES, keyPath);
|
||||||
|
assertEquals(null, result, testName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testNullKeyPath() throws Exception {
|
||||||
|
String testName = "keyPath 为 null 时加密返回 null";
|
||||||
|
File file = createTempFile("null_keypath");
|
||||||
|
File result = EncryptionAndDecryption.EncryptionFile(file, EncryptionType.AES, null);
|
||||||
|
assertEquals(null, result, testName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testNullKeyFile() throws Exception {
|
||||||
|
String testName = "keyfile 为 null 时解密返回 null";
|
||||||
|
File file = createTempFile("null_keyfile");
|
||||||
|
File result = EncryptionAndDecryption.DecryptionFile(file, EncryptionType.AES, null);
|
||||||
|
assertEquals(null, result, testName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testFileNotExist() throws Exception {
|
||||||
|
String testName = "文件不存在时加密返回 null";
|
||||||
|
Path keyPath = createTempKeyPath();
|
||||||
|
File notExist = new File("non_existent_file_12345.txt");
|
||||||
|
File result = EncryptionAndDecryption.EncryptionFile(notExist, EncryptionType.AES, keyPath);
|
||||||
|
assertEquals(null, result, testName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testKeyFileNotExist() throws Exception {
|
||||||
|
String testName = "密钥文件不存在时解密返回 null";
|
||||||
|
File file = createTempFile("no_keyfile");
|
||||||
|
File notExistKey = new File("non_existent_key_12345.key");
|
||||||
|
File result = EncryptionAndDecryption.DecryptionFile(file, EncryptionType.AES, notExistKey);
|
||||||
|
assertEquals(null, result, testName);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user