This note describes what a DKEK is, how DKEK shares work for key management on SmartCard-HSM class devices, and how that relates to the Smart Card Shell (scsh) distribution. It is aimed at operators and integrators; it does not replace manufacturer documentation or a formal security analysis. The SmartCard-HSM site is https://www.smartcard-hsm.com/. Smart Card Shell 3 is distributed from https://www.openscdp.org/scsh3/download.html.
Terminology
On SmartCard-HSM devices, DKEK usually denotes Device Key Encryption Key: a 256-bit symmetric key held inside the device that acts as a key-encryption key (KEK) for wrapping sensitive key material when using backup, restore, or migration features.
The same three-letter acronym can appear elsewhere in cryptography with different meanings (for example some standards use KEK hierarchies without this exact name). In this document, DKEK refers to the SmartCard-HSM mechanism unless stated otherwise.
Why a DKEK exists
Many HSMs and smart-card HSMs never release private keys in plaintext. To move a key between devices, or to keep an offline backup, the implementation encrypts the key under a KEK that exists on the card. On SmartCard-HSM, that KEK is the DKEK.
Typical properties:
- Keys generated on the card can be exported only if a DKEK key domain was configured during initialisation (or equivalent setup), depending on device options and policy.
- If the device is re-initialised and the DKEK is wiped, encrypted backups that depended on the old DKEK cannot be recovered.
- The DKEK is not intended to be held as a single secret by one person alone; the design allows splitting the material that builds the DKEK into shares.
What a DKEK share is
A DKEK share is a random 256-bit (32-byte) value. During setup the device is configured to expect a chosen number of shares. Each share is generated inside the device (using the card RNG), then passed to a custodian who stores it, usually as a password-encrypted file or using other formats such as a printable encoding.
The final DKEK is assembled by combining the shares with exclusive-or (XOR): each share is XORed into a running 256-bit value until all shares are imported. Published technical descriptions for SmartCard-HSM state that multiple shares are XORed into a single KEK value inside the key domain.
Important distinction: this is not Shamir secret sharing. With plain XOR composition, you normally need every share to reconstruct the DKEK. Published material also describes optional threshold schemes applied to the password that protects a share file (n-of-m password fragments), which is a separate layer from the XOR combination of random shares.
Roles in key management
- Key domain: a logical grouping for keys and for the KEK material used to wrap them. Newer devices support multiple key domains; older or simpler profiles may expose a single DKEK domain.
- Custodians: individuals who receive and protect distinct DKEK shares. Organisational policy decides how many shares to use (common examples in public guides are one to three shares).
- Key check value (KCV): a short fingerprint used to confirm that the assembled DKEK on a device matches expectations before you rely on backup or import operations.
Off-card handling of shares (files and passwords)
Shares leave the device only in forms that depend on custodian-chosen secrets:
- Password-based encryption of the share (for example
.pbefiles in command-line workflows). - Optional password threshold splitting, where several people hold fragments of the password needed to decrypt one share.
- Alternative encodings (for example human-entered formats) aimed at offline storage.
The security of an encrypted share file depends on password strength, resistance to offline guessing, and physical protection of the storage medium.
PKCS#12 import, DKEK shares, and protected card memory (Smart Card Shell Key Manager)
In the Key Manager sources shipped with Smart Card Shell 3 (under keymanager/ in the unpacked distribution), the Key Manager loads PKCS#12 (.p12) files with BouncyCastle (KeyStore("BC", "PKCS12", ...)). The PKCS#12 password only decrypts the container on the host; it is not the DKEK. The shell then has to move private keys into the SmartCard-HSM without sending them in plaintext over the card interface. That step uses the same DKEK-based wrap format as other tooling: the host builds a key blob with DKEK.encodeKey(privateKey, publicKeyFromCertificate), and HSMKeyStore.importRSAKey / importECCKey call unwrapKey on the device so the key material is loaded into protected storage and PKCS#15-style metadata is written. Certificates are stored separately (storeEndEntityCertificate for end-entity certs, storeCACertificate when the P12 entry has no usable private key).
The excerpts below cite concrete paths and line numbers from one unpacked tree; after installation your top-level directory name typically matches the release you downloaded (for example scsh-3.x.y), and line numbers may shift in other releases.
Two implementations exist side by side; both hinge on assembling the same 256-bit DKEK on the host as the card holds when unwrapKey runs.
Shares entered on the host (classic “Import from PKCS#12” in keymanager.js)
The handler importPKCS12 asks how many DKEK shares to apply (often one). For each share, the operator supplies material through the same paths as ordinary DKEK share import (password-protected file, n-of-m password fragments, or PaperKey). Each 32-byte share is XORed into the host DKEK instance. After all shares are combined, the tool opens the PKCS#12 file, extracts the private key and certificate, forms the wrapped blob, and calls importRSAKey or importECCKey followed by certificate storage.
Share assembly and wrapping:
KeyManager.prototype.importPKCS12 = function(node) {
var str = Dialog.prompt(KeyManager.DKEK_NO_OF_SHARES, "1");
if (str == null) {
return;
}
var shares = parseInt(str);
var dkek = new DKEK(this.crypto);
for (var cnt = 0; cnt < shares; cnt++) {
var dkekshare = this.inputDKEKShare();
dkek.importDKEKShare(dkekshare);
dkekshare.clear();
}
if (key != null) {
print("Importing key and certificate...");
var pubkey = cert.getPublicKey();
var blob = dkek.encodeKey(key, pubkey);
if (pubkey.getComponent(Key.MODULUS)) {
hkey = this.ks.importRSAKey(alias, blob, pubkey.getSize());
var signalgo = Crypto.RSA_PSS_SHA256;
} else {
hkey = this.ks.importECCKey(alias, blob, pubkey.getSize());
var signalgo = Crypto.ECDSA_SHA256;
}
this.ks.storeEndEntityCertificate(alias, cert);
// Test import
var msg = new ByteString("Hello World", ASCII);
var signature = hkey.sign(signalgo, msg);
assert(this.crypto.verify(pubkey, signalgo, msg, signature), "Signature verification of imported key failed");
print("Import completed");
} else {
print("Importing certificate...");
this.ks.storeCACertificate(alias, cert);
}
this.createOutline();
} while (aliases.length > 1 && Dialog.prompt("Import more keys ?"));
} while (Dialog.prompt("Import more PKCS#12 files ?"));
dkek.clear();
For this path to succeed, the SmartCard-HSM must already contain the same DKEK that those shares define. In practice that means the device was initialised for that key domain and all required shares were imported onto the card earlier; the Key Manager session only recombines the shares on the PC so it can encrypt the import blob consistently with the firmware’s unwrap. If the host DKEK and the card DKEK differ, unwrap fails or the import is rejected.
Transient key domain for PKCS#12 (220-importp12-plugin.js)
The plug-in “Import from PKCS#12” uses a different pattern when an empty key domain slot is available: it creates a fresh DKEK key domain that expects a single share, generates one random 32-byte share on the host, imports that share into the card, XORs it in the host DKEK object, performs the same encodeKey / importRSAKey or importECCKey / certificate store sequence, then clears the host state and calls deleteKEK on that key domain identifier.
Key-domain creation, share import, and teardown:
var kdid = -1;
do {
kdid++;
var kd = sc.queryKeyDomainStatus(kdid);
if ((kd.sw == 0x6A86) || (kd.sw == 0x6D00)) {
Dialog.prompt("No empty key domain found.");
return
}
} while (kd.sw != 0x6A88);
// Create DKEK domain with random DKEK
sc.createDKEKKeyDomain(kdid, 1);
var share = crypto.generateRandom(32);
sc.importKeyShare(kdid, share);
// Create DKEK encoder and import share
var dkek = new DKEK(crypto);
dkek.importDKEKShare(share);
} while (Dialog.prompt("Import more PKCS#12 files ?"));
dkek.clear();
sc.deleteKEK(kdid);
Here the share is created for a one-off import: the card and host agree on a temporary DKEK solely to wrap the PKCS#12 private key for unwrapKey. The plug-in then deletes the key-encryption key in that domain (deleteKEK); the imported asymmetric keys remain in the device’s normal key store, while the short-lived DKEK used for the transfer is not left in place for backup or migration unless you also use a longer-lived key-domain configuration elsewhere.
How many shares appear in practice
- One share is the minimal case: a single random or custodian-held 32-byte value XORed into the DKEK.
- Multiple shares mean the loop runs several times on the host (
importDKEKSharefor each); the card must have received the same number of shares during its own setup so the XOR result matches.
Operational distinction worth preserving
- PKCS#12 password: unwraps the file on the workstation only; choose it independently of DKEK share passwords.
- DKEK shares: define the KEK the card uses to accept wrapped private-key blobs; organisational controls (files, PaperKey, n-of-m on a share password) apply here, not to the PKCS#12 file’s own password.
Relationship to the Smart Card Shell installer
Smart Card Shell 3 is distributed as an IzPack-based, self-contained JAR (alongside zip archives) from OpenSCDP / CardContact. The downloadable artefact name follows the release, for example scsh-3.x.y-installer.jar. Current installers and archives are published at https://www.openscdp.org/scsh3/download.html. The JAR packs a large core payload (resources/packs/pack-Core) that contains JavaScript modules for card tooling.
Among those modules is a DKEK helper used with SmartCard-HSM:
- Module path in the bundle:
scsh/sc-hsm/DKEK(seerequire("scsh/sc-hsm/DKEK")inside the SmartCard-HSM support code). - It implements host-side operations that correspond to command-line tools for manipulating DKEK shares outside the card.
What the bundled DKEK helper does (implementation-level)
The following points summarise behaviour visible in the embedded DKEK.js source inside pack-Core. They describe the host library, not necessarily every firmware detail inside the chip.
Internal state
The helper keeps a 32-byte value initialised to zero. Importing a share XORs it into that value, matching the XOR assembly model.Key check value
The KCV is derived as the first eight bytes of SHA-256 over the 32-byte DKEK value. This lets operators compare devices without revealing the full key.Wrapping keys under the DKEK
From the 32-byte DKEK, two AES keys are derived with SHA-256 and distinct domain separation constants (labels00000001and00000002in hex) for encryption and integrity (CMAC-style use appears in the wrapping code paths). This matches the documented pattern that the DKEK seeds separate encryption and integrity keys for protected blobs.Encrypting a share for storage
- A random eight-byte salt is generated.
- A key and IV are produced from the salt and password using a stretching routine based on repeated MD5 processing (the code attempts a single-call MD5 with a very large iteration count, with a slower fallback loop).
- The plaintext share is padded and encrypted with AES-CBC.
- The on-disk form begins with the ASCII prefix
Salted__followed by the salt and ciphertext, similar in spirit to common OpenSSL password-based encryption envelopes.
- A random eight-byte salt is generated.
Card protocol surface in the same module family
The SmartCard-HSM host wrapper issues secure-message APDUs with instruction0x52and function variants such as creating a DKEK key domain (P1 = 0x01) and importing a share (P1 = 0x00). Wrap and unwrap operations use other implementation-specific INS codes in the same source. Exact allowable parameters depend on firmware and initialisation state.
Practical guidance (non-exhaustive)
- Decide how many shares you need based on organisational control, not on convenience alone. More shares increase operational friction; fewer shares increase concentration of risk.
- Treat encrypted share files as highly sensitive; offline guessing attacks are a real concern if files leak.
- Record KCVs and key-domain identifiers as part of your key-management records so restores can be validated.
- Distinguish DKEK key domains from XKEK-style domains on devices that support both: XKEK domains use different agreement mechanisms (documented authenticated ECDH-based setups), whereas DKEK domains are built from imported shares as described here.
References and further reading
- SmartCard-HSM: technical articles and documentation on DKEK shares, key domains, and recovery — https://www.smartcard-hsm.com/
- SmartCard-HSM hardware (tokens, cards, and related form factors that can be used with Smart Card Shell) is available from several suppliers; one catalogue is https://www.cardomatic.de/en/c/smartcard-hsm.
- OpenSC wiki: SmartCard-HSM section summarises DKEK share import and
sc-hsm-toolworkflows (OpenSC wiki). - Smart Card Shell 3: download IzPack installer or file archive from https://www.openscdp.org/scsh3/download.html; project overview at http://www.openscdp.org/scsh3/index.html. Use the current stable build from that page; code excerpts in this note were checked against a recent unpack of the shell.
Limitations of this note
Firmware evolves; APDU layouts, maximum numbers of shares, and domain features depend on device generation and version. Always verify behaviour against the documentation for your exact device and software stack. This document does not analyse side-channel resistance, PKCS#11 policy, or organisational compliance requirements.






0 comments:
Post a Comment