private static extern bool CreateDeltaB( DeltaFileType fileTypeSet, // File type set. DeltaFlag setFlags, // Set these flags. DeltaFlag resetFlags, // Reset (suppress) these flags. DeltaInput source, // Source memory block. DeltaInput target, // Target memory block. DeltaInput sourceOptions, // Memory block with source-specific options. DeltaInput targetOptions, // Memory block with target-specific options. DeltaInput globalOptions, // Memory block with global options. IntPtr targetFileTime, // Target file time to use, null to use current time. (need this overload because the compiler can't convert from "null" to "ref FILETIME") AlgId hashAlgId, out DeltaOutput delta);
private static extern bool CreateDeltaB( DeltaFileType fileTypeSet, // File type set. DeltaFlag setFlags, // Set these flags. DeltaFlag resetFlags, // Reset (suppress) these flags. DeltaInput source, // Source memory block. DeltaInput target, // Target memory block. DeltaInput sourceOptions, // Memory block with source-specific options. DeltaInput targetOptions, // Memory block with target-specific options. DeltaInput globalOptions, // Memory block with global options. ref System.Runtime.InteropServices.ComTypes.FILETIME targetFileTime, // Target file time to use, null to use current time. AlgId hashAlgId, out DeltaOutput delta);
// // This returns an allocated native memory block. Its lifetime (and that of any allocated subblocks it may point to) is that of "hb". // private static CMSG_RECIPIENT_ENCODE_INFO EncodeRecipientInfo(CmsRecipient recipient, AlgorithmIdentifier contentEncryptionAlgorithm, HeapBlockRetainer hb) { CMsgCmsRecipientChoice recipientChoice; string keyAlgorithmOid = recipient.Certificate.GetKeyAlgorithm(); AlgId algId = keyAlgorithmOid.ToAlgId(); switch (algId) { case AlgId.CALG_RSA_KEYX: recipientChoice = CMsgCmsRecipientChoice.CMSG_KEY_TRANS_RECIPIENT; break; case AlgId.CALG_DH_SF: case AlgId.CALG_DH_EPHEM: recipientChoice = CMsgCmsRecipientChoice.CMSG_KEY_AGREE_RECIPIENT; break; default: throw ErrorCode.CRYPT_E_UNKNOWN_ALGO.ToCryptographicException(); } CMSG_RECIPIENT_ENCODE_INFO recipientEncodeInfo; recipientEncodeInfo.dwRecipientChoice = recipientChoice; unsafe { switch (recipientChoice) { case CMsgCmsRecipientChoice.CMSG_KEY_TRANS_RECIPIENT: recipientEncodeInfo.pCmsRecipientEncodeInfo = (IntPtr)EncodeKeyTransRecipientInfo(recipient, hb); break; case CMsgCmsRecipientChoice.CMSG_KEY_AGREE_RECIPIENT: recipientEncodeInfo.pCmsRecipientEncodeInfo = (IntPtr)EncodeKeyAgreeRecipientInfo(recipient, contentEncryptionAlgorithm, hb); break; default: throw ErrorCode.CRYPT_E_UNKNOWN_ALGO.ToCryptographicException(); } } return(recipientEncodeInfo); }
static string AlgIdToJwsAlgId(AlgId algId) { if (algId == AlgId.CALG_SHA_256) { return("RS256"); } if (algId == AlgId.CALG_SHA_384) { return("RS384"); } if (algId == AlgId.CALG_SHA_512) { return("RS512"); } Console.Error.WriteLine("Only sha256, sha384, and sha512 is supported by Azure Key Vault signing"); return(null); }
public static int AuthenticodeDigestSign([In] IntPtr pSignerCert, [In] ref CRYPT_ATTR_BLOB pMetadataBlob, [In] AlgId digestAlgID, [In][MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] byte[] pbToBeSignedDigest, [In] int cbToBeSignedDigest, [Out] out CRYPT_ATTR_BLOB pSignedDigest ) { pSignedDigest = default; try { // var signerCert = new X509Certificate2(pSignerCert); var accessToken = Environment.GetEnvironmentVariable("KEYVAULT_ACCESSTOKEN"); var keyIdentifier = Environment.GetEnvironmentVariable("KEYVAULT_KEY_IDENTIFIER"); HookAssemblyLoad(); var kvalg = AlgIdToJwsAlgId(digestAlgID); if (kvalg == null) { return(-1); } var signed = SignWithKeyVault(keyIdentifier, accessToken, pbToBeSignedDigest, kvalg).Result; var buffer = Marshal.AllocHGlobal(signed.Length); Marshal.Copy(signed, 0, buffer, signed.Length); pSignedDigest = new CRYPT_ATTR_BLOB { pbData = buffer, cbData = signed.Length }; } catch (Exception e) { Console.Error.WriteLine(e.Message); return(Marshal.GetHRForException(e)); } return(0); }
// // This returns an allocated native memory block. Its lifetime (and that of any allocated subblocks it may point to) is that of "hb". // private static IntPtr GenerateEncryptionAuxInfoIfNeeded(AlgorithmIdentifier contentEncryptionAlgorithm, HeapBlockRetainer hb) { string algorithmOidValue = contentEncryptionAlgorithm.Oid.Value; AlgId algId = algorithmOidValue.ToAlgId(); if (!(algId == AlgId.CALG_RC2 || algId == AlgId.CALG_RC4)) { return(IntPtr.Zero); } unsafe { CMSG_RC2_AUX_INFO *pRc2AuxInfo = (CMSG_RC2_AUX_INFO *)(hb.Alloc(sizeof(CMSG_RC2_AUX_INFO))); pRc2AuxInfo->cbSize = sizeof(CMSG_RC2_AUX_INFO); pRc2AuxInfo->dwBitLen = contentEncryptionAlgorithm.KeyLength; if (pRc2AuxInfo->dwBitLen == 0) { // Desktop compat: If the caller didn't set the KeyLength property, set dwBitLength to the maxmium key length supported by RC2/RC4. The desktop queries CAPI for this but // since that requires us to use a prohibited api (CryptAcquireContext), we'll just hardcode what CAPI returns for RC2 and RC4. pRc2AuxInfo->dwBitLen = KeyLengths.DefaultKeyLengthForRc2AndRc4; } return((IntPtr)pRc2AuxInfo); } }
public static AlgorithmIdentifier ToAlgorithmIdentifier(this CRYPT_ALGORITHM_IDENTIFIER cryptAlgorithmIdentifer) { string oidValue = cryptAlgorithmIdentifer.pszObjId.ToStringAnsi(); AlgId algId = oidValue.ToAlgId(); int keyLength; switch (algId) { case AlgId.CALG_RC2: { if (cryptAlgorithmIdentifer.Parameters.cbData == 0) { keyLength = 0; } else { CRYPT_RC2_CBC_PARAMETERS rc2Parameters; unsafe { int cbSize = sizeof(CRYPT_RC2_CBC_PARAMETERS); if (!Interop.Crypt32.CryptDecodeObject(CryptDecodeObjectStructType.PKCS_RC2_CBC_PARAMETERS, cryptAlgorithmIdentifer.Parameters.pbData, (int)(cryptAlgorithmIdentifer.Parameters.cbData), &rc2Parameters, ref cbSize)) { throw Interop.CPError.GetLastWin32Error().ToCryptographicException(); } } switch (rc2Parameters.dwVersion) { case CryptRc2Version.CRYPT_RC2_40BIT_VERSION: keyLength = KeyLengths.Rc2_40Bit; break; case CryptRc2Version.CRYPT_RC2_56BIT_VERSION: keyLength = KeyLengths.Rc2_56Bit; break; case CryptRc2Version.CRYPT_RC2_64BIT_VERSION: keyLength = KeyLengths.Rc2_64Bit; break; case CryptRc2Version.CRYPT_RC2_128BIT_VERSION: keyLength = KeyLengths.Rc2_128Bit; break; default: keyLength = 0; break; } } break; } case AlgId.CALG_RC4: { int saltLength = 0; if (cryptAlgorithmIdentifer.Parameters.cbData != 0) { using (SafeHandle sh = Interop.Crypt32.CryptDecodeObjectToMemory(CryptDecodeObjectStructType.X509_OCTET_STRING, cryptAlgorithmIdentifer.Parameters.pbData, (int)cryptAlgorithmIdentifer.Parameters.cbData)) { unsafe { DATA_BLOB *pDataBlob = (DATA_BLOB *)(sh.DangerousGetHandle()); saltLength = (int)(pDataBlob->cbData); } } } // For RC4, keyLength = 128 - (salt length * 8). keyLength = KeyLengths.Rc4Max_128Bit - saltLength * 8; break; } case AlgId.CALG_DES: // DES key length is fixed at 64 (or 56 without the parity bits). keyLength = KeyLengths.Des_64Bit; break; case AlgId.CALG_3DES: // 3DES key length is fixed at 192 (or 168 without the parity bits). keyLength = KeyLengths.TripleDes_192Bit; break; default: // We've exhausted all the algorithm types that the desktop used to set the KeyLength for. Key lengths are not a viable way of // identifying algorithms in the long run so we will not extend this list any further. keyLength = 0; break; } AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Oid.FromOidValue(oidValue, OidGroup.All), keyLength); switch (oidValue) { case Oids.RsaOaep: algorithmIdentifier.Parameters = cryptAlgorithmIdentifer.Parameters.ToByteArray(); break; } return(algorithmIdentifier); }
internal static extern bool CryptGenKey(IntPtr hProv, AlgId Algid, int dwFlags, ref IntPtr phKey);
internal static extern bool CryptCreateHash(IntPtr hProv, AlgId algId, IntPtr hKey, uint dwFlags, ref IntPtr phHash);
// // This returns an allocated native memory block. Its lifetime (and that of any allocated subblocks it may point to) is that of "hb". // private static unsafe CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO *EncodeKeyAgreeRecipientInfo(CmsRecipient recipient, AlgorithmIdentifier contentEncryptionAlgorithm, HeapBlockRetainer hb) { // "recipient" is a deep-cloned CmsRecipient object whose lifetime this class controls. Because of this, we can pull out the CERT_CONTEXT* and CERT_INFO* pointers without // bringing in all the SafeCertContextHandle machinery, and embed pointers to them in the memory block we return. Yes, this code is scary. using (SafeCertContextHandle hCertContext = recipient.Certificate.CreateCertContextHandle()) { CERT_CONTEXT *pCertContext = hCertContext.DangerousGetCertContext(); CERT_INFO * pCertInfo = pCertContext->pCertInfo; CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO *pEncodeInfo = (CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO *)(hb.Alloc(sizeof(CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO))); pEncodeInfo->cbSize = sizeof(CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO); pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.Esdh); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = 0; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = IntPtr.Zero; pEncodeInfo->pvKeyEncryptionAuxInfo = null; string oidValue; AlgId algId = contentEncryptionAlgorithm.Oid.Value.ToAlgId(); if (algId == AlgId.CALG_RC2) { oidValue = Oids.CmsRc2Wrap; } else { oidValue = Oids.Cms3DesWrap; } pEncodeInfo->KeyWrapAlgorithm.pszObjId = hb.AllocAsciiString(oidValue); pEncodeInfo->KeyWrapAlgorithm.Parameters.cbData = 0; pEncodeInfo->KeyWrapAlgorithm.Parameters.pbData = IntPtr.Zero; pEncodeInfo->pvKeyWrapAuxInfo = GenerateEncryptionAuxInfoIfNeeded(contentEncryptionAlgorithm, hb); pEncodeInfo->hCryptProv = IntPtr.Zero; pEncodeInfo->dwKeySpec = 0; pEncodeInfo->dwKeyChoice = CmsKeyAgreeKeyChoice.CMSG_KEY_AGREE_EPHEMERAL_KEY_CHOICE; pEncodeInfo->pEphemeralAlgorithm = (CRYPT_ALGORITHM_IDENTIFIER *)(hb.Alloc(sizeof(CRYPT_ALGORITHM_IDENTIFIER))); *(pEncodeInfo->pEphemeralAlgorithm) = pCertInfo->SubjectPublicKeyInfo.Algorithm; pEncodeInfo->UserKeyingMaterial.cbData = 0; pEncodeInfo->UserKeyingMaterial.pbData = IntPtr.Zero; CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO *pEncryptedKey = (CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO *)(hb.Alloc(sizeof(CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO))); pEncryptedKey->cbSize = sizeof(CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO); pEncryptedKey->RecipientPublicKey = pCertInfo->SubjectPublicKeyInfo.PublicKey; pEncryptedKey->RecipientId = EncodeRecipientId(recipient, hCertContext, pCertContext, pCertInfo, hb); pEncryptedKey->Date = default(FILETIME); pEncryptedKey->pOtherAttr = null; CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO **ppEncryptedKey = (CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO **)(hb.Alloc(sizeof(CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO *))); ppEncryptedKey[0] = pEncryptedKey; pEncodeInfo->cRecipientEncryptedKeys = 1; pEncodeInfo->rgpRecipientEncryptedKeys = ppEncryptedKey; return(pEncodeInfo); } }
internal byte[] DecryptInternal(string password, byte[] encryptionInfo, byte[] encryptedPackage) { #region Parse the encryption info data using (System.IO.MemoryStream ms = new System.IO.MemoryStream(encryptionInfo)) { System.IO.BinaryReader reader = new System.IO.BinaryReader(ms); versionMajor = reader.ReadUInt16(); versionMinor = reader.ReadUInt16(); encryptionFlags = (EncryptionFlags)reader.ReadUInt32(); if (encryptionFlags == EncryptionFlags.fExternal) throw new Exception("An external cryptographic provider is not supported"); // Encryption header uint headerLength = reader.ReadUInt32(); int skipFlags = reader.ReadInt32(); headerLength -= 4; sizeExtra = reader.ReadUInt32(); headerLength -= 4; algId = (AlgId)reader.ReadUInt32(); headerLength -= 4; algHashId = (AlgHashId)reader.ReadUInt32(); headerLength -= 4; keySize = reader.ReadInt32(); headerLength -= 4; providerType = (ProviderType)reader.ReadUInt32(); headerLength -= 4; reader.ReadUInt32(); headerLength -= 4; // Reserved 1 reader.ReadUInt32(); headerLength -= 4; // Reserved 2 CSPName = System.Text.UnicodeEncoding.Unicode.GetString(reader.ReadBytes((int)headerLength)); // Encryption verifier saltSize = reader.ReadInt32(); salt = reader.ReadBytes(saltSize); encryptedVerifier = reader.ReadBytes(0x10); verifierHashSize = reader.ReadInt32(); encryptedVerifierHash = reader.ReadBytes(providerType == ProviderType.RC4 ? 0x14 : 0x20); } #endregion #region Encryption key generation Console.WriteLine("Encryption key generation"); byte[] encryptionKey = GeneratePasswordHashUsingSHA1(password); if (encryptionKey == null) return null; #endregion #region Password verification Console.WriteLine("Password verification"); if (PasswordVerifier(encryptionKey)) { Console.WriteLine("Password verification succeeded"); } else { Console.WriteLine("Password verification failed"); throw new InvalidPasswordException("The password is not valid"); } #endregion #region Decrypt // First 8 bytes hold the size of the stream long length = BitConverter.ToInt64(encryptedPackage, 0); // Decrypt the stream using the generated and validated key Console.WriteLine("Decrypt the stream using the generated and validated key"); encryptedPackage = AESDecrypt(encryptedPackage, 8, encryptedPackage.Length-8, encryptionKey); // !! IMPORTANT !! Make sure the final array is the correct size // Failure to do this will cause an error when the decrypted stream // is opened by the System.IO.Packaging.Package.Open() method. byte[] result = encryptedPackage; if (encryptedPackage.Length > length) { result = new byte[length]; Array.Copy(encryptedPackage, result, result.Length); } //using (System.IO.FileStream fs = new System.IO.FileStream(@"c:\x.zip", System.IO.FileMode.Create)) //{ // fs.Write(result, 0, result.Length); //} return result; #endregion }
public byte[] SignHash(byte[] rgbHash, AlgId hashType) { if (rgbHash == null) { throw new ArgumentNullException("rgbHash"); } if (this.rsaCertificate == null) { throw new NullReferenceException("Certificate can't be null."); } IntPtr pCertContext = rsaCertificate.Handle; IntPtr hCryptProv = IntPtr.Zero; uint keySpec = 0; bool freeProv = false; bool result = NativeMethods.CryptAcquireCertificatePrivateKey( pCertContext, (uint)CryptAcquireContextTypes.CRYPT_SILENT, IntPtr.Zero, out hCryptProv, out keySpec, out freeProv); if (!result) { throw new SEHException("Fail to invoke CryptAcquireCertificatePrivateKey failed."); } IntPtr hHashSend = IntPtr.Zero; IntPtr hHash = IntPtr.Zero; result = NativeMethods.CryptCreateHash(hCryptProv, hashType, IntPtr.Zero, 0, ref hHash); if (!result) { NativeMethods.CryptReleaseContext(hCryptProv, 0); throw new SEHException("Fail to invoke CryptCreateHash failed."); } hHashSend = Marshal.AllocHGlobal(rgbHash.Length); Marshal.Copy(rgbHash, 0, hHashSend, rgbHash.Length); result = NativeMethods.CryptSetHashParam(hHash, HashParameters.HP_HASHVAL, hHashSend, 0); if (!result) { NativeMethods.CryptReleaseContext(hCryptProv, 0); Marshal.FreeHGlobal(hHashSend); NativeMethods.CryptDestroyHash(hHash); throw new SEHException("Fail to invoke CryptSetHashParam failed."); } IntPtr pbSignature = IntPtr.Zero; uint signatureSize = 0; result = NativeMethods.CryptSignHash(hHash, NativeMethods.AT_SIGNATURE, IntPtr.Zero, this.flags, IntPtr.Zero, ref signatureSize); if (!result) { NativeMethods.CryptReleaseContext(hCryptProv, 0); Marshal.FreeHGlobal(hHashSend); NativeMethods.CryptDestroyHash(hHash); throw new SEHException("Fail to invoke CryptSignHash failed."); } pbSignature = Marshal.AllocHGlobal((int)signatureSize); result = NativeMethods.CryptSignHash(hHash, NativeMethods.AT_SIGNATURE, IntPtr.Zero, this.flags, pbSignature, ref signatureSize); if (!result) { Marshal.FreeHGlobal(pbSignature); NativeMethods.CryptReleaseContext(hCryptProv, 0); Marshal.FreeHGlobal(hHashSend); NativeMethods.CryptDestroyHash(hHash); throw new SEHException("Fail to invoke CryptSignHash failed."); } byte[] signature = new byte[signatureSize]; Marshal.Copy(pbSignature, signature, 0, signature.Length); //The byte order of signature should be reversed, don't know the reason. Array.Reverse(signature); Marshal.FreeHGlobal(pbSignature); Marshal.FreeHGlobal(hHashSend); NativeMethods.CryptReleaseContext(hCryptProv, 0); NativeMethods.CryptDestroyHash(hHash); return(signature); }
internal byte[] DecryptInternal(string password, byte[] encryptionInfo, byte[] encryptedPackage) { #region Parse the encryption info data using (System.IO.MemoryStream ms = new System.IO.MemoryStream(encryptionInfo)) { System.IO.BinaryReader reader = new System.IO.BinaryReader(ms); versionMajor = reader.ReadUInt16(); versionMinor = reader.ReadUInt16(); encryptionFlags = (EncryptionFlags)reader.ReadUInt32(); if (encryptionFlags == EncryptionFlags.fExternal) { throw new Exception("An external cryptographic provider is not supported"); } // Encryption header uint headerLength = reader.ReadUInt32(); int skipFlags = reader.ReadInt32(); headerLength -= 4; sizeExtra = reader.ReadUInt32(); headerLength -= 4; algId = (AlgId)reader.ReadUInt32(); headerLength -= 4; algHashId = (AlgHashId)reader.ReadUInt32(); headerLength -= 4; keySize = reader.ReadInt32(); headerLength -= 4; providerType = (ProviderType)reader.ReadUInt32(); headerLength -= 4; reader.ReadUInt32(); headerLength -= 4; // Reserved 1 reader.ReadUInt32(); headerLength -= 4; // Reserved 2 CSPName = System.Text.UnicodeEncoding.Unicode.GetString(reader.ReadBytes((int)headerLength)); // Encryption verifier saltSize = reader.ReadInt32(); salt = reader.ReadBytes(saltSize); encryptedVerifier = reader.ReadBytes(0x10); verifierHashSize = reader.ReadInt32(); encryptedVerifierHash = reader.ReadBytes(providerType == ProviderType.RC4 ? 0x14 : 0x20); } #endregion #region Encryption key generation Console.WriteLine("Encryption key generation"); byte[] encryptionKey = GeneratePasswordHashUsingSHA1(password); if (encryptionKey == null) { return(null); } #endregion #region Password verification Console.WriteLine("Password verification"); if (PasswordVerifier(encryptionKey)) { Console.WriteLine("Password verification succeeded"); } else { Console.WriteLine("Password verification failed"); throw new InvalidPasswordException("The password is not valid"); } #endregion #region Decrypt // First 8 bytes hold the size of the stream long length = BitConverter.ToInt64(encryptedPackage, 0); // Decrypt the stream using the generated and validated key Console.WriteLine("Decrypt the stream using the generated and validated key"); encryptedPackage = AESDecrypt(encryptedPackage, 8, encryptedPackage.Length - 8, encryptionKey); // !! IMPORTANT !! Make sure the final array is the correct size // Failure to do this will cause an error when the decrypted stream // is opened by the System.IO.Packaging.Package.Open() method. byte[] result = encryptedPackage; if (encryptedPackage.Length > length) { result = new byte[length]; Array.Copy(encryptedPackage, result, result.Length); } //using (System.IO.FileStream fs = new System.IO.FileStream(@"c:\x.zip", System.IO.FileMode.Create)) //{ // fs.Write(result, 0, result.Length); //} return(result); #endregion }
public byte[] SignHash(byte[] rgbHash, AlgId hashType) { if (rgbHash == null) { throw new ArgumentNullException("rgbHash"); } if (this.rsaCertificate == null) { throw new NullReferenceException("Certificate can't be null."); } IntPtr pCertContext = rsaCertificate.Handle; IntPtr hCryptProv = IntPtr.Zero; uint keySpec = 0; bool freeProv = false; bool result = NativeMethods.CryptAcquireCertificatePrivateKey( pCertContext, (uint)CryptAcquireContextTypes.CRYPT_SILENT, IntPtr.Zero, out hCryptProv, out keySpec, out freeProv); if (!result) { throw new SEHException("Fail to invoke CryptAcquireCertificatePrivateKey failed."); } IntPtr hHashSend = IntPtr.Zero; IntPtr hHash = IntPtr.Zero; result = NativeMethods.CryptCreateHash(hCryptProv, hashType, IntPtr.Zero, 0, ref hHash); if (!result) { NativeMethods.CryptReleaseContext(hCryptProv, 0); throw new SEHException("Fail to invoke CryptCreateHash failed."); } hHashSend = Marshal.AllocHGlobal(rgbHash.Length); Marshal.Copy(rgbHash, 0, hHashSend, rgbHash.Length); result = NativeMethods.CryptSetHashParam(hHash, HashParameters.HP_HASHVAL, hHashSend, 0); if (!result) { NativeMethods.CryptReleaseContext(hCryptProv, 0); Marshal.FreeHGlobal(hHashSend); NativeMethods.CryptDestroyHash(hHash); throw new SEHException("Fail to invoke CryptSetHashParam failed."); } IntPtr pbSignature = IntPtr.Zero; uint signatureSize = 0; result = NativeMethods.CryptSignHash(hHash, NativeMethods.AT_SIGNATURE, IntPtr.Zero, this.flags, IntPtr.Zero, ref signatureSize); if (!result) { NativeMethods.CryptReleaseContext(hCryptProv, 0); Marshal.FreeHGlobal(hHashSend); NativeMethods.CryptDestroyHash(hHash); throw new SEHException("Fail to invoke CryptSignHash failed."); } pbSignature = Marshal.AllocHGlobal((int)signatureSize); result = NativeMethods.CryptSignHash(hHash, NativeMethods.AT_SIGNATURE, IntPtr.Zero, this.flags, pbSignature, ref signatureSize); if (!result) { Marshal.FreeHGlobal(pbSignature); NativeMethods.CryptReleaseContext(hCryptProv, 0); Marshal.FreeHGlobal(hHashSend); NativeMethods.CryptDestroyHash(hHash); throw new SEHException("Fail to invoke CryptSignHash failed."); } byte[] signature = new byte[signatureSize]; Marshal.Copy(pbSignature, signature, 0, signature.Length); //The byte order of signature should be reversed, don't know the reason. Array.Reverse(signature); Marshal.FreeHGlobal(pbSignature); Marshal.FreeHGlobal(hHashSend); NativeMethods.CryptReleaseContext(hCryptProv, 0); NativeMethods.CryptDestroyHash(hHash); return signature; }