美文网首页安卓数据库&数据存储
SQlite数据库的加密与解密

SQlite数据库的加密与解密

作者: sunny_ke_ke | 来源:发表于2018-01-04 11:20 被阅读2540次

    一 关于SQlite

    Android系统自带的SQlite是明文存储,不支持加密

    二 SQlite加密方式

    1. 内容加密
      主要写入读取数据时候做加密与解密的动作
      缺点:
      • 表结构暴露
      • 无法直接搜索
    2. 数据库文件加密
      对整个数据库文件加密

    三 采用开源的SQLCipher进行加密

    SQLCipher使用256-bit AES加密,由于其基于免费版的SQLite,主要的加密接口和SQLite是相同的,但也增加了一些自己的接口

    3.1 对Android原生的数据库进行加密

    (1)导入SQLCipher加密库

        compile "net.zetetic:android-database-sqlcipher:3.5.9@aar"
    

    (2)替换原生的包

    * android.database.Cursor 为 net.sqlcipher.Cursor
    * android.database.sqlite.SQLiteDatabase 为 net.sqlcipher.database.SQLiteDatabase
    * android.database.SQLiteOpenHelper 为 net.sqlcipher.database.SQLiteOpenHelper
    

    (3)加载SQLCipher所需要的SO库

    SQLiteDatabase.loadLibs(this); 
    

    (4)获取读写对象时候附带密码

    SQLiteOpenHelper.getWritableDatabase("密码"):
    SQLiteOpenHelper.getReadableDatabase("密码")
    

    3.2 对第三方DbFlow数据库进行加密

    (1)替换为DbFlow加密库

        // sql-cipher database encryption (optional)
        compile "com.github.Raizlabs.DBFlow:dbflow-sqlcipher:${dbflow_version}"
        compile "net.zetetic:android-database-sqlcipher:${sqlcipher_version}@aar"
    

    (2)更改初始化的方法

        FlowManager.init(FlowConfig.builder(this)
                    .addDatabaseConfig(DatabaseConfig.builder(QiDatabase.class)
                            .openHelper(new DatabaseConfig.OpenHelperCreator() {
                                @Override
                                public OpenHelper createHelper(DatabaseDefinition databaseDefinition, DatabaseHelperListener helperListener) {
                                    return new SQLCipherOpenHelper(databaseDefinition, helperListener) {
                                        @Override
                                        protected String getCipherSecret() {
                                            return "密码";
                                        }
                                    };
                                }
                            })
                            .build())
                    .build());
    

    3.3 对未加密数据库的转换为加密的数据库

    在加载SQLCipher所需要的SO库后及SQLiteDatabase.loadLibs(this)后,调用以下加密方法

    /**
     * 对未加密的数据库文件做加密处理
     *
     * @param ctxt       上下文
     * @param dbName     数据库的文件名
     * @param passphrase 密码
     * @throws IOException
     */
    public static void encrypt(Context ctxt, String dbName, String passphrase) throws IOException {
            File originalFile = ctxt.getDatabasePath(dbName);
    
            if (originalFile.exists()) {
                File newFile =
                        File.createTempFile("sqlcipherutils", "tmp",
                                ctxt.getCacheDir());
                SQLiteDatabase db =
                        SQLiteDatabase.openDatabase(originalFile.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 = SQLiteDatabase.openDatabase(newFile.getAbsolutePath(),
                        passphrase, null,
                        SQLiteDatabase.OPEN_READWRITE);
                db.setVersion(version);
                db.close();
    
                originalFile.delete();
                newFile.renameTo(originalFile);
            }
    }
    

    3.4 对加密数据库的保存为未加密的数据库文件

    /**
         * 将加密数据库文件保存为非加密的数据库文件
         *
         * @param context  上下文
         * @param dbName   数据库名
         * @param password 密码
         * @param decFile  待保存的目标文件
         * @return
         */
        public static boolean decrypt(Context context, String dbName, String password, File decFile) {
            boolean flag = false;
            //先清空目标文件
            decFile.delete();
    
            try {
                File originalFile = context.getDatabasePath(dbName);
                SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(originalFile, password, null);
    
                if (database.isOpen()) {
                    database.rawExecSQL(String.format("ATTACH DATABASE '%s' as plaintext KEY '';", decFile.getAbsolutePath()));
                    database.rawExecSQL("SELECT sqlcipher_export('plaintext');");
                    database.rawExecSQL("DETACH DATABASE plaintext;");
                    android.database.sqlite.SQLiteDatabase sqlDB = android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(decFile, null);
                    if (sqlDB != null)
                        flag = true;
                    sqlDB.close();
                    database.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return flag;
            // databaseFile.delete();
        }
    

    参考:https://www.jianshu.com/p/733da189199b

    相关文章

      网友评论

        本文标题:SQlite数据库的加密与解密

        本文链接:https://www.haomeiwen.com/subject/grfrnxtx.html