I installed OpenSC and added it as PKCS#11 library to VeraCrypt. Importing the keyfile to VeraCrypt works as described, and I can see it as PrivDO1 with the token OpenPGP card (User PIN).
HOWEVER, there is a massive security issue! The keyfile is not protected by the PIN that I set for the card. It can be read without any authentication using e.g. openpgp-tool from OpenSC:
openpgp-tool.exe -d 1
Using reader with a card: Nitrokey CCID/ICCD Interface 0
69 D6 4D 55 6D BC 87 65 AF 26 55 99 31 39 A9 92 i.MUm..e.&U.19..
66 75 23 C1 CD 7E 60 15 42 4A 60 3A 22 9E 5A E1 fu#..~`.BJ`:".Z.
C0 EC 85 DF C3 EF A0 01 6B A9 46 F4 DC 96 63 9C ........k.F...c.
E7 31 44 B0 ED 2D 1D 87 D9 F9 11 5A 52 6B F8 6D .1D..-.....ZRk.m
… or gpg --edit-card:
gpg --edit-card
Reader ...........: Nitrokey CCID/ICCD Interface 0
Application ID ...: D276000124010304000FE16B14F70000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Nitrokey
Serial number ....: [redacted]
Name of cardholder: [redacted]
Language prefs ...: [nicht gesetzt]
Salutation .......:
URL of public key : [nicht gesetzt]
Login data .......: [nicht gesetzt]
Private DO 1 .....: i\xd6\x4dUm\xbc\x87e\xaf&U\x9919\xa9\x92fu#\xc1\xcd~`\x15BJ`:"\x9eZ\xe1\xc0\xec\x85\xdf\xc3\xef\xa0\x01k\xa9F\xf4\xdc\x96c\x9c\xe7\x31D\xb0\xed\x2d\x1d\x87\xd9\xf9\x11ZRk\xf8\x6d
This obviously defeats the purpose of putting the keyfile on the Nitrokey. Note that I unplugged the Nitrokey to clear any cached PINs.
Please advise how to secure the VeraCrypt keyfile on the Nitrokey with the PIN (or don’t advertise this feature in your documentation).
So, how do I get VeraCrypt / the Nitrokey to use PrivDO3 instead?
Imho, at the very least the documentation on the Nitrokey site should be removed or reworked, since having a key file always accessible defeats the purpose of putting it on the NK3 in the first place.
I did some debugging by capturing OpenSC’s debug output, while storing a keyfile on the Nitrokey with VeraCrypt. The relevant snippet is:
P:24016; T:17652 2026-02-12 22:07:46.329 [opensc-pkcs11] pkcs15-lib.c:2261:sc_pkcs15init_store_data_object: called
P:24016; T:17652 2026-02-12 22:07:46.329 [opensc-pkcs11] pkcs15-lib.c:2416:sc_pkcs15init_store_data: called
P:24016; T:17652 2026-02-12 22:07:46.329 [opensc-pkcs11] pkcs15-openpgp.c:433:openpgp_store_data: called
P:24016; T:17652 2026-02-12 22:07:46.329 [opensc-pkcs11] ===== App label test.bin
P:24016; T:17652 2026-02-12 22:07:46.329 [opensc-pkcs11] About to write to DO 0101
P:24016; T:17652 2026-02-12 22:07:46.329 [opensc-pkcs11] called; type=2, path=0101
P:24016; T:17652 2026-02-12 22:07:46.329 [opensc-pkcs11] card-openpgp.c:1459:pgp_select_file: called
P:24016; T:17652 2026-02-12 22:07:46.329 [opensc-pkcs11] called, tag=0101
This points towards the openpgp_store_data function in OpenSC, which has the following comment: “Currently, we only support DO 0101.”
This explains why the keyfile is always stored as Private Data Object PrivDO1 by VeraCrypt, which – again – does defeat the purpose of putting the keyfile on the Nitrokey in the first place.
Thank you for starting the PR regarding the documentation.
So, I’ve been writing my own PKCS#11 library from scratch that exposes the PIN-protected PrivDO3 to VeraCrypt to use as key file. It’s working now:
… though perhaps lacking some error handling and documentation. Depending on my spare time and public interest, I might polish it for future release.
Here is my PKCS11 library that allows VeraCrypt to use the PIN-protected PrivDO3 on the Nitrokey:
I’ve been using it daily for about a week, without encountering issues. But please note that it is provided “as is”, according to its license terms.