2

When attempting to create a secret key; I'm told that it's not possible to create your own key values and they must be generated/unwrapped onto the HSM. In case this isn't true I've attached both attempts/methods in case I'm missing something. Any help would be greatly appreciated!

Environment: Network Luna K6 5.1

Library: PKCS11Interop.Net

Attempt 1: Using Create Object

Error: CKR_TEMPLATE_INCONSISTENT

string keyLabel = "CustomSecretKey"
byte[] Value = HexStringToByteArray(value);

privateKey = new List<ObjectAttribute>
                                {
                                   //PKCS11V2.20 Common Attributes Defined @ 12.12.2
                                   new ObjectAttribute(CKA.CKA_LABEL, keyLabel),
                                   new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY),
                                   new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_AES),
                                   new ObjectAttribute(CKA.CKA_TOKEN, true),
                                   new ObjectAttribute(CKA.CKA_ENCRYPT, true),
                                   new ObjectAttribute(CKA.CKA_PRIVATE, true), 
                                   new ObjectAttribute(CKA.CKA_DECRYPT, true), 
                                   new ObjectAttribute(CKA.CKA_VALUE_LEN, 32),
                                   new ObjectAttribute(CKA.CKA_VALUE, Value)    

                               };

session.CreateObject(privateKey);

This apparently isn't supported?

Attempt 2: Using UnWrap Key

Error: CKR_WRAPPED_KEY_INVALID

using (Pkcs11 pkcs11 = new Pkcs11(HSM.Instance.vendorDLLPath, AppType.MultiThreaded))
            {
                List<Slot> slots = pkcs11.GetSlotList(SlotsType.WithTokenPresent); //Checks to see what slots have token on them.
                Slot slot = slots[HSM.Instance.activeSlot];
                using (Session session = slot.OpenSession(SessionType.ReadWrite)) // Open RW session
                {
                    session.Login(CKU.CKU_USER, HSM.Instance.loginPass); // Login as normal user   
                    try
                    {
                        byte[] Value = HexStringToByteArray(value);

                        if (!string.IsNullOrEmpty(keyLabel))
                        {

                            List<ObjectAttribute> wrapKey = new List<ObjectAttribute>
                            {
                            new ObjectAttribute(CKA.CKA_LABEL, "TempWrapKey"),
                            new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY),
                            new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_AES),
                            new ObjectAttribute(CKA.CKA_TOKEN, true),
                            new ObjectAttribute(CKA.CKA_PRIVATE, true),
                            new ObjectAttribute(CKA.CKA_ENCRYPT, true),
                            new ObjectAttribute(CKA.CKA_DECRYPT, true),
                            new ObjectAttribute(CKA.CKA_SENSITIVE, true),
                            new ObjectAttribute(CKA.CKA_VERIFY, true),
                            new ObjectAttribute(CKA.CKA_SIGN, true),
                            new ObjectAttribute(CKA.CKA_WRAP, true),
                            new ObjectAttribute(CKA.CKA_UNWRAP, true),
                            new ObjectAttribute(CKA.CKA_DERIVE, false),
                            new ObjectAttribute(CKA.CKA_EXTRACTABLE, false),
                            new ObjectAttribute(CKA.CKA_VALUE_LEN, 32)

                            };
                            ObjectHandle WrappingKey = session.GenerateKey(new Mechanism(CKM.CKM_AES_KEY_GEN), wrapKey);

                            byte[] keyValueBytes = session.Encrypt(new Mechanism(CKM.CKM_AES_ECB), WrappingKey, Value);

                            List<ObjectAttribute> privateKeyAttributes = new List<ObjectAttribute>
                            {

                                new ObjectAttribute(CKA.CKA_LABEL, keyLabel),
                                new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY),
                                new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_AES),
                                new ObjectAttribute(CKA.CKA_TOKEN, true),
                                new ObjectAttribute(CKA.CKA_PRIVATE, true),
                                new ObjectAttribute(CKA.CKA_ENCRYPT, true),
                                new ObjectAttribute(CKA.CKA_DECRYPT, true),
                                new ObjectAttribute(CKA.CKA_SENSITIVE, true),
                                new ObjectAttribute(CKA.CKA_VERIFY, true),
                                new ObjectAttribute(CKA.CKA_SIGN, true),
                                new ObjectAttribute(CKA.CKA_WRAP, true),
                                new ObjectAttribute(CKA.CKA_UNWRAP, true),
                                new ObjectAttribute(CKA.CKA_DERIVE, false),
                                new ObjectAttribute(CKA.CKA_EXTRACTABLE, false),
                                new ObjectAttribute(CKA.CKA_VALUE_LEN, 32)

                            };


                            session.UnwrapKey(new Mechanism(CKM.CKM_AES_ECB), WrappingKey, keyValueBytes, privateKeyAttributes);
                            session.DestroyObject(WrappingKey);
                            response.ErrorText = "Key Created?";

