Mechanism and its parameters (CK_MECHANISM alternative)
Inheritance: IDisposable
        public void _02_DigestMultiPartTest()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, Settings.UseOsLocking))
            {
                // Find first slot with token present
                Slot slot = Helpers.GetUsableSlot(pkcs11);
                
                // Open RO session
                using (Session session = slot.OpenSession(true))
                {
                    // Specify digesting mechanism
                    Mechanism mechanism = new Mechanism(CKM.CKM_SHA_1);
                    
                    byte[] sourceData = ConvertUtils.Utf8StringToBytes("Hello world");
                    byte[] digest = null;
                    
                    // Multipart digesting can be used i.e. for digesting of streamed data
                    using (MemoryStream inputStream = new MemoryStream(sourceData))
                    {
                        // Digest data
                        digest = session.Digest(mechanism, inputStream);
                    }

                    // Do something interesting with digest value
                    Assert.IsTrue(Convert.ToBase64String(digest) == "e1AsOh9IyGCa4hLN+2Od7jlnP14=");
                }
            }
        }
        public void _01_BasicSignEncryptAndDecryptVerifyTest()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, Settings.UseOsLocking))
            {
                // Find first slot with token present
                Slot slot = Helpers.GetUsableSlot(pkcs11);
                
                // Open RW session
                using (Session session = slot.OpenSession(false))
                {
                    // Login as normal user
                    session.Login(CKU.CKU_USER, Settings.NormalUserPin);

                    // Generate asymetric key pair
                    ObjectHandle publicKey = null;
                    ObjectHandle privateKey = null;
                    Helpers.GenerateKeyPair(session, out publicKey, out privateKey);
                    
                    // Specify signing mechanism
                    Mechanism signingMechanism = new Mechanism(CKM.CKM_SHA1_RSA_PKCS);

                    // Generate symetric key
                    ObjectHandle secretKey = Helpers.GenerateKey(session);

                    // Generate random initialization vector
                    byte[] iv = session.GenerateRandom(8);
                    
                    // Specify encryption mechanism with initialization vector as parameter
                    Mechanism encryptionMechanism = new Mechanism(CKM.CKM_DES3_CBC, iv);

                    byte[] sourceData = ConvertUtils.Utf8StringToBytes("Passw0rd");

                    // Sign and encrypt data
                    byte[] signature = null;
                    byte[] encryptedData = null;
                    session.SignEncrypt(signingMechanism, privateKey, encryptionMechanism, secretKey, sourceData, out signature, out encryptedData);
                    
                    // Do something interesting with signature and encrypted data
                    
                    // Decrypt data and verify signature of data
                    byte[] decryptedData = null;
                    bool isValid = false;
                    session.DecryptVerify(signingMechanism, publicKey, encryptionMechanism, secretKey, encryptedData, signature, out decryptedData, out isValid);

                    // Do something interesting with decrypted data and verification result
                    Assert.IsTrue(Convert.ToBase64String(sourceData) == Convert.ToBase64String(decryptedData));
                    Assert.IsTrue(isValid);

                    session.DestroyObject(privateKey);
                    session.DestroyObject(publicKey);
                    session.DestroyObject(secretKey);
                    session.Logout();
                }
            }
        }
        public void _01_BasicWrapAndUnwrapKeyTest()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, Settings.UseOsLocking))
            {
                // Find first slot with token present
                Slot slot = Helpers.GetUsableSlot(pkcs11);
                
                // Open RW session
                using (Session session = slot.OpenSession(false))
                {
                    // Login as normal user
                    session.Login(CKU.CKU_USER, Settings.NormalUserPin);
                    
                    // Generate asymetric key pair
                    ObjectHandle publicKey = null;
                    ObjectHandle privateKey = null;
                    Helpers.GenerateKeyPair(session, out publicKey, out privateKey);
                    
                    // Generate symetric key
                    ObjectHandle secretKey = Helpers.GenerateKey(session);

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

                    // Wrap key
                    byte[] wrappedKey = session.WrapKey(mechanism, publicKey, secretKey);

                    // Do something interesting with wrapped key
                    Assert.IsNotNull(wrappedKey);

                    // Define attributes for unwrapped 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));

                    // Unwrap key
                    ObjectHandle unwrappedKey = session.UnwrapKey(mechanism, privateKey, wrappedKey, objectAttributes);

                    // Do something interesting with unwrapped key
                    Assert.IsTrue(unwrappedKey.ObjectId != CK.CK_INVALID_HANDLE);

                    session.DestroyObject(privateKey);
                    session.DestroyObject(publicKey);
                    session.DestroyObject(secretKey);
                    session.Logout();
                }
            }
        }
        public void _04_ObjectParameterTest()
        {
            byte[]        data = new byte[24];
            System.Random rng  = new Random();
            rng.NextBytes(data);

            // Specify mechanism parameters
            ICkKeyDerivationStringData parameter = Settings.Factories.MechanismParamsFactory.CreateCkKeyDerivationStringData(data);

            // Create mechanism with the object as parameter
            IMechanism mechanism = Settings.Factories.MechanismFactory.Create(CKM.CKM_XOR_BASE_AND_DATA, parameter);

            Assert.IsTrue(mechanism.Type == ConvertUtils.UInt64FromCKM(CKM.CKM_XOR_BASE_AND_DATA));

            // We access private Mechanism member here just for the testing purposes
            if (Platform.NativeULongSize == 4)
            {
                if (Platform.StructPackingSize == 0)
                {
                    HLA40.Mechanism    mechanism40   = (HLA40.Mechanism)mechanism;
                    LLA40.CK_MECHANISM ckMechanism40 = (LLA40.CK_MECHANISM) typeof(HLA40.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism40);
                    Assert.IsTrue(ckMechanism40.Mechanism == ConvertUtils.UInt32FromCKM(CKM.CKM_XOR_BASE_AND_DATA));
                    Assert.IsTrue(ckMechanism40.Parameter != IntPtr.Zero);
                    Assert.IsTrue(Convert.ToInt32(ckMechanism40.ParameterLen) == UnmanagedMemory.SizeOf(typeof(LLA40.MechanismParams.CK_KEY_DERIVATION_STRING_DATA)));
                }
                else
                {
                    HLA41.Mechanism    mechanism41   = (HLA41.Mechanism)mechanism;
                    LLA41.CK_MECHANISM ckMechanism41 = (LLA41.CK_MECHANISM) typeof(HLA41.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism41);
                    Assert.IsTrue(ckMechanism41.Mechanism == ConvertUtils.UInt32FromCKM(CKM.CKM_XOR_BASE_AND_DATA));
                    Assert.IsTrue(ckMechanism41.Parameter != IntPtr.Zero);
                    Assert.IsTrue(Convert.ToInt32(ckMechanism41.ParameterLen) == UnmanagedMemory.SizeOf(typeof(LLA41.MechanismParams.CK_KEY_DERIVATION_STRING_DATA)));
                }
            }
            else
            {
                if (Platform.StructPackingSize == 0)
                {
                    HLA80.Mechanism    mechanism80   = (HLA80.Mechanism)mechanism;
                    LLA80.CK_MECHANISM ckMechanism80 = (LLA80.CK_MECHANISM) typeof(HLA80.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism80);
                    Assert.IsTrue(ckMechanism80.Mechanism == ConvertUtils.UInt64FromCKM(CKM.CKM_XOR_BASE_AND_DATA));
                    Assert.IsTrue(ckMechanism80.Parameter != IntPtr.Zero);
                    Assert.IsTrue(Convert.ToInt32(ckMechanism80.ParameterLen) == UnmanagedMemory.SizeOf(typeof(LLA80.MechanismParams.CK_KEY_DERIVATION_STRING_DATA)));
                }
                else
                {
                    HLA81.Mechanism    mechanism81   = (HLA81.Mechanism)mechanism;
                    LLA81.CK_MECHANISM ckMechanism81 = (LLA81.CK_MECHANISM) typeof(HLA81.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism81);
                    Assert.IsTrue(ckMechanism81.Mechanism == ConvertUtils.UInt64FromCKM(CKM.CKM_XOR_BASE_AND_DATA));
                    Assert.IsTrue(ckMechanism81.Parameter != IntPtr.Zero);
                    Assert.IsTrue(Convert.ToInt32(ckMechanism81.ParameterLen) == UnmanagedMemory.SizeOf(typeof(LLA81.MechanismParams.CK_KEY_DERIVATION_STRING_DATA)));
                }
            }
        }
        public void _01_BasicDigestEncryptAndDecryptDigestTest()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, Settings.UseOsLocking))
            {
                // Find first slot with token present
                Slot slot = Helpers.GetUsableSlot(pkcs11);
                
                // Open RW session
                using (Session session = slot.OpenSession(false))
                {
                    // Login as normal user
                    session.Login(CKU.CKU_USER, Settings.NormalUserPin);
                    
                    // Generate symetric key
                    ObjectHandle generatedKey = Helpers.GenerateKey(session);
                    
                    // Generate random initialization vector
                    byte[] iv = session.GenerateRandom(8);

                    // Specify encryption mechanism with initialization vector as parameter
                    Mechanism encryptionMechanism = new Mechanism(CKM.CKM_DES3_CBC, iv);

                    // Specify digesting mechanism
                    Mechanism digestingMechanism = new Mechanism(CKM.CKM_SHA_1);

                    byte[] sourceData = ConvertUtils.Utf8StringToBytes("Our new password");

                    // Encrypt and digest data
                    byte[] digest1 = null;
                    byte[] encryptedData = null;
                    session.DigestEncrypt(digestingMechanism, encryptionMechanism, generatedKey, sourceData, out digest1, out encryptedData);

                    // Do something interesting with encrypted data and digest

                    // Decrypt and digest data
                    byte[] digest2 = null;
                    byte[] decryptedData = null;
                    session.DecryptDigest(digestingMechanism, encryptionMechanism, generatedKey, encryptedData, out digest2, out decryptedData);

                    // Do something interesting with decrypted data and digest
                    Assert.IsTrue(Convert.ToBase64String(sourceData) == Convert.ToBase64String(decryptedData));
                    Assert.IsTrue(Convert.ToBase64String(digest1) == Convert.ToBase64String(digest2));

                    session.DestroyObject(generatedKey);
                    session.Logout();
                }
            }
        }
        public void _02_EmptyParameterTest()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            // Create mechanism without the parameter
            Mechanism mechanism = new Mechanism(CKM.CKM_RSA_PKCS);
            Assert.IsTrue(mechanism.Type == (uint)CKM.CKM_RSA_PKCS);

            // We access private Mechanism member just for the testing purposes
            Net.Pkcs11Interop.LowLevelAPI41.CK_MECHANISM ckMechanism = (Net.Pkcs11Interop.LowLevelAPI41.CK_MECHANISM)typeof(Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism);
            Assert.IsTrue(ckMechanism.Mechanism == (uint)CKM.CKM_RSA_PKCS);
            Assert.IsTrue(ckMechanism.Parameter == IntPtr.Zero);
            Assert.IsTrue(ckMechanism.ParameterLen == 0);
        }
        public void _02_EmptyParameterTest()
        {
            // Create mechanism without the parameter
            IMechanism mechanism = Settings.Factories.MechanismFactory.Create(CKM.CKM_RSA_PKCS);

            Assert.IsTrue(mechanism.Type == ConvertUtils.UInt64FromCKM(CKM.CKM_RSA_PKCS));

            // We access private Mechanism member just for the testing purposes
            if (Platform.NativeULongSize == 4)
            {
                if (Platform.StructPackingSize == 0)
                {
                    HLA40.Mechanism    mechanism40   = (HLA40.Mechanism)mechanism;
                    LLA40.CK_MECHANISM ckMechanism40 = (LLA40.CK_MECHANISM) typeof(HLA40.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism40);
                    Assert.IsTrue(ckMechanism40.Mechanism == ConvertUtils.UInt32FromCKM(CKM.CKM_RSA_PKCS));
                    Assert.IsTrue(ckMechanism40.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism40.ParameterLen == 0);
                }
                else
                {
                    HLA41.Mechanism    mechanism41   = (HLA41.Mechanism)mechanism;
                    LLA41.CK_MECHANISM ckMechanism41 = (LLA41.CK_MECHANISM) typeof(HLA41.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism41);
                    Assert.IsTrue(ckMechanism41.Mechanism == ConvertUtils.UInt32FromCKM(CKM.CKM_RSA_PKCS));
                    Assert.IsTrue(ckMechanism41.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism41.ParameterLen == 0);
                }
            }
            else
            {
                if (Platform.StructPackingSize == 0)
                {
                    HLA80.Mechanism    mechanism80   = (HLA80.Mechanism)mechanism;
                    LLA80.CK_MECHANISM ckMechanism80 = (LLA80.CK_MECHANISM) typeof(HLA80.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism80);
                    Assert.IsTrue(ckMechanism80.Mechanism == ConvertUtils.UInt64FromCKM(CKM.CKM_RSA_PKCS));
                    Assert.IsTrue(ckMechanism80.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism80.ParameterLen == 0);
                }
                else
                {
                    HLA81.Mechanism    mechanism81   = (HLA81.Mechanism)mechanism;
                    LLA81.CK_MECHANISM ckMechanism81 = (LLA81.CK_MECHANISM) typeof(HLA81.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism81);
                    Assert.IsTrue(ckMechanism81.Mechanism == ConvertUtils.UInt64FromCKM(CKM.CKM_RSA_PKCS));
                    Assert.IsTrue(ckMechanism81.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism81.ParameterLen == 0);
                }
            }
        }
