Building the Botan library for Android

Botan is a C++ crypto library with a wide range of supported cryptographic algorithms. In this article, I’ll walk you through building Botan for Android, so that it can be used in applications that are built with the Android NDK.

Preparations

In the following, I use Ubuntu 12.04 LTS (x86_64) with Eclipse as my development platform. If you use another operating system, the commands may differ.

First, we pull in the Java Development Kit (here: OpenJDK 6), some essential build tools and Python which is needed for the configure script:

sudo apt-get install openjdk-6-jdk build-essential python

We need to have the Android SDK and Eclipse with the Android Development Tools (ADT) installed. The easiest way to get both the SDK and Eclipse with ADT preinstalled is to get the ADT Bundle, extract it somewhere (I used /opt/adt-bundle) and run the eclipse/eclipse program from the resulting folder.

Next, we need to get the Android Native Development Kit (NDK) so that we can compile programs written in C or C++ for Android. I extracted it to /opt/android-ndk, but you can freely choose the location.

Generating the botan_all.* files

First, we download and extract the Botan sources. I recommend to get the Stable Series package, which is version 1.10 at the time of writing.

The configure script of Botan offers to put all of the code into one pair of .h/.cpp files, the botan_all.h and botan_all.cpp. This is called amalgamation and makes it easier to build Botan using the NDK, so we open a terminal, change to the Botan directory, and execute the configure script:

./configure.py --gen-amalgamation --cpu=armv5te --os=linux --cc=gcc --with-tr1=none

This works fine if we target ARM-based Android devices, which covers almost all devices out there. If you need to build for x86/Atom- or MIPS-based devices, you will likely need to adjust the argument to the –cpu parameter. The –with-tr1=none parameter seems to be necessary when using STLport instead of GNU STL (see below).

When the configure script is done, you should see the files botan_all.h and botan_all.cpp in the Botan folder.

Including Botan in an Android project

If you have not already started an Android project which should include Botan, create one now: In Eclipse/ADT, choose File -> New -> Android Application Project and follow the instructions.

Now that you created a project, create a subfolder named “jni” in the project folder which will hold the native code. Inside, create “Android.mk” and “Application.mk” files:

# jni/Android.mk:
include $(call all-subdir-makefiles)

# jni/Application.mk:
APP_ABI := armeabi
APP_CPPFLAGS += -fexceptions -frtti
APP_STL := stlport_shared

If you want to know more about these files, you can look it up in the docs folder of the Android NDK (files ANDROID-MK.html and APPLICATION-MK.html, or use the index in documentation.html in the NDK main directory). Basically, Android.mk tells the Android build system to look for makefiles in the subdirectories, while Application.mk introduces some settings that are used for all modules from the subfolders (ARM instruction set, allow C++ exceptions and RTTI, use STLport instead of the extremely restricted default Android STL).

When you have done this, it is time to create the directory “jni/botan”. Put the botan_all.* files in there and create another Android.mk file:

# jni/botan/Android.mk:
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := botan
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := botan_all.cpp
LOCAL_CPPFLAGS := -DBOTAN_USE_GCC_INLINE_ASM=0

include $(BUILD_SHARED_LIBRARY)

Again, detailed information can be found in ANDROID-MK.html. The LOCAL_CPPFLAGS line was necessary because, later on, the compiler complained about wrong assembler syntax when inline assembler was used.

Creating some native code that uses Botan

Now we need to build an interface so that our Java app can talk to our native code which will talk to Botan. We do this by creating a Native class which loads the necessary libraries in its static initializer, and which declares the methods that we intend to implement in C++, for example:

// src/de/tiwoc/botandemo/Native.java
package de.tiwoc.botandemo;

public class Native {
    static {
        System.loadLibrary("stlport_shared");
        System.loadLibrary("botan");
        System.loadLibrary("botandemo");
    }

    public static native String pbkdf2Demo(int iterations);
}

The order of the loadLibrary statements is significant: botandemo uses botan, which uses stlport_shared, so stlport_shared must be loaded first, then botan, then botandemo.

botandemo will hold our glue code, so we need to create the folder “jni/botandemo” and create an Android.mk for this module:

# jni/botandemo/Android.mk
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := botandemo
LOCAL_SRC_FILES := botandemo.cpp
LOCAL_SHARED_LIBRARIES := botan

include $(BUILD_SHARED_LIBRARY)

The one new line in here is the LOCAL_SHARED_LIBRARIES statement which holds a list of the other modules which botandemo will use.

As a next step, we generate a header file corresponding to the Native class. To do this, we use a terminal to change to the bin/classes folder of the app and issue the javah command from the JDK:

