Java加密Sqlite库 及文件

936 阅读2分钟

原因:最近在用Sqlite存储数据,因涉及数据安全,所以需要数据库加密,Sqlite库默认不带加密功能 目前已知的对 SQLite 加密的工具主要有「[SQLite Encryption Extension (SEE)]、[SQLiteEncrypt]、[SQLiteCrypt]、[SQLCipher],但是这里面仅有 SQLCipher 有免费版本。 所以自己有个方案,针对Sqlite无法就是限制不能直接查看,那就对文件进行加密,需要连接的时候进行文件解密就可以了,如果大神有更好的解决方案,请告知,谢谢!

package com.ts.tools;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;

import java.io.*;

/** 加密解密文件
 * @author xhc
 * @version 1.0.0
 * @date 2022-10-31
 */
public class FileEnDe {

    public static void main(String[] args) {
        try {
            //加密密码
            String key="abcdefghijklmnop";
            //FileEnDe.encryptFile("D:/test.db",key,true);
            //FileEnDe.decryptFile("D:/test.db",key);
            System.out.println(FileEnDe.isLocked("D:/sysDb.db"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 加密db文件(理论可以加密任何文件)
     * @param filePath 文件路径
     * @param key16 加密密码(必须16位)
     * @return boolean
     * @throws Exception
     */
    public static boolean encryptFile(String filePath,String key16,boolean isReadOnly){
        FileOutputStream fos =null;
        boolean bFlag=false;
        try {
            if(FileUtil.exist(filePath)) {
                byte[] key = key16.getBytes();
                //取文件名称含后缀
                String fileName=FileUtil.getName(filePath);
                //加密文件
                SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
                FileInputStream fis = new FileInputStream(filePath);
                String newFilePath=filePath+"_e";
                fos=new FileOutputStream(newFilePath);
                aes.encrypt(fis, fos, true);
                fos.close();
                //删除源文件,注意如果文件被使用会报:另一个程序正在使用此文件,进程无法访问
                boolean isDel=FileUtil.del(filePath);
                if(isDel){
                    //重命名加密文件为源文件
                    FileUtil.rename(new File(newFilePath),fileName,true);
                    //设置只读文件
                    if(isReadOnly) {
                        File f=new File(filePath);
                        f.setReadOnly();
                    }
                }
                bFlag=true;
            }else{
                throw new RuntimeException(filePath+" 文件不存在!");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            IoUtil.close(fos);
        }
        return bFlag;
    }

    /**
     * 解密Db库
     * @param filePath 文件路径
     * @param key16 加密密码(必须16位)
     * @return boolean
     * @throws Exception
     */
    public static boolean decryptFile(String filePath,String key16){
        boolean bFlag=false;
        FileOutputStream fos =null;
        try {
            if(FileUtil.exist(filePath)) {
                byte[] key = key16.getBytes();
                //取文件名称含后缀
                String fileName=FileUtil.getName(filePath);
                //解密文件
                SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
                FileInputStream fis = new FileInputStream(filePath);
                String newFilePath=filePath+"_d";
                fos = new FileOutputStream(newFilePath);
                aes.decrypt(fis, fos, true);
                //注意,解密之后 fos 并未关闭,请先关闭
                fos.close();
                //删除源文件,注意如果文件被使用会报:另一个程序正在使用此文件,进程无法访问
                boolean isDel=FileUtil.del(filePath);
                if(isDel){
                    //重命名加密文件为源文件
                    FileUtil.rename(new File(newFilePath),fileName,true);
                }
                bFlag=true;
            }else{
                throw new RuntimeException(filePath+" 文件不存在!");
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(filePath+" 文件不存在!");
        }catch (Exception e){
            throw new RuntimeException(e);
        }finally {
            IoUtil.close(fos);
        }
        return bFlag;
    }

    /**
     * 文件是否占用(采用重命名的方式)
     * @param filePath 文件路径
     * @return boolean
     */
    public static boolean  isLocked(String filePath){
        boolean bFlag=false;
        String newFileName="";
        String fileName="";
        try {
            if(FileUtil.exist(filePath)) {
                // 采用重命名的方式,如果占用无法修改文件名称,如果未占用修改新的文件名称后再修改回来
                fileName = FileUtil.getName(filePath);
                newFileName = fileName + "_n";
                FileUtil.rename(new File(filePath), newFileName, true);
            }
        } catch (Exception e) {
            bFlag=true;
        }finally {
            //如果未占用修改新的文件名称后再修改回来
            if(!bFlag) {
                FileUtil.rename(new File(filePath+"_n"), fileName, true);
            }
        }
        return bFlag;
    }
}