2

I was wondering whether it is possible using pkcs11interop to create a 3DES key and specify the key value for creation, or otherwise create a key and output the generated key value. Basically I need the secret key to be exported to another device.

I've tried using the CKA_VALUE attribute and passing the key as a byte[] array but with no success.

Is such thing possible please? Can someone assist me please?

EDIT:

Here is the code I have with no luck so far:

public ObjectHandle generate3DESKey(string keyLabel)
{
ObjectHandle key = null;
// Generate symetric key 

// Prepare attribute template of new key
List<ObjectAttribute> objectAttributes = new List<ObjectAttribute>();
objectAttributes.Add(new ObjectAttribute(CKA.CKA_TOKEN, true));
objectAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
objectAttributes.Add(new ObjectAttribute(CKA.CKA_ENCRYPT, true));
objectAttributes.Add(new ObjectAttribute(CKA.CKA_EXTRACTABLE, true));

objectAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, keyLabel));


// Specify key generation mechanism
Mechanism mechanism = new Mechanism(CKM.CKM_DES3_KEY_GEN);

// Generate key
key = _session.GenerateKey(mechanism, objectAttributes);

List<CKA> retrieveTemplate = new List<CKA>();
retrieveTemplate.Add(CKA.CKA_VALUE);

var test = _session.GetAttributeValue(key, retrieveTemplate);
var testval = test[0].GetValueAsString();
return key;
}

So what I'm trying with this code is to create a 3DES key and then get it's value using the GetAttributeValue as instructed below. I've tried the GetValueAsByteArray and GetValueAsString but all without success. What I've noticed is that the the cannotread properties on the retrieved attribute is set to true even though I've set the extractable attribute on creation.

Apart from this I also contemplated passing the key value on generating the 3DES key however what puzzled me is the fact that documentation says that the key value used with the CKA.CKA_VALUE should be a byte array of length 24. In my case the key that I need to create is 16 length long and not 24. I want to create a key similar to this which is represented in hex over here: 1616161616161616 1010101010101010

jariq
  • 11,681
  • 3
  • 33
  • 52
Andre
  • 31
  • 5
  • I have added a working code sample to my answer. If it does not work with your library/device then I believe you need to contact library/device vendor. BTW DES3 key is always 24 bytes long. If you have only 16 bytes then I believe you should create DES2 key. – jariq Oct 01 '16 at 21:13

2 Answers2

0

Secret key can be imported with Session::CreateObject() method. You will need to specify correct object attributes as defined in PKCS#11 specification.

Plain form of secret key can be exported with Session::GetAttributeValue() method. Key object will need to have correct attributes specified to allow you to read its plain value.

Please read at least "Chapter 10 - Objects" and "Chapter 12.15.3 - DES3 secret key objects" of PKCS#11 v2.20 specification and then post your code may you still be unable to solve your issue.

Following code sample works for me like a charm with SoftHSM 2.1.0:

using Net.Pkcs11Interop.Common;
using Net.Pkcs11Interop.HighLevelAPI;
using System;
using System.Collections.Generic;

namespace ExportTest
{
    class Program
    {
        static void Main(string[] args)
        {
            using (Pkcs11 pkcs11 = new Pkcs11(@"D:\SoftHSM2\lib\softhsm2.dll", false))
            {
                Slot slot = pkcs11.GetSlotList(true)[0];

                using (Session session = slot.OpenSession(false))
                {
                    session.Login(CKU.CKU_USER, "11111111");

                    // Generate exportable key
                    List<ObjectAttribute> objectAttributes = new List<ObjectAttribute>();
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, "Generated key"));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_TOKEN, true));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_ENCRYPT, true));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_DECRYPT, true));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_EXTRACTABLE, true));

                    ObjectHandle generatedKey = null;
                    using (Mechanism mechanism = new Mechanism(CKM.CKM_DES3_KEY_GEN))
                        generatedKey = session.GenerateKey(mechanism, objectAttributes);

                    // Export the key
                    byte[] plainKeyValue = null;
                    List<ObjectAttribute> readAttrs = session.GetAttributeValue(generatedKey, new List<CKA>() { CKA.CKA_VALUE });
                    if (readAttrs[0].CannotBeRead)
                        throw new Exception("Key cannot be exported");
                    else
                        plainKeyValue = readAttrs[0].GetValueAsByteArray();

                    // Import the key
                    objectAttributes = new List<ObjectAttribute>();
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, "Imported key"));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_TOKEN, true));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_ENCRYPT, true));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_DECRYPT, true));
                    objectAttributes.Add(new ObjectAttribute(CKA.CKA_VALUE, plainKeyValue));

                    ObjectHandle importedKey = session.CreateObject(objectAttributes);

                    // Test encryption with generated key and decryption with imported key
                    using (Mechanism mechanism = new Mechanism(CKM.CKM_DES3_CBC, session.GenerateRandom(8)))
                    {
                        byte[] sourceData = ConvertUtils.Utf8StringToBytes("Our new password");
                        byte[] encryptedData = session.Encrypt(mechanism, generatedKey, sourceData);
                        byte[] decryptedData = session.Decrypt(mechanism, importedKey, encryptedData);
                        if (Convert.ToBase64String(sourceData) != Convert.ToBase64String(decryptedData))
                            throw new Exception("Encryption test failed");
                    }

                    session.Logout();
                }
            }
        }
    }
}
jariq
  • 11,681
  • 3
  • 33
  • 52
  • 2
    Running this same exact code doesn't work for me. The HSM I'm testing on is a Safenet HSM. Will look whether it has to do with some configuration then cause running this code I get the cannotberead exception when exporting and CKR_TEMPLATE_INCONSISTENT when importing. Thanks. – Andre Oct 02 '16 at 06:47
  • @Andre any news in this case? – jariq Oct 10 '16 at 20:48
  • 1
    Well it turned out to be a limitation of the HSM we have, rather than a limitation it is more of a security feature. For security reasons you can't extract a key value! In fact they have a different product which allows for that. I've now opted for a workaround, the DES keys are generated using the generateRandom and then stored as data objects, for security encrypted using an AES key. – Andre Oct 12 '16 at 07:01
  • Hi jariq, I am using latest github version of pkcs11interop library. Above code is not compiling there.is it possible that you can provide updated equivalent code with your latest repository – Kamran Shahid Mar 06 '19 at 11:40
  • I meet same question. CKR_TEMPLATE_INCONSISTEN. Dose anyone know how to import key to HSM? – beehuang Jul 16 '21 at 06:27
0

Its possible you need to set the following attributes :

(CKA.CKA_SENSITIVE, false)
(CKA.CKA_PRIVATE, false)

From my experience, var testval = test[0].GetValueAsString(); usually gives an unreadable value hence i suggest you use Get as Byte array then convert to hexstring yourself.

Peter Csala
  • 17,736
  • 16
  • 35
  • 75