Skip to main content

Raymii.org Logo (IEC resistor symbol)logo

Quis custodiet ipsos custodes?
Home | About | All pages | RSS Feed | Gopher

Decrypt/Extract Nitrokey HSM/SmartCard-HSM RSA private keys

Published: 13-07-2016 | Author: Remy van Elst | Text only version of this article


Table of Contents


This is a guide which shows you how to extract private RSA key material from theNitrokey HSM / SmartCard-HSM using the DKEK. This way you can get the privatekey out of the HSM in an unencrypted form. It does require access to the HSMdevice, all the DKEK share and their passwords. Do note that doing this defeatsthe entire purpose of a HSM, namely that you never have access to the keys. Inthe article I'll go over some explanation why this might be a feature you needand why it might be a case of security over convinience.

If you like this article, consider sponsoring me by trying out a Digital OceanVPS. With this link you'll get $100 credit for 60 days). (referral link)

This is not a vulnerability, zero day or exploit. The HSM provides a way to dosecure backups of private key material and we utilize that in this article. Todecrypt the keys you need to have all the DKEK files used when the HSM wasinitialized, know all the DKEK passwords and have access to the HSM itself.

You can prevent decryption by not setting up a DKEK, thus using the randominternal DKEK of the HSM.

Recap of a HSM

The Nitrokey HSM in a sealed package

A Hardware Security Module, HSM, is a device where secure key material isstored. This private data only be accessed by the HSM, it can never leave thedevice. Most HSM devices are also tamper-resistant. This means that when opened,moved or otherwise (software) tampered with, they wipe the key material. HSM'scome in a variety of formfactors, ranging from SmartCards and small USB devices,to full size PCI cards and even 19" rackmountable server-like devices. Thedifference between all those devices is speed and storage capacity. Mostcommercial HSM's are certified to the FIPS-140-2 standard.

I have multiple articles on the Nitrokey HSM/SmartCard-HSM. I alsohave a lot of professional experience with large expensive HSM hardware.

If you want to know more on the Nitrokey HSM then please read the gettingstarted articles.

The main purpose of the HSM is to protect key material. It allows you to makesure that the private key material can never be stolen or compromised. It doesallow you to wrap a key for export/transport to another HSM, for example, tocreate redundancy or backup. We use this mechanism to decrypt the keys outsideof the HSM.

In the next section you can read the rationale, where I hope to explain why thisis both a security issue as well as how to mitigate it.

The Nitrokey HSM and the SmartCard-HSM

In this article I'll use the terms HSM, Nitrokey HSM and SmartCard-HSM, but whenI do I mean the same device.

The Nitrokey HSM is an open hardware and open software device. It is a USBversion of the SmartCard-HSM. Both the SmartCard-HSM as the NitrokeyHSM have sources available and are fully supported by the OpenSCproject.

The Nitrokey is as far as I know one of the few fully open source devices. Allthe big HSM's I've used were either under NDA or completely closed source. In myopinion a device like this can only be secure when they are open source. Thedevice supports up to 60 ECC GF(p) 256-bit keys and up to 48 RSA 2048-bit keys.

The SmartCard-HSM

Rationale

As said above, having access to the unencrypted private keys defeats the entirepurpose of an HSM, namely that you never have access to the private key. Thisdecrypted key can be stolen or abused.

However, to decrypt the wrapped key you need access to:

In a production environment you would not use the default pins. You changethose. You also don't have one DKEK share with one password, you have multipleDKEK shares where each DKEK share has multiple passwords (n-of-m scheme). TheseDKEK shares are stored in a secure place (keepass, printed in a bank safe, etc).Then multiple people and multiple passwords are required to initialize the HSM(or to calculate the unencrypted DKEK share).

This is a convinience because you might need to export the key out of the HSMwhen you are migrating to another HSM, from a different manufacturer. Or, youare decomissioning this HSM and the software attached to it, but want to archivethe key because it might be needed later. You might even just want to use thesame key in different software that does not support PKCS#11.

Since it requires so many steps and so much access, I don't think this is a hugerisk, but a rather nice convinience.

