I am working on a app that uses SQLite. It encrypts and decrypts SQLite database using FilesCipher
class in this answer
The app also saves images as byte[]
in SQLite database. Images column has BLOB
data type.
All these works as expected in Simulator & Android devices but NONE of these works in iOS device. I built these apps using build server.
When I use SQLite database WITHOUT encrypting it using FilesCipher
class above, images are saved as expected in Simulator & Android but they are NOT saved in iOS device.
When I use SQLite database which is encrypted using FilesCipher
class above, I can successfully decrypt and read records in database in Simulator & Android but in iOS it throws the following error ONLY.
java.io.IOException: SQL error in step. Code: 10
I catched this error and stacktrace using the following code
try {
} catch (Exception e) {
Log.p("Error " + e + "n" + getErrorInfo(e));
//save this error log to a shareable text file
}
public String getErrorInfo(Exception error) {
StringBuilder sbError = new StringBuilder();
StackTraceElement[] errorArr = error.getStackTrace();
for (StackTraceElement value : errorArr) {
sbError.append("at ").append(value).append("n");
}
return sbError.toString();
}
I created images table with the following query
CREATE TABLE IF NOT EXISTS pictures ( id INTEGER PRIMARY KEY AUTOINCREMENT, image BLOB)
Then inserted image with the following code
EncodedImage encodedImage = EncodedImage.create(image);
byte[] imageData = encodedImage.getImageData();
String query = "INSERT INTO pictures (image) VALUES (?)";
db.execute(query, imageData);
No error is thrown when inserting in iOS.
Note: FilesCipher encryptes & decrypts bytes[]
and images are saved as bytes[]
. That is, bytes[]
is used in both cases.
How can both cases work in iOS as they are working in Simulator & Android?
10
Main database file encrypted using FilesCipher
class above can’t be read or written into until it’s decrypted first.
I was decrypting and writing decrypted bytes[]
to the same main database file, execute queries in 1 request then after the request is successful or not, using } finally {}
block I encrypt the main database file to keep it encrypted.This idea of encrypting & decrypting the same file works in Simulator & Android but fails in iOS.
Seems there might be a problem in iOS when decrypting, reading & encrypting the same file.
I did the following for this to work in all platforms including iOS.
-
Decrypt main database which returns a decrypted
byte[]
-
Create a temp database and write this decrypted
byte[]
into it. -
Close main database to avoid GC warnings in iOS
-
Set this temp database as the database to use
-
Delete main database file
-
Execute requested query or queries like save records in temp database
-
Encrypt this temp database which returns encrypted
byte[]
-
Create main database file then write this encrypted
byte[]
to this newly created main database. -
Close the temp database to avoid GC warnings in iOS
-
Set this new main database as the database to use.
-
Delete the temp database file.
Repeat these steps for every request.
To enhance performance, if a class or a fuction is executing multiple different queries, the temp database should be reused until all queries have been executed then finally
go to steps 7, 8, 9, 10 & 11