first realm db can be open encrypted but writeCopyToPath cannot - realm

I'm using Realm 0.98.6 with Xcode 7.3 in an OSX app to create an encrypted realm database and then making a clean copy to place in my bundle. The original database opens with the Realm Browser (after pasting in the key), but the copy does not.
Here is the code I use to create both the databases. There are no writes in the routines called, just a mix of realm.adds and realm.appends to create a collection of related objects:
let config = Realm.Configuration(path: realmTempFile, encryptionKey: key)
let realm = try! Realm(configuration: config)
try! realm.write {
loadAuthors(authorFile, realm: realm)
loadVolumes(volumesFile, realm: realm)
}
try! realm.writeCopyToPath(realmFile, encryptionKey: key)
If I remove the encryptionKey parameters from the config and writecopy, then both databases open ok with the Realm Browser.
In case it matters, I'm deleting the db files with the Finder (and associated lock files) before each attempt. (I've also tried changing the names to mitigate any temporary files hanging around.). The only obvious difference between the two files is 7.5 vs 6.9 MB filesize for the 'original' and 'copy' respectively (i.e., as expected the copy is slightly smaller).
I'd love some suggestions! It's a pretty vanilla program of <400 lines that loads a db for later use in an iOS & Android app. I can always ship the bigger file, but it's making me wary of what else I might not know... thanks in advance!

Related

Where to Get Encryption Key for Realm App in Swift