I do am of the opinion that HSM's should not offer this option (getting accessto the private key). But then you would also not be able to backup and transferthe wrapped keys, since that can be reverse engineered. I've seen multiple big-name HSM's where their support was able to decrypt the key and transfer it toanother HSM model, but since I've signed an NDA I cannot tell which ones thatwere. You will have to take my word for it.

That does pose the question, how will you make sure you have a backup? Sincethese devices can fail, just as any device, you would want to make sure you havea backup, since your business probably depends on the availability of a HSM. Ifind it a hard problem and I don't know an actual solution to both providebackup possibilities and disallow access of the private key.

Some HSM manufacturers have the option to stream the transportkey over thenetwork to another device, or to use a smartcard to transfer the key. I dosuspect that they have a private key somewhere that protects the encrypted(wrapped) backup key and that it would be hard to reverse engineer theirprocess. But, a nation-state level actor would surely have the resources toreverse engineer the backup process, just as we did here.

I've also received feedback from Andreas, verbatim copy:

Access to the CardContact SDK

The process requires access to the CardContact SDK. This is a collection ofsoftware you can use in your own projects (SDK, software development kit). Italso includes examples to use the HSM, like a key manager or a .p12 importer.

To get access to the SDK you need a SmartCardHSM/Nitrokey HSM. You need togenerate a keypair in the device that will be used for accessing the contentnetwork and git repositories.

Access to the SDK does not cost money, but it does require you to have a HSMdevice.

Read this page to find out more about the CDN. First create and activateyour developer account and then clone all the repositories.

You will need the SmartCard Shell v3 which you can download here.

You will also need the SmartCard Script collection. If you have registereda developer account you will already have the scripts and smartcard shell.

Do note that this is a Java tool, so make sure you have Java installed as well.

Here is a screenshot of the SCSH (shell) running the key decryption:

The primes p and q are used to derive the private exponent d with thepublic exponent e. I'll show some simple python code later on to construct theprivate key in a usable format.

DKEK (Device Key Encryption Key)

The DKEK, device key encryption key, is used when initializing the HSM.Initializing a HSM means that you remove all the keys and other data stored init, basically formatting it. Simply said, the DKEK encrypts the keys on thedevice and the keys you export out of the device (wrap).

The Nitrokey HSM generates a DKEK when the device is initialized, but is alsoallows you go generate one or more DKEK's beforehand and import those in thedevice during the initialization process. You can have multiple DKEK's, spreadover multiple persons. A DKEK can even have multiple passwords (using ann-of-m threshold scheme.)

If you use the device in production you will (hopefully) have selected stronguser and SO PIN's, as well as have multiple DKEK shares with strong passwords onthem.

You can import the DKEK in another HSM device and then restore backups of theexported keys to this new device. As said, this way you can have a backup orredundancy of the HSM device. To find out how to do that please read thegetting started article.

We will use this DKEK to decrypt the secret key material on the HSM. Since it'sopen source, we can look at how the DKEK is made, how the DKEK wraps the keysand reverse that process. Do note that we still need all the DKEK shares, theirpasswords and access to the HSM device.

Decrypting a key with the example

THIS WILL REINITIALIZE YOU HSM

Make sure to backup important keys on your HSM first! (Test them as well).

I'll first talk about the example included to decrypt a key. This exampleinitializes the HSM with two DKEK shares, then generates a key and dumps thoseparameters.

The example states that it requires an NDA. I contacted the main developer andgot permission to publish, see the screenshot below. (Thank you for thatAndreas).

Fire up the SmartCard Shell and set up the workspace as the CDN documentationdescribes. Use the File menu -> Run Script and load the sc-hsm-workspace/sc-hsm-sdk-scripts/key_import/decrypt_keyblob.js script.

THIS WILL REINITIALIZE YOU HSM

This is the decrypt_keyblob.js script:

