⚠️ Consider this plugin to be experimental until the version v1.0.0 is published! ⚠️
:key: Encrypt files with fido2 keys that support the "hmac-secret" extension.
:hash: Unlimited generation of recipients/identities because generated fido2 credentials are stateless.
:memo: See the spec for more details.
Ubuntu (>= 20.04)
sudo apt install libfido2-1 libfido2-dev libfido2-doc fido2-tools
Fedora (>= 34)
sudo dnf install libfido2 libfido2-devel fido2-tools
Mac OS
brew install libfido2
Download a the latest binary from the release page. Copy the binary to your $PATH
(preferably in $(which age)
) and make sure it's executable.
You can also use the following script for installation:
~/.local/bin/age-plugin-fido2-hmac
(change to your preferred directory)OS
and ARCH
if needed (OS=darwin ARCH=arm64
for Apple Silicon, OS=darwin ARCH=amd64
for older Macs)cd "$(mktemp -d)"
VERSION=v0.2.3 OS=linux ARCH=amd64; curl -L "https://github.com/olastor/age-plugin-fido2-hmac/releases/download/$VERSION/age-plugin-fido2-hmac-$VERSION-$OS-$ARCH.tar.gz" -o age-plugin-fido2-hmac.tar.gz
tar -xzf age-plugin-fido2-hmac.tar.gz
mv age-plugin-fido2-hmac/age-plugin-fido2-hmac ~/.local/bin
Please note that Windows builds are currently not enabled, but if you need them please open a new issue and I'll try to look into it.
git clone https://github.com/olastor/age-plugin-fido2-hmac.git
cd age-plugin-fido2-hmac
make build
mv ./age-plugin-fido2-hmac ~/.local/bin/age-plugin-fido2-hmac
(requires Go 1.22)
Generate new credentials with the following command:
$ age-plugin-fido2-hmac -g
[*] Please insert your token now...
Please enter your PIN:
[*] Please touch your token...
[*] Do you want to require a PIN for decryption? [y/n]: y
[*] Please touch your token...
[*] Are you fine with having a separate identity (better privacy)? [y/n]: y
# created: 2024-04-21T16:54:23+02:00
# public key: age1zdy49ek6z60q9r34vf5mmzkx6u43pr9haqdh5lqdg7fh5tpwlfwqea356l
AGE-PLUGIN-FIDO2-HMAC-1QQPQZRFR7ZZ2WCV...
You can decide between storing your fido2 credential / salt inside the encrypted file header (benefit: no separate identity / downside: ciphertexts can be linked) or in a separate identity (benefit: native age recipient, unlinkabilty / downside: keep identity stored securely somewhere). To decrypt files without an identity, use the magic identity (age-plugin-fido2-hmac -m
).
You are responsible for knowing which token matches your recipient / identity. There is no token identifier stored. If you have multiple tokens and forgot which one you used, there's no other way than trial/error to find out which one it was.
If you require a PIN for decryption, you (obviously) must not forget it. The PIN check is not just an UI guard, but the token changes the secret it uses internal!
Encryption:
age -r age1... -o test.txt.enc test.txt
Decryption:
age-plugin-fido2-hmac -m > magic.txt
age -d -i magic.txt -o test-decrypted.txt test.txt.enc
or
age -d -i identity.txt -o test-decrypted.txt test.txt.enc
By default, one of the following algorithms is picked (in that order): ES256, EdDSA, RS256. If you want the credential to use a specific algorithm, use the -a
parameter:
age-plugin-fido2-hmac -a eddsa -g
Note that
The default (in most cases) is "es256", which should provide the smallest recipient/identity strings.
In order to run unit tests, execute:
make test
End-to-end tests can currently no be run in the CI/CD pipeline because they require a virtual fido2 token to be mounted.
Use the following to setup a virtual test device with pin "1234" that always accepts any assertions:
go install github.com/rogpeppe/go-internal/cmd/testscript@latest # check PATH includes $HOME/go/bin/
sudo dnf install usbip clang clang-devel
git clone https://github.com/Nitrokey/nitrokey-3-firmware.git
cd nitrokey-3-firmware/runners/usbip
cargo build
cargo run
make attach # separate shell
fido2-token -S "$(fido2-token -L | head | cut -d':' -f1)" # set to 1234
Then run the tests using:
make test-e2e
To make the backwards compatibility tests work, the test device must use the file system in e2e/test_device.bin
by running cargo run -- --ifs <path-to-fs>
instead of just cargo run
.