Skip to content

Age plugin for using ed25519 on OpenPGP Card devices (Yubikeys, Nitrokeys)

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

wiktor-k/age-plugin-openpgp-card

Age Plugin: OpenPGP Card

CI Crates.io

This age plugin lets you reuse your OpenPGP Card devices (such as Yubikeys or Nitrokeys) for age decryption.

Why? OpenPGP Card, contrary to its name, is just a generic cryptographic device standard. Most importantly the specification and the real-world devices (e.g. Yubikeys and Nitrokeys) support curve25519.

This application is a no-moving-parts solution which requires only pcsc-lite on Linux and reuses built-in smartcard services on Windows and macOS. No GnuPG needed, no other OpenPGP software is used or accessed.

If you don't need curve25519 and are using Yubikeys then the age-plugin-yubikey provides a more polished experience.

This plugin assumes that you have already provisioned the card. oct admin generate may be used to provision the card with a new curve25519 key. (This is actually how end-to-end tests are implemented. See scripts/encrypt-and-decrypt.sh).

Installation

At this moment the installation from crates.io is the only supported method:

cargo install --locked age-plugin-openpgp-card

Usage

Running the tool directly outputs the public keys and the identity stubs for all connected cards:

$ age-plugin-openpgp-card | tee identity.txt
# Card ident 0006:15422467
# age1dkfzfyk58yvkf07n32nygkyuqxtnq2am427sy79gjkh6krf96frsucn0me
AGE-PLUGIN-OPENPGP-CARD-1XQCRQD36XY6NGV3JXSMRWAN88PC

Note that the public key looks like a regular age ed25519 key. The stub encodes the card identifier and is mostly irrelevant. If the stub is lost it may be regenerated - if the key on the card is the same the decryption will succeed.

Any age-compatible tool can be used for encryption:

$ echo I like strawberries | age -r age1dkfzfyk58yvkf07n32nygkyuqxtnq2am427sy79gjkh6krf96frsucn0me -a > encrypted.age

And the identity stubs are required for decryption:

$ age -d -i identity.txt < encrypted.age
I like strawberries

The plugin will ask you for the PIN using built-in plugin protocol (e.g. rage would show a pin-entry prompt).

Tests

This repository contains end-to-end integration tests which run a virtual Nitrokey card, provision it with a new key and then encrypt and decrypt data using rage.

Thanks

The plugin is basically glue code for already existing, awesome libraries and tools:

  • openpgp-card which interacts with the smartcards,
  • age-plugin which provides easy to use framework for writing age plugins,

And, last but not least, opcard which provides us with a virtual card to test that all of this really works!

Thank you very much for all contributors to these projects 🙇‍♂️

License

This project is licensed under either of:

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.