/* * Decrypt Key Blob from SmartCard-HSM * * (c) 2014 CardContact Software & System Consulting, Andreas Schwier, Minden, Germany * * Information contained in this script is confidential and released under NDA * * This script initializes a SmartCard-HSM with two DKEK shares, generates and exports a RSA key * From the DKEK share it generates the Kenc/Mmac for key wrap and decodes the exported key blob * * Please note, that the sc-hsm-tool will further wrap the key blob generated by the SmartCard-HSM * with the private key description and the certificate read from an EF in the device. Please see * the sc-hsm-tool.c source for details. * * Warning: The device will be re-initialized by this script. */PublicKeyReference = require('scsh/eac/PublicKeyReference').PublicKeyReference;SmartCardHSM = require("scsh/sc-hsm/SmartCardHSM").SmartCardHSM;DKEK = require("scsh/sc-hsm/DKEK").DKEK;var pin = new ByteString("648219", ASCII);var initializationCode = new ByteString("57621880", ASCII);var dkekshare1 = new ByteString("A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5", HEX);var dkekshare2 = new ByteString("E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1", HEX);// Attach to SmartCard-HSMvar card = new Card(_scsh3.reader);var sc = new SmartCardHSM(card);if (sc.queryUserPINStatus() == 0x6984) {  var page = "<html><p><b>Warning:</b></p><br/>" +       "<p>This is a new device that has never been initialized before.</p><br/>" +       "<p>If you choose to continue this test, then the device initialization code will be set to " + initializationCode.toString(ASCII) + " </p><br/>" +       "<p>Please be advised, that this code can be changed later, however the same code must be used in subsequent re-initialization of the device.</p><br/>" +       "<p>Press OK to continue or Cancel to abort.</p>" +       "</html>";  var userAction = Dialog.prompt(page);  assert(userAction != null);}// Initialize Device with a double DKEK sharesc.initDevice(new ByteString("0001", HEX), pin, initializationCode, 3, 2);sc.importKeyShare(dkekshare1);var status = sc.importKeyShare(dkekshare2);print("Device initialized:");print("-------------------");print("SW          : " + status.sw.toString(HEX));print("Shares      : " + status.shares);print("Outstanding : " + status.outstanding); print("KVC         : " + status.kcv.toString(HEX));print("");// Determine keys for wrap/unwrapvar crypto = new Crypto();var dkek = new DKEK(crypto);dkek.importDKEKShare(dkekshare1);dkek.importDKEKShare(dkekshare2);var kenc = dkek.getKENC();var kmac = dkek.getKMAC();print("Values derived from DKEK shared:");print("--------------------------------");print("DKEK        : " + dkek.dkek.toString(HEX));print("KVC         : " + dkek.getKCV().toString(HEX));print("Kenc        : " + kenc.getComponent(Key.AES).toString(HEX));print("Kmac        : " + kmac.getComponent(Key.AES).toString(HEX));print("");// Generate a Test RSA Key with 1024 Bitsc.verifyUserPIN(pin);var chr = new PublicKeyReference("UT", "TESTKEY01", "00000");var innerCAR = new PublicKeyReference("DECA00001" + "00001");var algo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID);var keydata = SmartCardHSM.buildGAKPwithRSA(innerCAR, algo, chr, 1024);// SmartCardHSM.dumpKeyData(keydata);var rsp = this.sc.generateAsymmetricKeyPair(1, 0, keydata);// print("Card generated certificate signing request");// print(new ASN1(rsp));// Wrap keyvar keyblob = sc.wrapKey(1);print("Key blob");print("--------");print(keyblob);dkek.dumpKeyBLOB(keyblob);

This is example output:

