2016-10-25 15 views
2

Я хочу создать цифровую подпись с использованием стандарта pkcs11. Предположим, что у меня уже есть пара открытого и закрытого ключей, которая хранится на моей смарт-карте. Это клавиши были сгенерирован с помощью следующего кода:Как повторно использовать существующий закрытый ключ для генерации цифровой подписи с использованием смарт-карты и PKCS # 11

byte[] ckaId = session.GenerateRandom(20); 

// Prepare attribute template of new public key 
var publicKeyAttributes = new List<ObjectAttribute>(); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_TOKEN, true)); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_PRIVATE, false)); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, PKCS11Settings.ApplicationName)); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_ID, ckaId)); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_ENCRYPT, true)); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_VERIFY, true)); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_VERIFY_RECOVER, true)); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_WRAP, true)); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_MODULUS_BITS, 1024)); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_PUBLIC_EXPONENT, new byte[] { 0x01, 0x00, 0x01 })); 

// Prepare attribute template of new private key 
var privateKeyAttributes = new List<ObjectAttribute>(); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_TOKEN, true)); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_PRIVATE, true)); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, PKCS11Settings.ApplicationName)); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_ID, ckaId)); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_SENSITIVE, true)); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_DECRYPT, true)); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_SIGN, true)); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_SIGN_RECOVER, true)); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_UNWRAP, true)); 

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

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

Теперь я могу использовать эти ключи, чтобы подписать какие-то данные. Например:

var mechanism = new Mechanism(CKM.CKM_RSA_PKCS); 
byte[] byteContent = (ConvertUtils.Utf8StringToBytes("Hello World!!!")); 
byte[] signature = session.Sign(mechanism, derivedKey, byteContent); 

Этот код работает прекрасно, когда вы хотите создать ключи, а затем использовать его в методе C_sign

Но как получить доступ к уже существующим ключам, чтобы сделать подобную операцию? Как я понимаю, я должен получить закрытый ключ из существующего с помощью метода C_Derrive() и использовать его в методе C_Sign(). Для этого я написал следующий код:

// Prepare attribute template of new key 
List<ObjectAttribute> objectAttributes = new List<ObjectAttribute>(); 
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_DECRYPT, true)); 
objectAttributes.Add(new ObjectAttribute(CKA.CKA_DERIVE, true)); 
objectAttributes.Add(new ObjectAttribute(CKA.CKA_EXTRACTABLE, true)); 

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

// Generate key 
ObjectHandle baseKey = session.GenerateKey(mechanism, objectAttributes); 

byte[] dt = session.GenerateRandom(24); 

// Specify mechanism parameters 
var mechanismParams = new CkKeyDerivationStringData(dt); 

// Specify derivation mechanism with parameters 
Mechanism mech = new Mechanism(CKM.CKM_RSA_PKCS, mechanismParams); 

// Derive key 
ObjectHandle derivedKey = session.DeriveKey(mech, baseKey, null); 


byte[] byteContent = (ConvertUtils.Utf8StringToBytes("Hello World!")); 
byte[] signature = session.Sign(mech, derivedKey, byteContent); 

Но когда я запускаю этот код он будет бросать следующую ошибку:

Method C_GenerateKey returned CKR_MECHANISM_INVALID

Может кто-нибудь сказать мне, что я делаю неправильно и как решить Эта проблема ?

ответ

4

Если вы хотите приобрести ObjectHandle для существующего ключа вам необходимо найти клавишу на его атрибуты, такие как этикетки и т.д. Ключевой вывод полностью отличается криптографической операции.

После кода выборки поисках ключей вы порожденных кодом, присутствующих в вашем вопросе:

// Prepare attribute template that defines search criteria for public key 
List<ObjectAttribute> publicKeyAttributes = new List<ObjectAttribute>(); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PUBLIC_KEY)); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA)); 
publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, PKCS11Settings.ApplicationName)); 

// Find all objects that match provided attributes 
List<ObjectHandle> foundPublicKeys = session.FindAllObjects(publicKeyAttributes); 
if (foundPublicKeys == null || foundPublicKeys.Count != 1) 
    throw new Exception("Unable to find public key"); 

// Prepare attribute template that defines search criteria for private key 
List<ObjectAttribute> privateKeyAttributes = new List<ObjectAttribute>(); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY)); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA)); 
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, PKCS11Settings.ApplicationName)); 

// Find all objects that match provided attributes 
List<ObjectHandle> foundPrivateKeys = session.FindAllObjects(publicKeyAttributes); 
if (foundPrivateKeys == null || foundPrivateKeys.Count != 1) 
    throw new Exception("Unable to find private key"); 

// Use found object handles 
ObjectHandle publicKeyHandle = foundPublicKeys[0]; 
ObjectHandle privateKeyHandle = foundPrivateKeys[0]; 
+0

Большое спасибо! Это помогает мне, но после добавления дополнительных ключевых атрибутов (набранных в вашем ответе) в коде генерации ключей. – Tequila

0

Во-первых, я думаю, что я буду ссылки PKCS-11v2-20.pdf несколько раз, так возьмите его, если у вас еще нет копии (в нем также есть полезные примеры).

Во-вторых, я не программист на C#, поэтому ничего ниже, к сожалению, только псевдокод. первый адрес

Давайте вопрос CKR_MECHANISM_INVALID: Согласно стандарту, CKM.CKM_RSA_PKCS не может быть использован для C_DeriveKey (CHP 12, таблицы 34.).

И теперь проблема под рукой: У вас уже есть пара ключей на смарт-карты (и открыл сессию и вошли в систему по мере необходимости), вы должны искать то, что вам нужно, используя C_FindObjectsInit, C_FindObjects и C_FindObjectsFinal (стр 136 и далее, также приведен пример), , где вы предоставляете C_FindObjectsInit шаблон атрибута того, какой ключ вы ищете, например

// look for key allowing signing and decrypting 
var searchCriteria = new List<ObjectAttribute>(); 
searchCriteria.Add(new ObjectAttribute(CKA.CKA_DECRYPT, true)); 
searchCriteria.Add(new ObjectAttribute(CKA.CKA_SIGN, true)); 

// initialize the search. The number is actually the number of search attributes. 
session.FindObjectsInit(searchCriteria, 2); 
... 
session.FindObjects(out privateKeyHandle, ...); 
... 
session.FindObjectsFinal(); 

// we found the requested private key, now sign the message 
session.Sign(..., privateKeyHandle,...); 

Ключевой вывод вы пытались в последнем фрагменте кода предназначен для сценариев, где смарт-карта и приложение должны получить один или два общих секретный ключ (ы) (например, для безопасного обмена сообщений) с помощью асимметричной криптографии ,

Надеюсь, что помогло.