Using nitrokey directly without gpg or other dependancies

I want to use a nitrokey start as a license token for an application I have written.

To this end I need I way to implement challenge response on a USB stack like libusb or libusbp alone.

  1. I need to ask the nitrokey give me its public key.
  2. I need to ask the nitrokey to sign a nonce using the corresponding private key.
  3. I can then verify the returned signature in the application.

I cannot ask my users to install and set up gpg and all the cruft that comes with it.

Where can I find the documentation for direct access to the nitrokey? Do there exist convenient examples for this use case?


update:

I have done some reading of the pynitrokey source and see that there are iso7816 functions cmd_external_authenticate and cmd_internal_authenticate which i could use for mutual authentication.

These functions should be easy enough to port to my system.

However the input/outputs of these functions are not documented well enough and these functions seem not to be used by pynitrokey itself (grep doesn’t find them being called)

How to determine the keysize/algos etc. being used?

If you want to go low level, grab yourself OpenPGP card specification and study it. You can use tools like pkcs11-tool (higher level), openpgp-tool (middle level), pkcs15-tool (lower level) and opensc-explorer (very low level) from OpenSC learn about the PKCS#15 filesystem structure of an OpenPGP card (pretty complicated if you ask me).

Then you can start issuing raw protocol data units (“APDU”) with the tool of your choice. Section 7.1 of the spec gives you some “ISO commands” that can be supported.

Going deeper, your own CCID implementation is possible, too.

1 Like

Turns out that while it is technically possible talk with the nitrokey directly, getting direct access to the nitrokey is inconvenient. The best way is to use pcsc-lite or winscard, which conveniently also have the same C API. So far I’ve been able to establish a context and select the pgp application.

Here is a little Python script that uses the Nitrokey to sign some data and then verifies the signature. Maybe this helps you getting started.

Note:

  • It is a quick & dirty script that represents about an hour of work. It only does very little error checking. Use at your risk.
  • It assumes that the Nitrokey has nistp384 EC key pair in its OpenPGP signature key slot.
  • It assumes that the Nitrokey uses an OpenPGP PIN of “123456”. You probably don’t want to prompt your users for a PIN, anyway.
  • As it is, it is not suitable as copy protection. Any user of your software could just get a brand new Nitrokey and generate their own key pair.
  • Thus, you would probably need to sign the public key with your own private key and store that signature as a sort of “certificate” on the Nitrokey. Then you could check the authenticity of your dongle by checking this “certificate” in your application.
  • You might want to store the “certificate” as private use DO 2, which is always readable but can only be written with the admin PW. The “certificate” can just be the raw signature of the public key, no need for X.509 or similar.
  • But since you’re presumably developing a very expensive software, I’m not developing that part for you for free. :grinning_face_with_smiling_eyes:

ec_crypto_nk.zip (1.5 KB)

Looks something like this in C:

ended up using ed25519 because there’s a convenient MIT licensed lib for it and getting gpg to do secp256k1 or some of the other common curves requires extra steps.

zero deps beyond pcsclite/winscard! yay!

1 Like