Archive for December, 2007

Encrypting Data in AIR

AIR applications often need to store credentials. Many web services out there require authentication, which means that AIR applications need a secure way to store sensitive data. I first ran into this issue when I wrote Salsa, an Amazon S3 client. Salsa needs the end user’s public and private access keys for signing requests, but since both keys are long arbitrary strings that are almost impossible to memorize, I couldn’t ask the user to enter them each time they wanted to use the application. And for obvious reasons, I couldn’t store them in plain text. I needed a way to persist the user’s credentials in way that would not allow other users or processes to access them.

This was back in days of AIR beta 1. The only option I had at the time was to encrypt the credentials myself using a pass phrase provided by the end user. Each time the user started the application, therefore, I had to prompt them for their pass phrase which I’d use to decrypt the public and private keys. If they lost their pass phrase, they had to reenter their public and private keys, as well as enter a new pass phrase. From a usability perspective, this was not the experience I was after.

But then along with AIR beta 2 came the flash.data.EncryptedLocalStore API. There have been some small changes in M6 (the upcoming beta 3), but it’s essentially the same. The EncryptedLocalStore APIs use DPAPI on Windows and the Keychain on Mac to encrypt arbitrary data and associate it with a specific OS user, AIR application ID, and publisher ID. That means applications can encrypt and store data that only the current user and the current application can decrypt. And the best part is that it’s extremely easy to use:

// Writing encrypted information
var passwordBytes:ByteArray = new ByteArray();
passwordBytes.writeUTFBytes("secretPassword");
EncryptedLocalStore.setItem("password", passwordBytes);

// Reading encrypted information
var passwordBytes:ByteArray = EncryptedLocalStore.getItem("password");
var password:String = passwordBytes.readUTFBytes(passwordBytes.length);

To make using the EncryptedLocalStore even easier, my team has written a Preferences API on top of it which makes it extremely easy for applications to store either encrypted or non-encrypted user preferences using any serializable data type.

Whether you use our Preferences library or the EncryptedLocalStore directly, I really think the ease with which sensitive data can be encrypted and decrypted will encourage developers to build secure and user-friendly AIR applications.

Mapping File Extensions to MIME Types

When writing Salsa (an Amazon S3 client), I ran into a situation where I needed to map MIME types to file extensions and vice versa. So I wrote a simple but very handy utility to do it for me. The ActionScript code is here if you just want to copy it, or it’s available in as3corelib if you want grab the entire library (with tons of other useful APIs).

Multi-monitor Support in AIR

I’ve seen several people ask about multi-monitor support in AIR. The answer is: it’s there, and it’s very good.

Take a look at the flash.display.Screen class (AIR only — not available in the Flash Player). It contains the following properties:

  • bounds
  • colorDepth
  • mainScreen (for getting a Screen reference to the main screen when there are multiple monitors)
  • screens (an array of Screen objects for all attached monitors)
  • visibleBounds (returns a Rectangle that excludes unusable portions of the screen like the taskbar, menu bar, and the dock)

The Screen class also contains a very cool function called getScreensForRectangle that returns an array of screens that intersect the specified Rectangle.

We’ve also added a ScreenMouseEvent that is dispatched by SystemTrayIcon and gives you the coordinates of a click relative to the main screen as opposed to an application window.

For a relatively simple example of the Screen APIs in action, check out SPF on the Adobe Labs Sample Application page.