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):
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 :)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With