【开发实践】使用AES算法加密 .sql文件

一、需求分析

笔者在开发遇到一个小需求,导出数据的sql文件,由于安全监管的需要,对sql文件进行加密处理。实现将sql文件进行加密,最终呈现如下效果:

【开发实践】使用AES算法加密 .sql文件_第1张图片

二、加密文件

1、加密模块

    /**
     * AES加密算法
     *
     * @param sourceFilePath    文件路径
     * @param encryptedFilePath 目标文件路径
     * @param secretKey         密钥
     */
    public static void encrypt(String sourceFilePath, String encryptedFilePath, String secretKey) {
        try {
            // 生成密钥
            Key key = generateKey(secretKey);

            // 初始化加密器
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, key);

            // 读取文件内容
            int index = 0;
            // 读取文件内容
            List somwFileData = getSomwFileData(sourceFilePath);
            for (byte[] bytes : somwFileData) {
                // 加密文件
                byte[] outputBytes = cipher.doFinal(bytes);
                // 保存加密后的文件
                FileOutputStream fos = new FileOutputStream(encryptedFilePath + "\\" + fileName[index++]);
                fos.write(outputBytes);
                fos.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 笔者的文件分块:

【开发实践】使用AES算法加密 .sql文件_第2张图片

 完整加密解密类 代码:

package util;


import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.Key;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author : 枫蜜柚子茶
 * @date : 2023/11/7
 */
public class FileEncryption {

    //自己导出文件的名称数组
    private static String[] fileName = {"f1", "f2", "f3", "f4", "f5", "f6"};

    /**
     * 设置文件路径
     */
    public static void setFileList(String[] strings) {
        fileName = strings;
    }

    /**
     * 获取文件的字节数据
     *
     * @param sourceFilePath 文件路径
     * @param cipher         加密器
     * @return 字节数据
     */
    private static byte[] getAllFileData(String sourceFilePath, Cipher cipher) throws IOException, IllegalBlockSizeException, BadPaddingException {
        List res = new ArrayList<>();
        for (String s : fileName) {
            File file = new File(sourceFilePath + s);
            if (file.exists()) {
                FileInputStream fis = new FileInputStream(file);
                byte[] inputBytes = new byte[(int) fis.available()];
                fis.read(inputBytes);
                fis.close();
                res.add(cipher.doFinal(inputBytes));
            }
        }
        return concatAll(res);
    }

    /**
     * 获取文件的分片字节数据
     *
     * @param sourceFilePath 文件路径
     * @return 字节数据
     */
    private static List getSomwFileData(String sourceFilePath) throws IOException, IllegalBlockSizeException, BadPaddingException {
        FileInputStream fis = new FileInputStream(new File(sourceFilePath));
        byte[] inputBytes = new byte[(int) fis.available()];
        fis.read(inputBytes);
        fis.close();
        //加密数据
        return splitArr(inputBytes, fileName.length);
    }

    /**
     * 合并字节数据
     *
     * @param list 字节数组
     * @return 单个字节数组
     */
    private static byte[] concatAll(List list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        int totalLength = 0;
        for (byte[] bytes : list) {
            totalLength += bytes.length;
        }
        byte[] result = Arrays.copyOf(list.get(0), totalLength);
        int offset = list.get(0).length;
        for (int i = 1; i < list.size(); i++) {
            byte[] array = list.get(i);
            System.arraycopy(array, 0, result, offset, array.length);
            offset += array.length;
        }
        return result;
    }

    /**
     * 对字节数组进行分片
     *
     * @param array 字节数组
     * @param num   分片数量
     * @return 分片数组
     */
    private static List splitArr(byte[] array, int num) {
//        System.out.println(array.length);
        int everySize = array.length / num;
        List arrayList = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            int index = i * everySize;
            everySize = i != num - 1 ? everySize : array.length - index;
            byte[] arr = new byte[everySize];
            int j = 0;
            while (j < everySize && index < array.length) {
                arr[j] = array[index++];
                j++;
            }
            arrayList.add(arr);
        }
        return arrayList;
    }

    /**
     * AES加密算法
     *
     * @param sourceFilePath    文件路径
     * @param encryptedFilePath 目标文件路径
     * @param secretKey         密钥
     */
    public static void encrypt(String sourceFilePath, String encryptedFilePath, String secretKey) {
        try {
            // 生成密钥
            Key key = generateKey(secretKey);

            // 初始化加密器
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, key);

            // 读取文件内容
            int index = 0;
            // 读取文件内容
            List somwFileData = getSomwFileData(sourceFilePath);
            for (byte[] bytes : somwFileData) {
                // 加密文件
                byte[] outputBytes = cipher.doFinal(bytes);
                // 保存加密后的文件
                FileOutputStream fos = new FileOutputStream(encryptedFilePath + "\\" + fileName[index++]);
                fos.write(outputBytes);
                fos.close();
            }
//            System.out.println("文件加密成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * AES解密算法
     *
     * @param sourceFilePath    文件路径
     * @param decryptedFilePath 目标文件路径
     * @param secretKey         密钥
     */
    public static void decrypt(String sourceFilePath, String decryptedFilePath, String secretKey) {
        try {
            // 生成密钥
            Key key = generateKey(secretKey);

            // 初始化加密器
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, key);

            // 读取文件内容
            byte[] allFileData = getAllFileData(sourceFilePath, cipher);
            // 加密文件
//            byte[] outputBytes = cipher.doFinal(allFileData);
            // 保存加密后的文件
            FileOutputStream fos = new FileOutputStream(decryptedFilePath);
            fos.write(allFileData);
            fos.close();
//            System.out.println("文件解密成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 密钥对象
     *
     * @param secretKey 密钥
     * @return 对象
     */
    private static Key generateKey(String secretKey) throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128);
        SecretKey key = new SecretKeySpec(secretKey.getBytes(), "AES");
        return key;
    }
}

三、解密文件

解密算法已在完整代码中呈现,这里不在赘述。

解密器的图形化界面代码:

import config.SystemConfig;
import util.FileEncryption;
import util.FileNameCheck;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.*;

/**
 * @author : 枫蜜柚子茶
 * @date : 2023/11/8
 */
public class EncryptFrame extends JFrame {

    // 定义组件
    JPanel jp1, jp2, jp4;
    JLabel label;
    JButton start, reset, scanFile;
    JTextField textField;
    //当前文件类
    File curr;

    // 构造函数
    public EncryptFrame() {

        EncryptFrame encryptFrame = this;

        jp1 = new JPanel();
        jp2 = new JPanel();
        jp4 = new JPanel();

        label = new JLabel("请选择文件:");

        textField = new JTextField(20);// 文本域
        textField.setEnabled(false);
        scanFile = new JButton("浏览");// 钮1

        start = new JButton("开始");
        reset = new JButton("重置");

        //设置布局为4行1列
        GridLayout layout = new GridLayout(4, 1);
        this.setLayout(layout);

        // 加入各个组件
        jp2.add(label);
        jp2.add(textField);
        jp2.add(scanFile);

        jp4.add(start);
        jp4.add(reset);

        // 加入到JFrame
        this.add(jp1);
        this.add(jp2);
        this.add(jp4);

        //设置参数
        this.setSize(500, 260);
        this.setTitle("解密器");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        //使得窗口在屏幕中心显示
        Toolkit kit = Toolkit.getDefaultToolkit();
        Dimension screenSize = kit.getScreenSize();
        this.setBounds((screenSize.width - 500) / 2, (screenSize.height - 260) / 2, 500, 260);
        //获取所选择的文件
        scanFile.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JFileChooser chooser = new JFileChooser();
                chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
                JLabel jLabel = new JLabel();
                chooser.showDialog(jLabel, "选择");
                curr = chooser.getSelectedFile();
                if (curr != null) {
                    textField.setText(curr.getAbsoluteFile().toString());
                }
            }
        });
        //重置当前选择文件
        reset.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                textField.setText("");
            }
        });
        //开始处理数据
        start.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    String sourcePath = textField.getText() + "\\";
                    Date date = new Date();
                    SimpleDateFormat format = new SimpleDateFormat("yy年MM月dd日");
                    String decryptedFilePath = "sql\\" + format.format(date) + "数据文件.sql";
