From c38b8857d5e1acf14e9613bc183f0030834e2e21 Mon Sep 17 00:00:00 2001 From: database-mysql Date: Wed, 12 Aug 2026 03:00:02 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E6=96=B0=E5=A2=9E/=E6=9C=AA=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=20=E6=96=87=E4=BB=B6=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../java/gnu/java/utils/library/main.java | 21 +++++ .../utils/library/utils/file/CreateFile.java | 89 +++++++++++++++++++ .../utils/library/utils/file/Encryption.java | 15 ++++ .../java/gnu/java/utils/library/version.java | 2 +- 5 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/CreateFile.java create mode 100644 src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/Encryption.java diff --git a/pom.xml b/pom.xml index 0fc3426..ad3681b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ top.gtb520.java.gnu gnu_java_utils_library - 1.3-SNAPSHOT + 1.4-SNAPSHOT 25 diff --git a/src/main/java/top/gtb520/java/gnu/java/utils/library/main.java b/src/main/java/top/gtb520/java/gnu/java/utils/library/main.java index 565ffe9..df2cee3 100644 --- a/src/main/java/top/gtb520/java/gnu/java/utils/library/main.java +++ b/src/main/java/top/gtb520/java/gnu/java/utils/library/main.java @@ -2,6 +2,12 @@ package top.gtb520.java.gnu.java.utils.library; 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; + + public interface main { // 压缩包操作相关接口与方法 interface compress { @@ -127,4 +133,19 @@ 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); + } + } + } } diff --git a/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/CreateFile.java b/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/CreateFile.java new file mode 100644 index 0000000..790c192 --- /dev/null +++ b/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/CreateFile.java @@ -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; + } +} diff --git a/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/Encryption.java b/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/Encryption.java new file mode 100644 index 0000000..202bf9a --- /dev/null +++ b/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/Encryption.java @@ -0,0 +1,15 @@ +package top.gtb520.java.gnu.java.utils.library.utils.file; + +import java.io.File; + +public class Encryption { + /*** + * 文件加密 + * + * @param file 文件 + * @param type 加密类型 + */ + public static void EncryptionFile(File file, String type) { + + } +} diff --git a/src/main/java/top/gtb520/java/gnu/java/utils/library/version.java b/src/main/java/top/gtb520/java/gnu/java/utils/library/version.java index 1bdfef8..2e79b66 100644 --- a/src/main/java/top/gtb520/java/gnu/java/utils/library/version.java +++ b/src/main/java/top/gtb520/java/gnu/java/utils/library/version.java @@ -2,7 +2,7 @@ package top.gtb520.java.gnu.java.utils.library; 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 OpenJDK_VERSION = "25.0.0.0.1"; public static final String OpenJDK_Runtime_Environment = "25.0.0.0.1+36-GA"; -- 2.49.1 From e31384a848ccac9e13a6a1a4e3f28489a4429516 Mon Sep 17 00:00:00 2001 From: database-mysql Date: Wed, 12 Aug 2026 03:09:26 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=96=B0=E5=A2=9E/=E6=9C=AA=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=20=E6=96=87=E4=BB=B6=E5=8A=A0=E8=A7=A3=E5=AF=86?= =?UTF-8?q?=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/library/utils/file/Encryption.java | 15 -- .../utils/file/EncryptionAndDecryption.java | 198 ++++++++++++++++++ 2 files changed, 198 insertions(+), 15 deletions(-) delete mode 100644 src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/Encryption.java create mode 100644 src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/EncryptionAndDecryption.java diff --git a/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/Encryption.java b/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/Encryption.java deleted file mode 100644 index 202bf9a..0000000 --- a/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/Encryption.java +++ /dev/null @@ -1,15 +0,0 @@ -package top.gtb520.java.gnu.java.utils.library.utils.file; - -import java.io.File; - -public class Encryption { - /*** - * 文件加密 - * - * @param file 文件 - * @param type 加密类型 - */ - public static void EncryptionFile(File file, String type) { - - } -} diff --git a/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/EncryptionAndDecryption.java b/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/EncryptionAndDecryption.java new file mode 100644 index 0000000..9073c80 --- /dev/null +++ b/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/EncryptionAndDecryption.java @@ -0,0 +1,198 @@ +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.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 { + /*** + * 文件加密 + * 异步执行加密操作 + * 加密后的文件保存为原文件名加 .enc 后缀,位于同目录下 + * + * @param file 文件 + * @param type 加密类型 + * @return 加密后的文件,失败时返回 null + */ + public static File EncryptionFile(File file, EncryptionType type) { + File TargetFile = null; + + if (file == null || !file.exists() || !file.isFile()) { + return null; + } + + try { + TargetFile = CompletableFuture.supplyAsync(() -> { + try { + // 读取原文件内容 + byte[] plainBytes = Files.readAllBytes(file.toPath()); + + // 根据加密类型生成对称密钥 + SecretKey secretKey = generateSecretKey(type); + byte[] encryptedBytes = encryptBytes(plainBytes, secretKey, type); + + // 写入加密后的文件,文件格式:[1字节密钥长度][密钥字节][加密数据] + byte[] keyBytes = secretKey.getEncoded(); + String encryptedFileName = file.getName() + ".enc"; + File encryptedFile = new File(file.getParentFile(), encryptedFileName); + try (OutputStream os = Files.newOutputStream(encryptedFile.toPath(), + StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + os.write(keyBytes.length); + os.write(keyBytes); + os.write(encryptedBytes); + os.flush(); + } + return encryptedFile; + } 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); + } + + /*** + * 文件解密 + * 异步执行解密操作 + * 解密后的文件去除 .enc 后缀,保存在同目录下 + * + * @param file 加密文件(.enc) + * @param type 加密类型,须与加密时一致 + * @return 解密后的文件,失败时返回 null + */ + public static File DecryptionFile(File file, EncryptionType type) { + File TargetFile = null; + + if (file == null || !file.exists() || !file.isFile()) { + return null; + } + + try { + TargetFile = CompletableFuture.supplyAsync(() -> { + try { + byte[] fileBytes = Files.readAllBytes(file.toPath()); + + // 读取文件头中的密钥长度和密钥 + int keyLength = fileBytes[0] & 0xFF; + byte[] keyBytes = new byte[keyLength]; + System.arraycopy(fileBytes, 1, keyBytes, 0, keyLength); + + // 还原密钥 + String algorithm = switch (type) { + case AES -> "AES"; + case DES -> "DES"; + case RSA -> "AES"; + }; + SecretKey secretKey = new javax.crypto.spec.SecretKeySpec(keyBytes, algorithm); + + // 提取加密数据部分 + byte[] encryptedBytes = new byte[fileBytes.length - 1 - keyLength]; + System.arraycopy(fileBytes, 1 + keyLength, encryptedBytes, 0, encryptedBytes.length); + + byte[] decryptedBytes = decryptBytes(encryptedBytes, secretKey, type); + + // 生成解密后的文件名,去除 .enc 后缀 + String fileName = file.getName(); + String decryptedFileName = fileName.endsWith(".enc") + ? fileName.substring(0, fileName.length() - 4) + : fileName + ".dec"; + File decryptedFile = new File(file.getParentFile(), decryptedFileName); + try (OutputStream os = Files.newOutputStream(decryptedFile.toPath(), + StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + os.write(decryptedBytes); + os.flush(); + } + return decryptedFile; + } 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.49.1 From 9d452ded627eef8227a14ed1cbc87c6fbee14b17 Mon Sep 17 00:00:00 2001 From: database-mysql Date: Wed, 12 Aug 2026 03:43:22 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=8A=A0=E8=A7=A3?= =?UTF-8?q?=E5=AF=86=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/file/EncryptionAndDecryption.java | 74 ++++--- .../java/EncryptionAndDecryptionTest.java | 206 ++++++++++++++++++ 2 files changed, 245 insertions(+), 35 deletions(-) create mode 100644 src/test/java/EncryptionAndDecryptionTest.java diff --git a/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/EncryptionAndDecryption.java b/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/EncryptionAndDecryption.java index 9073c80..e1f0c3a 100644 --- a/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/EncryptionAndDecryption.java +++ b/src/main/java/top/gtb520/java/gnu/java/utils/library/utils/file/EncryptionAndDecryption.java @@ -3,6 +3,7 @@ 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; @@ -19,18 +20,23 @@ public class EncryptionAndDecryption { /*** * 文件加密 * 异步执行加密操作 - * 加密后的文件保存为原文件名加 .enc 后缀,位于同目录下 + * 加密后覆盖原文件,不添加额外后缀 + * 密钥保存到 keyPath 目录下,密钥名为 原文件名.key * * @param file 文件 * @param type 加密类型 - * @return 加密后的文件,失败时返回 null + * @param keyPath 密钥文件目录路径,密钥名为 文件名.key + * @return 加密后的文件(原文件),失败时返回 null */ - public static File EncryptionFile(File file, EncryptionType type) { + 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(() -> { @@ -42,18 +48,23 @@ public class EncryptionAndDecryption { SecretKey secretKey = generateSecretKey(type); byte[] encryptedBytes = encryptBytes(plainBytes, secretKey, type); - // 写入加密后的文件,文件格式:[1字节密钥长度][密钥字节][加密数据] - byte[] keyBytes = secretKey.getEncoded(); - String encryptedFileName = file.getName() + ".enc"; - File encryptedFile = new File(file.getParentFile(), encryptedFileName); - try (OutputStream os = Files.newOutputStream(encryptedFile.toPath(), + // 将密钥写入 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)) { - os.write(keyBytes.length); - os.write(keyBytes); + kos.write(secretKey.getEncoded()); + kos.flush(); + } + + // 加密后覆盖写回原文件 + try (OutputStream os = Files.newOutputStream(file.toPath(), + StandardOpenOption.TRUNCATE_EXISTING)) { os.write(encryptedBytes); os.flush(); } - return encryptedFile; + return file; } catch (Exception e) { return null; } @@ -111,30 +122,28 @@ public class EncryptionAndDecryption { /*** * 文件解密 * 异步执行解密操作 - * 解密后的文件去除 .enc 后缀,保存在同目录下 + * 解密后覆盖写回原文件,不添加额外后缀 * - * @param file 加密文件(.enc) + * @param file 加密文件 * @param type 加密类型,须与加密时一致 - * @return 解密后的文件,失败时返回 null + * @param keyfile 密钥文件,从中读取解密密钥 + * @return 解密后的文件(原文件),失败时返回 null */ - public static File DecryptionFile(File file, EncryptionType type) { + 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[] fileBytes = Files.readAllBytes(file.toPath()); - - // 读取文件头中的密钥长度和密钥 - int keyLength = fileBytes[0] & 0xFF; - byte[] keyBytes = new byte[keyLength]; - System.arraycopy(fileBytes, 1, keyBytes, 0, keyLength); - - // 还原密钥 + // 从密钥文件读取密钥 + byte[] keyBytes = Files.readAllBytes(keyfile.toPath()); String algorithm = switch (type) { case AES -> "AES"; case DES -> "DES"; @@ -142,24 +151,19 @@ public class EncryptionAndDecryption { }; SecretKey secretKey = new javax.crypto.spec.SecretKeySpec(keyBytes, algorithm); - // 提取加密数据部分 - byte[] encryptedBytes = new byte[fileBytes.length - 1 - keyLength]; - System.arraycopy(fileBytes, 1 + keyLength, encryptedBytes, 0, encryptedBytes.length); + // 读取加密文件内容 + byte[] encryptedBytes = Files.readAllBytes(file.toPath()); + // 解密 byte[] decryptedBytes = decryptBytes(encryptedBytes, secretKey, type); - // 生成解密后的文件名,去除 .enc 后缀 - String fileName = file.getName(); - String decryptedFileName = fileName.endsWith(".enc") - ? fileName.substring(0, fileName.length() - 4) - : fileName + ".dec"; - File decryptedFile = new File(file.getParentFile(), decryptedFileName); - try (OutputStream os = Files.newOutputStream(decryptedFile.toPath(), - StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + // 解密后覆盖写回原文件 + try (OutputStream os = Files.newOutputStream(file.toPath(), + StandardOpenOption.TRUNCATE_EXISTING)) { os.write(decryptedBytes); os.flush(); } - return decryptedFile; + return file; } catch (Exception e) { return null; } diff --git a/src/test/java/EncryptionAndDecryptionTest.java b/src/test/java/EncryptionAndDecryptionTest.java new file mode 100644 index 0000000..bed7479 --- /dev/null +++ b/src/test/java/EncryptionAndDecryptionTest.java @@ -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); + } +} -- 2.49.1 From a0d6c6570ff362a31335df3e0c2e2cf2e8b6e7a5 Mon Sep 17 00:00:00 2001 From: database-mysql Date: Wed, 12 Aug 2026 03:50:36 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=8A=A0=E8=A7=A3?= =?UTF-8?q?=E5=AF=86=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gtb520/java/gnu/java/utils/library/main.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/top/gtb520/java/gnu/java/utils/library/main.java b/src/main/java/top/gtb520/java/gnu/java/utils/library/main.java index df2cee3..f23959c 100644 --- a/src/main/java/top/gtb520/java/gnu/java/utils/library/main.java +++ b/src/main/java/top/gtb520/java/gnu/java/utils/library/main.java @@ -6,6 +6,7 @@ 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 { @@ -148,4 +149,16 @@ public interface main { } } } + + // 文件加解密操作 + 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); + } + } } -- 2.49.1