2

我正在使用以下方法解码文件:

string outFileName = zfoFileName.Replace(".zfo", "_tmp.zfo");
FileStream inFile = null;
FileStream outFile = null;
inFile = File.Open(zfoFileName, FileMode.Open);
outFile = File.Create(outFileName);
LargeCMS.CMS cms = new LargeCMS.CMS();
cms.Decode(inFile, outFile);

这在我的 Win 7 开发机器上运行良好,但在 Windows 2003 服务器生产机器上它失败,并出现以下异常:

异常:System.Exception:CryptMsgUpdate 错误 #-2146893816 ---> System.ComponentModel.Win32Exception:指定的算法无效---内部异常堆栈跟踪结束---在 LargeCMS.CMS.Decode(FileStream inFile,FileStream outFile)

下面是我调用来进行解码的类,如果需要,我可以上传一个示例文件进行解码,奇怪的是它在 Win 7 上工作,而不是在 Win2k3 服务器上:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace LargeCMS
{
    class CMS
    {
        // File stream to use in callback function
        private FileStream m_callbackFile;

        // Streaming callback function for encoding
        private Boolean StreamOutputCallback(IntPtr pvArg, IntPtr pbData, int cbData, Boolean fFinal)
        {
            // Write all bytes to encoded file
            Byte[] bytes = new Byte[cbData];
            Marshal.Copy(pbData, bytes, 0, cbData);
            m_callbackFile.Write(bytes, 0, cbData);

            if (fFinal)
            {
                // This is the last piece. Close the file
                m_callbackFile.Flush();
                m_callbackFile.Close();
                m_callbackFile = null;
            }

            return true;
        }



        // Decode CMS with streaming to support large data
        public void Decode(FileStream inFile, FileStream outFile)
        {
            // Variables
            Win32.CMSG_STREAM_INFO StreamInfo;
            Win32.CERT_CONTEXT SignerCertContext;

            BinaryReader stream = null;
            GCHandle gchandle = new GCHandle();

            IntPtr hMsg = IntPtr.Zero;
            IntPtr pSignerCertInfo = IntPtr.Zero;
            IntPtr pSignerCertContext = IntPtr.Zero;
            IntPtr pbPtr = IntPtr.Zero;
            IntPtr hStore = IntPtr.Zero;
            Byte[] pbData;
            Boolean bResult = false;
            int dwFileSize;
            int dwRemaining;
            int dwSize;
            int cbSignerCertInfo;

            try
            {
                // Get data to decode
                dwFileSize = (int)inFile.Length;
                stream = new BinaryReader(inFile);
                pbData = stream.ReadBytes(dwFileSize);

                // Prepare stream for decoded info
                m_callbackFile = outFile;

                // Populate Stream Info struct
                StreamInfo = new Win32.CMSG_STREAM_INFO();
                StreamInfo.cbContent = dwFileSize;
                StreamInfo.pfnStreamOutput = new Win32.StreamOutputCallbackDelegate(StreamOutputCallback);

                // Open message to decode
                hMsg = Win32.CryptMsgOpenToDecode(
                    Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                    0,
                    0,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    ref StreamInfo
                );
                if (hMsg.Equals(IntPtr.Zero))
                {
                    throw new Exception("CryptMsgOpenToDecode error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                }

                // Process the whole message
                gchandle = GCHandle.Alloc(pbData, GCHandleType.Pinned);
                pbPtr = gchandle.AddrOfPinnedObject();
                dwRemaining = dwFileSize;
                dwSize = (dwFileSize < 1024 * 1000 * 100) ? dwFileSize : 1024 * 1000 * 100;
                while (dwRemaining > 0)
                {
                    // Update message piece by piece     
                    bResult = Win32.CryptMsgUpdate(
                        hMsg,
                        pbPtr,
                        dwSize,
                        (dwRemaining <= dwSize) ? true : false
                    );
                    if (!bResult)
                    {
                        throw new Exception("CryptMsgUpdate error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                    }

                    // Move to the next piece
                    pbPtr = new IntPtr(pbPtr.ToInt64() + dwSize);
                    dwRemaining -= dwSize;
                    if (dwRemaining < dwSize)
                    {
                        dwSize = dwRemaining;
                    }
                }

                // Get signer certificate info
                cbSignerCertInfo = 0;
                bResult = Win32.CryptMsgGetParam(
                    hMsg,
                    Win32.CMSG_SIGNER_CERT_INFO_PARAM,
                    0,
                    IntPtr.Zero,
                    ref cbSignerCertInfo
                );
                if (!bResult)
                {
                    throw new Exception("CryptMsgGetParam error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                }

                pSignerCertInfo = Marshal.AllocHGlobal(cbSignerCertInfo);

                bResult = Win32.CryptMsgGetParam(
                    hMsg,
                    Win32.CMSG_SIGNER_CERT_INFO_PARAM,
                    0,
                    pSignerCertInfo,
                    ref cbSignerCertInfo
                );
                if (!bResult)
                {
                    throw new Exception("CryptMsgGetParam error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                }

                // Open a cert store in memory with the certs from the message
                hStore = Win32.CertOpenStore(
                    Win32.CERT_STORE_PROV_MSG,
                    Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                    IntPtr.Zero,
                    0,
                    hMsg
                );
                if (hStore.Equals(IntPtr.Zero))
                {
                    throw new Exception("CertOpenStore error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                }

                // Find the signer's cert in the store
                pSignerCertContext = Win32.CertGetSubjectCertificateFromStore(
                    hStore,
                    Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                    pSignerCertInfo
                );
                if (pSignerCertContext.Equals(IntPtr.Zero))
                {
                    throw new Exception("CertGetSubjectCertificateFromStore error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                }

                // Set message for verifying
                SignerCertContext = (Win32.CERT_CONTEXT)Marshal.PtrToStructure(pSignerCertContext, typeof(Win32.CERT_CONTEXT));
                bResult = Win32.CryptMsgControl(
                    hMsg,
                    0,
                    Win32.CMSG_CTRL_VERIFY_SIGNATURE,
                    SignerCertContext.pCertInfo
                );
                if (!bResult)
                {
                    throw new Exception("CryptMsgControl error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                }
            }
            finally
            {
                // Clean up
                if (gchandle.IsAllocated)
                {
                    gchandle.Free();
                }
                if (!pSignerCertContext.Equals(IntPtr.Zero))
                {
                    Win32.CertFreeCertificateContext(pSignerCertContext);
                }
                if (!pSignerCertInfo.Equals(IntPtr.Zero))
                {
                    Marshal.FreeHGlobal(pSignerCertInfo);
                }
                if (!hStore.Equals(IntPtr.Zero))
                {
                    Win32.CertCloseStore(hStore, Win32.CERT_CLOSE_STORE_FORCE_FLAG);
                }
                if (stream != null)
                {
                    stream.Close();
                }
                if (m_callbackFile != null)
                {
                    m_callbackFile.Close();
                }
                if (!hMsg.Equals(IntPtr.Zero))
                {
                    Win32.CryptMsgClose(hMsg);
                }
            }
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.ComponentModel;
using System.Security.Cryptography;

namespace LargeCMS
{
    class Win32
    {
        #region "CONSTS"

        public const int X509_ASN_ENCODING = 0x00000001;
        public const int PKCS_7_ASN_ENCODING = 0x00010000;
        public const int CMSG_SIGNED = 2;
        public const int CMSG_DETACHED_FLAG = 0x00000004;
        public const int AT_KEYEXCHANGE = 1;
        public const int AT_SIGNATURE = 2;
        public const String szOID_OIWSEC_sha1 = "1.3.14.3.2.26";
        public const int CMSG_CTRL_VERIFY_SIGNATURE = 1;
        public const int CMSG_CERT_PARAM = 12;
        public const int CMSG_SIGNER_CERT_INFO_PARAM = 7;
        public const int CERT_STORE_PROV_MSG = 1;
        public const int CERT_CLOSE_STORE_FORCE_FLAG = 1;

        #endregion

        #region "STRUCTS"

        [StructLayout(LayoutKind.Sequential)]
        public struct CRYPT_ALGORITHM_IDENTIFIER
        {
            public String pszObjId;
            BLOB Parameters;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CERT_ID
        {
            public int dwIdChoice;
            public BLOB IssuerSerialNumberOrKeyIdOrHashId;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CMSG_SIGNER_ENCODE_INFO
        {
            public int cbSize;
            public IntPtr pCertInfo;
            public IntPtr hCryptProvOrhNCryptKey;
            public int dwKeySpec;
            public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
            public IntPtr pvHashAuxInfo;
            public int cAuthAttr;
            public IntPtr rgAuthAttr;
            public int cUnauthAttr;
            public IntPtr rgUnauthAttr;
            public CERT_ID SignerId;
            public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
            public IntPtr pvHashEncryptionAuxInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CERT_CONTEXT
        {
            public int dwCertEncodingType;
            public IntPtr pbCertEncoded;
            public int cbCertEncoded;
            public IntPtr pCertInfo;
            public IntPtr hCertStore;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct BLOB
        {
            public int cbData;
            public IntPtr pbData;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CMSG_SIGNED_ENCODE_INFO
        {
            public int cbSize;
            public int cSigners;
            public IntPtr rgSigners;
            public int cCertEncoded;
            public IntPtr rgCertEncoded;
            public int cCrlEncoded;
            public IntPtr rgCrlEncoded;
            public int cAttrCertEncoded;
            public IntPtr rgAttrCertEncoded;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CMSG_STREAM_INFO
        {
            public int cbContent;
            public StreamOutputCallbackDelegate pfnStreamOutput;
            public IntPtr pvArg;
        }

        #endregion

        #region "DELEGATES"

        public delegate Boolean StreamOutputCallbackDelegate(IntPtr pvArg, IntPtr pbData, int cbData, Boolean fFinal);

        #endregion

        #region "API"

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean CryptAcquireContext(
          ref IntPtr hProv,
          String pszContainer,
          String pszProvider,
          int dwProvType,
          int dwFlags
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern IntPtr CryptMsgOpenToEncode(
            int dwMsgEncodingType,
            int dwFlags,
            int dwMsgType,
            ref CMSG_SIGNED_ENCODE_INFO pvMsgEncodeInfo,
            String pszInnerContentObjID,
            ref CMSG_STREAM_INFO pStreamInfo
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern IntPtr CryptMsgOpenToDecode(
            int dwMsgEncodingType,
            int dwFlags,
            int dwMsgType,
            IntPtr hCryptProv,
            IntPtr pRecipientInfo,
            ref CMSG_STREAM_INFO pStreamInfo
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern Boolean CryptMsgClose(
            IntPtr hCryptMsg
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern Boolean CryptMsgUpdate(
            IntPtr hCryptMsg,
            Byte[] pbData,
            int cbData,
            Boolean fFinal
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern Boolean CryptMsgUpdate(
            IntPtr hCryptMsg,
            IntPtr pbData,
            int cbData,
            Boolean fFinal
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern Boolean CryptMsgGetParam(
            IntPtr hCryptMsg,
            int dwParamType,
            int dwIndex,
            IntPtr pvData,
            ref int pcbData
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern Boolean CryptMsgControl(
            IntPtr hCryptMsg,
            int dwFlags,
            int dwCtrlType,
            IntPtr pvCtrlPara
        );

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern Boolean CryptReleaseContext(
            IntPtr hProv,
            int dwFlags
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern IntPtr CertCreateCertificateContext(
            int dwCertEncodingType,
            IntPtr pbCertEncoded,
            int cbCertEncoded
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern Boolean CertFreeCertificateContext(
            IntPtr pCertContext
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern IntPtr CertOpenStore(
            int lpszStoreProvider,
            int dwMsgAndCertEncodingType,
            IntPtr hCryptProv,
            int dwFlags,
            IntPtr pvPara
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern IntPtr CertGetSubjectCertificateFromStore(
            IntPtr hCertStore,
            int dwCertEncodingType,
            IntPtr pCertId
        );

        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern IntPtr CertCloseStore(
            IntPtr hCertStore,
            int dwFlags
        );

        #endregion
    }
}
4

3 回答 3

3

会不会是你的Win2003上没有安装你使用的CSP?我记得读过 SP3 之前的 XP 在 SHA-2 或其他方面存在一些问题,而我认为 XP 和 Win2003 或多或少是相同的基本操作系统。

我想您可以看到以下注册表项
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults上安装了什么

也许你可以比较你的机器。

于 2010-04-21T20:11:47.297 回答
3

您能否提供有关您的环境的更多信息。首先:哪个Service Pack有Windows 2003 Server。例如,在 SP3 http://support.microsoft.com/kb/324953/en中修复了一个错误“Web 注册页面上的默认 Diffie-Hellman SChannel 证书选择导致错误:0x80090008 - NTE_BAD_ALGID” 。如果这不是您的问题,您应该将证书和带有测试消息的二进制文件放在网络上的某处,并在此处发布 URL。然后一个人将能够重现和测试问题。

我想,要解决您的问题(如果最后一个 Service Pack 安装在 Windows Server 2003 上),必须更改用于签署消息的证书的某些属性。

顺便说一句,我不认为您证书使用 SHA-2 算法(SHA-256、SHA-384 和 SHA-512)。如果您确实使用这个并安装了最后一个 Service Pack,则可能需要明确使用“Microsoft Enhanced RSA and AES Cryptographic Provider”(或“Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)”,因为它在 Windows 上被调用XP SP3) 或 PROV_RSA_AES 或 MS_ENH_RSA_AES_PROV 而不是默认的 PROV_RSA_FULL 提供程序。(例如,参见http://blogs.msdn.com/alejacma/archive/2009/01/23/sha-2-support-on-windows-xp.aspx

更新1: 收到您的测试文件后,问题更清楚了。首先是一个好消息。您的程序运行正确!它在我的带有 SP2 的测试 Windows 2003 服务器上运行没有任何问题。所以我们有管理问题,而不是软件开发。我建议您在另一台 Windows 2003 Server 上测试该程序。在此服务器上,您可以重新安装 SP2,然后转到 Microsoft 更新并安装所有更新。

顺便说一句,您对 SHA256 或其他 SHA-2 算法没有任何问题。您在示例中使用标准 1.2.840.113549.1.1.5 sha1RSA 算法。

现在关于你的程序。我详细阅读了您的代码并准确了解您的工作。您收到一条 PKCS#7 签名消息,其中包含一个文本块(一个 XML 文件)。我如何理解您的示例来自http://blogs.msdn.com/alejacma/archive/2010/04/09/how-to-call-cryptmsg-api-in-streaming-mode-c.aspx描述了问题解密大于 100MB 的文件(另请参见http://blogs.msdn.com/alejacma/archive/2010/03/17/asn1-value-too-large-error-when-calling-signedcms-computesignature.aspx)。如果您没有这种情况,我建议您使用 System.Security.Cryptography.Pkcs 命名空间中的 .NET 加密函数。如果您确实有大量数据,那么您当前的代码就可以了。唯一可疑的地方是读取输入文件。我不读stream.ReadBytes()称呼。我会使用更好的内存映射文件,而不是在内存中加载一个巨大的文件。要在本机代码中执行此操作,您可以使用如下代码

DWORD MapFileInMemory (IN LPCWSTR pszFileName,
                       OUT PBYTE *ppbyFile, OUT PDWORD pdwFileSizeLow, OUT PDWORD pdwFileSizeHigh)
{
    HANDLE hFile = INVALID_HANDLE_VALUE, hFileMapping = NULL;
    DWORD  dwStatus = (DWORD)E_UNEXPECTED;

    __try {
        // Open the input file to be encrypted or decrypted
        hFile = CreateFileW (pszFileName, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING,
                             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
        if (hFile == INVALID_HANDLE_VALUE) {
            dwStatus = GetLastError();
            __leave;
        }

        *pdwFileSizeLow = GetFileSize (hFile, pdwFileSizeHigh);
        if (*pdwFileSizeLow == INVALID_FILE_SIZE){
            dwStatus = GetLastError();
            __leave;
        }

        hFileMapping = CreateFileMapping (hFile, NULL, PAGE_READONLY, 0, 0, NULL);
        if (!hFileMapping){
            dwStatus = GetLastError();
            __leave;
        }

        *ppbyFile = (PBYTE) MapViewOfFile (hFileMapping, FILE_MAP_READ, 0, 0, 0);
        if (*ppbyFile == NULL) {
            dwStatus = GetLastError();
            __leave;
        }

        dwStatus = NO_ERROR;
    }
    __finally {
        if (hFileMapping)
            CloseHandle (hFileMapping);

        if (hFile != INVALID_HANDLE_VALUE)
            CloseHandle (hFile);
    }

    return dwStatus;
}

BOOL UnmapFileFromMemory (LPCVOID lpBaseAddress)
{
    return UnmapViewOfFile (lpBaseAddress);
}

编写相应的 .NET 代码将不成问题。使用 Memory Mapped Files 只创建一个到文件的虚拟地址映射,只有在访问相应部分数据时才会读取数据。

再说一句。您验证消息不完整的代码部分。您要做的是验证用于签名消息的证书。如果您使用本机CryptoAPI,则可以针对CertGetCertificateChain(). 只有这样,您才能确定证书及其所有父级都是有效的。您还应该验证CertVerifyCertificateChainPolicy()证书链是否允许使用证书对消息进行签名。

顺便说一下,当前代码可以在没有错误消息的情况下工作,但是签署消息的证书的颁发者是“CN=PostSignum Qualified CA, O="Ceská pošta, sp [IC 47114983]", C=CZ" 并且在您的内部消息证书不存在。您可以使用例如certutil.exe -dump 31602.zfo查看详细信息:

Missing Issuer: CN=PostSignum Qualified CA, O="Ceská pošta, s.p. [IC 47114983]", C=CZ
  Issuer: CN=PostSignum Qualified CA, O="Ceská pošta, s.p. [IC 47114983]", C=CZ
  NotBefore: 03.12.2009 11:23
  NotAfter: 03.12.2010 10:33
  Subject: SERIALNUMBER=S7464, CN=Informacní systém datových schránek - zkušební prostredí, O="Ceská pošta, s.p. [IC 47114983]", C=CZ
  Serial: 04d3c5
  SubjectAltName: RFC822 Name=postsignum@cpost.cz, Other Name:Description=13 00
  59 c7 20 ba 70 b1 e6 93 ea c4 83 4b 3c 1e 35 dc b9 15 f5 ff
A certificate chain could not be built to a trusted root authority. 0x800b010a (-2146762486)

可能您不想将任何已签名的消息解释为有效。证书的验证是强制性的。此外,在许多情况下,最好定义您希望允许签名消息作为输入的 Issuer 的来源范围。想想这个。

更新 2:您在新的 331879.zfo 文件中是正确的,您确实使用 sha256RSA (1.2.840.113549.1.1.11) 进行签名。尝试在http://thehotfixshare.net/board/index.php?showtopic=12629&hl=968730上安装我喜欢的http://support.microsoft.com/kb/968730/en。这是一个数字签名的文件。所以我一定是安全的。绝对确定您可以从 Microsoft 收到此修复程序。我希望这个修复能解决你的问题。

更新 3:我对您的代码示例进行了更多思考。在我看来,要获得最佳实现,您应该将消息解码的整个代码实现为非托管(本机)代码。因此,在解码大数据期间,您不会花费任何额外的时间在本机代码和托管代码之间进行封送处理。您应该将此本机代码放置在 DLL 中并导出可在主托管代码中使用的函数。

关于使用内存映射文件的另一句话。内存映射文件的使用主要是优化方式访问Windows 中的任何文件以进行读写。您必须知道的一件事是内存使用情况。如果您查看任务管理器的已用内存,您会发现程序使用的内存映射文件技术可以使用非常大的内存。这根本不是问题。该内存不是物理内存,也不是来自分页文件的分页内存。虚拟地址将直接映射到您在内存中映射的文件。因此,数据分页将针对文件数据本身进行。不需要操作系统页面文件的附加部分。该文件中的 I/O 已针对相应的嵌入式处理器特性进行了优化和实现。

最终解决方案:因为我无法停止思考这个问题,所以我不得不解决它。这是基于我之前写过的完整解决方案。

public const int PROV_RSA_AES = 24;
public const String MS_ENH_RSA_AES_PROV =
    "Microsoft Enhanced RSA and AES Cryptographic Provider";
public const String MS_ENH_RSA_AES_PROV_XP =
    "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)";
public const int CRYPT_VERIFYCONTEXT = unchecked((int)0xF0000000U);
[StructLayout (LayoutKind.Sequential)]
    public struct OSVERSIONINFOEX {
        public int dwOSVersionInfoSize;
        public int dwMajorVersion;
        public int dwMinorVersion;
        public int dwBuildNumber;
        public int dwPlatformId;
        [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 128)]
        public string szCSDVersion;
        public short wServicePackMajor;
        public short wServicePackMinor;
        public short wSuiteMask;
        public byte wProductType;
        public byte wReserved;
    }
[DllImport ("kernel32.dll")]
public static extern bool GetVersionEx (ref OSVERSIONINFOEX osVersionInfo);
  • 修改public void Decode(FileStream inFile, FileStream outFile)为在 Windows Server 2003 或 XP 上显式使用 RSA 和 AES 加密提供程序
// insert next line before of try block like after this line
IntPtr hStore = IntPtr.Zero;
IntPtr hProv = IntPtr.Zero;

//...
// insert Windows versions test before CryptMsgOpenToDecode like after this line
StreamInfo.pfnStreamOutput = new Win32.StreamOutputCallbackDelegate(StreamOutputCallback);

Win32.OSVERSIONINFOEX osVersionInfo = new Win32.OSVERSIONINFOEX ();
osVersionInfo.dwOSVersionInfoSize = Marshal.SizeOf (typeof (Win32.OSVERSIONINFOEX));
if (Win32.GetVersionEx (ref osVersionInfo)) {
    Console.WriteLine ("dwMajorVersion={0}, dwMinorVersion={1}, wProductType={2}",
        osVersionInfo.dwMajorVersion, osVersionInfo.dwMinorVersion, osVersionInfo.wProductType);
    if (osVersionInfo.dwMajorVersion == 5 &&
        (osVersionInfo.dwMinorVersion == 2 || osVersionInfo.dwMinorVersion == 1)) {
        // Windows 2003 or XP
        string provider = Win32.MS_ENH_RSA_AES_PROV;
        if (osVersionInfo.dwMajorVersion == 5 && osVersionInfo.dwMinorVersion == 1)
            provider = Win32.MS_ENH_RSA_AES_PROV_XP;
        Win32.CryptAcquireContext (ref hProv, null, provider,
            Win32.PROV_RSA_AES, Win32.CRYPT_VERIFYCONTEXT);
    }
}

// Open message to decode
hMsg = Win32.CryptMsgOpenToDecode(
    Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
    0,
    0,
    hProv,
    IntPtr.Zero,
    ref StreamInfo
);
  • 关于 CryptReleaseContext 函数解码关闭句柄后
    //...
    // insert CryptReleaseContext somewhere inside of finally block like after this line
    if (!hMsg.Equals(IntPtr.Zero))
    {
    Win32.CryptMsgClose(hMsg);
    }
    if (hProv != IntPtr.Zero)
    Win32.CryptReleaseContext (hProv, 0);

现在该程序可以处理使用 SHA-2 算法签名的数据(例如使用 1.2.840.113549.1.1.11 sha256RSA 签名的 331879.zfo)

我建议您不要忘记内存映射文件。如果您使用 .NET 4.0,则可以使用新的 .NET 框架类(请参阅http://msdn.microsoft.com/en-us/library/dd997372%28v=VS.100%29.aspx)。

于 2010-04-26T15:21:14.480 回答
1

MD5 和其他遗留/损坏的加密算法可以通过组策略禁用(美国政府需要使用)。

于 2010-04-26T15:57:00.660 回答