Cơ sở dữ liệu được mã hóa để ngăn chặn INDIRECT ATTACKS
. Thuật ngữ này và các lớp: KeyManager.java , Crypto.java được lấy từ cuốn sách Bảo mật ứng dụng Android của Sheran Gunasekera . Tôi giới thiệu tất cả cuốn sách này để đọc.
INDIRECT ATTACKS
được đặt tên như vậy, bởi vì vi-rút không truy cập trực tiếp vào ứng dụng của bạn. Thay vào đó, nó đi theo hệ điều hành Android. Mục đích là sao chép tất cả cơ sở dữ liệu SQLite với hy vọng tác giả của virus có thể sao chép bất kỳ thông tin nhạy cảm nào được lưu trữ ở đó. Tuy nhiên, nếu bạn đã thêm một lớp bảo vệ khác, thì tất cả những gì tác giả vi rút sẽ thấy là dữ liệu bị cắt xén. Hãy xây dựng một thư viện mật mã mà chúng ta có thể sử dụng lại trong tất cả các ứng dụng của mình. Hãy bắt đầu bằng cách tạo một bộ thông số kỹ thuật ngắn gọn:
Sử dụng thuật toán đối xứng: Thư viện của chúng tôi sẽ sử dụng thuật toán đối xứng, hoặc mật mã khối, để mã hóa và giải mã dữ liệu của chúng tôi. Chúng tôi sẽ giải quyết trên AES, mặc dù chúng tôi có thể sửa đổi điều này vào một ngày sau đó.
Sử dụng khóa cố định: Chúng tôi cần có một khóa mà chúng tôi có thể lưu trữ trên thiết bị sẽ được sử dụng để mã hóa và giải mã dữ liệu.
Khóa được lưu trữ trên thiết bị: Khóa sẽ nằm trên thiết bị. Mặc dù đây là một rủi ro đối với ứng dụng của chúng tôi từ quan điểm của các cuộc tấn công trực tiếp, nhưng nó đủ để bảo vệ chúng tôi trước các cuộc tấn công gián tiếp.
Hãy bắt đầu với mô-đun quản lý khóa của chúng ta (xem Liệt kê 1 ). Bởi vì chúng tôi dự định sử dụng một khóa cố định, chúng tôi sẽ không cần tạo một khóa ngẫu nhiên như chúng tôi đã làm trong các ví dụ trước đây. Các KeyManager do đó sẽ thực hiện các nhiệm vụ sau đây:
- Chấp nhận một khóa làm tham số (
setId(byte[] data)
phương thức)
- Chấp nhận một vectơ khởi tạo làm tham số (
setIv(byte[] data)
phương thức)
- Lưu khóa bên trong tệp trong cửa hàng nội bộ
- Lấy khóa từ tệp trong cửa hàng nội bộ (
getId(byte[] data)
phương thức)
- Lấy IV từ một tệp trong cửa hàng nội bộ (
getIv(byte[] data)
phương thức)
(Liệt kê 1. Mô-đun 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());
}
}
}
Tiếp theo, chúng tôi thực hiện mô-đun Crypto (xem Liệt kê 2 ). Mô-đun này đảm nhiệm việc mã hóa và giải mã. Chúng tôi đã thêm một armorEncrypt()
và armorDecrypt()
phương thức vào mô-đun để giúp dễ dàng chuyển đổi dữ liệu mảng byte thành dữ liệu Base64 có thể in được và ngược lại. Chúng tôi sẽ sử dụng thuật toán AES với chế độ mã hóa Cipher Block Chaining (CBC) và phần đệm PKCS # 5 .
(Liệt kê 2. Mô-đun mật mã 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)));
}
}
Bạn có thể đưa hai tệp này vào bất kỳ ứng dụng nào của mình yêu cầu bộ nhớ dữ liệu được mã hóa. Trước tiên, hãy đảm bảo rằng bạn có một giá trị cho khóa và vectơ khởi tạo, sau đó gọi bất kỳ một trong các phương thức mã hóa hoặc giải mã trên dữ liệu của bạn trước khi bạn lưu trữ. Liệt kê 3 và Liệt kê 4 chứa một ví dụ ứng dụng đơn giản của các lớp này bằng cách sử dụng. Chúng tôi tạo một Hoạt động với 3 Nút Mã hóa, Giải mã, Xóa; 1 EditText để nhập dữ liệu; 1 TextView cho đầu ra dữ liệu.
(Ví dụ 3. Một ví dụ. 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);
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 ");
}
});
}
}
(Ví dụ 4. Một ví dụ. 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="
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="
<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="
android:text="Encrypted/Decrypted Data View"
android:textColor="
android:textColorHint="
android:textColorLink="
<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>