如何使用 aes 算法加密 sqlite 文件?
Posted
技术标签:
【中文标题】如何使用 aes 算法加密 sqlite 文件?【英文标题】:How to encrypt sqlite file using aes algorithm? 【发布时间】:2022-01-21 08:58:20 【问题描述】:我正在尝试使用 aes 算法加密 sql 文件。我在整个互联网上看到的是只加密字符串数据或使用 sqlite 密码加密数据库中的每个数据。我想使用带有AES算法的android密码术加密数据库中的每个数据,但不添加像SQLiteCipher这样的依赖项。并将密码短语保存在外部存储中的新文件中。可以做到吗?帮帮我
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
import com.example.sqlitepractise.model.Contact;
import com.example.sqlitepractise.params.Params;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import javax.crypto.NoSuchPaddingException;
public class MyDbHandler extends SQLiteOpenHelper
public MyDbHandler(Context context)
super(context, Params.DB_NAME, null, Params.DB_VERSION);
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase)
String create = "CREATE TABLE " + Params.TABLE_NAME + "("
+ Params.KEY_ID + " INTEGER PRIMARY KEY," + Params.KEY_NAME
+ " TEXT, " + Params.KEY_PHONE + " TEXT, " + Params.KEY_SECRET + " TEXT, " + Params.KEY_IV + " TEXT" + ")";
Log.d("practise", "Query being run is : " + create);
sqLiteDatabase.execSQL(create);
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1)
public void addContact(Contact contact)
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
try
values.put(Params.KEY_NAME, contact.getName());
values.put(Params.KEY_PHONE, contact.getPhone_number());
db.insert(Params.TABLE_NAME, null,values);
Log.d("practise", "Successfully inserted");
db.close();
// I wanted the encryption to be executed in this method
catch (Exception e)
e.printStackTrace();
public List<Contact> getAllContact()
// I wanted the decryption to be executed in this method
List<Contact> contactList = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
//Generate the query to read from the database
String select = "SELECT * FROM " + Params.TABLE_NAME;
Cursor cursor = db.rawQuery(select, null);
//Loop Through now
if (cursor.moveToFirst())
do
Contact contact = new Contact();
contact.setId(Integer.parseInt(cursor.getString(0)));
contact.setName(cursor.getString(1));
contact.setPhone_number(cursor.getString(2));
contactList.add(contact);
while (cursor.moveToNext());
return contactList;
private static int READ_WRITE_BLOCK_BUFFER = 1024;
private static String ALGO_FILE_ENCRYPTOR = "AES/CBC/PKCS5Padding";
private final static String ALGO_SECRET_KEY = "AES";
public static void encryptFile(String keyStr, String specStr,
InputStream in, OutputStream out)
throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException,
IOException
try
IvParameterSpec iv = new
IvParameterSpec(specStr.getBytes("UTF-8"));
SecretKeySpec keySpec = new
SecretKeySpec(keyStr.getBytes("UTF-8"), ALGO_SECRET_KEY);
Cipher c = Cipher.getInstance(ALGO_FILE_ENCRYPTOR);
c.init(Cipher.ENCRYPT_MODE,keySpec,iv);
out = new CipherOutputStream(out, c);
int count = 0;
byte[] buffer = new byte[READ_WRITE_BLOCK_BUFFER];
while ((count = in.read(buffer))>0)
out.write(buffer,0,count);
finally
out.close();
【问题讨论】:
I am trying to encrypt the sql file using aes algorithm.
文件就是文件。文件包含什么无关紧要。
encrypting only the string data or encrypting every data inside the database
好吧,您可以这样做,但是您不是在加密文件,而是在加密文件中的数据。加密文件!容易得多。
也许您应该考虑一下您的需求 - 以加密形式存储数据很简单,但数据库旨在将存储的数据返回给用户。如果您尝试找到一个数据集,则需要解密每个数据集,将其与您的搜索模式进行比较,依此类推。通常只有敏感数据(列)需要加密(例如电话号码)。在 Android 上,如果您需要其他依赖项,它取决于目标 sdk-version。
【参考方案1】:
我想加密数据库中的每一个数据......
-
使用你的数据库是不可能的,因为表中包含
Params.KEY_ID + " INTEGER PRIMARY KEY,"
-
您包含注释代码(包含在下面),这表明理论上您要按行加密。
:-
public void addContact(Contact contact)
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
try
values.put(Params.KEY_NAME, contact.getName());
values.put(Params.KEY_PHONE, contact.getPhone_number());
db.insert(Params.TABLE_NAME, null,values);
Log.d("practise", "Successfully inserted");
db.close();
// I wanted the encryption to be executed in this method
catch (Exception e)
e.printStackTrace();
除非您完全加密数据库文件,否则插入一行然后加密是没有用的。因此,考虑到第 1 点以及在行级别加密的明显希望,那么您要么
将数据作为一个整体加密并插入单行或
您单独加密每一列,然后插入加密数据。
-
减少开销并仅加密敏感列是有意义的
选项 2 将是最简单的选项 1,您不仅需要加密/解密的方法,而且还需要连接和拆分多个数据项的方法。 p>
您的加密方法假定加密文件,各个行不是文件,它们是文件的一部分。这种方法只适合加密整个数据库,需要在将数据库打开到另一个文件之前解密整个数据库文件,并将整个数据库加密到加密文件中,这有其自身的复杂性。
基于选项 2 的示例
获取您的代码并将其修改为(用于演示原理):-
那么 MyDbHandler 可能是:-
@SuppressLint("Range")
public class MyDbHandler extends SQLiteOpenHelper
EncryptDecrypt ed;
String KEYSTR = "this is my key string";
String SPECSTR = "this is my specstring";
public MyDbHandler(Context context)
super(context, Params.DB_NAME, null, Params.DB_VERSION);
ed = new EncryptDecrypt();
EncryptDecrypt.setIvParameterSpec(new
IvParameterSpec(SPECSTR.substring(0,16).getBytes(StandardCharsets.UTF_8)));
EncryptDecrypt.setSecretKeySpec(new
SecretKeySpec(KEYSTR.substring(0,16).getBytes(StandardCharsets.UTF_8), ALGO_SECRET_KEY));
try
ed.setCipher(Cipher.getInstance(ALGO_FILE_ENCRYPTOR));
catch (Exception e)
e.printStackTrace();
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase)
String create = "CREATE TABLE " + Params.TABLE_NAME + "("
+ Params.KEY_ID + " INTEGER PRIMARY KEY," + Params.KEY_NAME
+ " TEXT, " + Params.KEY_PHONE + " TEXT, " + Params.KEY_SECRET + " TEXT, " + Params.KEY_IV + " TEXT" + ")";
Log.d("practise", "Query being run is : " + create);
sqLiteDatabase.execSQL(create);
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1)
public void addContact(Contact contact)
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
try
values.put(Params.KEY_NAME,ed.encrypt(contact.getName()));
values.put(Params.KEY_PHONE,ed.encrypt(contact.getPhone_number()));
db.insert(Params.TABLE_NAME, null,values);
Log.d("practise", "Successfully inserted");
db.close();
catch (Exception e)
e.printStackTrace();
public List<Contact> getAllContact()
List<Contact> contactList = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
//Generate the query to read from the database
String select = "SELECT * FROM " + Params.TABLE_NAME;
Cursor cursor = db.rawQuery(select, null);
//Loop Through now
if (cursor.moveToFirst())
do
Contact contact = new Contact();
contact.setId(cursor.getInt(cursor.getColumnIndex(Params.KEY_ID)));
contact.setName(ed.decrypt(cursor.getString(cursor.getColumnIndex(Params.KEY_NAME))));
contact.setPhone_number(ed.decrypt(cursor.getString(cursor.getColumnIndex(Params.KEY_PHONE))));
contactList.add(contact);
while (cursor.moveToNext());
cursor.close(); //<<<< SHOULD ALWAYS CLOSE CURSORS
return contactList;
private static int READ_WRITE_BLOCK_BUFFER = 1024;
private static String ALGO_FILE_ENCRYPTOR = "AES/CBC/PKCS5Padding";
private final static String ALGO_SECRET_KEY = "AES";
/*
public static void encryptFile(String keyStr, String specStr,
InputStream in, OutputStream out)
throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException,
IOException
try
IvParameterSpec iv = new
IvParameterSpec(specStr.getBytes("UTF-8"));
SecretKeySpec keySpec = new
SecretKeySpec(keyStr.getBytes("UTF-8"), ALGO_SECRET_KEY);
Cipher c = Cipher.getInstance(ALGO_FILE_ENCRYPTOR);
c.init(Cipher.ENCRYPT_MODE,keySpec,iv);
out = new CipherOutputStream(out, c);
int count = 0;
byte[] buffer = new byte[READ_WRITE_BLOCK_BUFFER];
while ((count = in.read(buffer))>0)
out.write(buffer,0,count);
finally
out.close();
*/
以及支持的 EncryptDecrypt 类:-
class EncryptDecrypt
private Cipher cipher;
private static SecretKeySpec secretKeySpec;
private static IvParameterSpec ivParameterSpec;
/**
*
* @Param toEncrypt The string to be encrypted
* @return The encrypted data as a string
*/
String encrypt(String toEncrypt)
byte[] encrypted;
try
cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec,ivParameterSpec);
encrypted = cipher.doFinal(toEncrypt.getBytes());
catch (Exception e)
//e.printStackTrace();
return null;
return Base64.encodeToString(encrypted,Base64.DEFAULT);
/**
* Decrypt an encrypted string
* @param toDecrypt The encrypted string to be decrypted
* @return The decrypted string
*/
String decrypt(String toDecrypt)
byte[] decrypted;
try
cipher.init(Cipher.DECRYPT_MODE,secretKeySpec,ivParameterSpec);
decrypted = cipher.doFinal(Base64.decode(toDecrypt,Base64.DEFAULT));
catch (Exception e)
//e.printStackTrace();
return null;
return new String(decrypted);
public void setCipher(Cipher cipher)
this.cipher = cipher;
public static IvParameterSpec getIvParameterSpec()
return ivParameterSpec;
public static void setIvParameterSpec(IvParameterSpec ivParameterSpec)
EncryptDecrypt.ivParameterSpec = ivParameterSpec;
public static SecretKeySpec getSecretKeySpec()
return secretKeySpec;
public static void setSecretKeySpec(SecretKeySpec secretKeySpec)
EncryptDecrypt.secretKeySpec = secretKeySpec;
并将 MainActivity 演示为:-
public class MainActivity extends AppCompatActivity
MyDbHandler db;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = new MyDbHandler(this);
db.addContact(new Contact(0,"Fred Bloggs","1111111111"));
db.addContact(new Contact(0,"Jane Doe","2222222222"));
db.addContact(new Contact(0,"Miss Scarlet","3333333333"));
Cursor csr = db.getWritableDatabase().query(Params.TABLE_NAME,null,null,null,null,null,"(random())");
DatabaseUtils.dumpCursor(csr);
csr.close();
for(Contact c : db.getAllContact())
Log.d("DBINFO","Name is " + c.getName() + " Phone is " + c.getPhone_number());
日志的输出将是(作为新安装运行时):-
2021-12-21 09:54:30.083 D/practise: Query being run is : CREATE TABLE mytable(_id INTEGER PRIMARY KEY,_name TEXT, _phone TEXT, _secret TEXT, _iv TEXT)
2021-12-21 09:54:30.086 D/practise: Successfully inserted
2021-12-21 09:54:30.100 I/chatty: uid=10164(a.a.so70410018javasqliteencryptdb) identical 1 line
2021-12-21 09:54:30.113 D/practise: Successfully inserted
2021-12-21 09:54:30.121 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@ec73c85
2021-12-21 09:54:30.121 I/System.out: 0
2021-12-21 09:54:30.121 I/System.out: _id=2
2021-12-21 09:54:30.121 I/System.out: _name=at3jvwWB4LcYZHFWcdVhbw==
2021-12-21 09:54:30.121 I/System.out: _phone=qqypV3kzmDrj6MruN1npvA==
2021-12-21 09:54:30.122 I/System.out: _secret=null
2021-12-21 09:54:30.122 I/System.out: _iv=null
2021-12-21 09:54:30.122 I/System.out:
2021-12-21 09:54:30.122 I/System.out: 1
2021-12-21 09:54:30.122 I/System.out: _id=3
2021-12-21 09:54:30.122 I/System.out: _name=DLeinhF4EoxeNZCRUZyOFw==
2021-12-21 09:54:30.122 I/System.out: _phone=V1ZkbeIPV3Rqm6Uajc93Sg==
2021-12-21 09:54:30.122 I/System.out: _secret=null
2021-12-21 09:54:30.122 I/System.out: _iv=null
2021-12-21 09:54:30.122 I/System.out:
2021-12-21 09:54:30.122 I/System.out: 2
2021-12-21 09:54:30.122 I/System.out: _id=1
2021-12-21 09:54:30.122 I/System.out: _name=lRGUesUDAZegVCgfIKVDIg==
2021-12-21 09:54:30.122 I/System.out: _phone=Q/CNAvw/xV1+LzWWSw8SKg==
2021-12-21 09:54:30.122 I/System.out: _secret=null
2021-12-21 09:54:30.122 I/System.out: _iv=null
2021-12-21 09:54:30.122 I/System.out:
2021-12-21 09:54:30.122 I/System.out: <<<<<
2021-12-21 09:54:30.127 D/DBINFO: Name is Fred Bloggs Phone is 1111111111
2021-12-21 09:54:30.127 D/DBINFO: Name is Jane Doe Phone is 2222222222
2021-12-21 09:54:30.127 D/DBINFO: Name is Miss Scarlet Phone is 3333333333
使用 App Inspection 查看数据库显示:-
以上代码基于您可能希望考虑的以下更全面的答案:-
Encrypt data in SQLite
和
How to encrypt sqlite texts without 3rd party libraries (Android)
【讨论】:
以上是关于如何使用 aes 算法加密 sqlite 文件?的主要内容,如果未能解决你的问题,请参考以下文章