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.