//                    System.out.println(sourcePath);
                    if (sourcePath == null || "".equals(sourcePath)) {
                        JOptionPane.showMessageDialog(encryptFrame, "文件路径不能为空!", "警告", JOptionPane.WARNING_MESSAGE);
                    } else if (!curr.exists()) {
                        JOptionPane.showMessageDialog(encryptFrame, "当前文件或者文件夹不存在!", "警告", JOptionPane.WARNING_MESSAGE);
                    } else if (curr.isFile()) {
                        JOptionPane.showMessageDialog(encryptFrame, "请选择文件夹!", "警告", JOptionPane.WARNING_MESSAGE);
                    } else if (curr.listFiles() == null || curr.listFiles().length == 0) {
                        JOptionPane.showMessageDialog(encryptFrame, "该文件夹为空!", "警告", JOptionPane.WARNING_MESSAGE);
                    } else {
                        //遍历当前文件夹下的文件
                        File[] files = curr.listFiles();
                        //收集文件名
                        Set fileName = new HashSet<>();
                        for (File file : files) {
                            fileName.add(file.getName());
                        }
                        if (!FileNameCheck.checkFileName(fileName)) {
                            JOptionPane.showMessageDialog(encryptFrame, "文件不符合解密对象要求!", "警告", JOptionPane.WARNING_MESSAGE);
                        } else {
                            File target = new File("sql");
                            if (!target.exists()) {
                                target.mkdirs();
                            }
                            FileEncryption.decrypt(sourcePath, decryptedFilePath, SystemConfig.secretKey);
                            JOptionPane.showMessageDialog(encryptFrame, "解密成功,已导出到当前文件夹下!", "成功", JOptionPane.INFORMATION_MESSAGE);
                        }
                    }
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(encryptFrame, "导出错误!", "失败", JOptionPane.ERROR_MESSAGE);
                }
            }
        });

    }
}

【运行结果】 

【开发实践】使用AES算法加密 .sql文件_第3张图片

【开发实践】使用AES算法加密 .sql文件_第4张图片

成功将6个乱码文件解密为 .sql文件。

【开发实践】使用AES算法加密 .sql文件_第5张图片

你可能感兴趣的:(算法,java,sql)