>load("/home/remy/git/sc-hsm-workspace/sc-hsm-sdk-scripts/key_import/decrypt_keyblob.js");Device initialized:-------------------SW          : 9000Shares      : 2Outstanding : 0KVC         : BB391415C05E39D7Values derived from DKEK shared:--------------------------------DKEK        : 4444444444444444444444444444444444444444444444444444444444444444KVC         : BB391415C05E39D7Kenc        : 34423C9AB36899BD772D73DA3E350709F009634946C288A7B5E8A248868AE9FFKmac        : 1392790984A79DA93E797C0FD1919E16C9FE90D652A147DF16186E6840E9F2EBKey blob--------0000  BB 39 14 15 C0 5E 39 D7 06 00 0A 04 00 7F 00 07  .9...^9.........[...]0200  89 41 86 5F 7A 07 EA 6C F2 72 53                 .A._z..l.rSValues from key blob:---------------------Checking the MAC      : PassedKCV                   : BB391415C05E39D7    [Must match the KCV of the DKEK for import]Key type              : 6    [6=RSA, 12=ECC]Default Algorithm ID  : 0.4.0.127.0.7.2.2.2.1.2 (10)     [Matches algo in buildGAKPwithRSA()]Allowed Algorithm IDs :  (0)    [Not used]Access Conditions     :  (0)    [Not used]Key OID               :  (0)    [Not used]0000  81 BD 22 DC 7A 59 9E AD 04 00 00 40 E6 11 4D E4  ..".zY.....@..M.[...]01D0  06 37 89 6A 04 A9 00 03 01 00 01 80 00 00 00 00  .7.j............Randomize             : 81BD22DC7A599EAD    [Random data prepended at export]Key size              : 1024    [Key size in bits]DP1 = d mod (p - 1)   : E6114DE413BB84118673B60947D04D1B95C8BA489467F86A050D3CEDC8654C2C7ED1A1340D1B87234B3C99AA434833025CA306FF3DEE36EDBDC6089CA10BF431 (64)DQ1 = d mod (q - 1)   : ACCD4794CC41372263B859C1B9448C91E3082B9C96CBF6A19BFB8AB495B7EF83C29F87B58F79661D68395F0978CCFD91E0AE823594DF33043269270994CD45F9 (64)Prime factor p        : FD6D83D3ABBB6527AA612008CD8B1F57579FAFA9DE8B30DAA4051A617043D4FAC7D94F29672990F2B04FBE59F79C8BCCFBFEEA038844858AB55A97D089DD531F (64)PQ = q - 1 mod p      : BFE203FE566E0CCED58565C26B30D68D984EE42DC9B766C7598E264E6E558D41B24E72D04D96C394F4FF10728DF2895975A6BD5E605C75271DE28BEE6CED3548 (64)Prime factor q        : D604513568BD59C9E83FECC653FA1168A198275859D4FD1ADA62EB0B0354B9FC2DC33F70727A5DE328890B103C2CED16931C84C5439436471F968AAF7F4EB737 (64)Modulus               : D3DDD24D86EF89F0DA9EE2933517A1117AB0C9B75ACAF261B8699A8F8A76351468B641C9F51071EAA7C681E975D9AF7BB8F6E3B1BB234DD4A6A65B4E089A94BB7441F6FD8210D4B5CA0275B64921F081181AD3CD137B2EB9BEE9545B2919617B89C4A4634205342A1A989BB0491C0A20682646D2DCE7699371300637896A04A9 (128)Exponent              : 010001 (3)>

You now have a re-initialized HSM and all the data you need to reconstruct theprivate key. We will continue this article with adapting the script to decryptan existing key (and not hose the HSM). Then we will use some simple Python codeto transform those values we got (p, q etc) into a usable RSA keypair.

Reconstruct a DKEK and decrypt an existing key

The above script reinitializes your HSM, which might not be what you want if youwant to export an existing key. In the code it has two DKEK shares set:

var dkekshare1 = new ByteString("A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5", HEX);var dkekshare2 = new ByteString("E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1", HEX);

The device is initialized and then the shares are loaded in the device:

sc.initDevice(new ByteString("0001", HEX), pin, initializationCode, 3, 2);sc.importKeyShare(dkekshare1);var status = sc.importKeyShare(dkekshare2);

We can load our own DKEK in by converting it to a HEX string. It took me quitesome time to figure out how to do that. I decided to look into how the DKEK isgenerated and reverse that.

DKEK decryption

If you like this article, consider sponsoring me by trying out a Digital OceanVPS. With this link you'll get a $5 VPS for 2 months free (as in, you get $10credit). (referral link)

I basically adapted the load_dkek_in_device function and stripped out theactual loading the DKEK in the device. Instead, I added a simple function thatprints the u8 char as HEX in the format that the decrypt_keyblob.jsunderstands.

