热门使用机制 CKM_ECDH1_DERIVE 与 pkcs11interop
Hot to use mechanisms CKM_ECDH1_DERIVE with pkcs11interop
我买了一个 NitroKey HSM,想用 EC 导出一个秘密。
为此,我想使用 CKM_ECDH1_DERIVE
机制。此 HSM 支持哪些,请参阅:
提到PKCS#11 specification这个必须考虑:
- 机制
CKM_ECDH1_DERIVE
必须与函数 Derive
(第 188 页)一起使用
- 机制
CKM_ECDH1_DERIVE
需要具有以下参数的参数 CK_ECDH1_DERIVE_PARAMS
(第 222 页):
- kdf:共享秘密值(CKD)上使用的密钥推导函数
- sharedData: 双方共享的部分数据
- public数据:对方ECpublic键值
- 函数
DeriveKey
需要这些参数:
- 机制 CKM.CKM_ECDH1_DERIVE
- 对象句柄私钥
- 对象属性(第 338 页)
- CKA.CKA_CLASS -> CKO.CKO_SECRET_KEY
- CKA.CKA_KEY_TYPE -> CKK.CKK_GENERIC_SECRET
- 但是“但是,由于这些事实都隐含在机制中,因此无需指定任何一个”所以这些可以为空?
问题
因此,根据这些信息,我尝试实现一种方法。
但是我得到这个错误:
Net.Pkcs11Interop.Common.Pkcs11Exception : Method C_DeriveKey returned CKR_TEMPLATE_INCOMPLETE
在 Session.DeriveKey
.
CKR_TEMPLATE_INCOMPLETE
(第 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.
这里(第 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.
但我使用了必要的属性:
- CKA.CKA_CLASS -> CKO.CKO_SECRET_KEY
- CKA.CKA_KEY_TYPE -> CKK.CKK_GENERIC_SECRET
想法?
代码
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;
}
}
}
另见要点(相同代码)https://gist.github.com/dhcgn/4ea235cdb20155ec5ea9dc9bbf3c9887
更新
现在有了更新的 ObjectAttributes 列表(感谢答案)我得到了异常 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.
对于 CKA.CKA_VALUE_LEN
我尝试了不同的值但没有成功:
CKA_VALUE_LEN
-------------
24 (192)
40 (320)
48 (384)
我偶然发现了 public 键,我不确定我是否以正确的方式提取了 public 键。因为它的长度是664 Bit
.
CKA.CKA_VALUE
of CKO.CKO_PUBLIC_KEY
(664 Bit
):
BFEEelKE3TrpE3e3f5nJATxEZrU0UeauhV/dFZXeXz5gqgZjuCtkJaUTainC/Mh357x3FyO7sGoPhzokD34oj5PJs0ItvATIKYtzvwaUkdZlDc0=
使用 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
和 CKO.CKO_PUBLIC_KEY
的 public 键不同?
CkEcdh1DeriveParams
期望 publicData
使用哪种格式?
- 我提取
publicData
的方式是否正确?或者怎样才是正确的做法?
CKA.CKA_VALUE_LEN
的值必须等于我的 EC (320 Bit
) 的长度吗?
这是一个非常好的和完整的问题描述。
CKR_TEMPLATE_INCOMPLETE
处理起来总是很痛苦,因为几乎每个库供应商都希望提供不同的属性集,并且此错误不会显示缺少哪些确切属性。
快速浏览 OpenSC source code 后,我会尝试使用以下模板:
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, ???)
};
但是我不确定 CKA_VALUE_LEN
属性的正确值是多少。
我买了一个 NitroKey HSM,想用 EC 导出一个秘密。
为此,我想使用 CKM_ECDH1_DERIVE
机制。此 HSM 支持哪些,请参阅:
提到PKCS#11 specification这个必须考虑:
- 机制
CKM_ECDH1_DERIVE
必须与函数Derive
(第 188 页)一起使用 - 机制
CKM_ECDH1_DERIVE
需要具有以下参数的参数CK_ECDH1_DERIVE_PARAMS
(第 222 页):- kdf:共享秘密值(CKD)上使用的密钥推导函数
- sharedData: 双方共享的部分数据
- public数据:对方ECpublic键值
- 函数
DeriveKey
需要这些参数:- 机制 CKM.CKM_ECDH1_DERIVE
- 对象句柄私钥
- 对象属性(第 338 页)
- CKA.CKA_CLASS -> CKO.CKO_SECRET_KEY
- CKA.CKA_KEY_TYPE -> CKK.CKK_GENERIC_SECRET
- 但是“但是,由于这些事实都隐含在机制中,因此无需指定任何一个”所以这些可以为空?
问题
因此,根据这些信息,我尝试实现一种方法。
但是我得到这个错误:
Net.Pkcs11Interop.Common.Pkcs11Exception : Method C_DeriveKey returned CKR_TEMPLATE_INCOMPLETE
在 Session.DeriveKey
.
CKR_TEMPLATE_INCOMPLETE
(第 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.
这里(第 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.
但我使用了必要的属性:
- CKA.CKA_CLASS -> CKO.CKO_SECRET_KEY
- CKA.CKA_KEY_TYPE -> CKK.CKK_GENERIC_SECRET
想法?
代码
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;
}
}
}
另见要点(相同代码)https://gist.github.com/dhcgn/4ea235cdb20155ec5ea9dc9bbf3c9887
更新
现在有了更新的 ObjectAttributes 列表(感谢答案)我得到了异常 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.
对于 CKA.CKA_VALUE_LEN
我尝试了不同的值但没有成功:
CKA_VALUE_LEN
-------------
24 (192)
40 (320)
48 (384)
我偶然发现了 public 键,我不确定我是否以正确的方式提取了 public 键。因为它的长度是664 Bit
.
CKA.CKA_VALUE
of CKO.CKO_PUBLIC_KEY
(664 Bit
):
BFEEelKE3TrpE3e3f5nJATxEZrU0UeauhV/dFZXeXz5gqgZjuCtkJaUTainC/Mh357x3FyO7sGoPhzokD34oj5PJs0ItvATIKYtzvwaUkdZlDc0=
使用 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
和CKO.CKO_PUBLIC_KEY
的 public 键不同? CkEcdh1DeriveParams
期望publicData
使用哪种格式?- 我提取
publicData
的方式是否正确?或者怎样才是正确的做法? CKA.CKA_VALUE_LEN
的值必须等于我的 EC (320 Bit
) 的长度吗?
这是一个非常好的和完整的问题描述。
CKR_TEMPLATE_INCOMPLETE
处理起来总是很痛苦,因为几乎每个库供应商都希望提供不同的属性集,并且此错误不会显示缺少哪些确切属性。
快速浏览 OpenSC source code 后,我会尝试使用以下模板:
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, ???)
};
但是我不确定 CKA_VALUE_LEN
属性的正确值是多少。