Archive for October, 2011

Secure Data Persistence with AIR 3

AIR 3 offers two new capabilities that can make data persistence much more secure than what was possible with previous versions of AIR. If your AIR application persists information like credentials or sensitive relational data that must remain secure, this article is for you.

flash.crypto.generateRandomBytes()

The new flash.crypto.generateRandomBytes function provides a way to generate far more random data than was previously possible. As you probably already know, functions like Math.random are known as pseudorandom number generators because they rely on relatively small sets of initial data (like timestamps). Bytes generated in such a manner are insufficient for use as encryption keys because if the random number generation algorithm is known (and you should always assume that it is), and the mechanism for seeding it is known and constrained, it isn’t hard for an attacker to guess the encryption key and gain access to your data.

The new generateRandomBytes function uses a much more random (and therefore, much more secure) method for generating random bytes. Rather than implementing our own algorithm, the runtime uses the underlying operating system’s random byte generation function. The table below shows which function is used on each platform:

Operating System Function
Windows CryptGenRandom()
Mac OS X /dev/random
Linux /dev/random
Android /dev/urandom
iOS SecRandomCopyBytes()

The natural question at this point is what makes the operating systems’ random byte generation implementations so secure — or, put another way, how is the OS able to generate random data which is more cryptographically secure than Math.random? The answer is something called an entropy pool. An entropy pool is essentially a collection of randomness. When a process needs random bytes, they can be taken from the entropy pool through one of the functions listed above, and when a process believes it has random data, it can choose to add those bytes to the entropy pool. Processes can obtain random data in several ways:

  • Hardware jitter (deviations caused by things like electromagnetic interference or thermal noise).
  • Mouse movements and/or the time between keystrokes.
  • Unpredictable hardware events like disk head seek times, or network traffic.
  • A hardware random number generator.

(Now is a good time to state that it’s probably more correct to say that an entropy pool contains unguessable data as opposed to truly random data, but in the world of encryption, the two amount to essentially the same thing.)

So now that you have access to unguessable bytes, what can you do with them to make your data more secure? The most obvious use for the new generateRandomBytes function is probably the creation of encryption keys. The database implementation embedded inside of the AIR runtime supports encrypted database files, and the quality of the encryption is largely based on the quality of your encryption key. The generateRandomBytes function gives you a cryptographically secure way to generate an encryption key, and the EncryptedLocalStore API gives you a secure method for storing it (more on this below). Other uses of the generateRandomBytes function include generating session identifiers, GUIDs, and salt to be used in hashes (salt is additional data added to the data you want to hash which makes looking the hash up in rainbow table much less feasible).

Mobile Encrypted Local Store

Update (11/3/2011): If you’re having trouble getting ELS to work in the iOS emulator or in “fast packaging” mode, add the following to your compiler arguments: -swf-version=13

A second feature in AIR 3 which can make data persistence more secure is the introduction of the mobile EncryptedLocalStore (ELS) API. ELS has been available for the desktop profile since 1.0, but AIR 3 is the first version which makes it available on mobile.

ELS provides a secure storage mechanism implemented by the underlying operating system. On Windows, ELS uses DPAPI, and on OS X, ELS uses Keychain services.

The new mobile implementations of ELS require some additional explanation. On iOS, ELS uses Keychain services just as it does on OS X, however Android does not provide a encrypted storage service for the runtime to leverage. Data is therefore "sandboxed" rather than encrypted. In other words, it is stored in a secure, isolated location (inaccessible to other processes), but since the data isn’t actually encrypted, if an attacker has access to the physical device, or if a user has rooted his or her device, it is possible for the data to be compromised. According to the internal ELS specification:

On Android, ELS can guarantee that on a non-rooted device in the hands of an authorized user, ELS data of an AIR application will not be accessible/modifiable by any other application (AIR or native) running on the device.

It’s possible that Android will provide a more secure storage service in the future, and we can simply swap out our implementation, however for the time being, it’s worth noting that the Android implementation lacks the additional step of encryption on top of isolation.

So what kinds of data should mobile developers store with ELS? The same data that you would store in desktop applications. Namely:

  • Encryption keys (the sequence of random bytes obtained through the generateRandomBytes function).
  • Account credentials. If you want to store users’ credentials so they don’t have to enter them every time they use your app, ELS is the correct API to use.
  • Salts for hashes. Once you’ve salted and hashed something like a password, you need to be able to securely persist the salt for future comparisons.

Summary

If you just need to generate random numbers for something like a game, you should stick to using Math.random. In fact, on some platforms, the generateRandomBytes function could temporarily block if the entropy pool has been entirely drained which means you don’t want to pull large amounts of data from it in an endless loop. Rather, generateRandomBytes should be reserved for generating unguessable cryptographically secure random data for things like encryption and session keys, GUIDs, and salts for hashes.

Whenever you need to store sensitive information like credentials, encryption keys, or salts, you should always use the EncryptedLocalStore APIs. Since they are now supported everywhere, you can use them in a completely cross-platform manner.

Whether you’re updating an existing application that needs to persist data securely, or building an entirely new one, I strongly recommend that you use the new best practices made possible in AIR 3.

Parsing Exif Data From Images on Mobile Devices