printf("DKEK Share HEX: \n\n");  for (i = 0; i < sizeof(dkekinfo.dkek_share); i++)  {      printf("%02X", dkekinfo.dkek_share[i]);  }  printf("\n\n");

The rest of the function is almost the same, including the password entry anddecryption part.

See my fork for the code. I've included the code at the end of thisarticle, if for whatever reason the pull request isn't accepted.

To build it, clone the repo:

https://github.com/RaymiiOrg/OpenSC.git

Switch to the branch:

cd OpenSCgit checkout dkek_share_print

Bootstrap:

bash ./bootstrap

Build the tools:

make all tools

Now you have a binary in the src/tools/ folder named sc-hsm-tool.

Use this to deconstruct the DKEK. You of course need to have loaded a DKEK whenyou initialized your HSM. To find out how to do that please read the gettingstarted article.

$ ./src/tools/sc-hsm-tool --print-dkek-share ./dkek-share-1.pbe 

Example Output:

Using reader with a card: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00Enter password to decrypt DKEK share : Deciphering DKEK share, please wait...DKEK Share HEX: 20B3EE1CABA5ECA7ECEB6BE51F11BD9A04F5FE9A6B0A1E0A8BC13074D32CF830

If you have multiple DKEK shares you need to decrypt all of them.

Do note that this is the unencrypted DKEK share. Never share it.

Decrypting an existing key

Now we have the DKEK we can change the script to use this DKEK. We also removeall the initializing code and change the KEY REF in the wrapkey() function tothe correct key we want to export (find with: pkcs15-tool -D).

This is the script, decrypt_keyblob_2.js:

PublicKeyReference = require('scsh/eac/PublicKeyReference').PublicKeyReference;SmartCardHSM = require("scsh/sc-hsm/SmartCardHSM").SmartCardHSM;DKEK = require("scsh/sc-hsm/DKEK").DKEK;var pin = new ByteString("648219", ASCII);var initializationCode = new ByteString("57621880", ASCII);//var dkekshare1 = new ByteString("A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5", HEX);//var dkekshare2 = new ByteString("E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1", HEX);var dkekshare2 = new ByteString("20B3EE1CABA5ECA7ECEB6BE51F11BD9A04F5FE9A6B0A1E0A8BC13074D32CF830", HEX);// Attach to SmartCard-HSMvar card = new Card(_scsh3.reader);var sc = new SmartCardHSM(card);if (sc.queryUserPINStatus() == 0x6984) {  var page = "<html><p><b>Warning:</b></p><br/>" +       "<p>This is a new device that has never been initialized before.</p><br/>" +       "<p>If you choose to continue this test, then the device initialization code will be set to " + initializationCode.toString(ASCII) + " </p><br/>" +       "<p>Please be advised, that this code can be changed later, however the same code must be used in subsequent re-initialization of the device.</p><br/>" +       "<p>Press OK to continue or Cancel to abort.</p>" +       "</html>";  var userAction = Dialog.prompt(page);  assert(userAction != null);}// Determine keys for wrap/unwrapvar crypto = new Crypto();var dkek = new DKEK(crypto);//dkek.importDKEKShare(dkekshare1);dkek.importDKEKShare(dkekshare2);var kenc = dkek.getKENC();var kmac = dkek.getKMAC();print("Values derived from DKEK shared:");print("--------------------------------");print("DKEK        : " + dkek.dkek.toString(HEX));print("KVC         : " + dkek.getKCV().toString(HEX));print("Kenc        : " + kenc.getComponent(Key.AES).toString(HEX));print("Kmac        : " + kmac.getComponent(Key.AES).toString(HEX));print("");// Generate a Test RSA Key with 1024 Bitsc.verifyUserPIN(pin);// Wrap key (KEY REF 1)var keyblob = sc.wrapKey(1);print("Key blob");print("--------");print(keyblob);dkek.dumpKeyBLOB(keyblob);

This script will not reinitialize the HSM, it will use the existing DKEK we'vecalculated. Read on to see the full procedure.

