Thursday, March 3, 2011

Device Encryption in Android 3.0

Transparent encryption of block devices in Android 3.0.

The Motorola Xoom and several other new tablets on the market run Android 3.0, Honeycomb, which is built on the 2.6.36 Linux kernel. Most, if not all, of these Android tablets feature an Nvidia Tegra 2 processor. The 2.6.36 Linux kernel on these Android 3.0 Tegra 2 tablets introduces transparent, whole-disk encryption to everyday users. This encryption is provided by the dm-crypt device-mapper target in the Linux kernel, which creates a virtual layer on top of an existing block device and uses the crypto APIs in the Linux kernel for encryption and decryption of the underlying block devices.

Whether you are typing commands via a shell over a serial port or using the email application to check your email, the reads and writes to the file system are performed in the same manner with no changes to the upper-level applications.

After pressing the power button on the back of the Xoom tablet, the device boots up, and the user is presented with the desktop environment, from which he or she can choose to play a game, check email, or read an e-book. By tapping on Settings and then Location & Security, one can choose to "Encrypt tablet" from the screen. The encryption process takes approximately one hour, and the user is presented with a few basic screens upon completion.

After the encryption process is complete, the tablet is powered down. Upon rebooting the tablet, the user is prompted to input a PIN code, which is used to unlock the device. After entering the correct PIN code, the tablet powers up as normal, and the user can proceed with standard activities such as checking email, reading e-books, etc.

The Linux 2.6.36 kernel supports the device mapper framework, which allows virtual layers to be mapped on top of block devices for doing things like striping and mirroring. The device-mapper also provides a convenient target called dm-crypt, which is a device-mapper crypto target. The dm-crypt target provides transparent encryption of block devices.

Before the encryption operation, the output of the mount command shows the device name and mount point, indicating the partition where the user's data is stored, and this is the partition that will be encrypted.

/dev/block/platform/sdhci-tegra.3/by-name/userdata on /data type ext4 (rw,nosuid,nodev,noatime,barrier=1,data=ordered)
A few mount options to take note of:  noatime, barriers and data=ordered

...And after the encryption operation
/dev/block/dm-0 /data ext4 rw,nosuid,nodev,noatime,barrier=1,data=ordered 0 0

dmsetup will give us more information. As you can see from the below command, a dm-crypto device mapper target called crypt, has been setup in the kernel.  The dm-crypt target provides transparent encryption and decryption of data on the block device using the crypto APIs in the Linux kernel.

# dmsetup targets
crypt            v1.7.0
striped          v1.3.0
linear           v1.1.0
error            v1.0.1
# dmsetup status
datadev: 0 61326304 crypt           v1.0.1
Albeit the details surrounding key storage (see kernel source), supported ciphers (cat /proc/crypto), and hardware acceleration (see kernel source), here are some rudimentary performance tests that I ran before and after encrypting /data.  For the interested reader, there are some kernel level details related to the Tegra 2 processor which one can discover by going through the source code for the Linux 2.6.36 Tegra 2 branch.

The initial results of the the basic tests look good. There is a dedicated kernel thread for handling IO.  The read latency appears to be related to the kernel IO thread since reads on flash based storage devices can usually be performed in near constant time.

Unencrypted (2 GB Write - 104857 2k blocks)
/data/local/tmp # time dd if=/dev/zero of=ofile bs=2k count=1048572

1048572+0 records in
1048572+0 records out
2147475456 bytes (2.0GB) copied, 255.912521 seconds, 8.0MB/s
real    4m 17.25s
user    0m 0.73s
sys     0m 24.55s
Unencrypted (2 GB Read - 104857 2k blocks)
/data/local/tmp # time dd of=/dev/null if=ofile bs=2k count=1048572

1048572+0 records in
1048572+0 records out
2147475456 bytes (2.0GB) copied, 101.749864 seconds, 20.1MB/s
real    1m 41.79s
user    0m 1.15s
sys     0m 17.62s
Encrypted (2 GB Write - 104857 2k blocks)
/data/local/tmp # time dd if=/dev/zero of=ofile bs=2k count=1048572

1048572+0 records in
1048572+0 records out
2147475456 bytes (2.0GB) copied, 260.219584 seconds, 7.9MB/s
real    4m 26.94s
user    0m 0.64s
sys     0m 24.12s
Encrypted (2 GB Read - 104857 2k blocks)
/data/local/tmp # time dd of=/dev/null if=ofile bs=2k count=1048572

1048572+0 records in
1048572+0 records out
2147475456 bytes (2.0GB) copied, 124.291204 seconds, 16.5MB/s
real    2m 4.31s
user    0m 0.47s
sys     0m 7.74s