3

I use an already existing database in my App (see also 1). I encrypted the database with a Java Application. In my App I try to read the encrypted_database with the following code, but I get a 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;

I already encrypted my database with SQLCipher and I also can read the data, so everything works fine.

The problem with SQLCipher and an already existing database is that I have to copy the complete unencrypted_database to an encrypted_database. This takes a long time when I do this on my phone.

My idea was: Write an Application in java that encrypts the database and take this encrypted_database in your app. This has the result that I just have to open the already existing encrypted_database in my app and no copying is required.

Now I wrote an Java Application (based on 2,3) but there are still some questions related to SQLCipher and its design (4):

  • how can I divide my database in database pages? In 4 a database page is just defined by its size (1024 bytes). But what I have to write into my encrypted_database file to say "database page starts" or "database page ends"
  • is the salt and the random initialization vector (iv) part of the 1024 bytes?

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

I appreciate every help/idea/comment :)

Community
  • 1
  • 1
owe
  • 4,890
  • 7
  • 36
  • 47

1 Answers1

2

THe approach of trying to recreate a SQLCipher file from scratch is not advised. The format is more complicated than what you are doing, and it will be non-trivial reproduce a valid SQLCipher file. Instead, you should just use the SQLCipher command line program to encrypt your database for distribution.

Stephen Lombardo
  • 1,503
  • 8
  • 7
  • Thank you for the answer. I saw the SQLCipher API, but I didn't understand how to solve my problem. Your answer helped me to get an idea :). I'll try it next time. – owe Dec 23 '12 at 12:51