android中数据库的加密,通过百度都可以看到,大多都使用的是sqlcipher,好处之一是因为:1.它是开源的,免费的。2.它的运用非常简单,方便,跟sqlite的操作一样,只不过是换成了sqlcipher的包而已。
好的,废话不多说,网上的文章加密数据库,基本上都是新建一个数据库,而对已有的数据库进行加密,却少之又少。我找了好半天,也才找到下面两篇,大家可以作为参考。
这里说一下思路:加密已有的sqlite数据库,其实是对原有的数据库进行了一份拷贝。只是拷贝后的数据库有了加密功能。拷贝的话就是拷贝原有数据库的表或者数据。这里我选择拷贝表。
使用流程如下(这里以AS开发工具为例):
1.新建android工程,在app的build.gradle中加入如下代码编译代码:
dependencies {
compile 'net.zetetic:android-database-sqlcipher:3.5.7@aar'
}
我这里的sqlcipher版本是3.5.7,具体最新版可以查看 官网
2.等待编译成功后,便可在MainActivity中添加加密函数,这里注意,读取原始数据库和生成新的加密数据库不能在外部SD卡中,具体原因我还不知,我也在mainfest.xml中配置了外部读写权限和代码中书写了运行时权限,也不行。有测试可行或者知道的读者请告诉我哈。下面给出加密和读取加密数据库的函数。还有在读取数据库时路径要取绝对路径,如果是自己定义的路径,会报错(我这里ce's)。
1.MainActivity.java
package com.example.**.sqlclipher;
import android.Manifest;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import net.sqlcipher.database.SQLiteDatabase; //注意导入的包
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final int SUCCESS_ID = 1;
private static final int FAIL_ID = 0;
private Button mEncryptButton;
private Button mDecryptButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 该语句必不可少
SQLiteDatabase.loadLibs(MainActivity.this);
mEncryptButton = (Button) findViewById(R.id.btn_encry);
mDecryptButton = (Button) findViewById(R.id.btn_read);
// 开启按钮点击进行加密
mEncryptButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 开启一个子线程来作为加密的耗时操作
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 这里传入新加密后的数据库名,未加密数据库名,以及加密的密码
encrypt("cliper.db", "origin.db", "key");
}
});
thread.start();
}
});
mDecryptButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//这里因为加密好的数据库放到了/data/data/包名/files/目录下,注意这里取得是绝对路径
String path = MainActivity.this.getFilesDir().getAbsolutePath()
+ File.separator + "encrypted.db";
readClipherData(path, "key");
}
});
}
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case SUCCESS_ID:
Toast.makeText(MainActivity.this, "加密成功", Toast.LENGTH_SHORT).show();
break;
case FAIL_ID:
Toast.makeText(MainActivity.this, "加密失败", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
};
/**
* 加密数据库
*/
private void encrypt(String encryptedName,String decryptedName,String key) {
Message msg = new Message();
try {
File file = new File(getApplication().getDatabasePath(DATA_PATH + encryptedName).getPath());
// 新建加密后的数据库文件,并设置其密码key
SQLiteDatabase dataTarget = SQLiteDatabase.openOrCreateDatabase(MainActivity.this.getFilesDir().getAbsolutePath()
+ File.separator + encryptedName, key, null);
String path = File.separator + "data" + File.separator +decryptedName;
//执行sql语句,连接未加密的数据库,并将其取别名为sourceLib,因为未加密数据库没密码,所以密码为""
dataTarget.execSQL("attach '"+path+"' as sourceLib key '';");
/*String passwordString = "1234"; //只能对已加密的数据库修改密码,且无法直接修改为“”或null的密码
database.changePassword(passwordString.toCharArray());*/
// 执行sql语句,在加密后的数据库文件中新建表,并将未加密的数据库表拷贝到新的加密数据库中,原数据库有多张表,该操作重复多少次
dataTarget.execSQL("create table new_table as select * from sourceLib.table");
//断开同加密后的数据库的连接
dataTarget.execSQL("detach database 'sourceLib'");
dataTarget.close();
msg.what = SUCCESS_ID;
} catch (Exception e) {
msg.what = FAIL_ID;
e.printStackTrace();
}finally {
mHandler.sendMessage(msg);
}
}
/*
*读取加密后的数据
*/
private void readClipherData(String databasePath, String key){
try{
SQLiteDatabase encrypteddatabase = SQLiteDatabase.openOrCreateDatabase(databasePath, key, null);
String[] columns = new String[]{
"*"
};
String sections = "**"; //这里填写查询条件
Cursor cursor = encrypteddatabase.query("wordings", columns, sections, null, null, null, null);
if (cursor == null){
Toast.makeText(MainActivity.this, "未查询到数据", Toast.LENGTH_SHORT).show();
}else {
if (cursor.moveToFirst()) {
do {
String value = cursor.getString(cursor.getColumnIndexOrThrow("value"));
Log.e(TAG, "readClipherData: value = " + value);
} while (cursor.moveToNext());
}
cursor.close();
}
encrypteddatabase.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
其实纵观整个加密过程,就是用sqlcipher包含的方法打开或者建立加密数据库,然后执行相应的sql语句。
上面只给出了主要的代码,查询应该也放到子线程中等写的不规范,见谅。