The logs of attempt 2:

12:02:28 03696-5152:STRTOpenSession {Slot=1 Flgs=6 }
12:02:28 03696-5152:FINIOpenSession CKR_OK(1609ms) {Sesn=1 }

12:02:28 03696-5152:STRTLogin {Sesn=1 User=1 PIN="********" }
12:02:28 03696-5152:FINILogin CKR_OK(1734ms) {}

12:02:28 03696-5152:STRTGenerateKey {Sesn=1 Mech=(CKM_AES_KEY_GEN,"") AttrList={CKA_CLASS="04000000" CKA_KEY_TYPE="1f000000" CKA_TOKEN="01" CKA_ENCRYPT="01" CKA_LABEL="TempWrapKey" CKA_CLASS="04000000" CKA_KEY_TYPE="1f000000" CKA_TOKEN="01" CKA_ENCRYPT="01" CKA_PRIVATE="01" CKA_DECRYPT="01" CKA_VALUE_LEN="20000000" CKA_WRAP="01" CKA_UNWRAP="01" CKA_SENSITIVE="01" CKA_SIGN="01" CKA_DERIVE="00" CKA_EXTRACTABLE="00" } }
12:02:29 03696-5152:FINIGenerateKey CKR_OK(1750ms) {Obj=2000001 }

12:02:29 03696-5152:STRTEncrypt_Init {Sesn=1 Mech=(CKM_AES_ECB,"") Obj=2000001 }
12:02:29 03696-5152:FINIEncrypt_Init CKR_OK(1750ms) {}

12:02:29 03696-5152:STRTEncrypt {Sesn=1 "23724cf301e85a53fc3f5aea6384c16e" pusEncryptedDataLen=0xf91ddca0 *pusEncryptedDataLen=0 }
12:02:29 03696-5152:FINIEncrypt CKR_OK(1750ms) {"" pusEncryptedDataLen=0xf91ddca0 *pusEncryptedDataLen=16 }

12:02:29 03696-5152:STRTEncrypt {Sesn=1 "23724cf301e85a53fc3f5aea6384c16e" pusEncryptedDataLen=0xf91ddca0 *pusEncryptedDataLen=16 }
12:02:29 03696-5152:FINIEncrypt CKR_OK(1750ms) {"2e151cc889470864b5fb5a24146fecb2" pusEncryptedDataLen=0xf91ddca0 *pusEncryptedDataLen=16 }

12:02:29 03696-5152:STRTUnwrapKey {Sesn=1 Mech=(CKM_AES_ECB,"") Obj=2000001 "2e151cc889470864b5fb5a24146fecb2" AttrList={CKA_LABEL="Key2372" CKA_CLASS="04000000" CKA_KEY_TYPE="1f000000" CKA_TOKEN="01" CKA_PRIVATE="01" CKA_ENCRYPT="01" CKA_DECRYPT="01" CKA_SENSITIVE="01" CKA_VERIFY="01" CKA_SIGN="01" CKA_WRAP="01" CKA_UNWRAP="01" CKA_DERIVE="00" CKA_EXTRACTABLE="00" CKA_VALUE_LEN="20000000" } }
12:02:29 03696-5152:FINIUnwrapKey ***CKR_WRAPPED_KEY_INVALID***(1750ms) {Obj=0 }

