I used Tergent to setup a hardware-managed SSH key with Termux and Termux:API. This cannot use existing SSH keys and will require generating a new key. Instructions:
Install the Tergent package:
pkg install tergent
Create a new EC key with a 60-second timeout. The EC curve can be secp256r1, secp384r1 or secp521r1, but 521 is sometimes not usable. Replace $device with an appropriate alias for the device (first line retrieves the device maker and model):
SSH will now automatically try this key, prompting for device unlock if necessary. However, Termux:API will notify of error UserNotAuthenticatedException each time. To avoid this error, you will need to have unlocked your phone within the past 60 seconds, or must invoke termux-fingerprint for a fresh unlock.
Key management
List keys: termux-keystore list
Delete a key: termux-keystore delete <alias>
Scripting device unlock
termux-fingerprint always exits with 0, so we have to parse the output instead:
Match exec termux-fingerprint PKCS11Provider /data/data/com.termux/files/usr/lib/libtergent.so
This causes ssh to invoke the fingerprint UI without relying on a shell alias. This is slightly nicer, although you still have to reauthenticate every time.
Devices without fingerprint scanners
Things break when the device has no fingerprint scanner. On an Onyx Boox e-reader, I get ERROR_NO_HARDWAREand the authentication fails. However, the hardware secure enclave does exist, and device unlock makes the SSH key available. It just cannot be triggered using termux-fingerprint. This is inconvenient on a Boox since device lock disconnects Wi-Fi and unlock takes several seconds for the network to be available again. I’ve filed a ticket asking for unlock with device credentials.
Workaround
I have the following in my Obsidian vault sync script just before git pull --rebase && git push. This avoids the error notification, has a fallback for devices without biometric hardware, and the 60 second timeout should be long enough for two uses between the pull and push:
# In Termux, unlock device credentialsif command -v termux-fingerprint >/dev/null; then if termux-fingerprint | grep ERROR_NO_HARDWARE >/dev/null; then # If there is no biometric hardware, use device unlock am start -a android.app.action.CONFIRM_DEVICE_CREDENTIAL > /dev/null read -rsn 1 -p "Press any key to continue" echo fifi
Security
The SSH key becomes available for 60 seconds after each device unlock. I thinkthe key is only available to Termux but I have not confirmed this.
The key is stored in the hardware secure enclave. The private key cannot be extracted, even with root access. If you lose or retire your device, you must remove the public key from your servers as the private key cannot be transferred to another device.
Code signing: ideally should not use device-bound authentication keys. Since the public key must be stable for long term verifiability, private key management needs extra care. todo