For most developers, security is a prime concern when developing web applications: Password fields, SSL connections, and likely additional measures on the server. What happens when you're developing a desktop application for Adobe AIR where there is no server? With features like file IO, you could clearly store sensitive information on disk, but you don't want to use plain text. This article explores the encrypted local store feature in Adobe AIR to help you protect your users' data.
In order to make the most of this article, you need the following software and files:
General experience of building applications with HTML or Ajax is suggested.
To gain access to the encryption functionality that is built
into Adobe AIR, you leverage the EncryptedLocalStore class. The class has only three methods and all of them are static (that is,
they don't require an instance of the class):
EncryptedLocalStore.setItem(). EncryptedLocalStore.getItem(). EncryptedLocalStore.removeItem().Note: The encrypted local store was added in AIR beta 2.
The storage mechanism has changed in Adobe AIR 1.0 and previously existing
encrypted data is no longer accessible. Before Adobe AIR 1.0 can use this
feature you must call EncryptedLocalStore.reset() to clear all
previously existing data. You may want to use an Adobe AIR beta 2 application
to retrieve the data prior to resetting the store, as all existing data will be
destroyed.
Here's an overview of how encryption is implemented in Adobe AIR:
Everything is put in the store, and retrieved from the
store, as a ByteArray. This can be a little confusing at first when you
think about just simple data such as passwords. The encryption mechanism
however can be leveraged on entire files, not just text, and the ByteArray accommodates more diverse scenarios.
Take a look at the common case of remembering a user's login
information starting with storing the data. This means getting the information
out of the input field, writing it to a ByteArray, and then
putting the data in the encrypted store:
function doSignIn()
{
var data = null;
var email = null;
var password = null;
if( document.getElementById( 'remember' ).checked )
{
email = document.getElementById( 'email' ).value;
password = document.getElementById( 'password'
).value;
data = new air.ByteArray();
data.writeUTFBytes( email );
air.EncryptedLocalStore.setItem( 'email', data );
data = new air.ByteArray();
data.writeUTFBytes( password );
air.EncryptedLocalStore.setItem( 'password', data );
} else {
removeUser();
}
document.getElementById( 'login' ).style.visibility =
'hidden';
}
When calling EncryptedLocalStore.setItem(), you need
to have the data already in a ByteArray. When storing a string, this can be
easily accomplished by creating a new ByteArray instance, and
then using ByteArray.writeUTFBytes(),
which takes a string argument. The other important part of EncryptedLocalStore.setItem() is the name of the item you're setting. This acts as a label for
reference later when you want to get, change, or remove the data.
When using the encrypted local store, it is important to always read and write the data using UTF-8.
When you choose to store the user's login credentials is really up to you. You might choose to store the data when the user clicks the Remember me check box. You might choose to store the data when the user clicks the Sign In button. Or you might even wait to store the data, until a successful login has been made. As a general rule, you'll probably want to wait for a successful login so you can be sure that the data you are storing will actually be accurate for future use.
Next up comes getting the data back out of the encrypted
local store. In the case of "Remember me" functionality, this will
most commonly be done when the Adobe AIR application starts. You get the data
using the item name (label) you used previously. Using ByteArray.readUTFBytes() will get the string back out of the ByteArray.
function rememberUser()
{
var email = air.EncryptedLocalStore.getItem( 'email' );
var pass = air.EncryptedLocalStore.getItem( 'password' );
if( email != null )
{
document.getElementById( 'email' ).value = email.readUTFBytes( email.bytesAvailable );
document.getElementById( 'password' ).value = pass.readUTFBytes( pass.bytesAvailable );
document.getElementById( 'remember' ).checked = true;
} else {
document.getElementById( 'email' ).value = '';
document.getElementById( 'password' ).value = '';
document.getElementById( 'remember' ).checked = false;
}
}
In this scenario a call is made for each value, user name
and password. You might choose to concatenate both user name and password into
one comma-separated value before you store it. That in turn would mean only one
call to get that value back out of the store. If you went that direction here,
you'd likely end up with more code to split the values back apart (that is, String.split()).
Keep in mind that EncryptedLocalStore doesn't really care about
the independent values, just that it is encrypting a ByteArray.
Finally comes the task of removing the data in the situation
that the user no longer wants the application to store it. The EncryptedLocalStore class also makes that task easy enough by providing EncryptedLocalStore.removeItem().
Just like EncryptedLocalStore.getItem(),
you pass the label of the item you want to remove when calling EncryptedLocalStore.removeItem(),
which returns no value.
function removeUser()
{
air.EncryptedLocalStore.removeItem( 'email' );
air.EncryptedLocalStore.removeItem( 'password' );
}
Just like the decision as to when to store the data, and how
to store the data, when to remove the data is also up to you. The data that
you're encrypting doesn't have to be text, it can be anything that can be
represented by a ByteArray. The encrypted local store is flexible. The
important part of course is that your user's data can now be securely stored on
the desktop as part of your application's functionality.