/// <summary> /// Obtains a list of mechanism types supported by a token /// </summary> /// <returns>List of mechanism types supported by a token</returns> public List <CKM> GetMechanismList() { NativeULong mechanismCount = 0; CKR rv = _p11.C_GetMechanismList(_slotId, null, ref mechanismCount); if (rv != CKR.CKR_OK) { throw new Pkcs11Exception("C_GetMechanismList", rv); } if (mechanismCount < 1) { return(new List <CKM>()); } CKM[] mechanismList = new CKM[mechanismCount]; rv = _p11.C_GetMechanismList(_slotId, mechanismList, ref mechanismCount); if (rv != CKR.CKR_OK) { throw new Pkcs11Exception("C_GetMechanismList", rv); } if (mechanismList.Length != NativeLongUtils.ConvertToInt32(mechanismCount)) { Array.Resize(ref mechanismList, NativeLongUtils.ConvertToInt32(mechanismCount)); } return(new List <CKM>(mechanismList)); }
/// <summary> /// Initializes a new instance of the CkTlsPrfParams class. /// </summary> /// <param name='seed'>Input seed</param> /// <param name='label'>Identifying label</param> /// <param name='outputLen'>Length in bytes that the output to be created shall have</param> public CkTlsPrfParams(byte[] seed, byte[] label, NativeULong outputLen) { _lowLevelStruct.Seed = IntPtr.Zero; _lowLevelStruct.SeedLen = 0; _lowLevelStruct.Label = IntPtr.Zero; _lowLevelStruct.LabelLen = 0; _lowLevelStruct.Output = IntPtr.Zero; _lowLevelStruct.OutputLen = IntPtr.Zero; if (seed != null) { _lowLevelStruct.Seed = UnmanagedMemory.Allocate(seed.Length); UnmanagedMemory.Write(_lowLevelStruct.Seed, seed); _lowLevelStruct.SeedLen = NativeLongUtils.ConvertFromInt32(seed.Length); } if (label != null) { _lowLevelStruct.Label = UnmanagedMemory.Allocate(label.Length); UnmanagedMemory.Write(_lowLevelStruct.Label, label); _lowLevelStruct.LabelLen = NativeLongUtils.ConvertFromInt32(label.Length); } if (outputLen < 1) { throw new ArgumentException("Value has to be positive number", "outputLen"); } _lowLevelStruct.Output = UnmanagedMemory.Allocate(NativeLongUtils.ConvertToInt32(outputLen)); byte[] outputLenBytes = NativeLongUtils.ConvertToByteArray(outputLen); _lowLevelStruct.OutputLen = UnmanagedMemory.Allocate(outputLenBytes.Length); UnmanagedMemory.Write(_lowLevelStruct.OutputLen, outputLenBytes); }
public void _10_CustomAttributeTest() { Helpers.CheckPlatform(); byte[] originalValue = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; // Create attribute without the value CK_ATTRIBUTE attr = CkaUtils.CreateAttribute(CKA.CKA_VALUE); Assert.IsTrue(attr.type == NativeLongUtils.ConvertFromCKA(CKA.CKA_VALUE)); Assert.IsTrue(attr.value == IntPtr.Zero); Assert.IsTrue(attr.valueLen == 0); // Allocate unmanaged memory for attribute value.. attr.value = UnmanagedMemory.Allocate(originalValue.Length); // ..then set the value of attribute.. UnmanagedMemory.Write(attr.value, originalValue); // ..and finally set the length of attribute value. attr.valueLen = NativeLongUtils.ConvertFromInt32(originalValue.Length); Assert.IsTrue(attr.type == NativeLongUtils.ConvertFromCKA(CKA.CKA_VALUE)); Assert.IsTrue(attr.value != IntPtr.Zero); Assert.IsTrue(attr.valueLen == NativeLongUtils.ConvertFromInt32(originalValue.Length)); // Read the value of attribute byte[] recoveredValue = UnmanagedMemory.Read(attr.value, NativeLongUtils.ConvertToInt32(attr.valueLen)); Assert.IsTrue(ConvertUtils.BytesToBase64String(originalValue) == ConvertUtils.BytesToBase64String(recoveredValue)); // Free attribute value UnmanagedMemory.Free(ref attr.value); attr.valueLen = 0; Assert.IsTrue(attr.type == NativeLongUtils.ConvertFromCKA(CKA.CKA_VALUE)); Assert.IsTrue(attr.value == IntPtr.Zero); Assert.IsTrue(attr.valueLen == 0); }
/// <summary> /// Initializes a new instance of the CkOtpSignatureInfo class. /// </summary> /// <param name='signature'>Signature value returned by all OTP mechanisms in successful calls to Sign method</param> public CkOtpSignatureInfo(byte[] signature) { if (signature == null) { throw new ArgumentNullException("signature"); } // PKCS#11 v2.20a1 page 14: // Since C_Sign and C_SignFinal follows the convention described in Section 11.2 of [1] // on producing output, a call to C_Sign (or C_SignFinal) with pSignature set to // NULL_PTR will return (in the pulSignatureLen parameter) the required number of bytes // to hold the CK_OTP_SIGNATURE_INFO structure as well as all the data in all its // CK_OTP_PARAM components. If an application allocates a memory block based on this // information, it shall therefore not subsequently de-allocate components of such a received // value but rather de-allocate the complete CK_OTP_PARAMS structure itself. A // Cryptoki library that is called with a non-NULL pSignature pointer will assume that it // points to a contiguous memory block of the size indicated by the pulSignatureLen // parameter. // Create CK_OTP_SIGNATURE_INFO from C_Sign or C_SignFinal output // TODO : This may require different low level delegate with IntPtr as output // but currently I am not aware of any implementation I could test with. IntPtr tmpSignature = IntPtr.Zero; try { tmpSignature = UnmanagedMemory.Allocate(signature.Length); UnmanagedMemory.Write(tmpSignature, signature); UnmanagedMemory.Read(tmpSignature, _lowLevelStruct); } finally { UnmanagedMemory.Free(ref tmpSignature); } // Read all CK_OTP_PARAMs from CK_OTP_SIGNATURE_INFO int ckOtpParamSize = UnmanagedMemory.SizeOf(typeof(CK_OTP_PARAM)); for (int i = 0; i < NativeLongUtils.ConvertToInt32(_lowLevelStruct.Count); i++) { // Read CK_OTP_PARAM from CK_OTP_SIGNATURE_INFO IntPtr tempPointer = new IntPtr(_lowLevelStruct.Params.ToInt64() + (i * ckOtpParamSize)); CK_OTP_PARAM ckOtpParam = new CK_OTP_PARAM(); UnmanagedMemory.Read(tempPointer, ckOtpParam); // Read members of CK_OTP_PARAM structure NativeULong ckOtpParamType = ckOtpParam.Type; byte[] ckOtpParamValue = UnmanagedMemory.Read(ckOtpParam.Value, NativeLongUtils.ConvertToInt32(ckOtpParam.ValueLen)); // Construct new high level CkOtpParam object (creates copy of CK_OTP_PARAM structure which is good) _params.Add(new CkOtpParam(ckOtpParamType, ckOtpParamValue)); } }
/// <summary> /// Initializes a new instance of the CkWtlsKeyMatOut class. /// </summary> /// <param name='ivLength'>Length of initialization vector or 0 if IV is not required</param> internal CkWtlsKeyMatOut(NativeULong ivLength) { _lowLevelStruct.MacSecret = 0; _lowLevelStruct.Key = 0; _lowLevelStruct.IV = IntPtr.Zero; _ivLength = ivLength; if (_ivLength > 0) { _lowLevelStruct.IV = UnmanagedMemory.Allocate(NativeLongUtils.ConvertToInt32(_ivLength)); } }
/// <summary> /// Initializes a new instance of the CkSsl3KeyMatOut class. /// </summary> /// <param name='ivLength'>Length of initialization vectors or 0 if IVs are not required</param> internal CkSsl3KeyMatOut(NativeULong ivLength) { _lowLevelStruct.ClientMacSecret = 0; _lowLevelStruct.ServerMacSecret = 0; _lowLevelStruct.ClientKey = 0; _lowLevelStruct.ServerKey = 0; _lowLevelStruct.IVClient = IntPtr.Zero; _lowLevelStruct.IVServer = IntPtr.Zero; _ivLength = ivLength; if (_ivLength > 0) { _lowLevelStruct.IVClient = UnmanagedMemory.Allocate(NativeLongUtils.ConvertToInt32(_ivLength)); _lowLevelStruct.IVServer = UnmanagedMemory.Allocate(NativeLongUtils.ConvertToInt32(_ivLength)); } }
/// <summary> /// Obtains a list of slots in the system /// </summary> /// <param name="slotsType">Type of slots to be obtained</param> /// <returns>List of available slots</returns> public List <Slot> GetSlotList(SlotsType slotsType) { if (this._disposed) { throw new ObjectDisposedException(this.GetType().FullName); } NativeULong slotCount = 0; CKR rv = _p11.C_GetSlotList((slotsType == SlotsType.WithTokenPresent), null, ref slotCount); if (rv != CKR.CKR_OK) { throw new Pkcs11Exception("C_GetSlotList", rv); } if (slotCount == 0) { return(new List <Slot>()); } else { NativeULong[] slotList = new NativeULong[slotCount]; rv = _p11.C_GetSlotList((slotsType == SlotsType.WithTokenPresent), slotList, ref slotCount); if (rv != CKR.CKR_OK) { throw new Pkcs11Exception("C_GetSlotList", rv); } if (slotList.Length != NativeLongUtils.ConvertToInt32(slotCount)) { Array.Resize(ref slotList, NativeLongUtils.ConvertToInt32(slotCount)); } List <Slot> list = new List <Slot>(); foreach (NativeULong slot in slotList) { list.Add(new Slot(_p11, slot)); } return(list); } }
public void _01_GetAttributeValueTest() { Helpers.CheckPlatform(); CKR rv = CKR.CKR_OK; using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath)) { rv = pkcs11.C_Initialize(Settings.InitArgs81); if ((rv != CKR.CKR_OK) && (rv != CKR.CKR_CRYPTOKI_ALREADY_INITIALIZED)) { Assert.Fail(rv.ToString()); } // Find first slot with token present NativeULong slotId = Helpers.GetUsableSlot(pkcs11); NativeULong session = CK.CK_INVALID_HANDLE; rv = pkcs11.C_OpenSession(slotId, (CKF.CKF_SERIAL_SESSION | CKF.CKF_RW_SESSION), IntPtr.Zero, IntPtr.Zero, ref session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Login as normal user rv = pkcs11.C_Login(session, CKU.CKU_USER, Settings.NormalUserPinArray, NativeLongUtils.ConvertFromInt32(Settings.NormalUserPinArray.Length)); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Create object NativeULong objectId = CK.CK_INVALID_HANDLE; rv = Helpers.CreateDataObject(pkcs11, session, ref objectId); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Prepare list of empty attributes we want to read CK_ATTRIBUTE[] template = new CK_ATTRIBUTE[2]; template[0] = CkaUtils.CreateAttribute(CKA.CKA_LABEL); template[1] = CkaUtils.CreateAttribute(CKA.CKA_VALUE); // Get size of each individual attribute value in first call rv = pkcs11.C_GetAttributeValue(session, objectId, template, NativeLongUtils.ConvertFromInt32(template.Length)); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // In LowLevelAPI we have to allocate unmanaged memory for attribute value for (int i = 0; i < template.Length; i++) { template[i].value = UnmanagedMemory.Allocate(NativeLongUtils.ConvertToInt32(template[i].valueLen)); } // Get attribute value in second call rv = pkcs11.C_GetAttributeValue(session, objectId, template, NativeLongUtils.ConvertFromInt32(template.Length)); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Do something interesting with attribute value byte[] ckaLabel = UnmanagedMemory.Read(template[0].value, NativeLongUtils.ConvertToInt32(template[0].valueLen)); Assert.IsTrue(ConvertUtils.BytesToBase64String(ckaLabel) == ConvertUtils.BytesToBase64String(Settings.ApplicationNameArray)); // In LowLevelAPI we have to free unmanaged memory taken by attributes for (int i = 0; i < template.Length; i++) { UnmanagedMemory.Free(ref template[i].value); template[i].valueLen = 0; } rv = pkcs11.C_DestroyObject(session, objectId); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_Logout(session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_CloseSession(session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_Finalize(IntPtr.Zero); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } } }
public void _01_BasicDigestEncryptAndDecryptDigestTest() { Helpers.CheckPlatform(); CKR rv = CKR.CKR_OK; using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath)) { rv = pkcs11.C_Initialize(Settings.InitArgs40); if ((rv != CKR.CKR_OK) && (rv != CKR.CKR_CRYPTOKI_ALREADY_INITIALIZED)) { Assert.Fail(rv.ToString()); } // Find first slot with token present NativeULong slotId = Helpers.GetUsableSlot(pkcs11); NativeULong session = CK.CK_INVALID_HANDLE; rv = pkcs11.C_OpenSession(slotId, (CKF.CKF_SERIAL_SESSION | CKF.CKF_RW_SESSION), IntPtr.Zero, IntPtr.Zero, ref session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Login as normal user rv = pkcs11.C_Login(session, CKU.CKU_USER, Settings.NormalUserPinArray, NativeLongUtils.ConvertFromInt32(Settings.NormalUserPinArray.Length)); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Generate symetric key NativeULong keyId = CK.CK_INVALID_HANDLE; rv = Helpers.GenerateKey(pkcs11, session, ref keyId); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Generate random initialization vector byte[] iv = new byte[8]; rv = pkcs11.C_GenerateRandom(session, iv, NativeLongUtils.ConvertFromInt32(iv.Length)); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Specify encryption mechanism with initialization vector as parameter. // Note that CkmUtils.CreateMechanism() automaticaly copies iv into newly allocated unmanaged memory. CK_MECHANISM encryptionMechanism = CkmUtils.CreateMechanism(CKM.CKM_DES3_CBC, iv); // Specify digesting mechanism (needs no parameter => no unamanaged memory is needed) CK_MECHANISM digestingMechanism = CkmUtils.CreateMechanism(CKM.CKM_SHA_1); byte[] sourceData = ConvertUtils.Utf8StringToBytes("Our new password"); byte[] encryptedData = null; byte[] digest1 = null; byte[] decryptedData = null; byte[] digest2 = null; // Multipart digesting and encryption function C_DigestEncryptUpdate can be used i.e. for digesting and encryption of streamed data using (MemoryStream inputStream = new MemoryStream(sourceData), outputStream = new MemoryStream()) { // Initialize digesting operation rv = pkcs11.C_DigestInit(session, ref digestingMechanism); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Initialize encryption operation rv = pkcs11.C_EncryptInit(session, ref encryptionMechanism, keyId); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Prepare buffer for source data part // Note that in real world application we would rather use bigger buffer i.e. 4096 bytes long byte[] part = new byte[8]; // Prepare buffer for encrypted data part // Note that in real world application we would rather use bigger buffer i.e. 4096 bytes long byte[] encryptedPart = new byte[8]; NativeULong encryptedPartLen = NativeLongUtils.ConvertFromInt32(encryptedPart.Length); // Read input stream with source data int bytesRead = 0; while ((bytesRead = inputStream.Read(part, 0, part.Length)) > 0) { // Process each individual source data part encryptedPartLen = NativeLongUtils.ConvertFromInt32(encryptedPart.Length); rv = pkcs11.C_DigestEncryptUpdate(session, part, NativeLongUtils.ConvertFromInt32(bytesRead), encryptedPart, ref encryptedPartLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Append encrypted data part to the output stream outputStream.Write(encryptedPart, 0, NativeLongUtils.ConvertToInt32(encryptedPartLen)); } // Get length of digest value in first call NativeULong digestLen = 0; rv = pkcs11.C_DigestFinal(session, null, ref digestLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } Assert.IsTrue(digestLen > 0); // Allocate array for digest value digest1 = new byte[digestLen]; // Get digest value in second call rv = pkcs11.C_DigestFinal(session, digest1, ref digestLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Get the length of last encrypted data part in first call byte[] lastEncryptedPart = null; NativeULong lastEncryptedPartLen = 0; rv = pkcs11.C_EncryptFinal(session, null, ref lastEncryptedPartLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Allocate array for the last encrypted data part lastEncryptedPart = new byte[lastEncryptedPartLen]; // Get the last encrypted data part in second call rv = pkcs11.C_EncryptFinal(session, lastEncryptedPart, ref lastEncryptedPartLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Append the last encrypted data part to the output stream outputStream.Write(lastEncryptedPart, 0, NativeLongUtils.ConvertToInt32(lastEncryptedPartLen)); // Read whole output stream to the byte array so we can compare results more easily encryptedData = outputStream.ToArray(); } // Do something interesting with encrypted data and digest // Multipart decryption and digesting function C_DecryptDigestUpdate can be used i.e. for digesting and decryption of streamed data using (MemoryStream inputStream = new MemoryStream(encryptedData), outputStream = new MemoryStream()) { // Initialize decryption operation rv = pkcs11.C_DecryptInit(session, ref encryptionMechanism, keyId); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Initialize digesting operation rv = pkcs11.C_DigestInit(session, ref digestingMechanism); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Prepare buffer for encrypted data part // Note that in real world application we would rather use bigger buffer i.e. 4096 bytes long byte[] encryptedPart = new byte[8]; // Prepare buffer for decrypted data part // Note that in real world application we would rather use bigger buffer i.e. 4096 bytes long byte[] part = new byte[8]; NativeULong partLen = NativeLongUtils.ConvertFromInt32(part.Length); // Read input stream with encrypted data int bytesRead = 0; while ((bytesRead = inputStream.Read(encryptedPart, 0, encryptedPart.Length)) > 0) { // Process each individual encrypted data part partLen = NativeLongUtils.ConvertFromInt32(part.Length); rv = pkcs11.C_DecryptDigestUpdate(session, encryptedPart, NativeLongUtils.ConvertFromInt32(bytesRead), part, ref partLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Append decrypted data part to the output stream outputStream.Write(part, 0, NativeLongUtils.ConvertToInt32(partLen)); } // Get the length of last decrypted data part in first call byte[] lastPart = null; NativeULong lastPartLen = 0; rv = pkcs11.C_DecryptFinal(session, null, ref lastPartLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Allocate array for the last decrypted data part lastPart = new byte[lastPartLen]; // Get the last decrypted data part in second call rv = pkcs11.C_DecryptFinal(session, lastPart, ref lastPartLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Append the last decrypted data part to the output stream outputStream.Write(lastPart, 0, NativeLongUtils.ConvertToInt32(lastPartLen)); // Read whole output stream to the byte array so we can compare results more easily decryptedData = outputStream.ToArray(); // Get length of digest value in first call NativeULong digestLen = 0; rv = pkcs11.C_DigestFinal(session, null, ref digestLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } Assert.IsTrue(digestLen > 0); // Allocate array for digest value digest2 = new byte[digestLen]; // Get digest value in second call rv = pkcs11.C_DigestFinal(session, digest2, ref digestLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } } // Do something interesting with decrypted data and digest Assert.IsTrue(ConvertUtils.BytesToBase64String(sourceData) == ConvertUtils.BytesToBase64String(decryptedData)); Assert.IsTrue(ConvertUtils.BytesToBase64String(digest1) == ConvertUtils.BytesToBase64String(digest2)); // In LowLevelAPI we have to free unmanaged memory taken by mechanism parameter (iv in this case) UnmanagedMemory.Free(ref encryptionMechanism.Parameter); encryptionMechanism.ParameterLen = 0; rv = pkcs11.C_DestroyObject(session, keyId); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_Logout(session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_CloseSession(session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_Finalize(IntPtr.Zero); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } } }
/// <summary> /// Creates the PKCS#1 v1.5 RSA signature with SHA-1 mechanism /// </summary> /// <param name="data">Data that should be signed</param> /// <param name="uri">PKCS#11 URI identifying PKCS#11 library, token and private key</param> /// <returns>PKCS#1 v1.5 RSA signature</returns> private byte[] SignData(byte[] data, string uri) { // Verify input parameters if (data == null) { throw new ArgumentNullException("data"); } if (string.IsNullOrEmpty(uri)) { throw new ArgumentNullException("uri"); } // Parse PKCS#11 URI Pkcs11Uri pkcs11Uri = new Pkcs11Uri(uri); // Verify that URI contains all information required to perform this operation if (pkcs11Uri.ModulePath == null) { throw new Exception("PKCS#11 URI does not specify PKCS#11 library"); } if (pkcs11Uri.PinValue == null) { throw new Exception("PKCS#11 URI does not specify PIN"); } if (!pkcs11Uri.DefinesObject || pkcs11Uri.Type != CKO.CKO_PRIVATE_KEY) { throw new Exception("PKCS#11 URI does not specify private key"); } // Load and initialize PKCS#11 library specified by URI CKR rv = CKR.CKR_OK; using (Pkcs11 pkcs11 = new Pkcs11(pkcs11Uri.ModulePath, true)) { rv = pkcs11.C_Initialize(Settings.InitArgs41); if ((rv != CKR.CKR_OK) && (rv != CKR.CKR_CRYPTOKI_ALREADY_INITIALIZED)) { Assert.Fail(rv.ToString()); } // Obtain a list of all slots with tokens that match URI NativeULong[] slots = null; rv = Pkcs11UriUtils.GetMatchingSlotList(pkcs11Uri, pkcs11, true, out slots); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } if ((slots == null) || (slots.Length == 0)) { throw new Exception("None of the slots matches PKCS#11 URI"); } // Open read only session with first token that matches URI NativeULong session = CK.CK_INVALID_HANDLE; rv = pkcs11.C_OpenSession(slots[0], (CKF.CKF_SERIAL_SESSION | CKF.CKF_RW_SESSION), IntPtr.Zero, IntPtr.Zero, ref session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Login as normal user with PIN acquired from URI byte[] pinValue = ConvertUtils.Utf8StringToBytes(pkcs11Uri.PinValue); rv = pkcs11.C_Login(session, CKU.CKU_USER, pinValue, NativeLongUtils.ConvertFromInt32(pinValue.Length)); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Get list of object attributes for the private key specified by URI CK_ATTRIBUTE[] attributes = null; Pkcs11UriUtils.GetObjectAttributes(pkcs11Uri, out attributes); // Find private key specified by URI NativeULong foundObjectCount = 0; NativeULong[] foundObjectIds = new NativeULong[] { CK.CK_INVALID_HANDLE }; rv = pkcs11.C_FindObjectsInit(session, attributes, NativeLongUtils.ConvertFromInt32(attributes.Length)); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_FindObjects(session, foundObjectIds, NativeLongUtils.ConvertFromInt32(foundObjectIds.Length), ref foundObjectCount); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_FindObjectsFinal(session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } if ((foundObjectCount == 0) || (foundObjectIds[0] == CK.CK_INVALID_HANDLE)) { throw new Exception("None of the private keys match PKCS#11 URI"); } // Create signature with the private key specified by URI CK_MECHANISM mechanism = CkmUtils.CreateMechanism(CKM.CKM_SHA1_RSA_PKCS); rv = pkcs11.C_SignInit(session, ref mechanism, foundObjectIds[0]); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } NativeULong signatureLen = 0; rv = pkcs11.C_Sign(session, data, NativeLongUtils.ConvertFromInt32(data.Length), null, ref signatureLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } Assert.IsTrue(signatureLen > 0); byte[] signature = new byte[signatureLen]; rv = pkcs11.C_Sign(session, data, NativeLongUtils.ConvertFromInt32(data.Length), signature, ref signatureLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } if (signature.Length != NativeLongUtils.ConvertToInt32(signatureLen)) { Array.Resize(ref signature, NativeLongUtils.ConvertToInt32(signatureLen)); } // Release PKCS#11 resources rv = pkcs11.C_Logout(session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_CloseSession(session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_Finalize(IntPtr.Zero); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } return(signature); } }
public void _03_EncryptAndDecryptSinglePartOaepTest() { Helpers.CheckPlatform(); CKR rv = CKR.CKR_OK; using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath)) { rv = pkcs11.C_Initialize(Settings.InitArgs81); if ((rv != CKR.CKR_OK) && (rv != CKR.CKR_CRYPTOKI_ALREADY_INITIALIZED)) { Assert.Fail(rv.ToString()); } // Find first slot with token present NativeULong slotId = Helpers.GetUsableSlot(pkcs11); NativeULong session = CK.CK_INVALID_HANDLE; rv = pkcs11.C_OpenSession(slotId, (CKF.CKF_SERIAL_SESSION | CKF.CKF_RW_SESSION), IntPtr.Zero, IntPtr.Zero, ref session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Login as normal user rv = pkcs11.C_Login(session, CKU.CKU_USER, Settings.NormalUserPinArray, NativeLongUtils.ConvertFromInt32(Settings.NormalUserPinArray.Length)); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Generate asymetric key pair NativeULong pubKeyId = CK.CK_INVALID_HANDLE; NativeULong privKeyId = CK.CK_INVALID_HANDLE; rv = Helpers.GenerateKeyPair(pkcs11, session, ref pubKeyId, ref privKeyId); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Specify mechanism parameters CK_RSA_PKCS_OAEP_PARAMS mechanismParams = new CK_RSA_PKCS_OAEP_PARAMS(); mechanismParams.HashAlg = NativeLongUtils.ConvertFromCKM(CKM.CKM_SHA_1); mechanismParams.Mgf = NativeLongUtils.ConvertFromCKG(CKG.CKG_MGF1_SHA1); mechanismParams.Source = NativeLongUtils.ConvertFromUInt32(CKZ.CKZ_DATA_SPECIFIED); mechanismParams.SourceData = IntPtr.Zero; mechanismParams.SourceDataLen = 0; // Specify encryption mechanism with parameters // Note that CkmUtils.CreateMechanism() automaticaly copies mechanismParams into newly allocated unmanaged memory. CK_MECHANISM mechanism = CkmUtils.CreateMechanism(CKM.CKM_RSA_PKCS_OAEP, mechanismParams); // Initialize encryption operation rv = pkcs11.C_EncryptInit(session, ref mechanism, pubKeyId); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } byte[] sourceData = ConvertUtils.Utf8StringToBytes("Hello world"); // Get length of encrypted data in first call NativeULong encryptedDataLen = 0; rv = pkcs11.C_Encrypt(session, sourceData, NativeLongUtils.ConvertFromInt32(sourceData.Length), null, ref encryptedDataLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } Assert.IsTrue(encryptedDataLen > 0); // Allocate array for encrypted data byte[] encryptedData = new byte[encryptedDataLen]; // Get encrypted data in second call rv = pkcs11.C_Encrypt(session, sourceData, NativeLongUtils.ConvertFromInt32(sourceData.Length), encryptedData, ref encryptedDataLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Do something interesting with encrypted data // Initialize decryption operation rv = pkcs11.C_DecryptInit(session, ref mechanism, privKeyId); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Get length of decrypted data in first call NativeULong decryptedDataLen = 0; rv = pkcs11.C_Decrypt(session, encryptedData, NativeLongUtils.ConvertFromInt32(encryptedData.Length), null, ref decryptedDataLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } Assert.IsTrue(decryptedDataLen > 0); // Allocate array for decrypted data byte[] decryptedData = new byte[decryptedDataLen]; // Get decrypted data in second call rv = pkcs11.C_Decrypt(session, encryptedData, NativeLongUtils.ConvertFromInt32(encryptedData.Length), decryptedData, ref decryptedDataLen); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } // Array may need to be shrinked if (decryptedData.Length != NativeLongUtils.ConvertToInt32(decryptedDataLen)) { Array.Resize(ref decryptedData, NativeLongUtils.ConvertToInt32(decryptedDataLen)); } // Do something interesting with decrypted data Assert.IsTrue(ConvertUtils.BytesToBase64String(sourceData) == ConvertUtils.BytesToBase64String(decryptedData)); // In LowLevelAPI we have to free unmanaged memory taken by mechanism parameter UnmanagedMemory.Free(ref mechanism.Parameter); mechanism.ParameterLen = 0; rv = pkcs11.C_DestroyObject(session, privKeyId); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_DestroyObject(session, pubKeyId); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_Logout(session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_CloseSession(session); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } rv = pkcs11.C_Finalize(IntPtr.Zero); if (rv != CKR.CKR_OK) { Assert.Fail(rv.ToString()); } } }