Testing with an existing key

We will initialize the HSM with one DKEK and create a keypair. This keypair isused to encrypt a small file with OpenSSL. Then we retreive the private key to afile and use OpenSSL to decrypt the earlier encrypted file with the exportedkey.

Generate a DKEK, example password 123456789:

sc-hsm-tool --create-dkek-share dkek-share-1.pbe

Output:

Using reader with a card: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00The DKEK share will be enciphered using a key derived from a user supplied password.The security of the DKEK share relies on a well chosen and sufficiently long password.The recommended length is more than 10 characters, which are mixed letters, numbers andsymbols.Please keep the generated DKEK share file in a safe location. We also recommend to keep apaper printout, in case the electronic version becomes unavailable. A printable versionof the file can be generated using "openssl base64 -in <filename>".Enter password to encrypt DKEK share : <123456789>Please retype password to confirm : <123456789>Enciphering DKEK share, please wait...DKEK share created and saved to dkek-share-1.pbe

(Re)initialize the HSM:

THIS WILL REINITIALIZE YOU HSM

Make sure to backup important keys on your HSM first! (Test them as well).

sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 648219 --dkek-shares 1

Output:

Using reader with a card: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00

The HSM is now waiting for the DKEK share:

$ sc-hsm-tool 

Output:

Using reader with a card: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00Version              : 2.0Config options       :  User PIN reset with SO-PIN enabledSO-PIN tries left    : 15User PIN tries left  : 3DKEK shares          : 1DKEK import pending, 1 share(s) still missing

Load the DKEK share:

sc-hsm-tool --import-dkek-share dkek-share-1.pbe

Output:

Using reader with a card: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00Enter password to decrypt DKEK share : Deciphering DKEK share, please wait...DKEK share importedDKEK shares          : 1DKEK key check value : 0FB85F69F6EBF256

The DKEK is now loaded:

sc-hsm-tool 

Output:

Using reader with a card: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00Version              : 2.0Config options       :  User PIN reset with SO-PIN enabledSO-PIN tries left    : 15User PIN tries left  : 3DKEK shares          : 1DKEK key check value : 0FB85F69F6EBF256

Generate a keypair in slot 2:

$ pkcs11-tool --module opensc-pkcs11.so --login --pin 648219 --keypairgen --key-type rsa:1024 --id 2 --label "HSM RSA Key Remy"

Output:

Using slot 0 with a present token (0x0)Key pair generated:Private Key Object; RSA   label:      HSM RSA Key Remy  ID:         02  Usage:      decrypt, sign, unwrapPublic Key Object; RSA 1024 bits  label:      HSM RSA Key Remy  ID:         02  Usage:      encrypt, verify, wrap

You can, if you want, also import a wrapped key. See the getting started guideto find out how to do that.

Find the correct keyref:

pkcs15-tool -D

Output:

Private RSA Key [HSM RSA Key Remy]  Object Flags   : [0x3], private, modifiable  Usage          : [0x2E], decrypt, sign, signRecover, unwrap  Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local  ModLength      : 1024  Key ref        : 1 (0x1)  Native         : yes  Auth ID        : 01  ID             : 02  MD:guid        : 557bcb43-47a3-d83f-f863-ccb6b8432192

The keyref is 1 in this case.

Get the public key from the HSM:

pkcs15-tool --read-public-key 2

Output:

Using reader with a card: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9DEoPbDQTZczSTOZsj83ZqJai+3ZVqD5fFILqE92w3zlcG+0qntLhwxCnYQIRv0reAJIQT5EN4WC0RP+vH2j43onM+o2oVxCPqlckc4wQ0SD3h3ncbFO40zSKLGr9kJd7IIxyvces6ZtVdcxO49Ucv74Bx4D/jWFARAirngU6LQIDAQAB-----END PUBLIC KEY-----

Save it to a file, hsm.pub.

Please read the getting started article to see what to put in the opensslhsm.conf. Read the guide on encrypting with OpenSSL as well.

Create a small file with text to encrypt:

echo 'Remy is awesome' > smallfile

