Skip to main content

Signing: APKs

This guide explains how to sign Android APKs with signing keys that are stored in a security key or a Hardware Security Module (HSM).

Prerequisites

  • An Android app project and build setup.
  • A working installation of Java and the Android SDK.
  • A hardware token that exposes a PKCS#11 API. See the key management guide.
  • A pre-created private key and self-signed certificate on the hardware token.

This guide is tested with Java 21 and Android SDK 35.

Install dependencies

sudo apt install --no-install-recommends apksigner

Installing apksigner from apt is easier than downloading the full Android SDK from Google (especially on dedicated computers).

Create config

Create a p11provider.cfg file with the following contents:

name = MyP11Config
library = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so # for the Nitrokey
# library = /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so # for SoftHSM
slotListIndex = 0

Java-based tools (such as keytool or apksigner) need this config to discover the PKCS#11 token. The format of this file is documented in the Java PKCS#11 guide.

Build an unsigned APK

To build an unsigned APK, simply omit the signingConfig from the desired build flavour in your project's build.gradle. Then build the APK:

./gradlew assembleRelease

Sign the APK

Use the apksigner tool to sign the unsigned APK with a private signing key stored on the PKCS#11 token. The "keystore password" that you are prompted for is the User PIN of your PKCS#11 token.

export P11CONF=./p11provider.cfg
export KEY_ALIAS=fmd-test

export APK_IN=./app/build/outputs/apk/prod/release/app-prod-release-unsigned.apk
export APK_OUT=./app-prod-release-signed.apk

apksigner -J-add-opens=jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED sign --provider-class sun.security.pkcs11.SunPKCS11 --provider-arg ${P11CONF} --ks NONE --ks-type PKCS11 --ks-pass stdin --ks-key-alias ${KEY_ALIAS} --in ${APK_IN} --out ${APK_OUT} --alignment-preserved

The -J flag is needed due to a bug in apksigner. It makes reflection work on recent Java versions.

The --alignment-preserved is needed so that the APK can be verified to be reproducible with apksigcopier (which is used by F-Droid).

Next steps

You can now publish your signed APK to your users!

Additionally, it is recommended to make sure that your APK is built reproducibly, and that the signing process has not broken reproducibility. Being reproducible is a requirement if you want to publish a developer-signed APK to the F-Droid main repository. For details on how FMD is reproducible, see the Reproducible Builds section.

References

Note: not all of these guides worked in 2025, some commands required modification. Nevertheless, they were useful inspiration for writing this tutorial.