Exemple #8
0
        public void _02_EmptyParameterTest()
        {
            // Create mechanism without the parameter
            Mechanism mechanism = new Mechanism(CKM.CKM_RSA_PKCS);

            Assert.IsTrue(mechanism.Type == (ulong)CKM.CKM_RSA_PKCS);

            // We access private Mechanism member just for the testing purposes
            if (Platform.UnmanagedLongSize == 4)
            {
                if (Platform.StructPackingSize == 0)
                {
                    HLA40.Mechanism    mechanism40   = (HLA40.Mechanism) typeof(Mechanism).GetField("_mechanism40", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism);
                    LLA40.CK_MECHANISM ckMechanism40 = (LLA40.CK_MECHANISM) typeof(HLA40.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism40);
                    Assert.IsTrue(ckMechanism40.Mechanism == (uint)CKM.CKM_RSA_PKCS);
                    Assert.IsTrue(ckMechanism40.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism40.ParameterLen == 0);
                }
                else
                {
                    HLA41.Mechanism    mechanism41   = (HLA41.Mechanism) typeof(Mechanism).GetField("_mechanism41", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism);
                    LLA41.CK_MECHANISM ckMechanism41 = (LLA41.CK_MECHANISM) typeof(HLA41.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism41);
                    Assert.IsTrue(ckMechanism41.Mechanism == (uint)CKM.CKM_RSA_PKCS);
                    Assert.IsTrue(ckMechanism41.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism41.ParameterLen == 0);
                }
            }
            else
            {
                if (Platform.StructPackingSize == 0)
                {
                    HLA80.Mechanism    mechanism80   = (HLA80.Mechanism) typeof(Mechanism).GetField("_mechanism80", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism);
                    LLA80.CK_MECHANISM ckMechanism80 = (LLA80.CK_MECHANISM) typeof(HLA80.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism80);
                    Assert.IsTrue(ckMechanism80.Mechanism == (ulong)CKM.CKM_RSA_PKCS);
                    Assert.IsTrue(ckMechanism80.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism80.ParameterLen == 0);
                }
                else
                {
                    HLA81.Mechanism    mechanism81   = (HLA81.Mechanism) typeof(Mechanism).GetField("_mechanism81", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism);
                    LLA81.CK_MECHANISM ckMechanism81 = (LLA81.CK_MECHANISM) typeof(HLA81.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism81);
                    Assert.IsTrue(ckMechanism81.Mechanism == (ulong)CKM.CKM_RSA_PKCS);
                    Assert.IsTrue(ckMechanism81.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism81.ParameterLen == 0);
                }
            }
        }
        public void _01_BasicSignAndVerifyRecoverTest()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, Settings.UseOsLocking))
            {
                // Find first slot with token present
                Slot slot = Helpers.GetUsableSlot(pkcs11);
                
                // Open RW session
                using (Session session = slot.OpenSession(false))
                {
                    // Login as normal user
                    session.Login(CKU.CKU_USER, Settings.NormalUserPin);
                    
                    // Generate key pair
                    ObjectHandle publicKey = null;
                    ObjectHandle privateKey = null;
                    Helpers.GenerateKeyPair(session, out publicKey, out privateKey);
                    
                    // Specify signing mechanism
                    Mechanism mechanism = new Mechanism(CKM.CKM_RSA_PKCS);
                    
                    byte[] sourceData = ConvertUtils.Utf8StringToBytes("Hello world");
                    
                    // Sign data
                    byte[] signature = session.SignRecover(mechanism, privateKey, sourceData);
                    
                    // Do something interesting with signature

                    // Verify signature
                    bool isValid = false;
                    byte[] recoveredData = session.VerifyRecover(mechanism, publicKey, signature, out isValid);

                    // Do something interesting with verification result and recovered data
                    Assert.IsTrue(isValid);
                    Assert.IsTrue(Convert.ToBase64String(sourceData) == Convert.ToBase64String(recoveredData));

                    session.DestroyObject(privateKey);
                    session.DestroyObject(publicKey);
                    session.Logout();
                }
            }
        }
        public void _01_BasicDeriveKeyTest()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, Settings.UseOsLocking))
            {
                // Find first slot with token present
                Slot slot = Helpers.GetUsableSlot(pkcs11);
                
                // Open RW session
                using (Session session = slot.OpenSession(false))
                {
                    // Login as normal user
                    session.Login(CKU.CKU_USER, Settings.NormalUserPin);
                    
                    // Generate symetric key
                    ObjectHandle baseKey = Helpers.GenerateKey(session);

                    // Generate random data needed for key derivation
                    byte[] data = session.GenerateRandom(24);

                    // Specify mechanism parameters
                    CkKeyDerivationStringData mechanismParams = new CkKeyDerivationStringData(data);

                    // Specify derivation mechanism with parameters
                    Mechanism mechanism = new Mechanism(CKM.CKM_XOR_BASE_AND_DATA, mechanismParams);
                    
                    // Derive key
                    ObjectHandle derivedKey = session.DeriveKey(mechanism, baseKey, null);

                    // Do something interesting with derived key
                    Assert.IsTrue(derivedKey.ObjectId != CK.CK_INVALID_HANDLE);

                    session.DestroyObject(baseKey);
                    session.DestroyObject(derivedKey);
                    session.Logout();
                }
            }
        }
        public void _01_DisposeMechanismTest()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            byte[] parameter = new byte[8];
            System.Random rng = new Random();
            rng.NextBytes(parameter);
            
            // Unmanaged memory for mechanism parameter stored in low level CK_MECHANISM struct
            // is allocated by constructor of Mechanism class.
            Mechanism mechanism1 = new Mechanism(CKM.CKM_DES_CBC, parameter);
            
            // Do something interesting with mechanism
            
            // This unmanaged memory is freed by Dispose() method.
            mechanism1.Dispose();
            
            
            // Mechanism class can be used in using statement which defines a scope 
            // at the end of which an object will be disposed (and unmanaged memory freed).
            using (Mechanism mechanism2 = new Mechanism(CKM.CKM_DES_CBC, parameter))
            {
                // Do something interesting with mechanism
            }


            #pragma warning disable 0219

            // Explicit calling of Dispose() method can also be ommitted
            // and this is the prefered way how to use Mechanism class.
            Mechanism mechanism3 = new Mechanism(CKM.CKM_DES_CBC, parameter);
            
            // Do something interesting with mechanism
            
            // Dispose() method will be called (and unmanaged memory freed) by GC eventually
            // but we cannot be sure when will this occur.

            #pragma warning restore 0219
        }
        public void _01_GenerateKeyTest()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, Settings.UseOsLocking))
            {
                // Find first slot with token present
                Slot slot = Helpers.GetUsableSlot(pkcs11);
                
                // Open RW session
                using (Session session = slot.OpenSession(false))
                {
                    // Login as normal user
                    session.Login(CKU.CKU_USER, Settings.NormalUserPin);

                    // 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));

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

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

                    // Do something interesting with generated key

                    // Destroy object
                    session.DestroyObject(objectHandle);
                    
                    session.Logout();
                }
            }
        }
        /// <summary>
        /// Decrypts data and verifies a signature of data
        /// </summary>
        /// <param name="verificationMechanism">Verification mechanism</param>
        /// <param name="verificationKeyHandle">Handle of the verification key</param>
        /// <param name="decryptionMechanism">Decryption mechanism</param>
        /// <param name="decryptionKeyHandle">Handle of the decryption key</param>
        /// <param name="inputStream">Input stream from which data to be processed should be read</param>
        /// <param name="outputStream">Output stream where decrypted data should be written</param>
        /// <param name="signature">Signature</param>
        /// <param name="isValid">Flag indicating whether signature is valid</param>
        /// <param name="bufferLength">Size of read buffer in bytes</param>
        public void DecryptVerify(Mechanism verificationMechanism, ObjectHandle verificationKeyHandle, Mechanism decryptionMechanism, ObjectHandle decryptionKeyHandle, Stream inputStream, Stream outputStream, byte[] signature, out bool isValid, int bufferLength)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (verificationMechanism == null)
                throw new ArgumentNullException("verificationMechanism");
            
            if (verificationKeyHandle == null)
                throw new ArgumentNullException("verificationKeyHandle");
            
            if (decryptionMechanism == null)
                throw new ArgumentNullException("decryptionMechanism");
            
            if (decryptionKeyHandle == null)
                throw new ArgumentNullException("decryptionKeyHandle");
            
            if (inputStream == null)
                throw new ArgumentNullException("inputStream");
            
            if (outputStream == null)
                throw new ArgumentNullException("outputStream");
            
            if (signature == null)
                throw new ArgumentNullException("signature");

            if (bufferLength < 1)
                throw new ArgumentException("Value has to be positive number", "bufferLength");

            CK_MECHANISM ckVerificationMechanism = verificationMechanism.CkMechanism;

            CKR rv = _p11.C_VerifyInit(_sessionId, ref ckVerificationMechanism, verificationKeyHandle.ObjectId);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_VerifyInit", rv);

            CK_MECHANISM ckDecryptionMechanism = decryptionMechanism.CkMechanism;

            rv = _p11.C_DecryptInit(_sessionId, ref ckDecryptionMechanism, decryptionKeyHandle.ObjectId);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DecryptInit", rv);

            byte[] encryptedPart = new byte[bufferLength];
            byte[] part = new byte[bufferLength];
            uint partLen = Convert.ToUInt32(part.Length);

            int bytesRead = 0;
            while ((bytesRead = inputStream.Read(encryptedPart, 0, encryptedPart.Length)) > 0)
            {
                partLen = Convert.ToUInt32(part.Length);
                rv = _p11.C_DecryptVerifyUpdate(_sessionId, encryptedPart, Convert.ToUInt32(bytesRead), part, ref partLen);
                if (rv != CKR.CKR_OK)
                    throw new Pkcs11Exception("C_DecryptVerifyUpdate", rv);

                outputStream.Write(part, 0, Convert.ToInt32(partLen));
            }

            byte[] lastPart = null;
            uint lastPartLen = 0;
            rv = _p11.C_DecryptFinal(_sessionId, null, ref lastPartLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DecryptFinal", rv);

            lastPart = new byte[lastPartLen];
            rv = _p11.C_DecryptFinal(_sessionId, lastPart, ref lastPartLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DecryptFinal", rv);

            if (lastPartLen > 0)
                outputStream.Write(lastPart, 0, Convert.ToInt32(lastPartLen));

            rv = _p11.C_VerifyFinal(_sessionId, signature, Convert.ToUInt32(signature.Length));
            if (rv == CKR.CKR_OK)
                isValid = true;
            else if (rv == CKR.CKR_SIGNATURE_INVALID)
                isValid = false;
            else 
                throw new Pkcs11Exception("C_VerifyFinal", rv);
        }
        /// <summary>
        /// Decrypts data and verifies a signature of data
        /// </summary>
        /// <param name="verificationMechanism">Verification mechanism</param>
        /// <param name="verificationKeyHandle">Handle of the verification key</param>
        /// <param name="decryptionMechanism">Decryption mechanism</param>
        /// <param name="decryptionKeyHandle">Handle of the decryption key</param>
        /// <param name="inputStream">Input stream from which data to be processed should be read</param>
        /// <param name="outputStream">Output stream where decrypted data should be written</param>
        /// <param name="signature">Signature</param>
        /// <param name="isValid">Flag indicating whether signature is valid</param>
        public void DecryptVerify(Mechanism verificationMechanism, ObjectHandle verificationKeyHandle, Mechanism decryptionMechanism, ObjectHandle decryptionKeyHandle, Stream inputStream, Stream outputStream, byte[] signature, out bool isValid)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (verificationMechanism == null)
                throw new ArgumentNullException("verificationMechanism");
            
            if (verificationKeyHandle == null)
                throw new ArgumentNullException("verificationKeyHandle");
            
            if (decryptionMechanism == null)
                throw new ArgumentNullException("decryptionMechanism");
            
            if (decryptionKeyHandle == null)
                throw new ArgumentNullException("decryptionKeyHandle");
            
            if (inputStream == null)
                throw new ArgumentNullException("inputStream");

            if (outputStream == null)
                throw new ArgumentNullException("outputStream");

            if (signature == null)
                throw new ArgumentNullException("signature");

            DecryptVerify(verificationMechanism, verificationKeyHandle, decryptionMechanism, decryptionKeyHandle, inputStream, outputStream, signature, out isValid, 4096);
        }
        /// <summary>
        /// Decrypts data and verifies a signature of data
        /// </summary>
        /// <param name="verificationMechanism">Verification mechanism</param>
        /// <param name="verificationKeyHandle">Handle of the verification key</param>
        /// <param name="decryptionMechanism">Decryption mechanism</param>
        /// <param name="decryptionKeyHandle">Handle of the decryption key</param>
        /// <param name="data">Data to be processed</param>
        /// <param name="signature">Signature</param>
        /// <param name="decryptedData">Decrypted data</param>
        /// <param name="isValid">Flag indicating whether signature is valid</param>
        public void DecryptVerify(Mechanism verificationMechanism, ObjectHandle verificationKeyHandle, Mechanism decryptionMechanism, ObjectHandle decryptionKeyHandle, byte[] data, byte[] signature, out byte[] decryptedData, out bool isValid)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (verificationMechanism == null)
                throw new ArgumentNullException("verificationMechanism");
            
            if (verificationKeyHandle == null)
                throw new ArgumentNullException("verificationKeyHandle");
            
            if (decryptionMechanism == null)
                throw new ArgumentNullException("decryptionMechanism");
            
            if (decryptionKeyHandle == null)
                throw new ArgumentNullException("decryptionKeyHandle");

            if (data == null)
                throw new ArgumentNullException("data");
            
            if (signature == null)
                throw new ArgumentNullException("signature");

            using (MemoryStream inputMemoryStream = new MemoryStream(data), outputMemorySteam = new MemoryStream())
            {
                DecryptVerify(verificationMechanism, verificationKeyHandle, decryptionMechanism, decryptionKeyHandle, inputMemoryStream, outputMemorySteam, signature, out isValid);
                decryptedData = outputMemorySteam.ToArray();
            }
        }
        /// <summary>
        /// Signs and encrypts data
        /// </summary>
        /// <param name="signingMechanism">Signing mechanism</param>
        /// <param name="signingKeyHandle">Handle of the signing key</param>
        /// <param name="encryptionMechanism">Encryption mechanism</param>
        /// <param name="encryptionKeyHandle">Handle of the encryption key</param>
        /// <param name="inputStream">Input stream from which data to be processed should be read</param>
        /// <param name="outputStream">Output stream where encrypted data should be written</param>
        /// <param name="bufferLength">Size of read buffer in bytes</param>
        /// <returns>Signature</returns>
        public byte[] SignEncrypt(Mechanism signingMechanism, ObjectHandle signingKeyHandle, Mechanism encryptionMechanism, ObjectHandle encryptionKeyHandle, Stream inputStream, Stream outputStream, int bufferLength)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (signingMechanism == null)
                throw new ArgumentNullException("signingMechanism");
            
            if (signingKeyHandle == null)
                throw new ArgumentNullException("signingKeyHandle");
            
            if (encryptionMechanism == null)
                throw new ArgumentNullException("encryptionMechanism");
            
            if (encryptionKeyHandle == null)
                throw new ArgumentNullException("encryptionKeyHandle");
            
            if (inputStream == null)
                throw new ArgumentNullException("inputStream");
            
            if (outputStream == null)
                throw new ArgumentNullException("outputStream");

            if (bufferLength < 1)
                throw new ArgumentException("Value has to be positive number", "bufferLength");

            CK_MECHANISM ckSigningMechanism = signingMechanism.CkMechanism;

            CKR rv = _p11.C_SignInit(_sessionId, ref ckSigningMechanism, signingKeyHandle.ObjectId);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_SignInit", rv);

            CK_MECHANISM ckEncryptionMechanism = encryptionMechanism.CkMechanism;

            rv = _p11.C_EncryptInit(_sessionId, ref ckEncryptionMechanism, encryptionKeyHandle.ObjectId);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_EncryptInit", rv);

            byte[] part = new byte[bufferLength];
            byte[] encryptedPart = new byte[bufferLength];
            uint encryptedPartLen = Convert.ToUInt32(encryptedPart.Length);

            int bytesRead = 0;
            while ((bytesRead = inputStream.Read(part, 0, part.Length)) > 0)
            {
                encryptedPartLen = Convert.ToUInt32(encryptedPart.Length);
                rv = _p11.C_SignEncryptUpdate(_sessionId, part, Convert.ToUInt32(bytesRead), encryptedPart, ref encryptedPartLen);
                if (rv != CKR.CKR_OK)
                    throw new Pkcs11Exception("C_SignEncryptUpdate", rv);

                outputStream.Write(encryptedPart, 0, Convert.ToInt32(encryptedPartLen));
            }

            byte[] lastEncryptedPart = null;
            uint lastEncryptedPartLen = 0;
            rv = _p11.C_EncryptFinal(_sessionId, null, ref lastEncryptedPartLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_EncryptFinal", rv);

            lastEncryptedPart = new byte[lastEncryptedPartLen];
            rv = _p11.C_EncryptFinal(_sessionId, lastEncryptedPart, ref lastEncryptedPartLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_EncryptFinal", rv);

            if (lastEncryptedPartLen > 0)
                outputStream.Write(lastEncryptedPart, 0, Convert.ToInt32(lastEncryptedPartLen));

            uint signatureLen = 0;
            rv = _p11.C_SignFinal(_sessionId, null, ref signatureLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_SignFinal", rv);

            byte[] signature = new byte[signatureLen];
            rv = _p11.C_SignFinal(_sessionId, signature, ref signatureLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_SignFinal", rv);

            if (signature.Length != signatureLen)
                Array.Resize(ref signature, Convert.ToInt32(signatureLen));

            return signature;
        }
        /// <summary>
        /// Signs and encrypts data
        /// </summary>
        /// <param name="signingMechanism">Signing mechanism</param>
        /// <param name="signingKeyHandle">Handle of the signing key</param>
        /// <param name="encryptionMechanism">Encryption mechanism</param>
        /// <param name="encryptionKeyHandle">Handle of the encryption key</param>
        /// <param name="inputStream">Input stream from which data to be processed should be read</param>
        /// <param name="outputStream">Output stream where encrypted data should be written</param>
        /// <returns>Signature</returns>
        public byte[] SignEncrypt(Mechanism signingMechanism, ObjectHandle signingKeyHandle, Mechanism encryptionMechanism, ObjectHandle encryptionKeyHandle, Stream inputStream, Stream outputStream)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (signingMechanism == null)
                throw new ArgumentNullException("signingMechanism");
            
            if (signingKeyHandle == null)
                throw new ArgumentNullException("signingKeyHandle");
            
            if (encryptionMechanism == null)
                throw new ArgumentNullException("encryptionMechanism");
            
            if (encryptionKeyHandle == null)
                throw new ArgumentNullException("encryptionKeyHandle");
            
            if (inputStream == null)
                throw new ArgumentNullException("inputStream");

            if (outputStream == null)
                throw new ArgumentNullException("outputStream");

            return SignEncrypt(signingMechanism, signingKeyHandle, encryptionMechanism, encryptionKeyHandle, inputStream, outputStream, 4096);
        }
        public void _03_ByteArrayParameterTest()
        {
            byte[]        parameter = new byte[16];
            System.Random rng       = new Random();
            rng.NextBytes(parameter);

            // Create mechanism with the byte array parameter
            IMechanism mechanism = Settings.Factories.MechanismFactory.Create(CKM.CKM_AES_CBC, parameter);

            Assert.IsTrue(mechanism.Type == ConvertUtils.UInt64FromCKM(CKM.CKM_AES_CBC));

            // We access private members here just for the testing purposes
            if (Platform.NativeULongSize == 4)
            {
                if (Platform.StructPackingSize == 0)
                {
                    HLA40.Mechanism    mechanism40   = (HLA40.Mechanism)mechanism;
                    LLA40.CK_MECHANISM ckMechanism40 = (LLA40.CK_MECHANISM) typeof(HLA40.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism40);
                    Assert.IsTrue(ckMechanism40.Mechanism == ConvertUtils.UInt32FromCKM(CKM.CKM_AES_CBC));
                    Assert.IsTrue(ckMechanism40.Parameter != IntPtr.Zero);
                    Assert.IsTrue(Convert.ToInt32(ckMechanism40.ParameterLen) == parameter.Length);
                }
                else
                {
                    HLA41.Mechanism    mechanism41   = (HLA41.Mechanism)mechanism;
                    LLA41.CK_MECHANISM ckMechanism41 = (LLA41.CK_MECHANISM) typeof(HLA41.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism41);
                    Assert.IsTrue(ckMechanism41.Mechanism == ConvertUtils.UInt32FromCKM(CKM.CKM_AES_CBC));
                    Assert.IsTrue(ckMechanism41.Parameter != IntPtr.Zero);
                    Assert.IsTrue(Convert.ToInt32(ckMechanism41.ParameterLen) == parameter.Length);
                }
            }
            else
            {
                if (Platform.StructPackingSize == 0)
                {
                    HLA80.Mechanism    mechanism80   = (HLA80.Mechanism)mechanism;
                    LLA80.CK_MECHANISM ckMechanism80 = (LLA80.CK_MECHANISM) typeof(HLA80.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism80);
                    Assert.IsTrue(ckMechanism80.Mechanism == ConvertUtils.UInt64FromCKM(CKM.CKM_AES_CBC));
                    Assert.IsTrue(ckMechanism80.Parameter != IntPtr.Zero);
                    Assert.IsTrue(Convert.ToInt32(ckMechanism80.ParameterLen) == parameter.Length);
                }
                else
                {
                    HLA81.Mechanism    mechanism81   = (HLA81.Mechanism)mechanism;
                    LLA81.CK_MECHANISM ckMechanism81 = (LLA81.CK_MECHANISM) typeof(HLA81.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism81);
                    Assert.IsTrue(ckMechanism81.Mechanism == ConvertUtils.UInt64FromCKM(CKM.CKM_AES_CBC));
                    Assert.IsTrue(ckMechanism81.Parameter != IntPtr.Zero);
                    Assert.IsTrue(Convert.ToInt32(ckMechanism81.ParameterLen) == parameter.Length);
                }
            }

            parameter = null;

            // Create mechanism with null byte array parameter
            mechanism = Settings.Factories.MechanismFactory.Create(CKM.CKM_AES_CBC, parameter);
            Assert.IsTrue(mechanism.Type == ConvertUtils.UInt64FromCKM(CKM.CKM_AES_CBC));

            // We access private members here just for the testing purposes
            if (Platform.NativeULongSize == 4)
            {
                if (Platform.StructPackingSize == 0)
                {
                    HLA40.Mechanism    mechanism40   = (HLA40.Mechanism)mechanism;
                    LLA40.CK_MECHANISM ckMechanism40 = (LLA40.CK_MECHANISM) typeof(HLA40.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism40);
                    Assert.IsTrue(ckMechanism40.Mechanism == ConvertUtils.UInt32FromCKM(CKM.CKM_AES_CBC));
                    Assert.IsTrue(ckMechanism40.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism40.ParameterLen == 0);
                }
                else
                {
                    HLA41.Mechanism    mechanism41   = (HLA41.Mechanism)mechanism;
                    LLA41.CK_MECHANISM ckMechanism41 = (LLA41.CK_MECHANISM) typeof(HLA41.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism41);
                    Assert.IsTrue(ckMechanism41.Mechanism == ConvertUtils.UInt32FromCKM(CKM.CKM_AES_CBC));
                    Assert.IsTrue(ckMechanism41.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism41.ParameterLen == 0);
                }
            }
            else
            {
                if (Platform.StructPackingSize == 0)
                {
                    HLA80.Mechanism    mechanism80   = (HLA80.Mechanism)mechanism;
                    LLA80.CK_MECHANISM ckMechanism80 = (LLA80.CK_MECHANISM) typeof(HLA80.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism80);
                    Assert.IsTrue(ckMechanism80.Mechanism == ConvertUtils.UInt64FromCKM(CKM.CKM_AES_CBC));
                    Assert.IsTrue(ckMechanism80.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism80.ParameterLen == 0);
                }
                else
                {
                    HLA81.Mechanism    mechanism81   = (HLA81.Mechanism)mechanism;
                    LLA81.CK_MECHANISM ckMechanism81 = (LLA81.CK_MECHANISM) typeof(HLA81.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism81);
                    Assert.IsTrue(ckMechanism81.Mechanism == ConvertUtils.UInt64FromCKM(CKM.CKM_AES_CBC));
                    Assert.IsTrue(ckMechanism81.Parameter == IntPtr.Zero);
                    Assert.IsTrue(ckMechanism81.ParameterLen == 0);
                }
            }
        }
        public void _04_ObjectParameterTest()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            byte[] data = new byte[24];
            System.Random rng = new Random();
            rng.NextBytes(data);

            // Specify mechanism parameters
            CkKeyDerivationStringData parameter = new CkKeyDerivationStringData(data);

            // Create mechanism with the object as parameter
            Mechanism mechanism = new Mechanism(CKM.CKM_XOR_BASE_AND_DATA, parameter);
            Assert.IsTrue(mechanism.Type == (uint)CKM.CKM_XOR_BASE_AND_DATA);

            // We access private Mechanism member here just for the testing purposes
            Net.Pkcs11Interop.LowLevelAPI41.CK_MECHANISM ckMechanism = (Net.Pkcs11Interop.LowLevelAPI41.CK_MECHANISM)typeof(Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism);
            Assert.IsTrue(ckMechanism.Mechanism == (uint)CKM.CKM_XOR_BASE_AND_DATA);
            Assert.IsTrue(ckMechanism.Parameter != IntPtr.Zero);
            Assert.IsTrue(ckMechanism.ParameterLen == Net.Pkcs11Interop.Common.UnmanagedMemory.SizeOf(typeof(Net.Pkcs11Interop.LowLevelAPI41.MechanismParams.CK_KEY_DERIVATION_STRING_DATA)));
        }
        /// <summary>
        /// Decrypts multi-part data
        /// </summary>
        /// <param name="mechanism">Decryption mechanism</param>
        /// <param name="keyHandle">Handle of the decryption key</param>
        /// <param name="inputStream">Input stream from which encrypted data should be read</param>
        /// <param name="outputStream">Output stream where decrypted data should be written</param>
        /// <param name="bufferLength">Size of read buffer in bytes</param>
        public void Decrypt(Mechanism mechanism, ObjectHandle keyHandle, Stream inputStream, Stream outputStream, int bufferLength)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (mechanism == null)
                throw new ArgumentNullException("mechanism");
            
            if (keyHandle == null)
                throw new ArgumentNullException("keyHandle");
            
            if (inputStream == null)
                throw new ArgumentNullException("inputStream");
            
            if (outputStream == null)
                throw new ArgumentNullException("outputStream");
            
            if (bufferLength < 1)
                throw new ArgumentException("Value has to be positive number", "bufferLength");

            CK_MECHANISM ckMechanism = mechanism.CkMechanism;

            CKR rv = _p11.C_DecryptInit(_sessionId, ref ckMechanism, keyHandle.ObjectId);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DecryptInit", rv);

            byte[] encryptedPart = new byte[bufferLength];
            byte[] part = new byte[bufferLength];
            uint partLen = Convert.ToUInt32(part.Length);

            int bytesRead = 0;
            while ((bytesRead = inputStream.Read(encryptedPart, 0, encryptedPart.Length)) > 0)
            {
                partLen = Convert.ToUInt32(part.Length);
                rv = _p11.C_DecryptUpdate(_sessionId, encryptedPart, Convert.ToUInt32(bytesRead), part, ref partLen);
                if (rv != CKR.CKR_OK)
                    throw new Pkcs11Exception("C_DecryptUpdate", rv);

                outputStream.Write(part, 0, Convert.ToInt32(partLen));
            }

            byte[] lastPart = null;
            uint lastPartLen = 0;
            rv = _p11.C_DecryptFinal(_sessionId, null, ref lastPartLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DecryptFinal", rv);

            lastPart = new byte[lastPartLen];
            rv = _p11.C_DecryptFinal(_sessionId, lastPart, ref lastPartLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DecryptFinal", rv);

            if (lastPartLen > 0)
                outputStream.Write(lastPart, 0, Convert.ToInt32(lastPartLen));
        }
        /// <summary>
        /// Decrypts single-part data
        /// </summary>
        /// <param name="mechanism">Decryption mechanism</param>
        /// <param name="keyHandle">Handle of the decryption key</param>
        /// <param name="encryptedData">Data to be decrypted</param>
        /// <returns>Decrypted data</returns>
        public byte[] Decrypt(Mechanism mechanism, ObjectHandle keyHandle, byte[] encryptedData)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (mechanism == null)
                throw new ArgumentNullException("mechanism");
            
            if (keyHandle == null)
                throw new ArgumentNullException("keyHandle");
            
            if (encryptedData == null)
                throw new ArgumentNullException("encryptedData");

            CK_MECHANISM ckMechanism = mechanism.CkMechanism;

            CKR rv = _p11.C_DecryptInit(_sessionId, ref ckMechanism, keyHandle.ObjectId);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DecryptInit", rv);

            uint decryptedDataLen = 0;
            rv = _p11.C_Decrypt(_sessionId, encryptedData, Convert.ToUInt32(encryptedData.Length), null, ref decryptedDataLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_Decrypt", rv);

            byte[] decryptedData = new byte[decryptedDataLen];
            rv = _p11.C_Decrypt(_sessionId, encryptedData, Convert.ToUInt32(encryptedData.Length), decryptedData, ref decryptedDataLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_Decrypt", rv);

            if (decryptedData.Length != decryptedDataLen)
                Array.Resize(ref decryptedData, Convert.ToInt32(decryptedDataLen));

            return decryptedData;
        }
        /// <summary>
        /// Wraps (i.e., encrypts) a private or secret key
        /// </summary>
        /// <param name="mechanism">Wrapping mechanism</param>
        /// <param name="wrappingKeyHandle">Handle of wrapping key</param>
        /// <param name="keyHandle">Handle of key to be wrapped</param>
        /// <returns>Wrapped key</returns>
        public byte[] WrapKey(Mechanism mechanism, ObjectHandle wrappingKeyHandle, ObjectHandle keyHandle)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (mechanism == null)
                throw new ArgumentNullException("mechanism");
            
            if (wrappingKeyHandle == null)
                throw new ArgumentNullException("wrappingKeyHandle");
            
            if (keyHandle == null)
                throw new ArgumentNullException("keyHandle");

            CK_MECHANISM ckMechanism = mechanism.CkMechanism;

            uint wrappedKeyLen = 0;
            CKR rv = _p11.C_WrapKey(_sessionId, ref ckMechanism, wrappingKeyHandle.ObjectId, keyHandle.ObjectId, null, ref wrappedKeyLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_WrapKey", rv);

            byte[] wrappedKey = new byte[wrappedKeyLen];
            rv = _p11.C_WrapKey(_sessionId, ref ckMechanism, wrappingKeyHandle.ObjectId, keyHandle.ObjectId, wrappedKey, ref wrappedKeyLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_WrapKey", rv);

            if (wrappedKey.Length != wrappedKeyLen)
                Array.Resize(ref wrappedKey, Convert.ToInt32(wrappedKeyLen));

            return wrappedKey;
        }
        /// <summary>
        /// Generates a secret key or set of domain parameters, creating a new object
        /// </summary>
        /// <param name="mechanism">Generation mechanism</param>
        /// <param name="attributes">Attributes of the new key or set of domain parameters</param>
        /// <returns>Handle of the new key or set of domain parameters</returns>
        public ObjectHandle GenerateKey(Mechanism mechanism, List<ObjectAttribute> attributes)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (mechanism == null)
                throw new ArgumentNullException("mechanism");

            CK_MECHANISM ckMechanism = mechanism.CkMechanism;

            CK_ATTRIBUTE[] template = null;
            uint templateLength = 0;
            
            if (attributes != null)
            {
                templateLength = Convert.ToUInt32(attributes.Count);
                template = new CK_ATTRIBUTE[templateLength];
                for (int i = 0; i < templateLength; i++)
                    template[i] = attributes[i].CkAttribute;
            }

            uint keyId = CK.CK_INVALID_HANDLE;
            CKR rv = _p11.C_GenerateKey(_sessionId, ref ckMechanism, template, templateLength, ref keyId);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_GenerateKey", rv);

            return new ObjectHandle(keyId);
        }
        /// <summary>
        /// Generates a public/private key pair, creating new key objects
        /// </summary>
        /// <param name="mechanism">Key generation mechanism</param>
        /// <param name="publicKeyAttributes">Attributes of the public key</param>
        /// <param name="privateKeyAttributes">Attributes of the private key</param>
        /// <param name="publicKeyHandle">Handle of the new public key</param>
        /// <param name="privateKeyHandle">Handle of the new private key</param>
        public void GenerateKeyPair(Mechanism mechanism, List<ObjectAttribute> publicKeyAttributes, List<ObjectAttribute> privateKeyAttributes, out ObjectHandle publicKeyHandle, out ObjectHandle privateKeyHandle)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (mechanism == null)
                throw new ArgumentNullException("mechanism");

            CK_MECHANISM ckMechanism = mechanism.CkMechanism;

            CK_ATTRIBUTE[] publicKeyTemplate = null;
            uint publicKeyTemplateLength = 0;
            
            if (publicKeyAttributes != null)
            {
                publicKeyTemplateLength = Convert.ToUInt32(publicKeyAttributes.Count);
                publicKeyTemplate = new CK_ATTRIBUTE[publicKeyTemplateLength];
                for (int i = 0; i < publicKeyTemplateLength; i++)
                    publicKeyTemplate[i] = publicKeyAttributes[i].CkAttribute;
            }

            CK_ATTRIBUTE[] privateKeyTemplate = null;
            uint privateKeyTemplateLength = 0;
            
            if (privateKeyAttributes != null)
            {
                privateKeyTemplateLength = Convert.ToUInt32(privateKeyAttributes.Count);
                privateKeyTemplate = new CK_ATTRIBUTE[privateKeyTemplateLength];
                for (int i = 0; i < privateKeyTemplateLength; i++)
                    privateKeyTemplate[i] = privateKeyAttributes[i].CkAttribute;
            }

            uint publicKeyId = CK.CK_INVALID_HANDLE;
            uint privateKeyId = CK.CK_INVALID_HANDLE;
            CKR rv = _p11.C_GenerateKeyPair(_sessionId, ref ckMechanism, publicKeyTemplate, publicKeyTemplateLength, privateKeyTemplate, privateKeyTemplateLength, ref publicKeyId, ref privateKeyId);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_GenerateKeyPair", rv);

            publicKeyHandle = new ObjectHandle(publicKeyId);
            privateKeyHandle = new ObjectHandle(privateKeyId);
        }
        /// <summary>
        /// Verifies a signature of data, where the signature is an appendix to the data
        /// </summary>
        /// <param name="mechanism">Verification mechanism;</param>
        /// <param name="keyHandle">Verification key</param>
        /// <param name="inputStream">Input stream from which data that was signed should be read</param>
        /// <param name="signature">Signature</param>
        /// <param name="isValid">Flag indicating whether signature is valid</param>
        public void Verify(Mechanism mechanism, ObjectHandle keyHandle, Stream inputStream, byte[] signature, out bool isValid)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (mechanism == null)
                throw new ArgumentNullException("mechanism");
            
            if (keyHandle == null)
                throw new ArgumentNullException("keyHandle");
            
            if (inputStream == null)
                throw new ArgumentNullException("inputStream");
            
            if (signature == null)
                throw new ArgumentNullException("signature");

            Verify(mechanism, keyHandle, inputStream, signature, out isValid, 4096);
        }
        /// <summary>
        /// Derives a key from a base key, creating a new key object
        /// </summary>
        /// <param name="mechanism">Derivation mechanism</param>
        /// <param name="baseKeyHandle">Handle of base key</param>
        /// <param name="attributes">Attributes for the new key</param>
        /// <returns>Handle of derived key</returns>
        public ObjectHandle DeriveKey(Mechanism mechanism, ObjectHandle baseKeyHandle, List<ObjectAttribute> attributes)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (mechanism == null)
                throw new ArgumentNullException("mechanism");
            
            if (baseKeyHandle == null)
                throw new ArgumentNullException("baseKeyHandle");

            CK_MECHANISM ckMechanism = mechanism.CkMechanism;

            CK_ATTRIBUTE[] template = null;
            uint templateLen = 0;
            if (attributes != null)
            {
                template = new CK_ATTRIBUTE[attributes.Count];
                for (int i = 0; i < attributes.Count; i++)
                    template[i] = attributes[i].CkAttribute;
                templateLen = Convert.ToUInt32(attributes.Count);
            }

            uint derivedKey = CK.CK_INVALID_HANDLE;
            CKR rv = _p11.C_DeriveKey(_sessionId, ref ckMechanism, baseKeyHandle.ObjectId, template, templateLen, ref derivedKey);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DeriveKey", rv);

            return new ObjectHandle(derivedKey);
        }
        /// <summary>
        /// Verifies a signature of data, where the signature is an appendix to the data
        /// </summary>
        /// <param name="mechanism">Verification mechanism;</param>
        /// <param name="keyHandle">Verification key</param>
        /// <param name="inputStream">Input stream from which data that was signed should be read</param>
        /// <param name="signature">Signature</param>
        /// <param name="isValid">Flag indicating whether signature is valid</param>
        /// <param name="bufferLength">Size of read buffer in bytes</param>
        public void Verify(Mechanism mechanism, ObjectHandle keyHandle, Stream inputStream, byte[] signature, out bool isValid, int bufferLength)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (mechanism == null)
                throw new ArgumentNullException("mechanism");
            
            if (keyHandle == null)
                throw new ArgumentNullException("keyHandle");
            
            if (inputStream == null)
                throw new ArgumentNullException("inputStream");
            
            if (signature == null)
                throw new ArgumentNullException("signature");

            if (bufferLength < 1)
                throw new ArgumentException("Value has to be positive number", "bufferLength");

            CK_MECHANISM ckMechanism = mechanism.CkMechanism;

            CKR rv = _p11.C_VerifyInit(_sessionId, ref ckMechanism, keyHandle.ObjectId);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_VerifyInit", rv);

            byte[] part = new byte[bufferLength];
            int bytesRead = 0;

            while ((bytesRead = inputStream.Read(part, 0, part.Length)) > 0)
            {
                rv = _p11.C_VerifyUpdate(_sessionId, part, Convert.ToUInt32(bytesRead));
                if (rv != CKR.CKR_OK)
                    throw new Pkcs11Exception("C_VerifyUpdate", rv);
            }

            rv = _p11.C_VerifyFinal(_sessionId, signature, Convert.ToUInt32(signature.Length));
            if (rv == CKR.CKR_OK)
                isValid = true;
            else if (rv == CKR.CKR_SIGNATURE_INVALID)
                isValid = false;
            else 
                throw new Pkcs11Exception("C_VerifyFinal", rv);
        }
        /// <summary>
        /// Decrypts multi-part data
        /// </summary>
        /// <param name="mechanism">Decryption mechanism</param>
        /// <param name="keyHandle">Handle of the decryption key</param>
        /// <param name="inputStream">Input stream from which encrypted data should be read</param>
        /// <param name="outputStream">Output stream where decrypted data should be written</param>
        public void Decrypt(Mechanism mechanism, ObjectHandle keyHandle, Stream inputStream, Stream outputStream)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (mechanism == null)
                throw new ArgumentNullException("mechanism");
            
            if (keyHandle == null)
                throw new ArgumentNullException("keyHandle");
            
            if (inputStream == null)
                throw new ArgumentNullException("inputStream");
            
            if (outputStream == null)
                throw new ArgumentNullException("outputStream");

            Decrypt(mechanism, keyHandle, inputStream, outputStream, 4096);
        }
        /// <summary>
        /// Verifies signature of data, where the data can be recovered from the signature
        /// </summary>
        /// <param name="mechanism">Verification mechanism;</param>
        /// <param name="keyHandle">Verification key</param>
        /// <param name="signature">Signature</param>
        /// <param name="isValid">Flag indicating whether signature is valid</param>
        /// <returns>Data recovered from the signature</returns>
        public byte[] VerifyRecover(Mechanism mechanism, ObjectHandle keyHandle, byte[] signature, out bool isValid)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (mechanism == null)
                throw new ArgumentNullException("mechanism");
            
            if (keyHandle == null)
                throw new ArgumentNullException("keyHandle");
            
            if (signature == null)
                throw new ArgumentNullException("signature");
            
            CK_MECHANISM ckMechanism = mechanism.CkMechanism;

            CKR rv = _p11.C_VerifyRecoverInit(_sessionId, ref ckMechanism, keyHandle.ObjectId);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_VerifyRecoverInit", rv);

            uint dataLen = 0;
            rv = _p11.C_VerifyRecover(_sessionId, signature, Convert.ToUInt32(signature.Length), null, ref dataLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_VerifyRecover", rv);

            byte[] data = new byte[dataLen];
            rv = _p11.C_VerifyRecover(_sessionId, signature, Convert.ToUInt32(signature.Length), data, ref dataLen);
            if (rv == CKR.CKR_OK)
                isValid = true;
            else if (rv == CKR.CKR_SIGNATURE_INVALID)
                isValid = false;
            else 
                throw new Pkcs11Exception("C_VerifyRecover", rv);

            if (data.Length != dataLen)
                Array.Resize(ref data, Convert.ToInt32(dataLen));

            return data;
        }
        /// <summary>
        /// Digests the value of a secret key
        /// </summary>
        /// <param name="mechanism">Digesting mechanism</param>
        /// <param name="keyHandle">Handle of the secret key to be digested</param>
        /// <returns>Digest</returns>
        public byte[] DigestKey(Mechanism mechanism, ObjectHandle keyHandle)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (mechanism == null)
                throw new ArgumentNullException("mechanism");
            
            if (keyHandle == null)
                throw new ArgumentNullException("keyHandle");

            CK_MECHANISM ckMechanism = mechanism.CkMechanism;
            
            CKR rv = _p11.C_DigestInit(_sessionId, ref ckMechanism);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DigestInit", rv);
            
            rv = _p11.C_DigestKey(_sessionId, keyHandle.ObjectId);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DigestKey", rv);
            
            uint digestLen = 0;
            rv = _p11.C_DigestFinal(_sessionId, null, ref digestLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DigestFinal", rv);
            
            byte[] digest = new byte[digestLen];
            rv = _p11.C_DigestFinal(_sessionId, digest, ref digestLen);
            if (rv != CKR.CKR_OK)
                throw new Pkcs11Exception("C_DigestFinal", rv);

            if (digest.Length != digestLen)
                Array.Resize(ref digest, Convert.ToInt32(digestLen));

            return digest;
        }
        /// <summary>
        /// Digests and decrypts data
        /// </summary>
        /// <param name="digestingMechanism">Digesting mechanism</param>
        /// <param name="decryptionMechanism">Decryption mechanism</param>
        /// <param name="keyHandle">Handle of the decryption key</param>
        /// <param name="data">Data to be processed</param>
        /// <param name="digest">Digest</param>
        /// <param name="decryptedData">Decrypted data</param>
        public void DecryptDigest(Mechanism digestingMechanism, Mechanism decryptionMechanism, ObjectHandle keyHandle, byte[] data, out byte[] digest, out byte[] decryptedData)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (digestingMechanism == null)
                throw new ArgumentNullException("digestingMechanism");
            
            if (decryptionMechanism == null)
                throw new ArgumentNullException("decryptionMechanism");
            
            if (keyHandle == null)
                throw new ArgumentNullException("keyHandle");

            if (data == null)
                throw new ArgumentNullException("data");

            using (MemoryStream inputMemoryStream = new MemoryStream(data), outputMemorySteam = new MemoryStream())
            {
                digest = DecryptDigest(digestingMechanism, decryptionMechanism, keyHandle, inputMemoryStream, outputMemorySteam);
                decryptedData = outputMemorySteam.ToArray();
            }
        }
        /// <summary>
        /// Digests and decrypts data
        /// </summary>
        /// <param name="digestingMechanism">Digesting mechanism</param>
        /// <param name="decryptionMechanism">Decryption mechanism</param>
        /// <param name="keyHandle">Handle of the decryption key</param>
        /// <param name="inputStream">Input stream from which data to be processed should be read</param>
        /// <param name="outputStream">Output stream where decrypted data should be written</param>
        /// <returns>Digest</returns>
        public byte[] DecryptDigest(Mechanism digestingMechanism, Mechanism decryptionMechanism, ObjectHandle keyHandle, Stream inputStream, Stream outputStream)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (digestingMechanism == null)
                throw new ArgumentNullException("digestingMechanism");
            
            if (decryptionMechanism == null)
                throw new ArgumentNullException("decryptionMechanism");
            
            if (keyHandle == null)
                throw new ArgumentNullException("keyHandle");
            
            if (inputStream == null)
                throw new ArgumentNullException("inputStream");

            if (outputStream == null)
                throw new ArgumentNullException("outputStream");

            return DecryptDigest(digestingMechanism, decryptionMechanism, keyHandle, inputStream, outputStream, 4096);
        }
        /// <summary>
        /// Signs and encrypts data
        /// </summary>
        /// <param name="signingMechanism">Signing mechanism</param>
        /// <param name="signingKeyHandle">Handle of the signing key</param>
        /// <param name="encryptionMechanism">Encryption mechanism</param>
        /// <param name="encryptionKeyHandle">Handle of the encryption key</param>
        /// <param name="data">Data to be processed</param>
        /// <param name="signature">Signature</param>
        /// <param name="encryptedData">Encrypted data</param>
        public void SignEncrypt(Mechanism signingMechanism, ObjectHandle signingKeyHandle, Mechanism encryptionMechanism, ObjectHandle encryptionKeyHandle, byte[] data, out byte[] signature, out byte[] encryptedData)
        {
            if (this._disposed)
                throw new ObjectDisposedException(this.GetType().FullName);

            if (signingMechanism == null)
                throw new ArgumentNullException("signingMechanism");
            
            if (signingKeyHandle == null)
                throw new ArgumentNullException("signingKeyHandle");
            
            if (encryptionMechanism == null)
                throw new ArgumentNullException("encryptionMechanism");
            
            if (encryptionKeyHandle == null)
                throw new ArgumentNullException("encryptionKeyHandle");

            if (data == null)
                throw new ArgumentNullException("data");

            using (MemoryStream inputMemoryStream = new MemoryStream(data), outputMemorySteam = new MemoryStream())
            {
                signature = SignEncrypt(signingMechanism, signingKeyHandle, encryptionMechanism, encryptionKeyHandle, inputMemoryStream, outputMemorySteam);
                encryptedData = outputMemorySteam.ToArray();
            }
        }
        public void _03_ByteArrayParameterTest()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            byte[] parameter = new byte[16];
            System.Random rng = new Random();
            rng.NextBytes(parameter);
            
            // Create mechanism with the byte array parameter
            Mechanism mechanism = new Mechanism(CKM.CKM_AES_CBC, parameter);
            Assert.IsTrue(mechanism.Type == (uint)CKM.CKM_AES_CBC);

            // We access private Mechanism member here just for the testing purposes
            Net.Pkcs11Interop.LowLevelAPI41.CK_MECHANISM ckMechanism = (Net.Pkcs11Interop.LowLevelAPI41.CK_MECHANISM)typeof(Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism);
            Assert.IsTrue(ckMechanism.Mechanism == (uint)CKM.CKM_AES_CBC);
            Assert.IsTrue(ckMechanism.Parameter != IntPtr.Zero);
            Assert.IsTrue(ckMechanism.ParameterLen == parameter.Length);

            parameter = null;
            
            // Create mechanism with null byte array parameter
            mechanism = new Mechanism(CKM.CKM_AES_CBC, parameter);
            Assert.IsTrue(mechanism.Type == (uint)CKM.CKM_AES_CBC);

            // We access private Mechanism member here just for the testing purposes
            ckMechanism = (Net.Pkcs11Interop.LowLevelAPI41.CK_MECHANISM)typeof(Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism);
            Assert.IsTrue(ckMechanism.Mechanism == (uint)CKM.CKM_AES_CBC);
            Assert.IsTrue(ckMechanism.Parameter == IntPtr.Zero);
            Assert.IsTrue(ckMechanism.ParameterLen == 0);
        }
