Неверный алгоритм указан только на Windows 2003 Server - PullRequest
2 голосов
/ 21 апреля 2010

Я декодирую файл, используя следующий метод:

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 error # -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
    }
}

Ответы [ 3 ]

3 голосов
/ 26 апреля 2010

Можете ли вы дать больше информации о вашей среде.Прежде всего: какой пакет обновления имеет Windows 2003 Server.Например, существует ошибка «Выбор сертификата Diffie-Hellman SChannel по умолчанию на странице регистрации через Интернет. Причины ошибки: 0x80090008 - NTE_BAD_ALGID», которые исправлены в SP3 http://support.microsoft.com/kb/324953/en..бинарный файл с тестовым сообщением где-то в сети и размещенный здесь URLТогда можно будет воспроизвести и протестировать проблему.

Полагаю, чтобы исправить вашу проблему (если последний пакет обновления установлен на Windows Server 2003), нужно будет изменить некоторые свойства сертификата.с которым сообщение подписано.

Не думаю, кстати, что в вашем сертификате используются алгоритмы SHA-2 (SHA-256, SHA-384 и SHA-512).Если вы используете этот пакет и у вас установлен последний пакет обновления, тогда может потребоваться явно использовать «Microsoft Enhanced RSA и AES Cryptographic Provider» (или «Microsoft Enhanced RSA и 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: После получения тестового файла проблема становится более ясной. Прежде всего, хорошие новости. Ваша программа работает правильно! На моем тестовом сервере Windows 2003 с пакетом обновления 2 (SP2) он работает без проблем. Итак, у нас административная проблема, а не разработка программного обеспечения. Я рекомендую вам протестировать программу на другом сервере Windows 2003. На этом серверевы можете переустановить пакет обновления 2, а затем перейти в раздел «Обновления 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, который описывает проблему с расшифровкой файлов размером более 100 МБ (см. также http://blogs.msdn.com/alejacma/archive/2010/03/17/asn1-value-too-large-error-when-calling-signedcms-computesignature.aspx). Если у вас нет этого cКроме того, я рекомендую вам использовать криптографические функции .NET из пространства имен System.Security.Cryptography.Pkcs.Если у вас есть большие данные, ваш текущий код в порядке.Единственное подозрительное место - чтение входного файла.Я не читаю stream.ReadBytes () call.Я бы использовал файлы с лучшим отображением в памяти вместо загрузки огромного файла в память.Чтобы сделать это в нативном коде, вы можете использовать код, подобный следующему

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 не будет проблемой.Используя файлы с отображением в памяти, создайте только виртуальное сопоставление адресов с файлом, данные будут считываться только при доступе к соответствующей части данных.

Еще одно замечание.Часть кода, в которой вы проверяете сообщение, не заполнена.Что вам нужно сделать, это проверка сертификата, с которым подписано сообщение.Если вы используете нативный 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)

Возможно, вы не хотите, чтобы любое подписанное сообщение считалось действительным.Проверка сертификата обязательна.Более того, во многих сценариях было бы хорошо определить диапазон источников, от которых эмитент хочет разрешить подписанные сообщения в качестве входных данных.Подумай об этом.

Обновлено 2: Вы правы в новом файле 331879.zfo, который вы действительно используете sha256RSA (1.2.840.113549.1.1.11) для подписи. Попробуйте установить http://support.microsoft.com/kb/968730/en, который мне нравится
http://thehotfixshare.net/board/index.php?showtopic=12629&hl=968730. Это файл с цифровой подписью. Так что я должен быть в безопасности. Чтобы быть абсолютно уверенным, вы можете получить это исправление от Microsoft. Я надеюсь, что это исправление решит вашу проблему.

Обновлено 3 : Я немного больше подумал о вашем примере кода. Мне кажется, что для получения наилучшей реализации вы должны реализовать весь код декодирования сообщений как неуправляемый (нативный) код. Таким образом, вы не будете тратить дополнительное время на маршалинг между собственным и управляемым кодом при декодировании больших данных. Этот нативный код вы должны поместить в DLL и экспортировать функцию, которую вы можете использовать внутри основного управляемого кода.

Еще одно замечание по поводу использования памяти в поле. Использование отображаемой памяти в поле в основном оптимизировано для доступа к любому файлу в Windows как для чтения, так и для записи. Одна вещь, которую вы должны знать, это использование памяти. Если вы посмотрите в диспетчере задач на использованную память, вы увидите, что программа, использующая технику отображенного в память файла, может использовать очень большой объем памяти. Это не проблема вообще. Эта память не является физической памятью и не выгружается из файла подкачки . Виртуальный адрес будет привязан непосредственно к файлу, который вы отобразили в памяти. Таким образом, подкачка данных будет выполняться в отношении самих данных файла. Никаких дополнительных частей файла подкачки операционной системы не требуется. Этот ввод / вывод из файла значительно оптимизирован и реализован с учетом соответствующих функций встроенного процессора.

Конечное решение : Поскольку я не мог перестать думать об этой проблеме, мне пришлось ее решить. Вот решение, которое полностью основано на том, что я уже написал ранее.

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), чтобы явно использовать поставщик шифрования RSA и AES в Windows Server 2003 или 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
);
  • после декодирования закрывать дескриптор с учетом функции CryptReleaseContext <pre>//... // 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 (например, 331879.zfo, подписанных с 1.2.840.113549.1.1.11 sha256RSA)

Рекомендую не забывать о файлах, отображенных в память. Если вы используете .NET 4.0, вы можете использовать новые классы .NET Framework (см. http://msdn.microsoft.com/en-us/library/dd997372%28v=VS.100%29.aspx).

3 голосов
/ 22 апреля 2010

Может ли быть так, что используемый вами CSP не установлен на Win2003? Я помню, как читал, что в XP до SP3 были некоторые проблемы с SHA-2 или чем-то еще, а XP и Win2003 - более или менее одна и та же базовая ОС, я думаю.

Я думаю, вы можете видеть, что установлено в следующем разделе реестра
HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Cryptography \ Defaults

Может быть, вы можете сравнить между своими машинами.

1 голос
/ 26 апреля 2010

MD5 и другие устаревшие / неработающие криптографические алгоритмы могут быть отключены групповой политикой (необходимо для использования правительством США).

...