12:02:29 03696-5152:STRTCloseSession {Sesn=1 }
12:02:29 03696-5152:FINICloseSession CKR_OK(1765ms) {}

Should I generate another key and use that to be unwrapped?

G .
  • 69
  • 10
  • 1
    Could you show the types and values of the variables `keyLabel` and the `Value`? – Maarten Bodewes Aug 31 '18 at 01:07
  • 1
    In the second attempt you first create the key, and then unwrap to it. If I'm not mistaken the key will be created automatically; there is no need to specify / create the key object in advance. Note that in the second attempt you have a lot of duplicate fields in the template. That doesn't show the precision required to tackle crypto. – Maarten Bodewes Aug 31 '18 at 01:14
  • Sorry for the confusion, I've added the types and values for the keyLabel and Value. The value is created by the user as a hex value. Accidentally posted the test attributes and the attempted create key object, the ones up there now are updated and match the log statements below, sorry again. The duplicates throw a different error and agreed not precise enough to tackle a consistent template :) As for the create key method I thought to create the object first and have the unwrap function overwrite the none valued key with the unwrapped value key. That doesn't work. – G . Aug 31 '18 at 14:28
  • 1
    In your attempt 2, have you tired to encrypt the key using CBC mode with IV, before unwrapping it? – always_a_rookie Sep 02 '18 at 04:52
  • Using the CBC mode with an IV before unwrapping did the trick. Thank you @always_a_rookie_to_learn! I'm sure I will have to change the attributes to check on the key value afterward but I'm noticing that when I use the same key value for two new keys they don't seem to match the encrypted & decrypted text at least on the Network HSM. Any thoughts on why that would be? – G . Sep 04 '18 at 20:44
  • @G. Have you tried encrypting with one key and decrypting with the other key by using the same cipher parameters in the decryption operation as the encryption operation? – always_a_rookie Sep 05 '18 at 02:35
  • @always_a_rookie_to_learn Yes, I get a CKR_DATA_INVALID on the decryption using the other key. But using same key I'm able to successfully encrypt and decrypt. I'm fairly new to SO/crypto (maybe something dumb);but here's the mechanisms: session.Encrypt(new Mechanism(CKM.CKM_AES_CBC_PAD, Iv), privateKeyHandles[0], rawData); session.Decrypt(new Mechanism(CKM.CKM_AES_CBC_PAD, Iv), privateKeyHandles[0], rawData); The IV values are the same as the ones used to create key. The rawData is a byte array. The privateHandle[0] simply is the returned key that matches on label and class. – G . Sep 06 '18 at 15:53
  • Different systems though maybe helpful; the encrypt with one key and the decrypt with the other key (along with key values/encrypt/decrypt matching in general) works perfectly on our software SafeNet HSM... – G . Sep 06 '18 at 15:54
  • @G. In the decrypt method, you are passing in `rawData` to be decrypted. You are supposed to pass in the encrypted value (returned value of encrypt method). – always_a_rookie Sep 06 '18 at 21:23
  • @always The encrypt and decrypt process are seperate methods though. So when I call the decrypt method it pulls in the text field that has the encrypted value (converts to bytes). I can post the code from them if it helps but it's a login, locate key on label and class, and run that encrypt/decrypt line. Would the mechanism for those methods cause any problems with the mechanism I use for unwrapping? – G . Sep 07 '18 at 13:16

2 Answers2

0

Apparently, after speaking with Gemalto and several comments, this cannot be done on the non-protectserver family of Network HSMs.The process works perfectly for the protect server HSMs (They now have a protect server Network HSM). After updating my unwrapping process to use the CBC mode with an IV, I was able to create the keys but not with specified key values..

G .
  • 69
  • 10
0

Update: Added GenerateKeyPair function to the example.

