Android + encryption on the G1 using cryptsetup and LUKS

A couple months ago, I started looking for a way to get volume encryption working on my Android G1 (running JF1.5). I couldn’t find any references to anyone else getting it working, or even much attempting to, so I gave it a shot. After a bit of work, I was able to build and run cryptsetup successfully, but it complained about the backend not being available. Unfortunately I hadn’t had much time to work on it until now. The final work on this was all done on CyanogenMod’s release, which I’ve recently moved to.

Disclaimer: The following instructions are rather lengthy, difficult to follow, partially or wholly incomplete, and possibly completely incorrect. If these instructions brick your phone, lose all of your data, rack up $50k in usage fees, and open a portal to hell in your kitchen, it’s up to you to deal with it.

Shortcut: Here’s a link to the cryptsetup binary for the G1. If you trust me, (and you really shouldn’t), then feel free to download it, adp push it to your phone and be on your way.
(sha1sum: 3db06da1c4248f8770b9d7a554c4629c0589137e)

A G1, or some other similar ARM device.
Building the binary was done inside a Fedora 11 VM (x86_64). If you’re running Fedora, or have a VM of it handy, this will be easy.

* Follow the instructions here, to setup a cross-compiler toolchain.
* In addition, you’ll want to grab the c++ compiler:
[shawn@argon ~]$ sudo yum install armv5tel-redhat-linux-gnueabi-gcc-c++

Once that’s complete, you’ll need to add a few more development tools, such as the rpmdevtools.

[shawn@argon ~]$ sudo yum groupinstall ‘Development Tools’

* Now, let’s make a couple quick additions to our ~/.rpmmacros file. This will tell rpmbuild a bit about what we want:

%_build armv5tel-redhat-linux-gnueabi
# This shouldn’t be necessary, but the compiler flags aren’t being set correctly when passing the architecture.
%__global_cflags  -O2 -g -march=armv5te

* Set a couple variables that we’ll be using:

[shawn@argon ~]$ CROSS_ROOT=/usr/armv5tel-redhat-linux-gnueabi/sys-root/
[shawn@argon ~]$ mkdir cryptsetup && cd cryptsetup

We’re building a static binary, so the typical shared objects (.so.* files) will not work. We need static libraries (*.a). Unfortunately, the libs in the libgcrypt RPM are dynamically linked. This means we need to rebuild this package from source as well. Before we get to that, we’ll also need to build libgpg-error, which libgcrypt uses.
* Grab the source RPM: wget $SOURCE_URL/libgpg-error-1.6-3.src.rpm
[shawn@argon cryptsetup]$ rpm -ivh libgpg-error-1.6-3.src.rpm
[shawn@argon cryptsetup]$ cd ~/rpmbuild/SPECS

We need to edit the specfile and make a single change to tell the build process that we want a static library. Use vim (or some other kind of editor) to open libgpg-error.spec. On line 39, change ‘–disable-static’ to ‘–enable-static’. Easy. Now let’s build it:

# -bc runs through the %build stage, doing a ‘configure’, and ‘make’ on our build. –target specifies the target architecture that we’re building for.
[shawn@argon SPECS]$ rpmbuild -bc –target armv5tel –nodeps libgpg-error.spec

