Using libsodium in Android and NativeScript.

Libsodium is a fantastic crypto library, however it’s documentation can be lacking. Libsodium supports many languages via native wrappers and javascript via asm.js. I’ll document here how I got it working in Android both in Java and NativeScript. The target audience is someone who knows web development but not Android development.

Java + Android

We’ll use libsodium-jni. The install instructions didn’t make sense to me at first because I’m not an experienced Android developer. There is no need to manually compile it – they publish builds (AAR files) to the Sonatype OSS repository. This is analogous to publishing packages to the NPM repository if you’re more familiar with javascript. Just like how there are a million ways to install javascript dependencies, there are a million and one ways to install java dependencies. This can make documentation appear confusing or contradictory. Here’s how I did it.

Make a new Android Studio project (I suggest starting simple instead of using your existing project). Edit app/build.gradle and in the dependencies section add:

compile 'com.github.joshjdevl.libsodiumjni:libsodium-jni-aar:1.0.6

Note the latest version might change. The format of that string is ‘groupId:artifactId:version’ which you can find in libsodium-jni’s readme. That’s actually all you need to do to install it. gradle will find the package for you. Now try to run the app, you may get errors about android:allowBackup and the minimum android version supported.

I don’t understand why allowBackup could have any connection to libsodium – Native dev kind of sucks if you are used to something nicer like Python or Web development. We can fix it by editing app/src/main/AndroidManifest.xml and adding an attribute to the application tag.

tools:replace="android:allowBackup"

If you run again, it will complain about the “tools” attribute. Android XML configuration is fucking awful – go add this attribute to the manifest tag.

xmlns:tools="http://schemas.android.com/tools"

Next we may need to fix the version number – this issue actually makes sense. Both your application and libsodium-jni declare the minimum android version supported. Just edit app/build.gradle and change minSdkVersion to whatever libsodium is asking for – at the time of this writing it’s minSdkVersion: 16.

It should now compile. Next let’s add some test code. Open MainActivity.java and we’ll generate a key pair to prove libsodium works. Add imports:

import org.libsodium.jni.SodiumConstants;
import org.libsodium.jni.crypto.Random;
import org.libsodium.jni.keys.KeyPair;

Modify the onCreate function to generate and print out the key pair’s public key:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    byte[] seed = new Random().randomBytes(SodiumConstants.SECRETKEY_BYTES);
    KeyPair encryptionKeyPair = new KeyPair(seed);
    System.out.println(encryptionKeyPair.getPublicKey());
    setContentView(R.layout.activity_main);
}

Now the app should run and the key should print out in logging (logcat). Success!

Nativescript

Screw Java and Android XML and gradle configuration – let’s use javascript. A few years ago this might have been a sarcastic remark…

Amazingly, you can generate typescript definitions using this. It works great – but I’d actually suggest getting a little familiar with the Java library in Java first. Java and javascript use very different conventions and the generated type definitions might not be perfect. Here’s a generated libsodium-jni type def. https://gitlab.com/snippets/1665527

To install make the same changes you made in the pure java app. The gradle and xml files are in platforms/android/. Drop in the libsodium type def file into the root of your project. You should now have code completion and type checking. Now let’s add that keypair generation test again to make sure it’s working.

let rand = new org.libsodium.jni.crypto.Random().randomBytes(org.libsodium.jni.SodiumConstants.SECRETKEY_BYTES);
let key = new org.libsodium.jni.keys.KeyPair(rand);
console.log(key.getPublicKey());

Looks weird right? But it should work. You probably want to make a wrapper around this in either javascript or Java. Mixing Java calls into your javascript will look strange and be hard to read and debug.

Hopefully you can run the project as usual with tns run android. You may want to build the project or run gradew clean first to avoid any cached builds. If you are successful you should again get the public key printed out in the log. Excellent! Now you can make a web/native hybrid app that uses libsodium’s cryptography and can run in the web and as an app!

One more gotcha

If you have used libsodium in another language like Python or Javascript you may be spoiled with higher level function wrappers. For example in javascript libsodium you can run “let keypair = sodium.crypto_box_keypair();” to generate a keypair. libsodium-jni has very few high level wrappers so you’ll need to write C-like code in Java to mimic the low level functions. To make matters worse libsodium-jni isn’t documented. I found searching the code for unit tests to be the only way to find the right syntax. If you just start calling functions at will you’ll probably get a missing implementation error. If this happens you may want to see how it’s done in a unit test. Here is a link to the earlier key pair example but in a low level way. Now you are writing C like code in Java in Javascript. This is your life now.

Leave a Reply

Your email address will not be published. Required fields are marked *

*