java - 为 SQLCipher 加密现有数据库

标签 java android database encryption sqlcipher

我在我的应用程序中使用了一个已经存在的数据库(另请参阅 1)。我用 Java 应用程序加密了数据库。 在我的应用程序中,我尝试使用以下代码读取 encrypted_database,但我得到了一个 SQLiteException: file is encrypted or is not a database:

    SQLiteDatabase.loadLibs(mContext);
    SQLiteDatabase dataBase = SQLiteDatabase.openDatabase(mPath, mPassword, null, SQLiteDatabase.OPEN_READONLY);
    String query = "Select distinct _id from TABLE";
    Cursor cursor = dataBase.rawQuery(query, null);
    return cursor;

我已经用 SQLCipher 加密了我的数据库,我也可以读取数据,所以一切正常。

SQLCipher 和现有数据库的问题是我必须将完整的未加密数据库复制到加密数据库。当我在手机上执行此操作时,这需要很长时间。

我的想法是:用 java 编写一个加密数据库的应用程序,并将此 encrypted_database 放入您的应用程序中。结果是我只需要在我的应用程序中打开已经存在的 encrypted_database,不需要复制。

现在我写了一个 Java 应用程序(基于 23 )但是仍然有一些与 SQLCipher 及其设计相关的问题( 4 ):

  • 如何在数据库页面中划分数据库?在 4数据库页面仅由其大小(1024 字节)定义。但是我必须在我的 encrypted_database 文件中写入“数据库页面开始”或“数据库页面结束”
  • 盐和随机初始化 vector (iv) 是 1024 字节的一部分吗?

    public static void main(String[] args) throws Exception{
    
        outFile_enc = new FileOutputStream(mFileNameEncrypted);
        outFile_dec = new FileOutputStream(mFileNameDecrypted);
    
        int keyLength = 256;
        // salt
        salt = new byte[16];
        Random rnd = new Random();
        rnd.nextBytes(salt);
        int iterations = 4000;
    
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec keySpec = new PBEKeySpec(mPassWord.toCharArray(), salt, iterations, keyLength);
        SecretKey passwordKey = keyFactory.generateSecret(keySpec);
        key = new SecretKeySpec(passwordKey.getEncoded(), "AES");
    
        // creates a cipher and init it for encryption
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
    
        AlgorithmParameters params = cipher.getParameters();
        iv = params.getParameterSpec(IvParameterSpec.class).getIV();
    
        encryptData(cipher);            
    }
    
    public static void encryptData(Cipher cipher) throws Exception{
        // File to encrypt
        inFile = new FileInputStream(mFileName);
    
        // unique random salt in the first 16 bytes of the file
        outFile_enc.write(salt);
    
        // Read file and encrypt its bytes
        byte[] input  = new byte[64];
        int bytesRead;
        while((bytesRead = inFile.read(input)) != -1){
        byte[] output = cipher.update(input, 0, bytesRead);
        if(output != null)
            outFile_enc.write(output);
        }
    
        byte[] output = cipher.doFinal();
        if(output != null)
            outFile_enc.write(output);
        // random initialization vector is stored at the end of a page
        outFile_enc.write(iv);
    
        inFile.close();
        outFile_enc.flush();
        outFile_enc.close();    
    }
    

我感谢每一个帮助/想法/评论:)

最佳答案

不建议尝试从头开始重新创建 SQLCipher 文件的方法。该格式比您正在做的更复杂,并且重现一个有效的 SQLCipher 文件将是非常重要的。相反,您应该只使用 SQLCipher command line programencrypt your database用于分发。

关于java - 为 SQLCipher 加密现有数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13969184/

相关文章:

java - 在 Java 中克隆

java - 如何使 SwipeRefreshLayout 不可滑动?

sql-server - SQL Server - 表元数据

android - 如何使用 viewpager 从选项卡布局中的 recyclerview 重新加载 fragment ?

android - 何时调用 glMatrixMode()

android - 什么时候关闭android上的数据库连接?每次操作完成或应用退出后

mysql - 将wordpress部署到服务器会破坏主题

java - Random.nextInt 返回连续的相同值整数(经常)

java - 如何减少 Full GC 的数量?

java - 与多个通用类型的接口(interface)?