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.


13 comments so far

  1. yo on

    THIS is what have an open source OS is all about. Nice work. Two questions:
    1)How has battery life been after enabling this?

    2)Did you succeed with the user data partitions?

    • shawnlower on

      Thanks. Sorry for the late approval, I missed your post amongst the spam.

      2) Unfortunately, I didn’t finish encrypting the user partitions. I was working on encrypting the user data, and getting a decent passphrase prompt at boot when the phone went MIA. Fortunately, most of the data was encrypted =) It also happened around the time the N900 was released, and, well… I sold out. Sorry (but cryptsetup in the extras-devel repo, thanks Jebba!).

      1) Didn’t see anything drastic, but didn’t do any extensive testing. Would be interesting to see.

  2. fsdfsdf on

    Any update on this?

  3. Anonymous on

    […] dm-crypt bereits enthalten sein, allein es fehlt an den Userland-Tools, siehe auch: Android + encryption on the G1 using cryptsetup and LUKS an android's Blog Nur was da auf der Seite steht, ist mir irgendwie noch zu kryptisch und der Autor hat wohl bereits […]

  4. Sigkill on

    I’m running my /data and /sdcard encrypted on my HTC Wildfire (with help from this guide). Support for dm-crypt and AES ciphers is included in the stock buzz kernel (Eclair).

    Had to modify my init.rc (easily done with the utility ‘kitchen’) and write a “gui” for unlocking the encrypted disks (very basic, written in C with the minui library).

    Havent noticed any significant changes in performance or battery life.

    I’ll post the C code online as soon as it is presentable

    • shawnlower on

      Outstanding! =) Please do share when you’ve posted the UI code, even if it’s not ‘presentable’. Doing a UI is something I’ve had on my TODO list for awhile.

      Also, I have a new Android phone (Samsung Galaxy S/Tmo Vibrant), so I hope to share some experiences on getting it working there soon as well.

  5. Ryan on

    Had a quick read through this after coming accross the wildfire post on xda, sorry for my lack of knowledge here,

    but what is all this for etc…?

    Many thanks in advance.


  6. Nathan of Guardian on

    Great work and thanks for sharing @Sigkill. Working on building it here for my NexusOne with CM6.1.

    BTW, I’m the lead on a project working on general secure Android distro – we’ve ported Tor, have an OTR IM app, and have supported other projects along those lines. Would love to talk more about supporting anyone working on this specific capability.

  7. Nathan of Guardian on

    We’ve got a new clean Makefile for this here working with Android NDK r5’s cross-compiling toolchain:

    Would love thoughts, feedback, and testers!

  8. […] create encrypted partitions/filesystems. I actually compiled it on my phone as that was easier than cross-compiling due to cryptsetup’s numerous dependencies. It seems to work fine on my rooted HTC G2 running […]

  9. […] first problem is cryptsetup is absent on a standard Android system. Thanks to this post I could get a hold of a binary(ideally one should compile their own). cryptsetup must be pushed to […]

  10. askillen on

    I’m having trouble compiling Sigkill’s luksunlock pre-boot authentication mechanism.

    I can launch the prebuilt luksunlock binary from my init.rc on an HTC Desire with CyanogenMod 7.1 using GuardianProject’s cryptsetup and luksunlock binaries but it fails to unlock after providing a passphrase. LUKS is working properly on loopback devices and SD card partitions from a shell (after the Android framework is loaded). My volumes are set up properly, as scribed in xda-forums and the luksunlock code/init.rc.

    My problem is compiling the luksunlock source. I’m using android-ndk-r6b cross-compiler toolchain. I can successfully compile static and dynamically linked applications that run on my phone. I experience eabi-gcc build errors on minui functions when compiling luksunlock.c.

    Any advice for compiling luksunlock with the NDK would be greatly appreciated (or any information on incorporating the Android recovery minui into a similar application). I can provide any further details or request (init.rc file, build environment, etc.).

    Sincerest Thanks.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: