/// <summary> /// Routes data written to the object into the <see cref="MD4"/> hash algorithm for computing the hash. /// </summary> /// <param name="array">The array of data bytes.</param> /// <param name="ibStart">The offset into the byte array from which to begin using data.</param> /// <param name="cbSize">The number of bytes in the array to use as data.</param> /// <exception cref="ObjectDisposedException">The MD4CryptoServiceProvider instance has been disposed.</exception> /// <exception cref="CryptographicException">The data could not be hashed.</exception> protected override void HashCore(byte[] array, int ibStart, int cbSize) { if (m_Disposed) { throw new ObjectDisposedException(this.GetType().FullName); } byte[] copy = new byte[cbSize]; Array.Copy(array, ibStart, copy, 0, cbSize); if (SspiProvider.CryptHashData(m_Hash, copy, copy.Length, 0) == 0) { throw new CryptographicException("The data could not be hashed."); } }
public bool VerifySignature(Certificate cert, byte[] signature, byte[] hash) { int provider = 0; int hashptr = 0; int pubKey = 0; try { if (SspiProvider.CryptAcquireContext(ref provider, IntPtr.Zero, null, SecurityConstants.PROV_RSA_FULL, 0) == 0) { if (Marshal.GetLastWin32Error() == SecurityConstants.NTE_BAD_KEYSET) { SspiProvider.CryptAcquireContext(ref provider, IntPtr.Zero, null, SecurityConstants.PROV_RSA_FULL, SecurityConstants.CRYPT_NEWKEYSET); } } if (provider == 0) { throw new CryptographicException("Unable to acquire a cryptographic context."); } if (SspiProvider.CryptCreateHash(provider, SecurityConstants.CALG_SSL3_SHAMD5, 0, 0, out hashptr) == 0) { throw new CryptographicException("Unable to create the SHA-MD5 hash."); } if (SspiProvider.CryptSetHashParam(hashptr, SecurityConstants.HP_HASHVAL, hash, 0) == 0) { throw new CryptographicException("Unable to set the value of the SHA-MD5 hash."); } CertificateInfo ci = cert.GetCertificateInfo(); CERT_PUBLIC_KEY_INFO pki = new CERT_PUBLIC_KEY_INFO(ci); if (SspiProvider.CryptImportPublicKeyInfo(provider, SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, ref pki, out pubKey) == 0) { throw new CryptographicException("Unable to get a handle to the public key of the specified certificate."); } byte[] sign_rev = new byte[signature.Length]; Array.Copy(signature, 0, sign_rev, 0, signature.Length); Array.Reverse(sign_rev); return(SspiProvider.CryptVerifySignature(hashptr, sign_rev, sign_rev.Length, pubKey, IntPtr.Zero, 0) != 0); } finally { if (pubKey != 0) { SspiProvider.CryptDestroyKey(pubKey); } if (hashptr != 0) { SspiProvider.CryptDestroyHash(hashptr); } if (provider != 0) { SspiProvider.CryptReleaseContext(provider, 0); } } }
/// <summary> /// Returns the computed <see cref="MD4CryptoServiceProvider"/> hash as an array of bytes after all data has been written to the object. /// </summary> /// <returns>The computed hash value.</returns> /// <exception cref="ObjectDisposedException">The MD4CryptoServiceProvider instance has been disposed.</exception> /// <exception cref="CryptographicException">The data could not be hashed.</exception> protected override byte[] HashFinal() { if (m_Disposed) { throw new ObjectDisposedException(this.GetType().FullName); } byte[] buffer = new byte[16]; int length = buffer.Length; if (SspiProvider.CryptGetHashParam(m_Hash, SecurityConstants.HP_HASHVAL, buffer, ref length, 0) == 0) { throw new CryptographicException("The hash value could not be read."); } return(buffer); }
protected override void Dispose(bool disposing) { if (!m_Disposed) { if (m_Hash != 0) { SspiProvider.CryptDestroyHash(m_Hash); m_Hash = 0; } try { GC.SuppressFinalize(this); } catch {} m_Disposed = true; } }
/// <summary> /// Initializes a new instance of the <see cref="CertificateStoreCollection"/> class. /// </summary> /// <param name="collection">The CertificateStoreCollection whose elements are copied to the new certificate store collection.</param> /// <exception cref="ArgumentNullException"><paramref name="collection"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception> /// <exception cref="CertificateException">An error occurs while adding a certificate to the collection.</exception> public CertificateStoreCollection(CertificateStoreCollection collection) : base(SspiProvider.CertOpenStore(new IntPtr(SecurityConstants.CERT_STORE_PROV_COLLECTION), 0, 0, 0, null), false) { if (collection == null) { throw new ArgumentNullException(); } m_Stores = new ArrayList(collection.m_Stores); // used to hold references to the certificate stores so they cannot be finalized for (int i = 0; i < m_Stores.Count; i++) { if (SspiProvider.CertAddStoreToCollection(this.Handle, ((CertificateStore)m_Stores[i]).Handle, 0, 0) == 0) { throw new CertificateException("Could not add the store to the collection."); } } }
/// <summary> /// Adds a certificate store to the collection. /// </summary> /// <param name="store">An instance of the <see cref="CertificateStore"/> class.</param> /// <exception cref="ArgumentNullException"><paramref name="store"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception> /// <exception cref="ArgumentException">The specified certificate store is a <see cref="CertificateStoreCollection"/> instance. This is not allowed to avoid circular dependencies.</exception> /// <exception cref="CertificateException">An error occurs while adding the certificate to the collection.</exception> public void AddStore(CertificateStore store) { if (store == null) { throw new ArgumentNullException(); } if (store.ToString() == this.ToString()) // avoid circular dependencies { throw new ArgumentException("A certificate store collection cannot hold other certificate store collections."); } if (SspiProvider.CertAddStoreToCollection(this.Handle, store.Handle, 0, 0) == 0) { throw new CertificateException("Could not add the store to the collection."); } m_Stores.Add(store); }
/// <summary> /// Releases all unmanaged resources. /// </summary> public void Dispose() { if (m_Handle != 0) { SspiProvider.CryptDestroyKey(m_Handle); } if (m_ExponentOfOne != 0) { SspiProvider.CryptDestroyKey(m_ExponentOfOne); } /* if (m_OwnsProvider && m_Provider != 0) * SspiProvider.CryptReleaseContext(m_Provider, 0);*/ m_Handle = m_ExponentOfOne = m_Provider = 0; try { GC.SuppressFinalize(this); } catch {} }
public byte[] CreateSignature(Certificate cert, byte[] hash) { int flags = 0, mustFree = 0, provider = 0, keySpec = 0, hashptr = 0, size = 0; try { if (!Environment.UserInteractive) { flags = SecurityConstants.CRYPT_ACQUIRE_SILENT_FLAG; } if (SspiProvider.CryptAcquireCertificatePrivateKey(cert.Handle, flags, IntPtr.Zero, ref provider, ref keySpec, ref mustFree) == 0) { throw new SslException(AlertDescription.InternalError, "Could not acquire private key."); } if (SspiProvider.CryptCreateHash(provider, SecurityConstants.CALG_SSL3_SHAMD5, 0, 0, out hashptr) == 0) { throw new CryptographicException("Unable to create the SHA-MD5 hash."); } if (SspiProvider.CryptSetHashParam(hashptr, SecurityConstants.HP_HASHVAL, hash, 0) == 0) { throw new CryptographicException("Unable to set the value of the SHA-MD5 hash."); } SspiProvider.CryptSignHash(hashptr, keySpec, IntPtr.Zero, 0, null, ref size); if (size == 0) { throw new CryptographicException("Unable to sign the data."); } byte[] buffer = new byte[size]; if (SspiProvider.CryptSignHash(hashptr, keySpec, IntPtr.Zero, 0, buffer, ref size) == 0) { throw new CryptographicException("Unable to sign the data."); } Array.Reverse(buffer); return(buffer); } finally { if (hashptr != 0) { SspiProvider.CryptDestroyHash(hashptr); } if (mustFree != 0 && provider != 0) { SspiProvider.CryptReleaseContext(provider, 0); } } }
/// <summary> /// Transforms the specified region of the specified byte array. /// </summary> /// <param name="inputBuffer">The input for which to compute the transform.</param> /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param> /// <param name="inputCount">The number of bytes in the byte array to use as data.</param> /// <returns>The computed transform.</returns> /// <exception cref="ObjectDisposedException">The object has been disposed.</exception> /// <exception cref="ArgumentNullException"><paramref name="inputBuffer"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception> /// <exception cref="ArgumentOutOfRangeException">The combination of offset and length is invalid.</exception> /// <exception cref="CryptographicException">An error occurs while transforming the specified data.</exception> public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) { if (m_Key == null) { throw new ObjectDisposedException(this.GetType().FullName); } if (inputBuffer == null) { throw new ArgumentNullException(); } if (inputCount < 0 || inputOffset < 0 || inputOffset + inputCount > inputBuffer.Length) { throw new ArgumentOutOfRangeException(); } int length = inputCount; byte[] ret; if (m_Method == CryptoMethod.Encrypt) { if (SspiProvider.CryptEncrypt(m_Key.Handle, 0, 1, 0, null, ref length, 0) == 0) { throw new CryptographicException("Could not encrypt data."); } ret = new byte[length]; Buffer.BlockCopy(inputBuffer, inputOffset, ret, 0, inputCount); length = inputCount; if (SspiProvider.CryptEncrypt(m_Key.Handle, 0, 1, 0, ret, ref length, ret.Length) == 0) { throw new CryptographicException("Could not encrypt data."); } } else // decrypt { byte[] orgCopy = new byte[inputCount]; Buffer.BlockCopy(inputBuffer, inputOffset, orgCopy, 0, inputCount); if (SspiProvider.CryptDecrypt(m_Key.Handle, 0, 1, 0, orgCopy, ref length) == 0) { throw new CryptographicException("Could not decrypt data."); } ret = new byte[length]; Buffer.BlockCopy(orgCopy, 0, ret, 0, length); } return(ret); }
/// <summary> /// Returns the bytes that represent the symmetric key. /// </summary> /// <returns>An array of bytes.</returns> /// <exception cref="ObjectDisposedException">The SymmetricKey has been disposed.</exception> public byte[] ToBytes() { if (m_Handle == 0) { throw new ObjectDisposedException(this.GetType().FullName); } IntPtr pbSessionBlob = IntPtr.Zero; try { int dwSessionBlob = 0; if (SspiProvider.CryptExportKey(m_Handle, m_ExponentOfOne, SecurityConstants.SIMPLEBLOB, 0, IntPtr.Zero, ref dwSessionBlob) == 0) { throw new SecurityException("Cannot export key."); } pbSessionBlob = Marshal.AllocHGlobal(dwSessionBlob); if (SspiProvider.CryptExportKey(m_Handle, m_ExponentOfOne, SecurityConstants.SIMPLEBLOB, 0, pbSessionBlob, ref dwSessionBlob) == 0) { throw new SecurityException("Cannot export key."); } // Get session key size in bits int dwSize = 4; // sizeof(DWORD) int dwKeyMaterial = 0; if (SspiProvider.CryptGetKeyParam(m_Handle, SecurityConstants.KP_KEYLEN, ref dwKeyMaterial, ref dwSize, 0) == 0) { throw new SecurityException("Cannot retrieve key parameters."); } // Get the number of bytes and allocate buffer dwKeyMaterial /= 8; byte[] pbKeyMaterial = new byte[dwKeyMaterial]; // Skip the header int offset = 4 + IntPtr.Size; // sizeof(BLOBHEADER); offset += IntPtr.Size; // sizeof(ALG_ID); Marshal.Copy(new IntPtr(pbSessionBlob.ToInt64() + offset), pbKeyMaterial, 0, pbKeyMaterial.Length); // the key is reversed Array.Reverse(pbKeyMaterial); return(pbKeyMaterial); } finally { if (pbSessionBlob != IntPtr.Zero) { Marshal.FreeHGlobal(pbSessionBlob); } } }
/// <summary> /// Initializes a new <see cref="CertificateChain"/> instance from a <see cref="Certificate"/>. /// </summary> /// <param name="cert">The certificate for which a chain is being built.</param> /// <param name="additional">Any additional store to be searched for supporting certificates and CTLs.</param> /// <param name="options">Additional certificate chain options.</param> /// <remarks><paramref name="cert"/> will always be the end certificate.</remarks> /// <exception cref="ArgumentNullException"><paramref name="cert"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception> /// <exception cref="CertificateException">An error occurs while building the certificate chain.</exception> public CertificateChain(Certificate cert, CertificateStore additional, CertificateChainOptions options) { if (cert == null) { throw new ArgumentNullException(); } IntPtr addstore = additional == null ? IntPtr.Zero : additional.Handle; ChainParameters para = new ChainParameters(); para.cbSize = Marshal.SizeOf(typeof(ChainParameters)); para.RequestedUsagecUsageIdentifier = 0; para.RequestedUsagedwType = 0; para.RequestedUsagergpszUsageIdentifier = IntPtr.Zero; if (SspiProvider.CertGetCertificateChain(IntPtr.Zero, cert.Handle, IntPtr.Zero, addstore, ref para, (int)options, IntPtr.Zero, ref m_Handle) == 0) { throw new CertificateException("Unable to find the certificate chain."); } m_Certificate = cert; }
public override void Initialize() { if (m_Disposed) { throw new ObjectDisposedException(this.GetType().FullName); } if (m_Hash != 0) { SspiProvider.CryptDestroyHash(m_Hash); } int type = SecurityConstants.CALG_SHA1; m_Size = 20; if (m_Type == HashType.MD5) { type = SecurityConstants.CALG_MD5; m_Size = 16; } SspiProvider.CryptCreateHash(m_Provider, type, 0, 0, out m_Hash); }
/// <summary> /// Releases the unmanaged resources used by the <see cref="MD4CryptoServiceProvider"/> and optionally releases the managed resources. /// </summary> /// <param name="disposing"><b>true</b> to release both managed and unmanaged resources; <b>false</b> to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { if (!m_Disposed) { if (m_Hash != 0) { SspiProvider.CryptDestroyHash(m_Hash); m_Hash = 0; } /* if (m_Provider != 0) { * SspiProvider.CryptReleaseContext(m_Provider, 0); * m_Provider = 0; * }*/ try { GC.SuppressFinalize(this); } catch {} m_Disposed = true; } }
/// <summary> /// Initializes a new instance of the <see cref="RC4CryptoServiceProvider"/> class. /// </summary> public RC4CryptoServiceProvider() { // acquire an RC4 context m_Provider = CAPIProvider.Handle; /* if (SspiProvider.CryptAcquireContext(ref m_Provider, IntPtr.Zero, null, SecurityConstants.PROV_RSA_FULL, 0) == 0) { * if (Marshal.GetLastWin32Error() == SecurityConstants.NTE_BAD_KEYSET) * SspiProvider.CryptAcquireContext(ref m_Provider, IntPtr.Zero, null, SecurityConstants.PROV_RSA_FULL, SecurityConstants.CRYPT_NEWKEYSET); * }*/ if (m_Provider != 0) { int dwFlags = SecurityConstants.CRYPT_FIRST; bool found = false; IntPtr provEnum = Marshal.AllocHGlobal(100); int dwSize; do { dwSize = 100; if (SspiProvider.CryptGetProvParam(m_Provider, SecurityConstants.PP_ENUMALGS_EX, provEnum, ref dwSize, dwFlags) == 0) { break; } dwFlags = 0; PROV_ENUMALGS_EX eax = (PROV_ENUMALGS_EX)Marshal.PtrToStructure(provEnum, typeof(PROV_ENUMALGS_EX)); if (eax.aiAlgid == SecurityConstants.CALG_RC4) { found = true; m_MinLen = eax.dwMinLen; m_MaxLen = eax.dwMaxLen; } } while (!found); Marshal.FreeHGlobal(provEnum); /* if (!found) { * SspiProvider.CryptReleaseContext(m_Provider, 0); * m_Provider = 0; * }*/ } m_Managed = new ARCFourManaged(); }
/// <summary> /// Returns the list of certificates in this <see cref="CertificateChain"/>. /// </summary> /// <returns>An array of <see cref="Certificate"/> instances.</returns> /// <remarks> /// The certificate with index 0 is the end certificate in the chain, the certificate with the highest index is the root certificate [if it can be found]. /// </remarks> // Thanks go out to Hernan de Lahitte and Neil for notifying us about a bug in this method. public virtual Certificate[] GetCertificates() { ArrayList ret = new ArrayList(); int dwVerificationFlags; IntPtr store; CertificateStoreCollection csc, cs = this.Certificate.Store as CertificateStoreCollection; if (cs != null) { csc = new CertificateStoreCollection(cs); } else { csc = new CertificateStoreCollection(new CertificateStore[0]); if (this.Certificate.Store == null) { csc.AddStore(new CertificateStore(this.Certificate.m_Context.hCertStore, true)); } else { csc.AddStore(this.Certificate.Store); } } csc.AddStore(CertificateStore.GetCachedStore(CertificateStore.RootStore)); csc.AddStore(CertificateStore.GetCachedStore(CertificateStore.CAStore)); store = csc.Handle; IntPtr cert = this.Certificate.DuplicateHandle(); while (cert != IntPtr.Zero) { ret.Add(new Certificate(cert, false)); dwVerificationFlags = 0; cert = SspiProvider.CertGetIssuerCertificateFromStore(store, cert, IntPtr.Zero, ref dwVerificationFlags); } csc.Dispose(); // don't use csc anymore after this line!!! return((Certificate[])ret.ToArray(typeof(Certificate))); }
protected override void HashCore(byte[] array, int ibStart, int cbSize) { if (ibStart > 0) { GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned); try { IntPtr address = handle.AddrOfPinnedObject(); if (SspiProvider.CryptHashData(m_Hash, new IntPtr(address.ToInt64() + ibStart), cbSize, 0) == 0) { throw new CryptographicException("The data could not be hashed."); } } finally { handle.Free(); } } else { if (SspiProvider.CryptHashData(m_Hash, array, cbSize, 0) == 0) { throw new CryptographicException("The data could not be hashed."); } } }
/// <summary> /// Transforms the specified region of the specified byte array. /// </summary> /// <param name="inputBuffer">The input for which to compute the transform.</param> /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param> /// <param name="inputCount">The number of bytes in the byte array to use as data.</param> /// <returns>The computed transform.</returns> /// <exception cref="ObjectDisposedException">The object has been disposed.</exception> /// <exception cref="ArgumentNullException"><paramref name="inputBuffer"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="inputOffset"/> or <paramref name="inputCount"/> is invalid.</exception> public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) { if (m_Key == null) { throw new ObjectDisposedException(this.GetType().FullName); } if (inputBuffer == null) { throw new ArgumentNullException(); } if (inputCount < 0 || inputOffset < 0 || inputOffset + inputCount > inputBuffer.Length) { throw new ArgumentOutOfRangeException(); } byte[] buffer = new byte[inputCount]; int length = buffer.Length; Buffer.BlockCopy(inputBuffer, inputOffset, buffer, 0, length); if (SspiProvider.CryptEncrypt(m_Key.Handle, 0, 1, 0, buffer, ref length, length) == 0) { throw new CryptographicException("Could not transform data."); } return(buffer); }
/// <summary> /// Initializes a new instance of the <see cref="CertificateStoreCollection"/> class. /// </summary> /// <param name="stores">An array of stores that should be added to the collection.</param> /// <exception cref="ArgumentNullException"><paramref name="stores"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception> /// <exception cref="ArgumentException">One of the <see cref="CertificateStore"/> objects in the array is a <see cref="CertificateStoreCollection"/> instance. This is not allowed to avoid circular dependencies.</exception> /// <exception cref="CertificateException">An error occurs while adding a certificate to the collection.</exception> public CertificateStoreCollection(CertificateStore[] stores) : base(SspiProvider.CertOpenStore(new IntPtr(SecurityConstants.CERT_STORE_PROV_COLLECTION), 0, 0, 0, null), false) { if (stores == null) { throw new ArgumentNullException(); } for (int i = 0; i < stores.Length; i++) { if (stores[i].ToString() == this.ToString()) { // used in order to avoid circular dependencies throw new ArgumentException("A certificate store collection cannot hold other certificate store collections."); } } for (int i = 0; i < stores.Length; i++) { if (SspiProvider.CertAddStoreToCollection(this.Handle, stores[i].Handle, 0, 0) == 0) { throw new CertificateException("Could not add the store to the collection."); } } m_Stores = new ArrayList(); // used to hold references to the certificate stores so they cannot be finalized m_Stores.AddRange(stores); }
/// <summary> /// Dynamically creates an exponent-of-one key. /// </summary> /// <returns>The handle of a exponent-of-one key.</returns> /// <exception cref="SecurityException">An error occurs while creating the key.</exception> private int CreateDynamicExponentOfOneKey() { int hPrivateKey = 0; int dwKeyBlob = 0; IntPtr keyblob = IntPtr.Zero; int dwBitLen; try { if (SspiProvider.CryptGenKey(m_Provider, new IntPtr(SecurityConstants.AT_KEYEXCHANGE), SecurityConstants.CRYPT_EXPORTABLE, ref hPrivateKey) == 0) { throw new SecurityException("Cannot generate key pair."); } // Export the private key, we'll convert it to a private // exponent of one key if (SspiProvider.CryptExportKey(hPrivateKey, 0, SecurityConstants.PRIVATEKEYBLOB, 0, IntPtr.Zero, ref dwKeyBlob) == 0) { throw new SecurityException("Cannot export generated key."); } keyblob = Marshal.AllocHGlobal(dwKeyBlob); if (SspiProvider.CryptExportKey(hPrivateKey, 0, SecurityConstants.PRIVATEKEYBLOB, 0, keyblob, ref dwKeyBlob) == 0) { throw new SecurityException("Cannot export generated key."); } SspiProvider.CryptDestroyKey(hPrivateKey); hPrivateKey = 0; // Get the bit length of the key dwBitLen = Marshal.ReadInt32(keyblob, 12); /* Modify the Exponent in Key BLOB format [Key BLOB format is documented in SDK] */ // Convert pubexp in rsapubkey to 1 int offset = 16; for (int i = 0; i < 4; i++) { if (i == 0) { Marshal.WriteByte(keyblob, offset, 1); } else { Marshal.WriteByte(keyblob, offset + i, 0); } } // Skip pubexp offset += 4; // Skip modulus, prime1, prime2 offset += dwBitLen / 8; offset += dwBitLen / 16; offset += dwBitLen / 16; // Convert exponent1 to 1 for (int i = 0; i < dwBitLen / 16; i++) { if (i == 0) { Marshal.WriteByte(keyblob, offset, 1); } else { Marshal.WriteByte(keyblob, offset + i, 0); } } // Skip exponent1 offset += dwBitLen / 16; // Convert exponent2 to 1 for (int i = 0; i < dwBitLen / 16; i++) { if (i == 0) { Marshal.WriteByte(keyblob, offset, 1); } else { Marshal.WriteByte(keyblob, offset + i, 0); } } // Skip exponent2, coefficient offset += dwBitLen / 16; offset += dwBitLen / 16; // Convert privateExponent to 1 for (int i = 0; i < dwBitLen / 8; i++) { if (i == 0) { Marshal.WriteByte(keyblob, offset, 1); } else { Marshal.WriteByte(keyblob, offset + i, 0); } } // Import the exponent-of-one private key. if (SspiProvider.CryptImportKey(m_Provider, keyblob, dwKeyBlob, 0, SecurityConstants.CRYPT_EXPORTABLE, ref hPrivateKey) == 0) { throw new SecurityException("Could not import modified key."); } } catch (Exception e) { if (hPrivateKey != 0) { SspiProvider.CryptDestroyKey(hPrivateKey); } throw e; } finally { if (keyblob != IntPtr.Zero) { Marshal.FreeHGlobal(keyblob); } } return(hPrivateKey); }
/// <summary> /// Decrypts data that has been encrypted with the <see cref="ProtectData"/> method. /// </summary> /// <param name="data">The data to decrypt.</param> /// <param name="offset">The zero-based position in the <i>data</i> parameter at which to begin decrypting.</param> /// <param name="size">The number of bytes to decrypt.</param> /// <param name="entropy">Additional entropy to use during the decryption process. This parameter can be set to null.</param> /// <exception cref="ArgumentNullException"><i>data</i> is a null reference (<b>Nothing</b> in Visual Basic).</exception> /// <exception cref="ArgumentException">The specified <i>offset</i> or <i>size</i> exceeds the size of buffer.</exception> /// <exception cref="CryptographicException">An error occurs during the encryption process. Under some circumstances, Microsoft cryptographic service providers may not allow encryption when used in France. This may occur on down-level platforms such as Windows 98 and Windows NT 4.0, depending on the system's configuration and the version of the CSPs.</exception> /// <returns>The decrypted data.</returns> /// <remarks>The entropy used during decryption must be the same as the entropy used during encryption.</remarks> public byte[] UnprotectData(byte[] data, int offset, int size, byte[] entropy) { if (m_Disposed) { throw new ObjectDisposedException(this.GetType().FullName); } if (data == null) { throw new ArgumentNullException(); } if (offset < 0 || offset + size > data.Length) { throw new ArgumentException(); } DataBlob input = new DataBlob(); DataBlob entr = new DataBlob(); DataBlob output = new DataBlob(); try { // initialize input structure input.cbData = size; input.pbData = Marshal.AllocHGlobal(size); Marshal.Copy(data, offset, input.pbData, size); // initialize entropy structure if (entropy == null) { entr.cbData = 0; entr.pbData = IntPtr.Zero; } else { entr.cbData = entropy.Length; entr.pbData = Marshal.AllocHGlobal(entr.cbData); Marshal.Copy(entropy, 0, entr.pbData, entr.cbData); } // initialize output structure output.cbData = 0; output.pbData = IntPtr.Zero; // call the function and check for errors int flags = 0; if (!Environment.UserInteractive) { flags = flags | SecurityConstants.CRYPTPROTECT_UI_FORBIDDEN; } if (SspiProvider.CryptUnprotectData(ref input, IntPtr.Zero, ref entr, IntPtr.Zero, IntPtr.Zero, flags, ref output) == 0 || output.pbData == IntPtr.Zero) { throw new CryptographicException("The data could not be unprotected."); } byte[] ret = new byte[output.cbData]; Marshal.Copy(output.pbData, ret, 0, output.cbData); return(ret); } finally { if (input.pbData != IntPtr.Zero) { Marshal.FreeHGlobal(input.pbData); } if (entr.pbData != IntPtr.Zero) { Marshal.FreeHGlobal(entr.pbData); } if (output.pbData != IntPtr.Zero) { Marshal.FreeHGlobal(output.pbData); } } }
/// <summary> /// Imports a specified key. /// </summary> /// <param name="provider">The handle of the CSP.</param> /// <param name="algorithm">One of the <see cref="CryptoAlgorithm"/> values.</param> /// <param name="key">The key to import.</param> /// <returns>The handle of the symmetric key.</returns> /// <exception cref="SecurityException">An error occurs while importing the specified key.</exception> private int KeyFromBytes(int provider, CryptoAlgorithm algorithm, byte[] key) { int dwFlags = SecurityConstants.CRYPT_FIRST, dwSize, dwProvSessionKeySize = 0, dwPublicKeySize = 0, dwSessionBlob, offset = 0, hTempKey = 0, hSessionKey = 0; IntPtr algo = new IntPtr((int)algorithm), dwPrivKeyAlg = IntPtr.Zero, pbSessionBlob = IntPtr.Zero; IntPtr provEnum = IntPtr.Zero; try { // Double check to see if this provider supports this algorithm // and key size bool found = false; provEnum = Marshal.AllocHGlobal(84 + IntPtr.Size); do { dwSize = 84 + IntPtr.Size; if (SspiProvider.CryptGetProvParam(provider, SecurityConstants.PP_ENUMALGS_EX, provEnum, ref dwSize, dwFlags) == 0) { break; } dwFlags = 0; if (Marshal.ReadIntPtr(provEnum) == algo) { found = true; } } while (!found); if (!found) { throw new SecurityException("CSP does not support selected algorithm."); } // We have to get the key size(including padding) // from an HCRYPTKEY handle. PP_ENUMALGS_EX contains // the key size without the padding so we can't use it. if (SspiProvider.CryptGenKey(provider, algo, 0, ref hTempKey) == 0) { throw new SecurityException("Cannot generate temporary key."); } dwSize = 4; // sizeof(int) if (SspiProvider.CryptGetKeyParam(hTempKey, SecurityConstants.KP_KEYLEN, ref dwProvSessionKeySize, ref dwSize, 0) == 0) { throw new SecurityException("Cannot retrieve key parameters."); } // Our key is too big, leave if ((key.Length * 8) > dwProvSessionKeySize) { throw new SecurityException("Key too big."); } // Get private key's algorithm dwSize = IntPtr.Size; //sizeof(ALG_ID) if (SspiProvider.CryptGetKeyParam(m_ExponentOfOne, SecurityConstants.KP_ALGID, ref dwPrivKeyAlg, ref dwSize, 0) == 0) { throw new SecurityException("Unable to get the private key's algorithm."); } // Get private key's length in bits dwSize = 4; // sizeof(DWORD) if (SspiProvider.CryptGetKeyParam(m_ExponentOfOne, SecurityConstants.KP_KEYLEN, ref dwPublicKeySize, ref dwSize, 0) == 0) { throw new SecurityException("Unable to get the key length."); } // calculate Simple blob's length dwSessionBlob = (dwPublicKeySize / 8) + IntPtr.Size /*sizeof(ALG_ID)*/ + 4 + IntPtr.Size /*sizeof(BLOBHEADER)*/; // allocate simple blob buffer pbSessionBlob = Marshal.AllocHGlobal(dwSessionBlob); // SIMPLEBLOB Format is documented in SDK // Copy header to buffer PUBLICKEYSTRUC pks = new PUBLICKEYSTRUC(); pks.bType = SecurityConstants.SIMPLEBLOB; pks.bVersion = 2; pks.reserved = 0; pks.aiKeyAlg = algo; Marshal.StructureToPtr(pks, pbSessionBlob, false); Marshal.WriteIntPtr(pbSessionBlob, offset = Marshal.SizeOf(pks), dwPrivKeyAlg); offset += IntPtr.Size; // sizeof(ALG_ID) // Place the key material in reverse order for (int i = 0; i < key.Length; i++) { Marshal.WriteByte(pbSessionBlob, offset + key.Length - i - 1, key[i]); } // 3 is for the first reserved byte after the key material + the 2 reserved bytes at the end. dwSize = dwSessionBlob - (IntPtr.Size /*sizeof(ALG_ID)*/ + IntPtr.Size + 4 /*sizeof(BLOBHEADER)*/ + key.Length + 3); offset += key.Length + 1; // Generate random data for the rest of the buffer // (except that last two bytes) if (SspiProvider.CryptGenRandom(provider, dwSize, new IntPtr(pbSessionBlob.ToInt64() + offset)) == 0) { throw new SecurityException("Could not generate random data."); } for (int i = 0; i < dwSize; i++) { if (Marshal.ReadByte(pbSessionBlob, offset) == 0) { Marshal.WriteByte(pbSessionBlob, offset, 1); } offset++; } Marshal.WriteByte(pbSessionBlob, dwSessionBlob - 2, 2); if (SspiProvider.CryptImportKey(provider, pbSessionBlob, dwSessionBlob, m_ExponentOfOne, SecurityConstants.CRYPT_EXPORTABLE, ref hSessionKey) == 0) { throw new SecurityException("Cannot import key [key has right size?]."); } } finally { if (provEnum != IntPtr.Zero) { Marshal.FreeHGlobal(provEnum); } if (hTempKey != 0) { SspiProvider.CryptDestroyKey(hTempKey); } if (pbSessionBlob != IntPtr.Zero) { Marshal.FreeHGlobal(pbSessionBlob); } } return(hSessionKey); }