I bought a NitroKey HSM and wanted to derive a secret with EC. Previosly question
For this, I want to use the CKM_ECDH1_DERIVE
mechanisms. Which is supported by this HSM, see:
Referring to the PKCS#11 specification this must be considered:
CKM_ECDH1_DERIVE
must be used with the function Derive
(Page 188)CKM_ECDH1_DERIVE
expects parameter CK_ECDH1_DERIVE_PARAMS
(Page 222) with this arguments:
DeriveKey
expects these arguments:
So with this information, I tried to implement a method.
But I get this Error:
Net.Pkcs11Interop.Common.Pkcs11Exception : Method C_DeriveKey returned CKR_TEMPLATE_INCOMPLETE
at Session.DeriveKey
.
Explanation of CKR_TEMPLATE_INCOMPLETE
(Page 64):
If the attribute values in the supplied template, together with any default attribute values and any attribute values contributed to the object by the object-creation function itself, are insufficient to fully specify the object to create, then the attempt should fail with the error code CKR_TEMPLATE_INCOMPLETE.
and here (Page 98)
CKR_TEMPLATE_INCOMPLETE: The template specified for creating an object is incomplete, and lacks some necessary attributes. See Section 10.1 for more information.
But I used the nesseary attributes:
Ideas?
private const string LibraryPath = @"C:\Windows\System32\opensc-pkcs11.dll";
public static byte[] Derive(string privateEc, string publicEc)
{
Func<string, Session, CKO, ObjectHandle> getObjectHandle = (label, session, keyType) =>
{
var objectAttributes = new List<ObjectAttribute>
{
new ObjectAttribute(CKA.CKA_CLASS, keyType),
new ObjectAttribute(CKA.CKA_LABEL, label),
new ObjectAttribute(CKA.CKA_TOKEN, true)
};
return session.FindAllObjects(objectAttributes).First();
};
Func<ObjectHandle, Session, CKA, byte[]> getDataFromObject = (handle, session, type) =>
{
var attributes = new List<ulong> {(ulong) type};
var requiredAttributes = session.GetAttributeValue(handle, attributes);
return requiredAttributes[0].GetValueAsByteArray();
};
using (Pkcs11 pk = new Pkcs11(LibraryPath, false))
{
var slot = pk.GetSlotList(false).First();
using (Session session = slot.OpenSession(false))
{
session.Login(CKU.CKU_USER, UserPin);
var objectPrivate = getObjectHandle(privateEc, session, CKO.CKO_PRIVATE_KEY);
var objectPublic = getObjectHandle(publicEc, session, CKO.CKO_PUBLIC_KEY);
var publicKey = getDataFromObject(objectPublic, session, CKA.CKA_VALUE);
byte[] data = session.GenerateRandom(32);
var mechanism = new Mechanism(CKM.CKM_ECDH1_DERIVE, new CkEcdh1DeriveParams(1000, data, publicKey));
var deriveAttributes = new List<ObjectAttribute>
{
new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY),
new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_GENERIC_SECRET),
};
var derivedKey = session.DeriveKey(mechanism, objectPrivate, deriveAttributes);
var derivedSecret = getDataFromObject(derivedKey, session, CKA.CKA_VALUE);
Console.Out.WriteLine(Convert.ToBase64String(derivedSecret));
return derivedSecret;
}
}
}
See also the gist (same code) https://gist.github.com/dhcgn/4ea235cdb20155ec5ea9dc9bbf3c9887
Now with updated List of ObjectAttributes (thx to the answer) I get the exception Net.Pkcs11Interop.Common.Pkcs11Exception : Method C_DeriveKey returned CKR_DATA_LEN_RANGE
.
CKR_DATA_LEN_RANGE: The plaintext input data to a cryptographic operation has a bad length. Depending on the operation’s mechanism, this could mean that the plaintext data is too short, too long, or is not a multiple of some particular blocksize. This return value has higher priority than CKR_DATA_INVALID.
For CKA.CKA_VALUE_LEN
I tried different values with no success:
CKA_VALUE_LEN
-------------
24 (192)
40 (320)
48 (384)
I stumble upon the public key, I not sure if I extract the public key the right way. Because it has a length of 664 Bit
.
CKA.CKA_VALUE
of CKO.CKO_PUBLIC_KEY
(664 Bit
):
BFEEelKE3TrpE3e3f5nJATxEZrU0UeauhV/dFZXeXz5gqgZjuCtkJaUTainC/Mh357x3FyO7sGoPhzokD34oj5PJs0ItvATIKYtzvwaUkdZlDc0=
Extracted with the pkcs15-tool
(864 Bit
)
pkcs15-tool.exe --read-public-key 20
-----BEGIN PUBLIC KEY-----
MGowFAYHKoZIzj0CAQYJKyQDAwIIAQEJA1IABHpShN066RN3t3+ZyQE8RGa1NFHm
roVf3RWV3l8+YKoGY7grZCWlE2opwvzId+e8dxcju7BqD4c6JA9+KI+TybNCLbwE
yCmLc78GlJHWZQ3N
-----END PUBLIC KEY-----
pkcs15-tool
and CKO.CKO_PUBLIC_KEY
?CkEcdh1DeriveParams
expect for publicData
?publicData
the right way? Or what is the right way?CKA.CKA_VALUE_LEN
equal to the lenght of my EC (320 Bit
)?That's a very nice and complete description of a problem.
CKR_TEMPLATE_INCOMPLETE
is always very painful to deal with because almost every library vendor expect different set of attributes to be provided and this error does not reveal which exact attributes are missing.
After a quick look at OpenSC source code I would try with following template:
var deriveAttributes = new List<ObjectAttribute>
{
new ObjectAttribute(CKA.CKA_TOKEN, false),
new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY),
new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_GENERIC_SECRET),
new ObjectAttribute(CKA.CKA_SENSITIVE, false),
new ObjectAttribute(CKA.CKA_EXTRACTABLE, true),
new ObjectAttribute(CKA.CKA_ENCRYPT, true),
new ObjectAttribute(CKA.CKA_DECRYPT, true),
new ObjectAttribute(CKA.CKA_WRAP, true),
new ObjectAttribute(CKA.CKA_UNWRAP, true),
new ObjectAttribute(CKA.CKA_VALUE_LEN, ???)
};
However I am not sure what is the correct value of CKA_VALUE_LEN
attribute.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With