Горячие для использования механизмов CKM_ECDH1_DERIVE с pkcs11interop
Я купил HSM NitroKey и хотел получить секрет с ЕС. Предыдущий вопрос
Для этого я хочу использовать CKM_ECDH1_DERIVE
механизмы. Который поддерживается этим HSM, смотрите:
Ссылаясь на спецификацию PKCS#11, это следует учитывать:
- Механизм
CKM_ECDH1_DERIVE
должен использоваться с функциейDerive
(Стр. 188) - Механизм
CKM_ECDH1_DERIVE
ожидает параметрCK_ECDH1_DERIVE_PARAMS
(Стр. 222) с такими аргументами:- kdf: функция вывода ключа, используемая для общего секретного значения (CKD)
- sharedData: некоторые данные совместно используются двумя сторонами
- publicData: значение открытого ключа EC другой стороны
- Функция
DeriveKey
ожидает этих аргументов:- Механизм CKM.CKM_ECDH1_DERIVE
- ObjectHandle PrivateKey
- ObjectAttributes (Страница 338)
- CKA.CKA_CLASS -> CKO.CKO_SECRET_KEY
- CKA.CKA_KEY_TYPE -> CKK.CKK_GENERIC_SECRET
- Но "Тем не менее, поскольку все эти факты неявно присутствуют в механизме, нет необходимости указывать какой-либо из них", поэтому они могут быть нулевыми?
проблема
Поэтому, используя эту информацию, я попытался реализовать метод.
Но я получаю эту ошибку:
Net.Pkcs11Interop.Common.Pkcs11Exception: метод C_DeriveKey возвратил CKR_TEMPLATE_INCOMPLETE
в Session.DeriveKey
,
Объяснение CKR_TEMPLATE_INCOMPLETE
(Стр. 64):
Если значений атрибутов в предоставленном шаблоне вместе со всеми значениями атрибутов по умолчанию и любыми значениями атрибутов, внесенными в объект самой функцией создания объекта, недостаточно для полного указания объекта для создания, тогда попытка должна завершиться неудачно с кодом ошибки CKR_TEMPLATE_INCOMPLETE.
и здесь (стр. 98)
CKR_TEMPLATE_INCOMPLETE: Шаблон, указанный для создания объекта, является неполным и не имеет некоторых необходимых атрибутов. См. Раздел 10.1 для получения дополнительной информации.
Но я использовал несессерные атрибуты:
- 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: Входные данные в незашифрованном виде для криптографической операции имеют неверную длину. В зависимости от механизма операции это может означать, что данные открытого текста слишком короткие, слишком длинные или не кратны некоторым конкретным размерам блоков. Это возвращаемое значение имеет более высокий приоритет, чем CKR_DATA_INVALID.
За CKA.CKA_VALUE_LEN
Я пробовал разные значения без успеха:
CKA_VALUE_LEN
-------------
24 (192)
40 (320)
48 (384)
Я натыкаюсь на открытый ключ, я не уверен, правильно ли я извлекаю открытый ключ. Потому что он имеет длину 664 Bit
,
CKA.CKA_VALUE
из 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
? - Какой формат делает
CkEcdh1DeriveParams
рассчитывать наpublicData
? - Должен ли я извлечь
publicData
правильный путь? Или как правильно? - Должен значение для
CKA.CKA_VALUE_LEN
равна длине моего ЕС (320 Bit
)?
1 ответ
Это очень хорошее и полное описание проблемы.
CKR_TEMPLATE_INCOMPLETE
всегда очень больно иметь дело, потому что почти каждый поставщик библиотек ожидает, что будет предоставлен различный набор атрибутов, и эта ошибка не показывает, какие именно атрибуты отсутствуют.
После быстрого взгляда на исходный код OpenSC я попробую использовать следующий шаблон:
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
приписывать.