Encrypt it with the HSM public key:

openssl rsautl -inkey publickey.pem -pubin -encrypt -pkcs -in smallfile -out encryptedsmallfile.pkcs1

It's encrypted:

cat encryptedsmallfile.pkcs1  |  base64

Output:

klI3DdYbMOW+WltGmSmCiEntXyI7NT/sFmGBjgXHpRDv8xS+CnUWc4hAKPC7cJERlg5Bl0E6me/Z8J4Q77xorFHSvoeKx0plIhIMlE429cBlMcJGj1o/wnSyaL7sk5H6JU03JNm3KB6wTt3B0vDf5U4OZ5pL4SVLXMwZk/utCms=

Opposed to the small file:

cat smallfile | base64

Output:

UmVteSBpcyBhd2Vzb21lCg==

Now we're going to use the DKEK to get the private key from the device. Use theearlier compiled sc-hsm-tool to get the HEX DKEK:

./src/tools/sc-hsm-tool --print-dkek-share ~/tmp/hsm/dkek-share-1.pbe 

Output:

Using reader with a card: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00Enter password to decrypt DKEK share : Deciphering DKEK share, please wait...DKEK Share HEX: 20B3EE1CABA5ECA7ECEB6BE51F11BD9A04F5FE9A6B0A1E0A8BC13074D32CF830

Place this value in the decrypt_keyblob_2.js script:

var dkekshare2 = new ByteString("20B3EE1CABA5ECA7ECEB6BE51F11BD9A04F5FE9A6B0A1E0A8BC13074D32CF830", HEX);

Also change the keyref if needed:

var keyblob = sc.wrapKey(1);

Use the SmartCard Shell to run this decrypt_keyblob_2.js script. The outputyou need is listed below:

Prime factor p        : FBC979E63BC8034B6D36008FA9482816F36C513B9905ED3CD089E74576260CB4E50F457452C88AD10646DE115AD37923D0B88F1779EA67D11D6D8F8DBFA670D7 (64)Prime factor q        : C0361270B921E5853077AE847B2EADB5C9E0285854F6E4AC27BEBE1D18BFF9DFF6DC5D5422B7AB560D351ACDCE15DAE81DB97FBB184A228480B427E3BE93589B (64)Modulus               : BD0C4A0F6C341365CCD24CE66C8FCDD9A896A2FB7655A83E5F1482EA13DDB0DF395C1BED2A9ED2E1C310A7610211BF4ADE0092104F910DE160B444FFAF1F68F8DE89CCFA8DA857108FAA5724738C10D120F78779DC6C53B8D3348A2C6AFD90977B208C72BDC7ACE99B5575CC4EE3D51CBFBE01C780FF8D61404408AB9E053A2D (128)Exponent              : 010001 (3)

You can see that the KCV is the same as the sc-hsm-tool DKEK key checkvalue:

sc-hsm-tool Using reader with a card: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00Version              : 2.0Config options       :  User PIN reset with SO-PIN enabledSO-PIN tries left    : 15User PIN tries left  : 3DKEK shares          : 1DKEK key check value : 0FB85F69F6EBF256# scshValues derived from DKEK shared:--------------------------------DKEK        : 20B3EE1CABA5ECA7ECEB6BE51F11BD9A04F5FE9A6B0A1E0A8BC13074D32CF830KVC         : 0FB85F69F6EBF256Kenc        : 6890320D25D318530C3AB5988E29D8DF445E5F5ACE223364F41000394614B763Kmac        : BE9BA334E3A89E75E7E8308AE2C28DF3CCC4FDA8B805112E03AD0C3FD452E9A0

Read on to see how to reconstruct the private key with some python.

Reconstructing the key

If you like this article, consider sponsoring me by trying out a Digital OceanVPS. With this link you'll get a $5 VPS for 2 months free (as in, you get $10credit). (referral link)

Make sure you have gmpy and PyCrypto installed. I'm using the followingpython code to recontruct the private key:

