Android使用SQLite數據庫存儲數據,我需要加密SQLite數據庫,這怎麼辦呢?我瞭解,應用程序數據是私人的。不過,我需要明確地加密我的應用程序正在使用的SQLite數據庫。Android數據庫加密
回答
http://sqlite-crypt.com/可能會幫助你創建一個加密的數據庫,雖然我從來沒有用過它在android上似乎有可能與源代碼。
如果數據庫很小,那麼可以通過將整個文件解密到一個臨時位置(不在SD卡上),然後在關閉它時重新進行加密,從而獲得一小部分安全性。問題:應用程序過早死亡,媒體上的鬼影。
稍微好一點的解決方案來加密數據字段。這會導致WHERE和ORDER BY子句出現問題。如果加密字段需要爲等價搜索建立索引,則可以存儲該字段的加密哈希並搜索該字段。但是這對範圍搜索或排序沒有幫助。
如果你想更有趣,你可以深入研究Android NDK,並將一些加密技術轉換爲SQLite的C代碼。
考慮到所有這些問題和部分解決方案,你確定你確實需要一個SQL數據庫的應用程序?您可能會更喜歡使用包含加密序列化對象的文件。
SQLCipher是一種SQLite擴展,它提供對數據庫文件的透明256位AES加密。
以前的sqlcipher是SQLite的開源完整數據庫加密不適用於android。但現在它可以作爲Android平臺的alpha版本。 開發人員已將標準android應用程序'Notepadbot'更新爲使用SQLCipher。
所以這絕對是目前最好的和最簡單的選項。
SQLCIpher for Android現在是SQLCipher官方項目的一部分:http://sqlcipher.net/sqlcipher-for-android/ – 2012-09-06 07:37:48
是免費使用還是必須購買許可證?我找不到準確的信息..:S – Ewoks 2012-11-16 12:40:46
許可證信息可在github頁面上獲得https://github.com/sqlcipher/android-database-sqlcipher/blob/master/LICENSE – vaichidrewar 2012-11-16 15:56:18
數據庫被加密以防止INDIRECT ATTACKS
。 這個詞和類:KeyManager.java,Crypto.java從Sheran Gunasekera書Android Apps Security拍攝。我推薦所有這本書閱讀。
INDIRECT ATTACKS
之所以如此命名,是因爲該病毒並沒有申請後直接去。相反,它追隨Android操作系統。其目的是將所有SQLite數據庫複製,病毒作者可以複製存儲有任何敏感信息的希望。如果您添加了另一個保護層,但是,那麼所有的病毒作者將看到的是亂碼數據。 讓我們建立,我們可以在我們所有的應用程序重複使用的密碼庫。讓我們創建一個簡單的一套規範入手:
使用對稱算法:我們的圖書館將使用對稱算法, 或塊密碼,加密和解密我們的數據。我們將在AES, 解決,但我們應該能夠在以後修改。
使用固定密鑰:我們需要能夠包含一個密鑰,我們可以在 上存儲將用於加密和解密數據的設備。
存儲在設備上的密鑰:密鑰將駐留在設備上。雖然從直接攻擊的角度來看,這對我們的應用來說是一個風險 ,但它應該足以在 保護我們免受間接攻擊。
讓我們開始我們的密鑰管理模塊(見清單1)。因爲我們打算使用固定密鑰,所以我們不需要像過去的例子那樣生成一個隨機密鑰。因此,的KeyManager將執行以下任務:
- 接受一個密鑰作爲參數(
setId(byte[] data)
方法) - 接受一個初始化向量作爲參數(
setIv(byte[] data)
方法) - 存儲密鑰在內部存儲的文件中
- 從內部存儲中的文件檢索密鑰(
getId(byte[] data)
方法) - 檢索從文件中IV在內部存儲(
getIv(byte[] data)
方法)
(清單1.的KeyManager模塊KeyManager.java)
package com.yourapp.android.crypto;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.Context;
import android.util.Log;
public class KeyManager {
private static final String TAG = "KeyManager";
private static final String file1 = "id_value";
private static final String file2 = "iv_value";
private static Context ctx;
public KeyManager(Context cntx) {
ctx = cntx;
}
public void setId(byte[] data) {
writer(data, file1);
}
public void setIv(byte[] data) {
writer(data, file2);
}
public byte[] getId() {
return reader(file1);
}
public byte[] getIv() {
return reader(file2);
}
public byte[] reader(String file) {
byte[] data = null;
try {
int bytesRead = 0;
FileInputStream fis = ctx.openFileInput(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
while ((bytesRead = fis.read(b)) ! = -1) {
bos.write(b, 0, bytesRead);
}
data = bos.toByteArray();
} catch (FileNotFoundException e) {
Log.e(TAG, "File not found in getId()");
} catch (IOException e) {
Log.e(TAG, "IOException in setId(): " + e.getMessage());
}
return data;
}
public void writer(byte[] data, String file) {
try {
FileOutputStream fos = ctx.openFileOutput(file,
Context.MODE_PRIVATE);
fos.write(data);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
Log.e(TAG, "File not found in setId()");
} catch (IOException e) {
Log.e(TAG, "IOException in setId(): " + e.getMessage());
}
}
}
接下來,我們做加密模塊(參見列表2)。該模塊負責加密和解密。我們已經將armorEncrypt()
和armorDecrypt()
方法添加到模塊中,以便將字節數組數據轉換爲可打印的Base64數據,反之亦然。我們將使用AES算法與Cipher Block Chaining (CBC) encryption mode和PKCS#5 padding。
(清單2.加密模塊Crypto.java)
package com.yourapp.android.crypto;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import android.content.Context;
import android.util.Base64;
public class Crypto {
private static final String engine = "AES";
private static final String crypto = "AES/CBC/PKCS5Padding";
private static Context ctx;
public Crypto(Context cntx) {
ctx = cntx;
}
public byte[] cipher(byte[] data, int mode) throws NoSuchAlgorithmException,NoSuchPaddingException,InvalidKeyException,IllegalBlockSizeException,BadPaddingException,InvalidAlgorithmParameterException {
KeyManager km = new KeyManager(ctx);
SecretKeySpec sks = new SecretKeySpec(km.getId(), engine);
IvParameterSpec iv = new IvParameterSpec(km.getIv());
Cipher c = Cipher.getInstance(crypto);
c.init(mode, sks, iv);
return c.doFinal(data);
}
public byte[] encrypt(byte[] data) throws InvalidKeyException,
NoSuchAlgorithmException, NoSuchPaddingException,
IllegalBlockSizeException, BadPaddingException,
InvalidAlgorithmParameterException {
return cipher(data, Cipher.ENCRYPT_MODE);
}
public byte[] decrypt(byte[] data) throws InvalidKeyException,
NoSuchAlgorithmException, NoSuchPaddingException,
IllegalBlockSizeException, BadPaddingException,
InvalidAlgorithmParameterException {
return cipher(data, Cipher.DECRYPT_MODE);
}
public String armorEncrypt(byte[] data) throws InvalidKeyException,NoSuchAlgorithmException,
NoSuchPaddingException,IllegalBlockSizeException,
BadPaddingException,InvalidAlgorithmParameterException {
return Base64.encodeToString(encrypt(data), Base64.DEFAULT);
}
public String armorDecrypt(String data) throws InvalidKeyException,NoSuchAlgorithmException,
NoSuchPaddingException,IllegalBlockSizeException,
BadPaddingException,InvalidAlgorithmParameterException {
return new String(decrypt(Base64.decode(data, Base64.DEFAULT)));
}
}
您可以在任何應用程序需要的數據存儲這兩個文件進行加密。首先,確保您的密鑰和初始化向量具有值,然後在存儲數據之前調用數據中的任何一種加密或解密方法。 清單3和清單4包含這些類使用的簡單應用程序示例。我們用3個按鈕創建一個活動加密,解密,刪除; 1用於數據輸入的EditText; 1個TextView用於數據輸出。
(清單3.一個例子。MainActivity.java)
package com.yourapp.android.crypto;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity {
TextView encryptedDataView;
EditText editInputData;
private Context cntx;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.cntx = getApplicationContext();
Button btnEncrypt = (Button) findViewById(R.id.buttonEncrypt);
Button btnDecrypt = (Button) findViewById(R.id.buttonDecrypt);
Button btnDelete = (Button) findViewById(R.id.buttonDelete);
editInputData = (EditText)findViewById(R.id.editInputData) ;
encryptedDataView = (TextView) findViewById(R.id.encryptView);
/**********************************************/
/** INITIALIZE KEY AND INITIALIZATION VECTOR **/
String key = "12345678909876543212345678909876";
String iv = "1234567890987654";
KeyManager km = new KeyManager(getApplicationContext());
km.setIv(iv.getBytes());
km.setId(key.getBytes());
/**********************************************/
btnEncrypt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String Data = editInputData.getText().toString();
String Encrypted_Data = "data";
try {
Crypto crypto = new Crypto(cntx);
Encrypted_Data = crypto.armorEncrypt(Data.getBytes());
} catch (InvalidKeyException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (NoSuchAlgorithmException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (NoSuchPaddingException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (IllegalBlockSizeException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (BadPaddingException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (InvalidAlgorithmParameterException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
}
encryptedDataView.setText(Encrypted_Data);
}
});
btnDecrypt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String Data = encryptedDataView.getText().toString();
String Decrypted_Data = "data";
try {
Crypto crypto = new Crypto(cntx);
Decrypted_Data = crypto.armorDecrypt(Data);
} catch (InvalidKeyException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (NoSuchAlgorithmException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (NoSuchPaddingException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (IllegalBlockSizeException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (BadPaddingException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (InvalidAlgorithmParameterException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
}
encryptedDataView.setText(Decrypted_Data);
}
});
btnDelete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
encryptedDataView.setText(" Deleted ");
}
});
}
}
(清單4.一個例子。activity_main.xml中)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#363636"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<EditText
android:id="@+id/editInputData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:ems="10"
android:textColor="#FFFFFF" >
<requestFocus />
</EditText>
<TextView
android:id="@+id/encryptView"
android:layout_width="fill_parent"
android:layout_height="100dp"
android:layout_alignLeft="@+id/editInputData"
android:layout_alignRight="@+id/editInputData"
android:layout_below="@+id/buttonEncrypt"
android:layout_marginTop="26dp"
android:background="#000008"
android:text="Encrypted/Decrypted Data View"
android:textColor="#FFFFFF"
android:textColorHint="#FFFFFF"
android:textColorLink="#FFFFFF" />
<Button
android:id="@+id/buttonEncrypt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/encryptView"
android:layout_alignRight="@+id/editInputData"
android:layout_below="@+id/editInputData"
android:layout_marginTop="26dp"
android:text="Encrypt" />
<Button
android:id="@+id/buttonDelete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/buttonDecrypt"
android:layout_alignRight="@+id/buttonDecrypt"
android:layout_below="@+id/buttonDecrypt"
android:layout_marginTop="15dp"
android:text="Delete" />
<Button
android:id="@+id/buttonDecrypt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/encryptView"
android:layout_alignRight="@+id/encryptView"
android:layout_below="@+id/encryptView"
android:layout_marginTop="21dp"
android:text="Decrypt" />
</RelativeLayout>
,加密有什麼好處使用該密鑰加密數據? – minhaz 2016-03-06 05:07:57
litereplica使用支持encryption ChaCha密碼。
Chacha與基於ARMv7的便攜式設備上的AES幾乎相比3 times faster。
Android版本有bindings。
要創建並打開我們使用URI這樣一個加密的數據庫:
"file:/path/to/file.db?cipher=...&key=..."
- 1. 在Android中加密數據庫文件
- 2. 如何加密android sqlite數據庫?
- 3. 數據庫加密
- 4. 加密/解密數據到數據庫
- 5. SQLite數據庫加密C#?
- 6. 加密MonetDB數據庫
- 7. 數據庫加密問題
- 8. 加密在MySQL數據庫
- 9. 加密領域數據庫
- 10. .net加密數據庫表
- 11. 加密的SQL數據庫?
- 12. 數據庫加密 - php/mysql
- 13. 加密整個數據庫
- 14. MongoDB數據庫加密
- 15. 加密訪問數據庫
- 16. 加密數據庫內容
- 17. 數據庫加密問題
- 18. 加密數據庫字段
- 19. SQLCipher Android,爲未加密的數據庫設置密鑰
- 20. 使用FileInputStream/Cipher在Android中加密/解密數據庫文件
- 21. 加密密碼並存儲在數據庫中android
- 22. 如何在Android上保護數據庫(加密)密碼?
- 23. 數據庫加密和數據庫解密使用C#代碼
- 24. Android數據加密困境
- 25. 加密或部分加密核心數據數據庫?
- 26. Prestashop - 如何加密數據庫密碼?
- 27. 加密數據庫上的密碼
- 28. SQLite3數據庫加密 - 確定加密庫?
- 29. 如何加密/解密SQLite數據庫中的數據?
- 30. 加密和解密數據庫中的所有數據
我已加密的所有值甚至主鍵和解密。它慢,但它的工作。什麼是最佳方案。 – 2011-02-24 09:40:33