* Hopefully, that will all work beautifully, and you’ll now have a static lib to use.
[shawn@argon SPECS]$ cd ../BUILD/libgpg-error-1.6/
[shawn@argon libgpg-error-1.6]$ ls -l src/.libs/*.a
-rw-r–r–. 1 shawn shawn 68938 2009-10-02 05:44 src/.libs/libgpg-error.a

* Copy that to the cross-compiler’s libs directory:
[shawn@argon libgpg-error-1.6]$ cp src/.libs/libgpg-error.a $CROSS_ROOT/usr/lib

Now, back to libgcrypt. That should build now, so let’s download and install the source RPM and try it:

* Grab the source RPM: wget $SOURCE_URL/libgcrypt-1.4.4-4.fc11.src.rpm
[shawn@argon libgpg-error-1.6]$ cd ~/cryptsetup
[shawn@argon cryptsetup]$ rpm -ivh libgcrypt-1.4.4-4.fc11.src.rpm

We need to edit the specfile and make a couple changes. Use vim (or some other kind of editor) to open libgcrypt.spec. On line 47 or so, change ‘–disable-static’ to read ‘–enable static’. Below that, you’ll also see a line that reads ‘–disable-asm’ on sparc64 systems. There’s some assembly code that gets built that doesn’t exist for (or build on) sparc64… same with our arm processor. Change that line from:

%ifarch sparc64
to read:
%ifarch sparc64 armv5tel

Save the file, and try the build:
[shawn@argon cryptsetup]$ cd ~/rpmbuild/SPECS
[shawn@argon SPECS]$ rpmbuild -bc –target armv5tel –nodeps libgcrypt.spec

When that finishes, copy the static library over to the $CROSS_ROOT:
[shawn@argon SPECS]$ cd ../BUILD/libgcrypt-1.4.4
[shawn@argon deps]$ cp src/.libs/libgcrypt.a /usr/armv5tel-redhat-linux-gnueabi/sys-root/usr/lib

If you’ve gotten this far, you only need to extract a few files before you can actually build the cryptsetup executable.

We’re going to just download the headers and library files for this project from the Fedora ARM project’s site. The following command will download the RPMs containing what we need. Do NOT install these RPMs once they’re downloaded. We just want to root around and pull out the files we need from them.

* Set a variable to save us some typing. This is where we’ll be pulling everything from:
[shawn@argon cryptsetup]$ SOURCE_URL=

1/4: e2fsprogs:

# Set the file we’re using
[shawn@argon cryptsetup]$ FILE=e2fsprogs-devel-1.41.3-2.fc11.armv5tel.rpm
# Download the file
[shawn@argon cryptsetup]$ wget $SOURCE_URL/$FILE
# Create a directory to extract to, and extract the files
[shawn@argon cryptsetup]$ mkdir root && rpm2cpio $FILE | ( cd root && cpio -idv)
# We need the libs under /usr/lib:
[shawn@argon cryptsetup]$ cp root/usr/lib/* $CROSS_ROOT/usr/lib

2/4: popt-static-1.13-5.fc11.armv5tel.rpm:
[shawn@argon cryptsetup]$ FILE=popt-static-1.13-5.fc11.armv5tel.rpm
[shawn@argon cryptsetup]$ wget $SOURCE_URL/$FILE
[shawn@argon cryptsetup]$ mkdir root && rpm2cpio $FILE | ( cd root && cpio -idv)
[shawn@argon cryptsetup]$ cp root/usr/lib/* $CROSS_ROOT/usr/lib

3/4: popt-devel-1.13-5.fc11.armv5tel.rpm
[shawn@argon cryptsetup]$ FILE=popt-devel-1.13-5.fc11.armv5tel.rpm
[shawn@argon cryptsetup]$ wget $SOURCE_URL/$FILE
[shawn@argon cryptsetup]$ mkdir root && rpm2cpio $FILE | ( cd root && cpio -idv)
# Just the headers this time:
[shawn@argon cryptsetup]$ cp root/usr/include/* $CROSS_ROOT/usr/include

4/4: libgcrypt-devel-1.4.4-4.fc11.armv5tel.rpm
[shawn@argon cryptsetup]$ FILE=popt-static-1.13-5.fc11.armv5tel.rpm
[shawn@argon cryptsetup]$ wget $SOURCE_URL/$FILE
[shawn@argon cryptsetup]$ mkdir root && rpm2cpio $FILE | ( cd root && cpio -idv)
# Just the headers this time also:
[shawn@argon cryptsetup]$ cp root/usr/include/* $CROSS_ROOT/usr/include

Oh, we need to the static devicemapper libs and headers, so that we can compile those in as well.

* Download the src RPM:
[shawn@argon SRPMS]$ wget

* Install it:
[shawn@argon SRPMS]$ rpm -ivh lvm2-2.02.43-1.fc11.src.rpm

* Modify our specfile
# Around line 47, add ‘–with-static_link’, and disable various things which we won’t need (if you’re using clvm on your phone, do tell):
%configure –enable-lvm1_fallback –enable-fsadm –with-clvmd=cman –with-cluster=internal –with-pool=internal –with-user= –with-group= –with-dmdir=device-mapper.%{device_mapper_version} –with-usrlibdir=/usr/%{_lib} –with-usrsbindir=/usr/sbin –with-device-uid=0 –with-device-gid=6 –with-device-mode=0660 –enable-pkgconfig –with-static_link –with-clvmd=none –with-pool=none –with-cluster=none –with-snapshots=none –with-mirrors=none

# Before we build, we need to set the following – autoconf sees that we’re cross compiling, but doesn’t set it. (Odd).
[shawn@argon SPECS]$ export ac_cv_func_malloc_0_nonnull=yes
[shawn@argon SPECS]$ rpmbuild -bc –target armv5tel –nodeps lvm2.spec

# Copy the static lib to its new home:
[shawn@argon LVM2.2.02.43]$ sudo cp ./libdm/ioctl/libdevmapper.a /usr/armv5tel-redhat-linux-gnueabi/sys-root/usr/lib/
# Copy the headers
[shawn@argon LVM2.2.02.43]$ sudo cp include/* /usr/armv5tel-redhat-linux-gnueabi/sys-root/usr/include/

Ok, we should now be able to build cryptsetup!

* Of course, we’ll need to grab the source code to cryptsetup itself:
[shawn@argon cryptsetup]$ yumdownloader –source cryptsetup-luks
* Install the source rpm (the ~/rpmbuild directories should be automatically created as well).
[shawn@argon cryptsetup]$ rpm -ivh cryptsetup-luks-1.0.6-7.fc11.src.rpm
[shawn@argon cryptsetup]$ cd ~/rpmbuild/SPECS

* Modify the specfile, to set it to be a static binary:
Line 67 or so should read:
%configure –enable-static –sbindir=/sbin –libdir=/%{_lib}

* Run rpmbuild:
[shawn@argon SPECS]$ rpmbuild -bc –target armv5tel –nodeps cryptsetup-luks.spec

If it built successfully, it probably worked! Let’s see what we have:

[shawn@argon SPECS]$ cd ../BUILD/cryptsetup-1.0.6/
[shawn@argon cryptsetup-1.0.6]$ ls -l src
total 2076
-rwxr-xr-x. 1 shawn shawn 2023875 2009-10-02 04:57 cryptsetup
-rw-r–r–. 1 shawn shawn   17254 2008-03-10 18:14 cryptsetup.c
-rw-r–r–. 1 shawn shawn     779 2006-11-21 04:06 cryptsetup.h
-rw-r–r–. 1 shawn shawn   29752 2009-10-02 04:57 cryptsetup.o
-rw-r–r–. 1 shawn shawn   15755 2009-10-02 04:57 Makefile
-rw-r–r–. 1 shawn shawn     528 2006-11-21 04:06
-rw-r–r–. 1 shawn shawn   16116 2008-03-10 18:37
[shawn@argon cryptsetup-1.0.6]$

# Nice. Let’s push it to the device (from a different machine):
[shawn@carbon ~]$ adb push /tmp/cryptsetup /system/sd/
1474 KB/s (2023875 bytes in 1.340s)

# Login to a shell on the device:
[shawn@carbon lib]$ adb shell
# cd /system/sd/
# ./cryptsetup
Usage: cryptsetup [-?vyrq] [-?|–help] [–usage] [-v|–verbose]
[-c|–cipher STRING] [-h|–hash STRING] [-y|–verify-passphrase]
[-d|–key-file STRING] [-s|–key-size BITS] [-S|–key-slot INT]
[-b|–size SECTORS] [-o|–offset SECTORS] [-p|–skip SECTORS]
[-r|–readonly] [-i|–iter-time msecs] [-q|–batch-mode] [–version]
[-t|–timeout secs] [-T|–tries INT] [–align-payload=SECTORS]
[OPTION…] <action> <action-specific>]
./cryptsetup: Argument <action> missing.

# It works!

* Using cryptsetup

Initially I tested that cryptsetup was setup correctly by using a loopback device. Something like:

# dd if=/dev/zero of=/sdcard/crypttest.img bs=1M count=16         # Yes, 16 MB
16+0 records in
16+0 records out
# losetup $(losetup -f) /sdcard/crypttest.img
# losetup
/dev/block/loop0: 0
/dev/block/loop1: 0
/dev/block/loop2: 0 /sdcard/crypttest.img
# There’s our new block device, that we’re going to encrypt

# You must use the aes-plain cipher
# ./cryptsetup luksFormat -c aes-plain /dev/block/loop2

This will overwrite data on /dev/block/loop2 irrevocably.

Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase:
Verify passphrase:
Command successful.
# ./cryptsetup luksOpen /dev/block/loop2 crypttest
Enter LUKS passphrase for /dev/block/loop2:
key slot 0 unlocked.
Command successful.
# echo “Four score and seven years ago our fathers brought forth on this continent” > /dev/block/crypttest
# ./cryptsetup luksClose crypttest

* Reading it back

# ./cryptsetup luksOpen /dev/block/loop2 crypttest
Enter LUKS passphrase for /dev/block/loop2:
key slot 0 unlocked.
Command successful.

# ash
/system/sd # cryptsetup status crypttest
/dev/mapper/crypttest is active:
cipher:  aes-cbc-plain
keysize: 128 bits
device:  /dev/block/loop2
offset:  1032 sectors
size:    31736 sectors
mode:    read/write

# ./cryptsetup luksOpen /dev/block/loop2 crypttest
Enter LUKS passphrase for /dev/block/loop2:
key slot 0 unlocked.
Command successful.

# dd if=/dev/mapper/crypttest bs=512 count=1 | hexdump -C
00000000  46 6f 75 72 20 73 63 6f  72 65 20 61 6e 64 20 73  |Four score and s|
00000010  65 76 65 6e 20 79 65 61  72 73 20 61 67 6f 20 6f  |even years ago o|
00000020  75 72 20 66 61 74 68 65  72 73 20 62 72 6f 75 67  |ur fathers broug|
00000030  68 74 20 66 6f 72 74 68  20 6f 6e 20 74 68 69 73  |ht forth on this|
00000040  20 63 6f 6e 74 69 6e 65  6e 74 0a 2e 8e fa bb 64  | continent…..d|
00000050  1e 4b 99 c4 6e 3f 30 ca  7c b6 7e 2e 8e fa bb 64  |.K..n?0.|.~….d|

# ./cryptsetup luksFormat /dev/block/loop2

Ok, so now it works – my actual setup (for now) has a partition on my SD card setup as a luks partition, formatted as ext4.

Disk /dev/block/mmcblk0: 4072 MB, 4072669184 bytes

4 heads, 16 sectors/track, 124288 cylinders
Units = cylinders of 64 * 512 = 32768 bytes

Device Boot      Start         End      Blocks  Id System
/dev/block/mmcblk0p1               1       76294     2441406   c Win95 FAT32 (LBA)
/dev/block/mmcblk0p2           76294       91553      488281+ 83 Linux
/dev/block/mmcblk0p3           91553      124288     1047528  83 Linux

# When formatting, the creation of a journal will fail due to a missing mtab — root is ro. So create it without the journal.
mke2fs -O uninit_bg,resize_inode,extent,dir_index -L DroidCrypt0 -FF /dev/mapper/crypt0

tune2fs -j /dev/mapper/crypt0

tune2fs 1.41.6 (30-May-2009)
ext2fs_check_if_mount: Can’t check if filesystem is mounted due to missing mtab file while determining whether /dev/mapper/crypt0 is mounted.

# eventually should do a tune2fs -j /dev/mapper/crypt0


Ok, I hope this has helped someone, or at least taught you something. My next steps are to get the user data partitions encrypted (/data, /system/sd, etc), and probably eliminate that /sdcard vfat partition.