I am transitioning my app to use SQLCipher through the 'appcelerator.encrypteddatabase' module.
Existing devices will have an unencrypted SQLite database which the app will need to do a sqlcipher_export() on.
See documentation here [
https://www.zetetic.net/sqlcipher/sqlcipher-api/#sqlcipher_export](
https://www.zetetic.net/sqlcipher/sqlcipher-api/#sqlcipher_export)
I am now able to get the ATTACH command to work. But I cannot use the database for anything afterwards. It is as though the encrypteddatabase module is holding on to a reference to the DB.
See my attached app.js example.
1.You can click the first button as many times as you like to create and add data to an unencrypted DB.
2. This will create an encrypted DB, attach it, export it.
3. This will now cause an exception
4. Restart the app
5. Button 3 now works perfectly.
I have tried everything I can think of to get around this, and there's nothing in the SQLCipher documentation that I appear to be doing wrong.
Thanks for your help!. [^app.js]
Hello [~mark.henderson@snagr.co.uk], Thanks for reporting this . Are you using 7.5.2SDK for build? Can you please test on 8.0.0.GA? And also share the console logs here.
Technically I'm using 7.5.2GA for production. But for this test I've also tried with 8.0.0GA. I'm pretty sure this is a bug with EncryptedDatabase module, as I've re-written this code 5 different ways today and tried almost everything. Whatever is locking it is removed when you re-launch the app. But after the attach / export / detach the database is completely locked. I also tried the second method of exporting a plaintext database into a new encrypted database. But this module gives an error message 'incorrect number of arguments'. I can also see that this module is using SQLCipher v3 not v4, as I need to set DB Browser for SQLite to this mode in order to decrypt and view the database. So I think it should be updated internally if there is a bug. Here are the console logs:
Thanks![ERROR] : file is not a database [ERROR] : A SQLite database error occurred on database '/Users/mark/Library/Developer/CoreSimulator/Devices/1D771BB8-BA4E-4C52-ADBA-E08AEC0E4B91/data/Containers/Data/Application/C04413E4-9003-40E9-90F3-0F14D343D473/Library/Private Documents/encryptedDB.db.sql': Error Domain=com.plausiblelabs.EncPLDatabase Code=4 "Cipher migrate: failed to attach new database." UserInfo={com.plausiblelabs.EncPLDatabase.error.vendor.string=file is not a database, NSLocalizedDescription=Cipher migrate: failed to attach new database., com.plausiblelabs.EncPLDatabase.error.vendor.code=26} (SQLite #26: file is not a database) (query: '<none>') [ERROR] : Script Error { [ERROR] : column = 42; [ERROR] : line = 97; [ERROR] : message = "Couldn't open database and migrate"; [ERROR] : nativeLocation = ""; [ERROR] : nativeReason = "encryptedDB.db"; [ERROR] : nativeStack = "3 testAttach 0x000000010793f7fd -[AppceleratorEncrypteddatabaseDBProxy open:] + 560\n4 testAttach 0x000000010793b519 -[AppceleratorEncrypteddatabaseModule open:] + 373\n5 CoreFoundation 0x000000010def94cc __invoking___ + 140\n6 CoreFoundation 0x000000010def6a45 -[NSInvocation invoke] + 325\n7 TitaniumKit0x000000010cc02c89 -[KrollMethod call:] + 1385\n8 TitaniumKit0x000000010cc01dcb __KrollCallAsFunction_block_invoke + 30\n9 TitaniumKit0x000000010cc01bdc KrollCallAsFunction + 496\n10 JavaScriptCore 0x0000000107ecc8d3 _ZN3JSC16JSCallbackObjectINS_20JSDestructibleObjectEE4callEPNS_9ExecStateE + 515\n11 JavaScriptCore 0x00000001083724fc _ZN3JSC5LLInt9setUpCallEPNS_9ExecStateENS_22CodeSpecializationKindENS_7JSValueEPNS_17LLIntCallLinkInfoE + 380\n12 JavaScriptCore 0x0000000107e97b63 llint_entry + 61648\n13 JavaScriptCore 0x0000000107e888d9 vmEntryToJavaScript + 200\n14 JavaScriptCore 0x000000010826e730 _ZN3JSC11Interpreter11executeCallEPNS_9ExecStateEPNS_8JSObjectENS_8CallTypeERKNS_8CallDataENS_7JSValueERKNS_7ArgListE + 464\n15 JavaScriptCore 0x00000001084b3634 _ZN3JSC12profiledCallEPNS_9ExecStateENS_15ProfilingReasonENS_7JSValueENS_8CallTypeERKNS_8CallDataES3_RKNS_7ArgListE + 196\n16 JavaScriptCore 0x0000000107ed36fe JSObjectCallAsFunction + 478\n17 TitaniumKit0x000000010cbde3e2 __TiBindingEventProcess_block_invoke + 53\n18 TitaniumKit0x000000010cbde30a TiBindingEventProcess + 723\n19 TitaniumKit0x000000010cbffdf5 -[KrollContext invoke:] + 109"; [ERROR] : sourceURL = "file:///Users/mark/Library/Developer/CoreSimulator/Devices/1D771BB8-BA4E-4C52-ADBA-E08AEC0E4B91/data/Containers/Bundle/Application/FE136192-6854-4DB9-893B-120FD5A806EE/testAttach.app/app.js"; [ERROR] : stack = " at [native code]\n at testExisting(/app.js:97:42)"; [ERROR] : toJSON = "<KrollCallback: 0x600000dec680>"; [ERROR] : }Hi Shak, do let me know if there's any other information you require. I'm happy to help with any testing etc.. Unfortunately as the module is closed source I can't do too much.
I seem to have got this working finally.. It seems for iOS by checking the cipher upgrade and also making sure that after initialising appcelerator.encrypteddatabase I only use that to open database connections, not Ti.Database anymore. Here's the change to the code in case it helps anyone else in the future:
function createEncryptedDBAttachAndExport() { //set password in case we are creating a new encrypted DB not opening EncryptedDatabase.password = 'testkey'; var newDB = EncryptedDatabase.open(newDBName); if (Ti.Platform.osname !== 'android') { Ti.API.info('UpgradeRequired? ' + newDB.isCipherUpgradeRequired(newDBName)); } var encDBFilePath = newDB.file.nativePath; newDB.close(); newDB = null; /*var origDB = Ti.Database.open(databaseName); var origDBFilePath = origDB.file.nativePath; origDB.close(); origDB = null;*/ //set password back to plaintest database so we can export EncryptedDatabase.password = ''; var unEncryptedDB = EncryptedDatabase.open(databaseName); unEncryptedDB.execute("ATTACH DATABASE '" + encDBFilePath + "' AS encrypted KEY 'testkey'"); unEncryptedDB.execute("SELECT sqlcipher_export('encrypted')"); unEncryptedDB.execute("DETACH DATABASE encrypted"); unEncryptedDB.close(); unEncryptedDB = null; //reset key back again EncryptedDatabase.password = 'testkey'; // wrong number of arguments exception if we try to go this way (must be old SQLCipher version I think) /*var unEncryptedDB = EncryptedDatabase.open(newDBName); unEncryptedDB.execute("PRAGMA key = 'testkey';"); unEncryptedDB.execute("ATTACH DATABASE '" + origDBFilePath + "' AS plain KEY ''"); unEncryptedDB.execute("SELECT sqlcipher_export('main', 'plain')"); unEncryptedDB.execute("DETACH DATABASE plain"); unEncryptedDB.close(); unEncryptedDB = null;*/ }