我正在使用HSM和PKCS11处理密钥派生问题,目前我无法理解为什么我会看到完全不同的结果,这取决于我是否使用generateKey()方法,而不是使用crypto()方法。在这两种情况下,我都尝试将DESede / ECB / NoPadding算法用于结果,但是根据我用来生成结果的方法(deriveKey与加密),我看到了不同的结果。
退后一会儿,以给出高层次的概述…我正在使用Global Platform使用的特定密钥派生方法来使用于智能卡的主密钥多样化。该方法以主密钥和用于导出新密钥的8字节数据(多样化数据)开始。实际上,仅使用DESede / ECB / NoPadding使用主密钥对div数据字节进行加密,并将结果用作新派生的3DES密钥的一部分。(实际上,执行了多次加密,并将结果串联在一起以形成新密钥,但这不是问题所在。)
我已经验证了这两种情况下的主密钥,验证了两种情况下的多样化数据都相同,并验证了我使用的是具有相同填充的相同算法。我还尝试将派生密钥模板更改为DES,2DES,3DES。所有这些都产生相似的结果,只是长度不同。
目前,我已经使用IAIK包装器(用Java编写的pkcs11包装器)实现了我的测试用例,我将在此处发布它。该键只是一个测试键,而div数据是示例div数据,因此此处没有敏感信息。我首先在HSM中创建一个基本密钥,然后尝试通过使用多样化数据调用session.deriveKey()来派生新密钥。派生的密钥字节以十六进制打印(根据我当前正在工作的实现(在内存中而不是在HSM中派生密钥),密钥值不正确)。接下来,我简单地初始化会话以使用主密钥执行加密,然后加密多样化数据。这样就产生了预期值(再次对照有效的实施方案进行了检查)。
我要寻找的是对为什么当我使用相同的基本密钥,相同的div数据和相同的加密算法时,这些操作为何产生不同结果的任何见解。我不明白表面上的generateKey()在做什么,而且我找不到任何文档或源代码来阐明这一点。我必须能够使用deriveKey()方法,因为派生密钥在HSM之外将不可用。
任何见解表示赞赏。
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's 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);
这是我运行上述代码时的相关输出:
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
事实证明,如果考虑DES奇偶校验的工作原理,则使用DeriveKey在HSM中生成的密钥和使用session.encrypt()生成的密钥字节本质上是相同的。
DES密钥中每个字节的最低有效位是奇偶校验位,在许多实现中都将其忽略,并且不用作密钥的一部分,因此,如果在加密结果上正确设置了奇偶校验位,则两个结果都将匹配。
0x3efe0eab6d3db397 <-HSM生成的值具有正确的奇校验 00111110 11111110 00001110 10101011 01101101 00111101 10110011 10010111
0x3fff0faa6c3cb297 <-–没有正确设置奇偶校验位的加密结果 00111111 11111111 00001111 10101010 01101100 00111100 10110010 10010111