I am working on the problem of key output using HSM and PKCS11, and currently I do not understand why I see completely different results depending on whether I use the deriveKey () method and not the encrypt () method. In both cases, I try to use the DESede / ECB / NoPadding algorithm for the result, but depending on which method (deriveKey vs. encrypt) I use to generate the result, I see different results.
Taking a moment to give a high-level overview ... I use the specific key derivation methodology used by the Global Platform to diversify the master key for use on a smart card. The method begins with a master key and 8 bytes of data (diversification data) that are used to obtain a new key. Div data bytes are literally simply encrypted using the master key using DESede / ECB / NoPadding, and the result is used as part of the new 3DES derived key. (In fact, multiple encryption is performed, and the results are combined together to form a new key, but this is not a problem here.)
I checked the master key in both cases, confirmed that the diversification data is the same in both cases, confirmed that I use the same algorithm with the same filling. I also tried changing the template of the derived key to DES, 2DES, 3DES. All give similar results, which differ only in length.
I have currently completed my test case using the IAIK shell (pkcs11 wrapper written in Java), which I will post here. A key is just a test key, and div data is sampled div data, so there is no important information here. First, I create the base key in HSM, and then try to get a new key by calling session.deriveKey () using the diversification data. The output key bytes are printed in hexadecimal format (the key value is incorrect, based on my current working implementation, which displays the key in memory instead of HSM). Then, I simply initialize the session to perform encryption using the master key, and then encrypt the diversification data. This gives the expected value (again, tested for working implementation).
What I'm looking for is any understanding of why these operations yield different results when I use the same basic key, the same div data and the same encryption algorithm. I donβt understand what deriveKey () does under the surface, and I cannot find the documentation or source code to shed any light on this. I should be able to use the deriveKey () method since the derived key will not be accessible outside of HSM.
Any insight was appreciated.
Mechanism keyGenerationMechanism = Mechanism.get(PKCS11Constants.CKM_DES3_KEY_GEN); List supportedMechanisms = Arrays.asList(token.getMechanismList()); if (!supportedMechanisms.contains(Mechanism.get(PKCS11Constants.CKM_DES3_KEY_GEN))) { output_.println("Mechanism not supported: DES3_KEY_GEN"); return; } // This is the master key that I want to diversify DES3SecretKey baseKeyTemplate = new DES3SecretKey(); baseKeyTemplate.getValue().setByteArrayValue(new byte[] {0x3d, 0x20, 0x5b, 0x29, (byte) 0xfd, 0x04, (byte) 0xd9, (byte) 0x89, (byte) 0xd0, (byte) 0xfd, (byte) 0x85, (byte) 0xd5, (byte) 0xf7, (byte) 0xb3, 0x31, (byte) 0xd3, 0x3d, 0x20, 0x5b, 0x29, (byte) 0xfd, 0x04, (byte) 0xd9, (byte) 0x89}); baseKeyTemplate.getDerive().setBooleanValue(Boolean.TRUE); baseKeyTemplate.getToken().setBooleanValue(Boolean.TRUE); baseKeyTemplate.getPrivate().setBooleanValue(Boolean.TRUE); baseKeyTemplate.getSensitive().setBooleanValue(Boolean.FALSE); baseKeyTemplate.getExtractable().setBooleanValue(Boolean.TRUE); baseKeyTemplate.getLabel().setCharArrayValue("GP-3des-aba".toCharArray()); baseKeyTemplate.getObjectClass().setLongValue(PKCS11Constants.CKO_SECRET_KEY); baseKeyTemplate.getKeyType().setLongValue(PKCS11Constants.CKK_DES3); baseKeyTemplate.getEncrypt().setBooleanValue(Boolean.TRUE); baseKeyTemplate.getDecrypt().setBooleanValue(Boolean.TRUE); baseKeyTemplate.getWrap().setBooleanValue(Boolean.TRUE); baseKeyTemplate.getUnwrap().setBooleanValue(Boolean.TRUE); output_.println("baseKeyTemplate: " + baseKeyTemplate.toString()); SecretKey baseKey = (SecretKey) session.createObject(baseKeyTemplate); System.out.println("Base key: "); System.out.println(baseKey.toString()); output_ .println("################################################################################"); output_.println("derive key"); //DES3 Key Template DESSecretKey derived3DESKeyTemplate = new DESSecretKey(); SecretKey derivedKeyTemplate = derived3DESKeyTemplate; derivedKeyTemplate.getSensitive().setBooleanValue(Boolean.FALSE); derivedKeyTemplate.getToken().setBooleanValue(Boolean.TRUE); derivedKeyTemplate.getExtractable().setBooleanValue(Boolean.TRUE); derivedKeyTemplate.getPrivate().setBooleanValue(Boolean.FALSE); derivedKeyTemplate.getKeyType().setLongValue(PKCS11Constants.CKK_DES); // This represents the diversification data (.ie div bytes from some smart card) byte[] data = new byte[] {0x00, (byte) 0x84, 0x30, (byte) 0x95, 0x35, 0x05,(byte) 0xf0, 0x01}; KeyDerivationStringDataParameters param = new KeyDerivationStringDataParameters(data); Mechanism mechanism = Mechanism.get(PKCS11Constants.CKM_DES3_ECB); if (!supportedMechanisms.contains(Mechanism .get(PKCS11Constants.CKM_DES3_ECB))) { output_.println("Mechanism not supported: CKM_DES3_ECB"); return; } mechanism.setParameters(param); System.out.println("Derivation Mechanism: "); output_.println(mechanism.toString()); output_ .println("--------------------------------------------------------------------------------"); Key derivedKey = session.deriveKey(mechanism, baseKey, derivedKeyTemplate); if (derivedKey == null) { output_.println("Found NO key that can be used for encryption."); output_.flush(); System.exit(0); } System.out.println("Derived key: "); output_.println(derivedKey.toString()); output_ .println("################################################################################"); output_.println("finished"); // initialize for encryption Mechanism encryptionMechanism = Mechanism.get(PKCS11Constants.CKM_DES3_ECB); session.encryptInit(encryptionMechanism, baseKey); byte[] encryptedData = session.encrypt(data); System.out.println("Encrypted data: " + new String(Hex.encodeHex(encryptedData))); // This is the second part of the derived key, let not worry about this yet since the first part isn't // working. // data = new byte[] {0x00, (byte) 0x84, 0x30, (byte) 0x95, 0x35, 0x05,(byte) 0x0f, 0x01, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // // session.encryptInit(encryptionMechanism, baseKey); // encryptedData = session.encrypt(data); // System.out.println("Encrypted data: " + new String(Hex.encodeHex(encryptedData))); session.closeSession(); pkcs11Module.finalize(null);
Here is the relevant output when I run the above code:
Base key: Object Class: Secret Key Token: true Private: true Modifiable: true Label: GP-3des-aba Key Type: DES3 ID: <NULL_PTR> Start Date: 00.00.0000 (DD.MM.YYYY) End Date: 00.00.0000 (DD.MM.YYYY) Derive: true Local: false Key Generation Mechanism: <Information unavailable> Allowed Mechanisms: <NULL_PTR> Sensitive: false Encrypt: true Decrypt: true Sign: false Verify: false Wrap: true Unwrap: true Extractable: true Always Sensitive: false Never Extractable: false Check Value: <Attribute not present> Wrap With Trusted: <Attribute not present> Trusted: <Attribute not present> Wrap Template: <Attribute not present> Unwrap Template: <Attribute not present> Value (hex): 3d205b29fd04d989d0fd85d5f7b331d33d205b29fd04d989