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 :)