If you’re interested in parsing Exif data from images on devices using AIR, you’re in the right place. But first, a little background to put this example in context.

Someone asked me a really good question at MAX about getting metadata about images on mobile devices. I don’t recommend using the file property of MediaPromise to get a reference to images because it doesn’t work across platforms (it works fine on Android, but not on iOS — for more information, see How to Use CameraUI in a Cross-platform Way), so that means you don’t have access to certain properties on File like creationDate, size, etc. The best way to get information about images on mobile devices, therefore, is to parse out the image’s Exif data.

Exif stands for "Exchangeable image file format," and it provides a way for digital cameras and applications to encode information about images directly in the images themselves. In other words, Exif is to images what ID3 is to MP3 files. Since the data is image-specific, it is typically much richer than information associated with a file reference. Of course, it’s also a little bit harder to get to, so I figured I would write a sample application to demonstrate one way of doing it.

ExifExample (Github project, Flash Builder project) is a simple application which allows the user to either take a photo, or browse to a photo already on the device, and then uses the ExifInfo library to parse the Exif data out of the image. The code is pretty simple, but there a few things to pay special attention to:

  1. I don’t use the file property of MediaPromise to access the image. As I mentioned above, that would work on Android, but it doesn’t work on iOS, and it’s not guaranteed to work on other platforms in the future. Instead, I use a MediaPromise to either synchronously or asynchronously get at the bytes of the image.
  2. I only read the first 64K of the image before parsing out the Exif data. Exif data has to be within the first 64K of an image which makes dealing with very large files much easier. If you’re downloading them, it saves time and bandwidth, and in the context of a mobile application, it saves memory. Now that the resolution of cameras on mobile devices is getting so high, you might not want to read entire images into RAM. (When mobile applications run out of memory, they tend to be shut down with little or no warning, so keeping your memory footprint as low as possible is always a good idea.) This is especially important if you want to display the thumbnails of multiple photos in a grid or list.
  3. Although the application supports both taking a picture using CameraUI and selecting a picture using CameraRoll, all the code that deals with the MediaPromise (both synchronous and asynchronous) is shared. If you have an application that supports both paths, I would recommend using this type of architecture in order to simplify your codebase.
  4. Even though this application is designed to run on mobile devices, it also supports selecting an image from a hard drive using the File.browseForOpen() function. If there’s an opportunity to add desktop functionality into a mobile application, I will usually do it since the more I can use and debug the application on the desktop before running it on a mobile device, the faster and smoother the development process goes. In order to support selecting an image from the desktop, I only had to add an additional 20 lines of code, and it definitely saved me much more time in testing and debugging than it cost me.

I should point out that this sample is not intended to highlight any particular Exif parsing library. I used the ExifInfo library because of its favorable license (MIT), but there are other libraries out there, as well (none of which I tried, so I can’t vouch for them). I should also point out that I had to modify the library according to Joe Ward’s instructions here in order to get it to work properly on iOS.

Providing Hints to the Garbage Collector in AIR 3

AIR 3 has a new API to allow developers to provide the runtime’s garbage collector with hints. The API is called System.pauseForGCIfCollectionImminent(), and it requires a little explanation to understand both it’s utility and value.

Before I get into how the function works, let’s start with why you’d want to give the garbage collector pointers (no pun intended) to help it decide when to reclaim memory. Running the garbage collector can cause the runtime to pause, and while the pause is typically imperceptible, if you’re doing something like playing a fast-paced game, you might notice it. In this particular scenario, a better time to garbage collect might be between game levels. Or, if you’re building something like an e-reader, it would be best to reclaim memory while the user is reading as opposed to during your super slick and smooth page-flip animation.

The System.gc() function can force the runtime to garbage collect, however it doesn’t always have 100% predictable results across all platforms, and forcing garbage collection on a regular basis is usually overkill. System.pauseForGCIfCollectionImminent(), on the other hand, does not force garbage collection, but rather serves as a mechanism to tell the runtime that a particular place in your application would be a good place to reclaim memory, and to specify how likely it is that runtime will take that advice. The function takes a single parameter called imminence which is a Number indicating the strength of your recommendation. From the spec:

The GC will synchronously finish the current collection cycle (complete the marking and perform finalization) if the current allocation budget has been exhausted by a fraction greater than the fraction indicated by the parameter imminence.

If it’s still not entirely clear, here are some examples:

Imminence Meaning / Result Likelihood
.25 If more than 25% of the allocation budget has been used, finish the current collection cycle. More likely
.75 If more than 75% of the allocation budget has been used, finish the current collection cycle. Less likely

In the former case, you’re essentially saying, "I really want you to garbage collect right now because a lot of animation is about to happen which I want to be as smooth as possible," and the latter case is essentially saying, "If you were going to garbage collect pretty soon anyway, now would be a pretty good time."

If you’re currently using System.gc() to force garbage collection in your AIR applications, I highly recommend you take a look at this new API.

Slides, Links, and Questions From my MAX 2011 Presentation

I wanted to post some additional information from my sessions at MAX 2011 for those of you who weren’t able to make it. Below you can find my slides, all the links contained in my presentation, and some of the questions (with answers) I received.

Slides

The recording of my presentation isn’t available yet is now available, but you can also just download the slides here (PDF).

Continue reading…