利用SQLCipher加解密資料庫(包括加解密已有的資料庫)
阿新 • • 發佈:2019-02-19
1、介紹
SQLCipher是一個在SQLite基礎之上進行擴充套件的開源資料庫,它主要是在SQLite的基礎之上增加了資料加密功能,如果我們在專案中使用它來儲存資料的話,就可以大大提高程式的安全性。SQLCipher支援很多種不同的平臺,這裡僅介紹Android中SQLCipher的用法。SQLCipher官網參見https://www.zetetic.net/sqlcipher/。
網上的很多資料,大都說的是用sqlcipher加密,並通過密碼來開啟資料庫及後續的增刪改查操作等。但這些例子都是新建帶密碼的資料庫,而非對已有的資料庫進行加密和解密。對於已有的未加密的資料庫,顯然有極大的不便。另外一些資料,是通過sqlcipher的命令模式直接改密碼,本人未做嘗試,暫不做評論。基於此,才有瞭如下的專案。
2、利用AndroidStudio新建專案,並以gradle的方式將SQLCipher匯入到我們的專案
在app級別的build.gradle中新增如下程式碼:
dependencies {
compile 'net.zetetic:android-database-sqlcipher:3.5.4@aar'
}
然後,編譯專案即可。 3、專案只有MainActivity.java和activity_main.xml兩個檔案:
然後,編譯專案即可。 3、專案只有MainActivity.java和activity_main.xml兩個檔案:
- 佈局檔案activity_main.xml程式碼如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" tools:context="com.wjk.sqlciphertest.MainActivity"> <Button android:id="@+id/bt_encry" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="加密" /> <Button android:id="@+id/bt_decry" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:text="解密" /> </LinearLayout>
- 接下來在MainActivity.java中編寫加密和解密方法。主要用到SQLiteDatabase.rawExecSQL()和sqlcipher_export()兩個方法。先上程式碼:
package com.***.sqlciphertest; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import net.sqlcipher.database.SQLiteDatabase; import java.io.File; public class MainActivity extends AppCompatActivity { private final String SDcardPath = "/mnt/sdcard/"; private Button mEncryptButton; private Button mDecryptButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SQLiteDatabase.loadLibs(this);//引用SQLiteDatabase的方法之前必須先新增這句程式碼 mEncryptButton = (Button) findViewById(R.id.bt_encry); mDecryptButton = (Button) findViewById(R.id.bt_decry); mEncryptButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { encrypt("encryptedtest.db","test.db","1234"); } }); mDecryptButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { decrypt("encryptedtest.db","decryptedtest.db","1234"); } }); } /** * 加密資料庫 * @param encryptedName 加密後的資料庫名稱 * @param decryptedName 要加密的資料庫名稱 * @param key 密碼 */ private void encrypt(String encryptedName,String decryptedName,String key) { try { File databaseFile = getDatabasePath(SDcardPath + decryptedName); SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "", null);//開啟要加密的資料庫 /*String passwordString = "1234"; //只能對已加密的資料庫修改密碼,且無法直接修改為“”或null的密碼 database.changePassword(passwordString.toCharArray());*/ File encrypteddatabaseFile = getDatabasePath(SDcardPath + encryptedName);//新建加密後的資料庫檔案 //deleteDatabase(SDcardPath + encryptedName); //連線到加密後的資料庫,並設定密碼 database.rawExecSQL(String.format("ATTACH DATABASE '%s' as "+ encryptedName.split("\\.")[0] +" KEY '"+ key +"';", encrypteddatabaseFile.getAbsolutePath())); //輸出要加密的資料庫表和資料到加密後的資料庫檔案中 database.rawExecSQL("SELECT sqlcipher_export('"+ encryptedName.split("\\.")[0] +"');"); //斷開同加密後的資料庫的連線 database.rawExecSQL("DETACH DATABASE "+ encryptedName.split("\\.")[0] +";"); //開啟加密後的資料庫,測試資料庫是否加密成功 SQLiteDatabase encrypteddatabase = SQLiteDatabase.openOrCreateDatabase(encrypteddatabaseFile, key, null); //encrypteddatabase.setVersion(database.getVersion()); encrypteddatabase.close();//關閉資料庫 database.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 解密資料庫 * @param encryptedName 要解密的資料庫名稱 * @param decryptedName 解密後的資料庫名稱 * @param key 密碼 */ private void decrypt(String encryptedName,String decryptedName,String key) { try { File databaseFile = getDatabasePath(SDcardPath + encryptedName); SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databaseFile, key, null); File decrypteddatabaseFile = getDatabasePath(SDcardPath + decryptedName); //deleteDatabase(SDcardPath + decryptedName); //連線到解密後的資料庫,並設定密碼為空 database.rawExecSQL(String.format("ATTACH DATABASE '%s' as "+ decryptedName.split("\\.")[0] +" KEY '';", decrypteddatabaseFile.getAbsolutePath())); database.rawExecSQL("SELECT sqlcipher_export('"+ decryptedName.split("\\.")[0] +"');"); database.rawExecSQL("DETACH DATABASE "+ decryptedName.split("\\.")[0] +";"); SQLiteDatabase decrypteddatabase = SQLiteDatabase.openOrCreateDatabase(decrypteddatabaseFile, "", null); //decrypteddatabase.setVersion(database.getVersion()); decrypteddatabase.close(); database.close(); } catch (Exception e) { e.printStackTrace(); } } }