Android加密已有的sqlite数据库---sqlcipher

来源:互联网 发布:mac 命令行卸载软件 编辑:程序博客网 时间:2024/06/07 01:00

 android中数据库的加密,通过百度都可以看到,大多都使用的是sqlcipher,好处之一是因为:1.它是开源的,免费的。2.它的运用非常简单,方便,跟sqlite的操作一样,只不过是换成了sqlcipher的包而已。

好的,废话不多说,网上的文章加密数据库,基本上都是新建一个数据库,而对已有的数据库进行加密,却少之又少。我找了好半天,也才找到下面两篇,大家可以作为参考。

文章1

文章2

这里说一下思路:加密已有的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语句。

上面只给出了主要的代码,查询应该也放到子线程中等写的不规范,见谅。