PKCS11 deriveKey () and encrypt () returns different results for 3DES

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 ################################################################################ derive key Derivation Mechanism: Mechanism: CKM_DES3_ECB Parameters: String data (hex): 008430953505f001 -------------------------------------------------------------------------------- 01/18/13 14:12:10 CALL: entering (in Java_iaik_pkcs_pkcs11_wrapper_PKCS11Implementation_C_1DeriveKey) [snip] Derived key: Object Class: Secret Key Token: true Private: false Modifiable: true Label: <NULL_PTR> Key Type: DES ID: <NULL_PTR> Start Date: 00.00.0000 (DD.MM.YYYY) End Date: 00.00.0000 (DD.MM.YYYY) Derive: false Local: false Key Generation Mechanism: CKM_DES3_ECB Allowed Mechanisms: <NULL_PTR> Sensitive: false Encrypt: false Decrypt: false Sign: false Verify: false Wrap: false Unwrap: false 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): 3efe0eab6d3db397 <--- call to deriveKey() value incorrect ################################################################################ finished 01/18/13 14:12:12 CALL: entering (in Java_iaik_pkcs_pkcs11_wrapper_PKCS11Implementation_C_1EncryptInit) 01/18/13 14:12:12 CALL: exiting (in Java_iaik_pkcs_pkcs11_wrapper_PKCS11Implementation_C_1EncryptInit) 01/18/13 14:12:12 CALL: entering (in Java_iaik_pkcs_pkcs11_wrapper_PKCS11Implementation_C_1Encrypt) 01/18/13 14:12:12 CALL: exiting (in Java_iaik_pkcs_pkcs11_wrapper_PKCS11Implementation_C_1Encrypt) Encrypted data: 3fff0faa6c3cb297 <--- call to encrypt() returns the expected value 
+4
source share
1 answer

It turns out that the key generated in HSM using DeriveKey and the key I bytes generated using session.encrypt () are essentially the same if you consider how the DES parity check works.

The least significant bit of each byte in the DES key is the parity bit, which is ignored in many implementations and is not used as part of the key, so if I set the parity bits correctly in my encryption result, then both results match.

0x3efe0eab6d3db397 <--- HSM generated value with correct odd parity
00111110 11111110 00001110 10101011 01101101 00111101 10110011 10010111

0x3fff0faa6c3cb297 <--- encryption result without parity bit set correctly
00111111 11111111 00001111 10101010 01101100 00111100 10110010 10010111

+8
source

Source: https://habr.com/ru/post/1204343/


All Articles