I have a Swift app that uses the Realm Object Server running remotely on a Linux server. Everything is working, including real-time sync.
Occasionally I want to inspect the contents of a local Realm file used by the iOS Simulator so I can do some debugging. When I browse here:
~/.../CoreSimulator/.../Documents/realm-object-server/<unique id>/
...and I try to open this file: realm%3A%2F%2F104%2E236%2E129%2E235%3A9080%2F%7E%2Fmyapp.realm
I get prompted with: Please enter a valid encryption key for this Realm file.
Where do I get this encryption key? I tried using the admin token from the server, but that doesn't appear to be working.
Also, can I turn off encryption everywhere? Or is it mandatory for any app using the Realm Object Server?
It is not possible to open the local version of a synced Realm file using the Browser (or anything else, for that matter). This is due to differing history types internally (but I won't go into that now). In order to inspect the contents of the Realm file, you have to open it using the previously defined syncURL. The browser will then download the file and show you the contents.
A few links on this topic:
https://github.com/realm/RealmTasks/issues/327
https://github.com/realm/realm-core/issues/2276
You may use old version of Realm Browser, please update it and check the result again.
Use Realm Studio instead which worked for me.
Here can download the file
byte[] key = new byte[64];
new SecureRandom().nextBytes(key);
String encryptionKey = byteArrayToHexString(key);
//encryptionKey is what you want byteArrayToHexString see
Log.d("test", "encryptionKey:"+encryptionKey);
byteArrayToHexString() method you can see:How to convert a byte array to a hex string in Java?

Encrypted SQLite database cannot be attached: "Unable to open the database file"

The database can be open()ed using the same encryption key and it works fine. Tried with multiple encrypted databases - all can be opened, but not attached.
This works when encrypted and when not encrypted (bytearray is null):
connection.open(file, "create", false, 1024, bytearray);
This only works when not encrypted:
connection.attach("db" + newnum.toString(), file, new Responder(attachEncryptedSuccess, openEncryptedError), bytearray);
Any help is appreciated.
UPDATE:
Just found a strange pattern here:
It seems that if I create an encrypted database, and then create new databases and attach them, everything works fine.
The created files, after unloading, will only be properly opened using the command that they were initially created with. Therefore, the encrypted database that I created before using open() will only open with open() method. All the encrypted databases that were initially created using attach() will only be able to be opened using attach(). It also doesn't matter which database was open()ed first, aka which one is the main database. It can even be not encrypted.
This is something very strange. Is this a bug? Or am I doing something wrong here?
One gotcha that I ran into awhile ago, and it sounds like it might be impacting you. If you are creating both db's from AIR then this should work fine, however if you have created one with any external tool - generally most tools will default the PRAGMA ENCODING = UTF8. AIR, being Adobe, does things a little different than just straight up telling you that they create theirs UTF16-LE.
According to sqlite rules, differing encoding types cannot be attached one way or the other. One way to verify is to use sqliteman or some other sqlite editor to verify the pragma settings.
For me, I ended up having to start from a seeded db (empty databases -just the header- were over written by AIR) that was to be initialized from a template database. If I allowed AIR to create my starting db, it was set to UTF16 to which I could not attach a UTF8 template.

How to Store User Preferences in an Adobe Flex/AIR Application

What's the standard way of storing user preferences in a Flex application for AIR? I need to store simple parameters like lists of recently opened files, window positions and sizes etc.
my favorite way to do it is to combine a VO with LSO (local shared object). If you have a LOT of settings, this doesn't work too well. The advantage is that you get a strongly typed settings object which is therfore bindable and has code introspection and completion.
The cool thing is it's only about 5 lines of code to manage an LSO. In addition, it's also pretty easy to manage a local encrypted store if you want to store any sensitive data.
registerClassAlias("SettingsVO",SettingsVO); //This lets us store a typed object in LSO
var settings:SettingsVO;
var settingsSO = SharedObject.getLocal("settings");
//Check to make sure settings exist... if not, create a new settings object
if( settingsSO.size && settingsSO.data && settingsSO.data.settings){
settings = settingsSO.data.settings as SettingsVO;
}else{
settings = new SettingsVO();
}
Now if you want to save settings you simply do
settings.someSetting = "newValue";
settingsSO.data.settings = settings;
settingsSO.flush();
And this solution works on BOTH AIR and Flex in any browser. Newer browsers will delete this data when clearing cookies, so beware of that.
I think the most flexible way is to use a local SQLite database. It gives you unlimited, structured storage and encryption if needed. See Peter Elst's introduction if you want to get more info.
There is no "Standard" way, but there are a lot of approaches, all which boil down to storing the user's preferences, then loading them up at runtime based on some uesr credentials, then changing the app based on those preferences.
You may store them in a server side database, such as SQL Server or MySQL; then have flex call a service which queries the database and returns the data.
You may store them as Shared Objects, which are the Flash version of browser cookies. (I believe they work on AIR applications too). This can get cumbersome with lots of data.
You may store them in an XML document and throw them on the server. Conceptually this is not much different than storing them in a server side database; but could get very tedious if you have a lot of users.
You could also store them, in an AIR app, locally using a SQLite database. SQLite is an embedded database used in Adobe AIR.
I don't bother with any of the fancy stuff. Just store it in an xml file in the application directory. Done.
Filestream does throw an error if you try to store it using File.applicationDirectory. I just trick the program...
var trickFile:File = File.applicationDirectory;
var file:File = new File(trickFile.nativePath + mySettings.xml);
Air falls for it every time.

Replacing SQLite database while accessing it

I am completely new to SQLite and I intend to use it in a M2M / client-server environment where a database is generated on the server, sent to the client as a file and used on the client for data lookup.
The question is: can I replace the whole database file while the client is using it at the same time?
The question may sound silly but the client is a Linux thin client and to replace the database file a temporary file would be renamed to the final file name. In Linux, a program which has still open the older version of the file will still access the older data since the old file is preserved by the OS until all file handles have been closed. Only new open()s will access the new version of the file.
So, in short:
client randomly accesses the SQLite database
a new version of the database is received from the server and written to a temporary file
the temporary file is renamed to the SQLite database file
I know it is a very specific question, but maybe someone can tell me if this would be a problem for SQLite or if there are similar methods to replace a database while the client is running. I do not want to send a bunch of SQL statements from the server to the client to update the database.
No, you cannot just replace an open SQLite3 DB file. SQLite will keep using the same file descriptor (or handle in Windows-speak), unless you close and re-open your database. More specifically:
Deleting and replacing an open file is either useless (Linux) or impossible (Windows). SQLite will never get to see the contents of the new file at all.
Overwriting an SQLite3 DB file is a recipe for data corruption. From the SQLite3 documentation:
Likewise, if a rogue process opens a
database file or journal and writes
malformed data into the middle of it,
then the database will become corrupt.
Arbitrarily overwriting the contents of the DB file can cause a whole pile of issues:
If you are very lucky it will just cause DB errors, forcing you to reopen the database anyway.
Depending on how you use the data, your application might just crash and burn.
Your application may try to apply an existing journal on the new file. Sounds painful? It is!
If you are really unlucky, the user will just get back invalid results from any queries.
The best way to deal with this would be a proper client-server implementation where the client DB file is updated from data coming from the server. In the long run that would allow for far more flexibility, while also reducing the bandwidth requirements by sending updates, rather than the whole file.
If that is not possible, you should update the client DB file in three discrete steps:
Send a message to the client application to close the DB. This allows the application to commit any changes, remove any journal files and clean-up its internal state.
Replace/Overwrite the file.
Send a message to the client application to re-open the DB. You would have to setup all prepared statements again, though.
If you do not want to close the DB file for some reason, then you should have your application - or even a separate process - update the original DB file using the new file as input. The SQLite3 backup API might be of interest to you in that case.

Using an encrypted file securely

I'm writing an application with a dBASE database file in Borland Delphi 7.
Note: I think this question is file-security related and you can forget the dBASE thing (consider it as a TXT file) in this question.
The database must be accessed just by the application. Then it must be encrypted. Unfortunately dBASE doesn't support any password mechanism and i had to encrypt the file by myself (and i also HAVE to use dBASE)
What approach do you suggest to secure the database file?
The simple one is:
Encrypting the database file and placing it near beside the application EXE file.
When the application runs, it should decrypt the file (with a hard-coded password) and copy the result to a temporary file that has DeleteOnClose and NoSharingPermission flags.
When Closing, application should encrypt the temp dBASE file and replaces the old encrypted file with the new one.
I think this is a fair secure approach. But it have two big problems:
With an undelete tool the user can restore and access to the deleted temp file.
Worse: When application is running, if the system rebooted suddenly the DeleteOnClose flag fails and the temp file remains on hard disk and user can access it.
Is there any solution for, at least, the second part?
Is there any other solution?
You could also try to create a TrueCrypt file-based containter, mount it, and then put the dBase file inside the mounted encrypted volume. TrueCrypt is free (in both senses) and it's accessible via command line parameters from your application (mount before start, unmount before quit).
Depending on what you're doing with the database, you may be able to get away with just decrypting the records you actually need. For example, you could build indexes based on hash codes (rather than real data); this would reduce seeks into the database to a smaller set of data. Each record in the subset would have to be decrypted, but this could be a lot better than decrypting the entire database.

Resources