SQlite數(shù)據(jù)庫(kù)的加密與解密

一 關(guān)于SQlite

Android系統(tǒng)自帶的SQlite是明文存儲(chǔ),不支持加密

二 SQlite加密方式

  1. 內(nèi)容加密
    主要寫入讀取數(shù)據(jù)時(shí)候做加密與解密的動(dòng)作
    缺點(diǎn):
    • 表結(jié)構(gòu)暴露
    • 無(wú)法直接搜索
  2. 數(shù)據(jù)庫(kù)文件加密
    對(duì)整個(gè)數(shù)據(jù)庫(kù)文件加密

三 采用開源的SQLCipher進(jìn)行加密

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

3.1 對(duì)Android原生的數(shù)據(jù)庫(kù)進(jìn)行加密

(1)導(dǎo)入SQLCipher加密庫(kù)

    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庫(kù)

SQLiteDatabase.loadLibs(this); 

(4)獲取讀寫對(duì)象時(shí)候附帶密碼

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

3.2 對(duì)第三方DbFlow數(shù)據(jù)庫(kù)進(jìn)行加密

(1)替換為DbFlow加密庫(kù)

    // 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 對(duì)未加密數(shù)據(jù)庫(kù)的轉(zhuǎn)換為加密的數(shù)據(jù)庫(kù)

在加載SQLCipher所需要的SO庫(kù)后及SQLiteDatabase.loadLibs(this)后,調(diào)用以下加密方法

/**
 * 對(duì)未加密的數(shù)據(jù)庫(kù)文件做加密處理
 *
 * @param ctxt       上下文
 * @param dbName     數(shù)據(jù)庫(kù)的文件名
 * @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 對(duì)加密數(shù)據(jù)庫(kù)的保存為未加密的數(shù)據(jù)庫(kù)文件

/**
     * 將加密數(shù)據(jù)庫(kù)文件保存為非加密的數(shù)據(jù)庫(kù)文件
     *
     * @param context  上下文
     * @param dbName   數(shù)據(jù)庫(kù)名
     * @param password 密碼
     * @param decFile  待保存的目標(biāo)文件
     * @return
     */
    public static boolean decrypt(Context context, String dbName, String password, File decFile) {
        boolean flag = false;
        //先清空目標(biāo)文件
        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();
    }

參考:http://www.itdecent.cn/p/733da189199b

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容