javah -o ../../jni/botandemo/native.h de.tiwoc.botandemo.Native

Now, we can write a .cpp file which implements the definitions from the header. The following method will invoke the PBKDF2 key derivation algorithm with some test data:

// snippet from jni/botandemo/botandemo.cpp
JNIEXPORT jstring JNICALL Java_de_tiwoc_botandemo_Native_pbkdf2Demo
    (JNIEnv * env, jclass cls, jint iterations)
{
    try {
        PBKDF* pbkdf = get_pbkdf("PBKDF2(SHA-256)");
        AutoSeeded_RNG rng;

        SecureVector<byte> salt = rng.random_vec(16);
        OctetString aes256_key = pbkdf->derive_key(
                32, "this_is_a_weak_password",
                &salt[0], salt.size(), iterations);
        return env->NewStringUTF(aes256_key.as_string().c_str());

    } catch (...) {
        std::string empty_str = "";
        return env->NewStringUTF(empty_str.c_str());
    }
}

This does nothing particularly useful, but it shows how to bridge the gap between a Java app and the Botan library. A full and working example of this file is part of the example project that can be found on GitHub.

Building the library and testing the app

At this time, all of the native code can be built. We open a terminal, change to the main folder of our project (in this case: BotanDemo) and invoke the Android build system:

# $(NDK) denotes the main folder of the NDK
$(NDK)/ndk-build

This will put all of the native files in the right place inside the project folder, so that the ADT packages all of it into the .apk when building the app.

For the test project on GitHub, I added an Activity that invokes the pbkdf2Demo method:

botan-demo-1

After touching the button:

botan-demo-2

We’re done!

Get the demo project sources from Github!

Resources

The following web sites helped me a lot while I figured out how to do this:

java -jar ignores classpath — Workaround

When you want to run a Java class wich needs additional libraries, you usually run java -cp mylib.jar MyClass or you specify the environment variable $CLASSPATH before running the class.

When you have a JAR file you want to run, you usually do this by issuing java -jar myjarfile.jar

If your’re smart, you’ll think: Hey, I want to run a JAR file with some additional library so I issue java -cp mylib.jar -jar myjarfile.jar ! Forget about it, it won’t work. Believe me. Look into the java man page (section “-jar”) if you don’t believe me. I wasted hours on sorting that out. Even setting the $CLASSPATH variable won’t work. Here’s the solution:

  1. Open the jar file with some ZIP program (JAR = renamed ZIP).
  2. Open META-INF/MANIFEST.MF in a text editor.
  3. Copy the path and name of the main class: If you see a line like “Main-Class: some.package.ClassName”, it’s the part after the colon.
  4. Run this on your command line instead of the command that doesn’t work: java -cp mylib.jar:myjarfile.jar some.package.ClassName

Now you shouldn’t get any more NoClassDefFoundErrors…

Concrete example: If you want to run Lecturnity Player under Linux, just download the .jar, install the Java Media Framework (I used the “Cross-platform Java” version) and run the following command:

java -cp /opt/JMF/lib/jmf.jar:player_30.jar imc.epresenter.player.Manager

This assumes that you put the Java Media Framework to /opt/JMF and you are in the directory where player_30.jar resides.

Caching using weak references

Some time ago I wrote a Java class that caches generated images so I don’t need to re-render them all the time (rendering SVG graphics takes some time…). There’s only one problem: As more and more different images are getting cached, the maximum heap space of the JVM will eventually get exhausted. Increasing this limit is not an option. This can be “fixed” by using a queue for the images: If it is full, the first image cached will get discarded so the memory usage will be limited. This can be improved by implementing a least recently used (LRU) caching strategy, which is exactly what I did.

This has the drawback that even if there is plenty of memory remaining, cached images are deleted if the queue is full and a new image is about to be added. Today, I learned about the java.lang.ref package and especially about it’s SoftReference class. Objects referenced by SoftReferences will be deleted by the garbage collector if the JVM runs out of memory, which should be the ideal way to implement a cache…

You can learn more about it at Wikipedia and IBM Developer Works.

Anonymous classes: references to parents

If you want to create an anonymous class (here: inherited frow OtherClass) and you need a reference to the containing class (here: MyClass), you should do it as follows:

class MyClass {
    void myProcedure() {
        OtherClass oc = new OtherClass() {
            void otherProcedure() {
                foo(MyClass.this);
            }
        };
    }
}

It is much easier to use “MyClass.this” than to introduce a line like “final MyClass selfref = this;” outside of the anonymous class and finally call “foo(selfref);”