An important feature added in Adobe AIR 1.5 is support for an encrypted local database. Previously, AIR applications could use a local database, but the database files are readable by any application, making them inappropriate for any use in which security is a concern. On the other hand, AIR has always supported an encrypted local store (that is, an encrypted text file), but that option provides none of the handy database functionality. As of AIR 1.5, your AIR applications can have the best of both worlds, by storing data in an encrypted database.
In this article, I'll start by highlighting the key points and minor differences of working with encrypted databases in an Adobe AIR application, versus working with unencrypted databases. From there, I'll get into the more important subject of using an encrypted database in the most secure method possible.
Creating and Using an Encrypted Database
Before getting into the code, you need to understand two things:
- As with any system that uses encryption, the same encryption key must always be used.
- Although you can later change a database's encryption key, you cannot retroactively encrypt an unencrypted database (or unencrypt an encrypted one, for that matter). In other words, the database must initially be created in an encrypted format.
Creating an encrypted database starts with a File object that represents the database file on the computer, and an SQLConnection object through which all queries will be executed:
var db = air.File.applicationStorageDirectory.resolvePath('example.db'); var conn = new air.SQLConnection();
Next, you establish the error and open-connection handlers; then, open the connection using open() or openAsync(), with the latter generally preferred.
To create the database, provide the mode SQLMode.CREATE as the second argument to either method:
conn.open(db, SQLMode.CREATE); conn.openAsync(db, SQLMode.CREATE);
That code works for unencrypted databases, but for encrypted ones you need to add the encryption key as the fifth argument to open() or the sixth to openAsync():
conn.open(db, SQLMode.CREATE, false, 1024, key); conn.openAsync(db, SQLMode.CREATE, null, false, 1024, key);
The key in that code is the important addition for an encrypted database. The encryption key must be a ByteArray object that's 16 bytes in length (it's therefore a 128-bit key). To create that object, you can do this:
var key = new ByteArray(); key.writeUTFBytes('ActualPassword16');
First, an empty ByteArray object is created, and 16 bytes of data are written to it. Note that the length of the provided string—ActualPassword16—is 16 characters long, each of those characters requiring one byte.
Once the database connection has been opened with the associated key, you would run a CREATE table SQL command on the database, and then insert records as needed. Subsequent uses of the same database merely need to use the same key but open the database using either SQLMode.READ or SQLMode.UPDATE, depending on what actions will later be taken. Attempts to connect to an encrypted database with an incorrect key will trigger an SQLError or SQLErrorEvent with an errorID of 3138. The generic error message will be File opened is not a database file (it actually is a database file—it just can't be decrypted).
This approach (hard-coding the key into the application) will work, but doesn't provide much security. There are two problems with this approach:
- The source code of an AIR application is viewable on the user's computer. With a little bit of effort, a malicious user could find the encryption key and then be able to unlock the database.
- Even if no one knew how to pick through the application's source code, anyone able to run the application—in other words, anyone with access to the computer—will effectively have access to the database as if it were not encrypted in the first place.