age-plugin-yubikey
is a plugin for age clients
like age
and rage
,
which enables files to be encrypted to age identities stored on YubiKeys.
Environment | CLI command |
---|---|
Cargo (Rust 1.67+) | cargo install age-plugin-yubikey |
Homebrew (macOS or Linux) | brew install age-plugin-yubikey |
Arch Linux | pacman -S age-plugin-yubikey |
Debian | Debian package |
NixOS | Add to config:environment.systemPackages = [ pkgs.age-plugin-yubikey ]; Or run nix-env -i age-plugin-yubikey |
Ubuntu 20.04+ | Debian package |
OpenBSD | pkg_add age-plugin-yubikey (security/age-plugin-yubikey) |
On Windows, Linux, and macOS, you can use the pre-built binaries.
Help from new packagers is very welcome.
On non-Windows, non-macOS systems, you need to ensure that the pcscd
service
is installed and running.
Environment | CLI command |
---|---|
Debian or Ubuntu | sudo apt-get install pcscd |
Fedora | sudo dnf install pcsc-lite |
OpenBSD | As root do:pkg_add pcsc-lite ccid rcctl enable pcscd rcctl start pcscd |
FreeBSD | As root do:pkg install pcsc-lite libccid service pcscd enable service pcscd start |
Arch | sudo pacman -S pcsclite pcsc-tools yubikey-manager sudo systemctl enable pcscd sudo systemctl start pcscd |
When installing via Cargo, you also need to ensure that the development headers
for the pcsc-lite
library are available, so that the pcsc-sys
crate can be
compiled.
Environment | CLI command |
---|---|
Debian or Ubuntu | sudo apt-get install libpcsclite-dev |
Fedora | sudo dnf install pcsc-lite-devel |
WSL does not currently provide native support for USB devices. However, Windows binaries installed on the host can be run from inside a WSL environment. This means that you can encrypt or decrypt files inside a WSL environment with a YubiKey:
- Install
age-plugin-yubikey
on the Windows host. - Install an age client inside the WSL environment.
- Ensure that
age-plugin-yubikey.exe
is available in the WSL environment'sPATH
. For default WSL setups, the Windows host'sPATH
is automatically added to the WSL environment'sPATH
(see this Microsoft blog post for more details).
age-plugin-yubikey
identities have two parts:
- The secret key material, which is stored inside a YubiKey.
- An age identity file, which contains information that an age client can use to figure out which YubiKey secret key should be used.
There are two ways to configure a YubiKey as an age identity. You can run the plugin binary directly to use a simple text interface, which will create an age identity file:
$ age-plugin-yubikey
Or you can use command-line flags to programmatically generate an identity and print it to standard output:
$ age-plugin-yubikey --generate \
[--serial SERIAL] \
[--slot SLOT] \
[--name NAME] \
[--pin-policy PIN-POLICY] \
[--touch-policy TOUCH-POLICY]
Once an identity has been created, you can regenerate it later:
$ age-plugin-yubikey --identity [--serial SERIAL] --slot SLOT
To use the identity with an age client, it needs to be stored in a file. When using the above programmatic flags, you can do this by redirecting standard output to a file. On a Unix system like macOS or Ubuntu:
$ age-plugin-yubikey --identity --slot SLOT > yubikey-identity.txt
The age recipients contained in all connected YubiKeys can be printed on standard output:
$ age-plugin-yubikey --list
To encrypt files to these YubiKey recipients, ensure that age-plugin-yubikey
is accessible in your PATH
, and then use the recipients with an age client as
normal (e.g. rage -r age1yubikey1...
).
The output of the --list
command can also be used directly to encrypt files to
all recipients (e.g. age -R filename.txt
).
To decrypt files encrypted to a YubiKey identity, pass the identity file to the
age client as normal (e.g. rage -d -i yubikey-identity.txt
).
age-plugin-yubikey
does not provide or interact with an agent for decryption.
It does however attempt to preserve the PIN cache by not soft-resetting the
YubiKey after a decryption or read-only operation, which enables YubiKey
identities configured with a PIN policy of once
to not prompt for the PIN on
every decryption. This does not work for YubiKey 4 series.
The session that corresponds to the once
policy can be ended in several ways,
not all of which are necessarily intuitive:
- Unplugging the YubiKey (the obvious way).
- Using a different applet (e.g. FIDO2). This causes the PIV applet to be closed
which clears its state.
- This is why the YubiKey 4 series does not support PIN cache preservation: their serial can only be obtained by switching to the OTP applet.
- Generating a new age identity via
age-plugin-yubikey --generate
or the CLI interface. This is to avoid leaving the YubiKey authenticated with the management key.
If the current PIN UX proves to be insufficient, a decryption agent will most
likely be implemented as a separate age plugin that interacts with
yubikey-agent
, enabling
YubiKeys to be used simultaneously with age and SSH.
age-plugin-yubikey
only officially supports the following YubiKey variants,
set up either via the text interface or the --generate
flag:
- YubiKey 4 series
- YubiKey 5 series
NOTE: Nano and USB-C variants of the above are also supported. The pre-YK4 YubiKey NEO series is NOT supported. The blue "Security Key by Yubico" will also not work (as it doesn't support PIV).
In practice, any PIV token with an ECDSA P-256 key and certificate in one of the 20 "retired" slots should work. You can list all age-compatible keys with:
$ age-plugin-yubikey --list-all
age-plugin-yubikey
implements several automatic security management features:
- If it detects that the default PIN is being used, it will prompt the user to change the PIN. The PUK is then set to the same value as the PIN.
- If it detects that the default management key is being used, it generates a
random management key and stores it in PIN-protected metadata.
age-plugin-yubikey
does not support custom management keys.
Licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.