使用I/O流实现文件加密小工具

时间:2023-01-16 14:01:26

效果展示

使用I/O流实现文件加密小工具使用I/O流实现文件加密小工具

代码展示

package com.xy;


import java.io.*;
import java.util.Objects;
import java.util.Scanner;

/**
 * @author 谢阳
 * @version 1.8.0_131
 * @date 2023/1/15 23:07
 * @description
 */
public class FileEncryptionApp {
    private static final byte[] IS_CODED = new byte[4]; // 默认解密校验码
    private static Integer mode; // 模式选择 1 加密 2解密
    private static Scanner scanner = new Scanner(System.in);
    private static String destName;

    static {
        IS_CODED[0] = 2;
        IS_CODED[1] = 0;
        IS_CODED[2] = 2;
        IS_CODED[3] = 3;
    }

    public static void main(String[] args) throws IOException {
        showMenu();
    }

    /**
     * 菜单展示
     *
     * @throws IOException
     */
    private static void showMenu() throws IOException {
        boolean loop = true;
        while (loop) {
            System.out.println("----------------文件加密、解密小程序---------------");
            System.out.println("\t\t\t\t\t1 文件加密");
            System.out.println("\t\t\t\t\t2 文件解密");
            System.out.println("\t\t\t\t\t3 退出");
            System.out.println("-----------------------------------------------");
            System.out.print("请输入您的选择:");
            char key = scanner.next().charAt(0);
            switch (key) {
                case '1':
                    System.out.print("请输入需加密文件路径:");
                    String enCodePath = scanner.next();
                    System.out.print("请输入文件的加密密码:");
                    String enCodePassword = scanner.next();
                    System.out.println(enCode(enCodePath, enCodePassword) ? "加密成功,文件路径为:" + destName : "加密失败");
                    break;
                case '2':
                    System.out.print("请输入需解密文件路径:");
                    String unCodePath = scanner.next();
                    System.out.print("请输入文件的解密密码:");
                    String unCodePassword = scanner.next();
                    System.out.println(unCode(unCodePath, unCodePassword) ? "解密成功,文件路径为:" + destName : "解密失败");
                    break;
                case '3':
                    System.out.println("退出程序成功,欢迎您的再次使用~");
                    loop = false;
                    break;
                default:
                    System.out.println("您的输入有误,请重新输入:)");
            }
        }


    }


    /**
     * 文件加密
     *
     * @param path     文件路径
     * @param password 加密文件密钥
     * @return 是否加密成功 (true/false)
     */
    private static boolean enCode(String path, String password) throws IOException {

        if (!checkPathAndPassword(path, password)) {
            return false;
        }

        // 加密后的文件名
        destName = path.substring(0, path.lastIndexOf(".")) + "-coded" + path.substring(path.lastIndexOf("."));

        try (
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destName))
        ) {
            bos.write(IS_CODED);// 写入默认加密密钥
            byte[] passwordBytes = password.getBytes();
            for (int i = 0; i < passwordBytes.length; i++) {
                passwordBytes[i] ^= password.hashCode();
            }
            bos.write(passwordBytes); // 写入用户加密密钥

            byte[] buf = new byte[1024];
            int len;
            int keyHash = password.hashCode(); // 加密hash值
            long length = new File(path).length() % 10; // 文件长度
            while ((len = bis.read(buf)) != -1) {
                // 加密
                for (int i = 0; i < len; i++) {
                    //buf[i] ^= keyHash;
                    buf[i] = (byte) ((buf[i] ^ keyHash) + length);
                }
                bos.write(buf, 0, len);
            }
        }

        return true;
    }

    /**
     * 文件解密
     *
     * @param path     文件路径
     * @param password 解密文件密钥
     * @return 是否解密成功 (true/false)
     */
    private static boolean unCode(String path, String password) throws IOException {
        if (!checkPathAndPassword(path, password)) {
            return false;
        }

        if (new File(path).length() < IS_CODED.length + password.getBytes().length) {
            System.out.println("该文件不属于加密文件");
            return false;
        }

        // 解密后的文件名
        destName = path.substring(0, path.lastIndexOf(".")) + "-unCode" + path.substring(path.lastIndexOf("."));

        try (
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
        ) {
            // 验证默认密钥和用户密钥是否正确
            if (!checkCodeAndPassword(bis, password)) {
                return false;
            }


            byte[] buf = new byte[1024];
            int len;
            int keyHash = password.hashCode(); // 解密hash值
            // 长度为上一次文件长度
            long length = (new File(path).length() - password.getBytes().length - IS_CODED.length) % 10;

            try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destName))) {
                while ((len = bis.read(buf)) != -1) {
                    // 解密
                    for (int i = 0; i < len; i++) {
                        //buf[i] ^= keyHash;
                        buf[i] = (byte) ((buf[i] - length) ^ keyHash);
                    }

                    bos.write(buf, 0, len);
                }
            }

        }
        return true;
    }


    /**
     * 验证默认密钥和用户密钥是否正确
     *
     * @param bis
     * @param password 用户密码
     * @return ture/false
     */
    private static boolean checkCodeAndPassword(BufferedInputStream bis, String password) throws IOException {
        byte[] codedKey = new byte[IS_CODED.length]; // 默认加密密钥
        bis.read(codedKey);

        // 验证默认密钥
        for (int i = 0; i < IS_CODED.length; i++) {
            if (codedKey[i] != IS_CODED[i]) {
                System.out.println("该文件不属于加密文件");
                return false;
            }
        }

        // 验证用户密钥
        byte[] passwordBytes = password.getBytes();
        byte[] pas = new byte[passwordBytes.length];
        bis.read(pas);
        for (int i = 0; i < passwordBytes.length; i++) {
            if (pas[i] != (byte) (passwordBytes[i] ^ password.hashCode())) {
                System.out.println("文件解密密码错误");
                return false;
            }
        }

        return true;
    }

    /**
     * 文件、文件路径、密钥检测
     *
     * @param path     文件路径
     * @param password 密钥
     * @return 文件是否存在(true/false)
     */
    private static boolean checkPathAndPassword(String path, String password) {
        if (Objects.isNull(path)) {
            System.out.println("文件路径不能为空");
            return false;
        }

        if (Objects.isNull(password)) {
            System.out.println("用户密钥不能为空");
            return false;
        }

        File file = new File(path);
        if (!file.exists()) {
            System.out.println("该路径不在在,请检查文件路径是否存在");
            return false;
        }
        if (!file.isFile()) {
            System.out.println("该路径不是文件,请输入文件名");
            return false;
        }

        if (!file.getName().contains(".")) {
            System.out.println("不知此该文件格式");
            return false;
        }

        return true;
    }

}