欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 数据库加密 SQLCipher使用方法

程序员文章站 2022-06-23 15:43:18
android sqlcipher使用方法 最近在做数据库加密,遇到了些问题,特此记录 greendao 支持数据库加密 网址https://greenrobot.org/greendao/doc...

android sqlcipher使用方法

最近在做数据库加密,遇到了些问题,特此记录

greendao 支持数据库加密
网址https://greenrobot.org/greendao/documentation/database-encryption/

sqlcipher 网址:https://www.zetetic.net/sqlcipher/

sqlcipher 如何依赖在android
网址:https://www.zetetic.net/sqlcipher/sqlcipher-for-android/

as依赖 compile ‘net.zetetic:android-database-sqlcipher:3.5.9@aar’

每次在操作数据库前,初始化sqlcipher 所以我放在了application下

sqlitedatabase.loadlibs(appapplication.this);

在操作数据库时与sqlitedatabase 基本一样,唯一的区别就是打开数据库,需要密码 首先打开一个加密的数据库

sqlcipher 打开加密数据库


net.sqlcipher.database.sqlitedatabase  sqlitedatabase = net.sqlcipher.database.sqlitedatabase.opendatabase(file.getabsolutepath(), password, null,
                        sqlitedatabase.open_readwrite
                                | sqlitedatabase.create_if_necessary
                                | sqlitedatabase.no_localized_collators, new sqlitedatabasehook() {
                            @override
                            public void prekey(net.sqlcipher.database.sqlitedatabase sqlitedatabase) {

                            }

                            @override
                            public void postkey(net.sqlcipher.database.sqlitedatabase sqlitedatabase) {
                               //操作数据与 android sqlitedatabase 用法一致
                            }
                        });


//greendao 操作数据库时 用这个方法 打开加密的库
openhelper.getencryptedwritabledb(contents.db_key);
openhelper.getencryptedreadabledb(contents.db_key);

greendao 中结合 sqlcipher 用法:


    /**
     * 获取可读数据库
     */
    private database getreadabledatabase() {
        if (contents.db_release) {
            dbencrypt.getinstences().encrypt(uiutil.getcontext(), contents.db_key);
            return openhelper.getencryptedreadabledb(contents.db_key);
        } else {
            return openhelper.getreadabledb();
        }
    }

    /**
     * 获取可写数据库
     */
    private database getwritabledatabase() {
        if (contents.db_release) {
            dbencrypt.getinstences().encrypt(uiutil.getcontext(), contents.db_key);
            return openhelper.getencryptedwritabledb(contents.db_key);
        } else {
            return openhelper.getreadabledb();
        }
    }

做完后遇到一个尴尬的问题,第一次进去时确实能显示,没毛病,当把进程杀死后在进去,都报错。。。

net.sqlcipher.database.sqliteexception: file is not a database: , while compiling: select count(*) from sqlite_master;

查询多次后发现 是加密 解密时出问题,当数据库原来未加密时用此方法打开,会报错。所以在查询数据之前,先把未加密的数据库加密,再去查询

代码附上:

    /**
     * 加密数据库
     * created by han on 2018/4/10
     * email:yin13753884368@163.com
     * csdn:https://blog.csdn.net/yin13753884368/article
     * github:https://github.com/yin13753884368
     */

    public class dbencrypt {
        public static dbencrypt dbencrypt;
        private boolean isopen = true;

        public static dbencrypt getinstences() {
            if (dbencrypt == null) {
                synchronized (dbencrypt.class) {
                    if (dbencrypt == null) {
                        dbencrypt = new dbencrypt();
                    }
                }
            }
            return dbencrypt;
        }

        /**
         * 如果有旧表 先加密数据库
         *
         * @param context
         * @param passphrase
         */
        public void encrypt(context context, string passphrase) {
            file file = new file("/data/data/" + context.getpackagename() + "/databases/db_name");
            if (file.exists()) {
                if (isopen) {
                    try {
                        file newfile = file.createtempfile("sqlcipherutils", "tmp", context.getcachedir());

                        net.sqlcipher.database.sqlitedatabase db = net.sqlcipher.database.sqlitedatabase.opendatabase(
                                file.getabsolutepath(), "", null, sqlitedatabase.open_readwrite);

                        db.rawexecsql(string.format("attach database '%s' as encrypted key '%s';",
                                newfile.getabsolutepath(), passphrase));
                        db.rawexecsql("select sqlcipher_export('encrypted')");
                        db.rawexecsql("detach database encrypted;");

                        int version = db.getversion();
                        db.close();

                        db = net.sqlcipher.database.sqlitedatabase.opendatabase(newfile.getabsolutepath(),
                                passphrase, null,
                                sqlitedatabase.open_readwrite);

                        db.setversion(version);
                        db.close();
                        file.delete();
                        newfile.renameto(file);
                        isopen = false;
                    } catch (exception e) {
                        isopen = false;
                    }
                }
            }
        }
    }