#/usr/bin/python2import gmpyfrom Crypto.PublicKey import RSA# pkcs15-tool --read-public-keypub = RSA.importKey("""-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9DEoPbDQTZczSTOZsj83ZqJai+3ZVqD5fFILqE92w3zlcG+0qntLhwxCnYQIRv0reAJIQT5EN4WC0RP+vH2j43onM+o2oVxCPqlckc4wQ0SD3h3ncbFO40zSKLGr9kJd7IIxyvces6ZtVdcxO49Ucv74Bx4D/jWFARAirngU6LQIDAQAB-----END PUBLIC KEY-----"")# Prime factor pp = int("FBC979E63BC8034B6D36008FA9482816F36C513B9905ED3CD089E74576260CB4E50F457452C88AD10646DE115AD37923D0B88F1779EA67D11D6D8F8DBFA670D7", 16)# Prime factor qq = int("C0361270B921E5853077AE847B2EADB5C9E0285854F6E4AC27BEBE1D18BFF9DFF6DC5D5422B7AB560D351ACDCE15DAE81DB97FBB184A228480B427E3BE93589B", 16)# Exponente = long(pub.e)# Modulusn = long(pub.n)# private exponentd = long(gmpy.invert(e,(p-1)*(q-1)))key = RSA.construct((n,e,d))print key.exportKey()print key.publickey().exportKey()

The output from this script:

# >>> print key.exportKey()-----BEGIN RSA PRIVATE KEY-----MIICXQIBAAKBgQC9DEoPbDQTZczSTOZsj83ZqJai+3ZVqD5fFILqE92w3zlcG+0qntLhwxCnYQIRv0reAJIQT5EN4WC0RP+vH2j43onM+o2oVxCPqlckc4wQ0SD3h3ncbFO40zSKLGr9kJd7IIxyvces6ZtVdcxO49Ucv74Bx4D/jWFARAirngU6LQIDAQABAoGASAr54jy677V4w5/YpAB9UvgjR8MKioQOGM/JQAkID9JRmp9t1zMlbDGZFCAs2LSMhGO1Rg/8WEzOPISa55LRvnRkOVPe7ps3NTGynlx028PFc7ddK2tFDgAAq3Sdsj6+1wskDOd0jHZ/rMsl2LZJHy6TgegDZEwpz8TCLaNWNQUCQQDANhJwuSHlhTB3roR7Lq21yeAoWFT25Kwnvr4dGL/53/bcXVQit6tWDTUazc4V2ugduX+7GEoihIC0J+O+k1ibAkEA+8l55jvIA0ttNgCPqUgoFvNsUTuZBe080InnRXYmDLTlD0V0UsiK0QZG3hFa03kj0LiPF3nqZ9EdbY+Nv6Zw1wJAB6efoGGfGfbt8TZADG/VdzHs/W5XI+YDfSm5hIshyh/DQw9sdF2AM1MfVEvx8yjeqaBjl93lxe4k+gfEqChSFQJBAMv/Xv5ErTbOI7u/FKZIygJeUwI10TNWFRG4yWIj6Ywd/AA1e5ue06mq9jvxv67a1UPEZFrW8i4O5VLhHi2Kwp0CQQCd6au8XXhtY64/Tei73LqqmJFXH+XLROB7Zmw6+OOYfCz66jLobiDBbX5ubdAkLbzot9LXbAAEE1eChUjNfJQs-----END RSA PRIVATE KEY-----

Place this private key in a file (hsm.priv).

Use OpenSSL to decrypt the encrypted file with the keyfile:

openssl rsautl -decrypt -inkey hsm.priv -in encryptedsmallfile.pkcs1 

Output:

Remy is awesome

You can also use the HSM to decrypt:

pkcs15-crypt --decipher --key 2 --input encryptedsmallfile.pkcs1 --pkcs1 --raw 

Output:

Using reader with a card: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00Enter PIN [UserPIN]: 648219Remy is awesome

sc-hsm-tool.c code

The full sc-hsm-tool.c file with the DKEK print option, is downloadable fromhere.

Tags: articles, cryptoki, dkek, hsm, nitrokey, nitrokey-hsm, openssl, pkcs11, safenet, sc-hsm, smartcard, smartcard-hsm