Exemple #35
0
        /// <summary>
        /// Signs single-part data, where the signature is an appendix to the data
        /// </summary>
        /// <param name="session">Instance of the extended class</param>
        /// <param name="mechanism">Signature mechanism</param>
        /// <param name="keyHandle">Signature key</param>
        /// <param name="data">Data to be signed</param>
        /// <param name="pin">Pin of user</param>
        /// <returns>Signature</returns>
        public static byte[] Sign(this HLA41.Session session, HLA41.Mechanism mechanism, HLA41.ObjectHandle keyHandle, byte[] data, byte[] pin)
        {
            if (session.Disposed)
            {
                throw new ObjectDisposedException(session.GetType().FullName);
            }

            if (mechanism == null)
            {
                throw new ArgumentNullException("mechanism");
            }

            if (keyHandle == null)
            {
                throw new ArgumentNullException("keyHandle");
            }

            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            byte[] pinValue    = null;
            uint   pinValueLen = 0;

            if (pin != null)
            {
                pinValue    = pin;
                pinValueLen = Convert.ToUInt32(pin.Length);
            }

            var ckMechanism40 = (LLA41.CK_MECHANISM) typeof(HLA41.Mechanism).GetField("_ckMechanism", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mechanism);

            CKR rv = session.LowLevelPkcs11.C_SignInit(session.SessionId, ref ckMechanism40, keyHandle.ObjectId);

            if (rv != CKR.CKR_OK)
            {
                throw new Pkcs11Exception("C_SignInit", rv);
            }

            rv = session.LowLevelPkcs11.C_Login(session.SessionId, CKU.CKU_CONTEXT_SPECIFIC, pinValue, pinValueLen);
            if (rv != CKR.CKR_OK)
            {
                throw new Pkcs11Exception("C_Login", rv);
            }

            uint signatureLen = 0;

            rv = session.LowLevelPkcs11.C_Sign(session.SessionId, data, Convert.ToUInt32(data.Length), null, ref signatureLen);
            if (rv != CKR.CKR_OK)
            {
                throw new Pkcs11Exception("C_Sign", rv);
            }

            byte[] signature = new byte[signatureLen];
            rv = session.LowLevelPkcs11.C_Sign(session.SessionId, data, Convert.ToUInt32(data.Length), signature, ref signatureLen);
            if (rv != CKR.CKR_OK)
            {
                throw new Pkcs11Exception("C_Sign", rv);
            }

            if (signature.Length != signatureLen)
            {
                Array.Resize(ref signature, Convert.ToInt32(signatureLen));
            }

            return(signature);
        }