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

2023-02-05 12:58:22

 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语句。

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



  • 作者:xiaobai_ol
  • 原文链接:https://blog.csdn.net/xiaobai_ol/article/details/75091251
    更新时间:2023-02-05 12:58:22