Question

I am decoding a file using the following method:

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

This is working fine on my Win 7 dev machine, but on a Windows 2003 server production machine it fails with the following exception:

Exception: System.Exception: CryptMsgUpdate error #-2146893816 ---> System.ComponentModel.Win32Exception: Invalid algorithm specified --- End of inner exception stack trace --- at LargeCMS.CMS.Decode(FileStream inFile, FileStream outFile)

Here are the classes below which I call to do the decoding, if needed I can upload a sample file for decoding, its just strange it works on Win 7, and not on Win2k3 server:

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

and

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
    }
}
Was it helpful?

Solution

Can you give more information about your environment. First of all: which Service Pack has Windows 2003 Server. There is for example a bug "Default Diffie-Hellman SChannel Certificate Selection on Web Enrollment Page Causes Error: 0x80090008 - NTE_BAD_ALGID" which are fixed in SP3 http://support.microsoft.com/kb/324953/en. If it is not your problem, you should place the certificate and a binary file with the test message somewhere on web and post URL here. Then one will be able to reproduce and test the problem.

I suppose, to fix your problem (if the last Service Pack is installed on the Windows Server 2003) one will be have to change some properties of the certificate with which the message are signed.

I don't think, by the way that you certificate use SHA-2 algorithms (SHA-256, SHA-384 and SHA-512). If you do use this one and have the last Service pack installed, then it can be needed to use explicitly "Microsoft Enhanced RSA and AES Cryptographic Provider" (or "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" as it's called on Windows XP SP3) or PROV_RSA_AES or MS_ENH_RSA_AES_PROV instead of default PROV_RSA_FULL provider. (see, for example, http://blogs.msdn.com/alejacma/archive/2009/01/23/sha-2-support-on-windows-xp.aspx)

Updated 1: After receiving your test file the problem is more clear. First of all a good news. Your program works correct! It works without any problem on my test Windows 2003 server with SP2. So we have administrative problem and not a software development. I recommend you to test the program on another Windows 2003 Server. On this server you can reinstall SP2 and then go to Microsoft Updates and install all updates.

By the way you have no problems with SHA256 or other SHA-2 algorithms. You use in your example a standard 1.2.840.113549.1.1.5 sha1RSA algorithm.

Now about your program. I read detailed your code and understand exactly what you do. You receive an PKCS#7 signed message which contain a text tile (an XML file) inside. How I understand your example come from http://blogs.msdn.com/alejacma/archive/2010/04/09/how-to-call-cryptmsg-api-in-streaming-mode-c.aspx which describes problem with decrypting of files larger as 100MB (see also http://blogs.msdn.com/alejacma/archive/2010/03/17/asn1-value-too-large-error-when-calling-signedcms-computesignature.aspx). If you not have this case, I recommend you to use .NET cryptographic functions from System.Security.Cryptography.Pkcs namespace. If you do have large data, you current code is OK. The only something suspected place is reading of input file. I don't read stream.ReadBytes() call. I would be use better memory mapped files instead of loading a huge file in memory. To do this in native code you can use code like following

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

Writing of the corresponding .NET code would be not a problem. Using Memory Mapped Files create only a virtual address mapping to the file, data will be read only if you access to the corresponding part of data.

One more remark. The part of you code, where you verify the message is not full. What you have to do is the verifying of the certificate with which the message signed. If you use native CryptoAPI, you can do this with respect of CertGetCertificateChain(). Only then you will be sure, that the certificate and all it's parent are valid. You should also verify with respect of CertVerifyCertificateChainPolicy() that the certificate chain allow usage of the certificate for signing of messages.

Current code by the way works without error messages, but the Issuer of the certificate with which the message are signed is "CN=PostSignum Qualified CA, O="Ceská pošta, s.p. [IC 47114983]", C=CZ" and inside your message the certificated is not exist. You can use for example certutil.exe -dump 31602.zfo to see details:

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)

Probably you don't want interpret any signed message as valid. Verification of the certificate is mandatory. Moreover in a lot of scenarios it would be good to define the range of origins from which Issuer you want to allow a signed messages as an input. Think about this.

Updated 2: You are right in new 331879.zfo file you really use sha256RSA (1.2.840.113549.1.1.11) for signature. Try to install http://support.microsoft.com/kb/968730/en which I fond on
http://thehotfixshare.net/board/index.php?showtopic=12629&hl=968730. It is a digitally signed file. So I it must be safe. To be absolutely sure you can receive this fix from Microsoft. I hope this fix will solve you problem.

Updated 3: I thought a little more about your code example. It seems to me, that to receive the best implementation you should implement the whole code of the message decoding as unmanaged (native) code. So you will not spend any additional time for marshaling between native and managed code during decoding of large data. This native code you should place inside a DLL and export a function which you can use inside you main managed code.

One more remark about using memory mapped filed. Usage of memory mapped filed is mostly optimized way access any file in Windows for both reading and writing. One thing which you must to know is memory usage. If you look at Task Manager for used memory you can see that a program used memory mapped file technique can use very large memory. It is not a problem at all. This memory is not a physical memory and not a paged memory from the paging file. A virtual addressed will be mapped directly to the file which you mapped in memory. So paging of data will be done with respect of the file data itself. No additional parts of the paging file of operation system are needed. This I/O from the file is much optimized and implemented with respect of corresponding embedded processor features.

End solution: Because I could not stop thinking about this problem I had to solve it. Here is the solution which full based on what I already written before.

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);
  • Modify public void Decode(FileStream inFile, FileStream outFile) to use explicitly RSA and AES Cryptographic Provider on Windows Server 2003 or XP
// 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
);
  • after decoding close handle with respect of CryptReleaseContext function
    //...
    // 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);

Now the program works with data signed with SHA-2 algorithms (like 331879.zfo signed with 1.2.840.113549.1.1.11 sha256RSA)

I recommend you don't forget about memory mapped files. If you use .NET 4.0 you can use new .NET framework classes (see http://msdn.microsoft.com/en-us/library/dd997372%28v=VS.100%29.aspx).

OTHER TIPS

Could it be that the CSP you use aren't installed on your Win2003? I remember reading that XP before SP3 had some problems with SHA-2 or something, and XP and Win2003 are more or less the same basic OS I think.

I think you can see what's installed on the following registry key
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults

Maybe you can compare between your machines.

MD5 and other legacy/broken cryptographic algorithms can be disabled by group policy (needed for US Government use).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top