I was able to 'load' an AES key into an HSM with the following code:

        // Create factories used by Pkcs11Interop library
        Pkcs11InteropFactories factories = new Pkcs11InteropFactories();

        // Load unmanaged PKCS#11 library
        using (IPkcs11Library pkcs11Library = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, options.PKCS11LibraryPath, AppType.SingleThreaded))
        {
            // Find first slot with token present
            ISlot slot = pkcs11Library.GetSlotList(SlotsType.WithTokenPresent)[0];

            // Open RW session
            using (ISession session = slot.OpenSession(SessionType.ReadWrite))
            {
                // Login as normal user
                session.Login(CKU.CKU_USER, options.Pin);

                // Generate asymmetric key encryption key pair
                IObjectHandle asymKeyEncrpytionPublicKey = null;
                IObjectHandle asymKeyEncryptionPrivateKey = null;
                Helpers.GenerateKeyPair(session, out asymKeyEncrpytionPublicKey, out asymKeyEncryptionPrivateKey, "KEK");

                // Load aes key from file
                // Generate the key with the following command: "openssl rand -out aes256-forImport.key 32"
                byte[] sourceKey = File.ReadAllBytes(options.aesKeyPath);
                Console.WriteLine($"Loaded AES key: {BitConverter.ToString(sourceKey)}");

                // Specify wrapping mechanism
                IMechanism asymMechanism = session.Factories.MechanismFactory.Create(CKM.CKM_RSA_PKCS);

                // Encrypt key in file
                byte[] encryptedKey = session.Encrypt(asymMechanism, asymKeyEncrpytionPublicKey, sourceKey);

                // Define attributes for unwrapped key
                List<IObjectAttribute> objectAttributes = new List<IObjectAttribute>();
                objectAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
                objectAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_KEY_TYPE, CKK.CKK_AES));
                objectAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ENCRYPT, true));
                objectAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_DECRYPT, true));
                objectAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_EXTRACTABLE, options.markExtractable));
                objectAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
                objectAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, $"Unwrapped at {DateTime.Now}"));

                // Symmetric unwrap key
                IObjectHandle symUnwrappedKey = session.UnwrapKey(asymMechanism, asymKeyEncryptionPrivateKey, encryptedKey, objectAttributes);
            }
        }

-----

        /// <summary>
        /// Generates asymetric key pair.
        /// </summary>
        /// <param name='session'>Read-write session with user logged in</param>
        /// <param name='publicKeyHandle'>Output parameter for public key object handle</param>
        /// <param name='privateKeyHandle'>Output parameter for private key object handle</param>
        public static void GenerateKeyPair(ISession session, out IObjectHandle publicKeyHandle, out IObjectHandle privateKeyHandle, string label = "")
        {
            // The CKA_ID attribute is intended as a means of distinguishing multiple key pairs held by the same subject
            byte[] ckaId = session.GenerateRandom(20);

            // Prepare attribute template of new public key
            List<IObjectAttribute> publicKeyAttributes = new List<IObjectAttribute>();
            ////publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, false));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, $"{label} public"));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, ckaId));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ENCRYPT, true));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_VERIFY, true));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_VERIFY_RECOVER, true));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_WRAP, true));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_MODULUS_BITS, 2048));
            publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PUBLIC_EXPONENT, new byte[] { 0x01, 0x00, 0x01 }));

            // Prepare attribute template of new private key
            List<IObjectAttribute> privateKeyAttributes = new List<IObjectAttribute>();
            ////privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, $"{label} private"));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, ckaId));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SENSITIVE, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_DECRYPT, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SIGN, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SIGN_RECOVER, true));
            privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_UNWRAP, true));

            // Specify key generation mechanism
            IMechanism mechanism = session.Factories.MechanismFactory.Create(CKM.CKM_RSA_PKCS_KEY_PAIR_GEN);

            // Generate key pair
            session.GenerateKeyPair(mechanism, publicKeyAttributes, privateKeyAttributes, out publicKeyHandle, out privateKeyHandle);
        }

Rufus Buschart
  • 362
  • 1
  • 13
  • can you please post implementation of Helpers.GenerateKeyPair(session, out asymKeyEncrpytionPublicKey, out asymKeyEncryptionPrivateKey, "KEK"); Trying same I get following error for mechanism : CKM_RSA_X9_31_KEY_PAIR_GEN C_GenerateKeyPair failed with error CKR_ATTRIBUTE_VALUE_INVALID : 0x00000013 – Pravin Apr 23 '20 at 08:55