Android数据库框架:Android数据库加密

关于Android数据库框架的问题,在android database encryption中经常遇到, Android 使用 SQLite 数据库来存储数据,我需要加密 SQLite 数据库,这怎么能做到?我理解应用程序数据是私有的。但是我需要明确加密我的应用程序正在使用的 SQLite 数据库。

Android 使用 SQLite 数据库来存储数据,我需要加密 SQLite 数据库,这怎么能做到?我理解应用程序数据是私有的。但是我需要明确加密我的应用程序正在使用的 SQLite 数据库。

70

SQLCipher是一个 SQLite 扩展,为数据库文件提供透明的 256 位 AES 加密。

早期的 sqlcipher 是开源的完整数据库加密的 SQLite 不适用于 android。但现在它可以作为 alpha 版本为 android 平台。开发人员已经更新了标准的 android 应用程序 'Notepadbot' 以使用 SQLCipher。

所以这绝对是目前最好和最简单的选择。

29

数据库是加密的,以防止INDIRECT ATTACKS。这个术语和类:KeyManager.javaCrypto.java取自Sheran GunasekerabookAndroid Apps Security。我推荐阅读所有这本书。

INDIRECT ATTACKS之所以如此命名,是因为该病毒不会直接针对您的应用程序。相反,它针对 Android OS。目的是复制所有 SQLite 数据库,希望病毒作者可以复制存储在其中的任何敏感信息。但是,如果您添加了另一层保护,那么病毒作者将看到的只是乱码数据。让我们构建一个可以在所有应用程序中重用的加密库。让我们从创建一个简短的规范开始:

使用对称算法:我们的库将使用对称算法或块密码来加密和解密我们的数据。

使用固定密钥:我们需要能够包含一个可以存储在设备上的密钥,该密钥将用于加密和解密数据。

密钥存储在设备上:密钥将驻留在设备上。虽然从直接攻击的角度来看,这对我们的应用程序是一个风险,但它应该足以保护我们免受间接攻击。

让我们从我们的密钥管理模块开始(参见清单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());
         }
     }
}

接下来,我们执行Crypto模块(请参见清单2)。该模块负责加密和解密。我们在模块中添加了armorEncrypt()armorDecrypt()方法,以便更轻松地将字节数组数据转换为可打印的Base64数据,反之亦然。我们将a

(清单 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)));
               }
}

您可以将这两个文件包含在任何需要加密数据存储的应用程序中。首先,确保您的密钥和初始化向量有值,然后在存储数据之前调用数据上的任何一个 encrypt 或 decrypt 方法。清单3清单 4包含使用的这些类的简单 App 示例。我们为 3 个按钮创建一个 Activity Encrypt,Decrypt View

(清单 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.onEncrypt);
        Button btnDecrypt = (Button) findViewById(R.id.onDecrypt);
        Button btnDelete = (Button) findViewById(R.id.onDelete);
        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/onEncrypt"
        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/onEncrypt"
        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/onDelete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/onDecrypt"
        android:layout_alignRight="@+id/onDecrypt"
        android:layout_below="@+id/onDecrypt"
        android:layout_marginTop="15dp"
        android:text="Delete" />
    <Button
        android:id="@+id/onDecrypt"
        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>
14

如果数据库很小,那么您可以通过将整个文件解密到临时位置(不在 sd 卡上)来获得少量的安全性,然后在关闭它时重新加密。问题:应用程序过早死亡,媒体上的鬼影。

稍微好一点的解决方案来加密数据字段。这会导致 WHERE 和 ORDER BY 子句的问题。如果加密的字段需要索引以进行等价搜索,那么您可以存储该字段的加密哈希并进行搜索。但这对范围搜索或排序没有帮助。

如果你想变得更漂亮,你可以深入研究 Android NDK,并将一些加密破解到 SQLite 的 C 代码中。

考虑到所有这些问题和部分解决方案,你确定你真的需要一个 SQL 数据库的应用程序?

4

您当然可以在 Android 上拥有一个加密的 SQLite 数据库。但是,您无法使用 Google 提供的开箱即用的类。

几个选择:

通过 NDK 编译自己的 SQLite,并包括加密编,例如,wxSQLite3(包中包含一个不错的免费编)

SQLCipher现在支持 Android

本站系公益性非盈利分享网址,本文来自用户投稿,不代表码文网立场,如若转载,请注明出处

(80)
E sun:Sun着色器不工作(sun shader)
上一篇
Python求平方根函数:平方根 python内的平方根
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(5条)