Может ли RSACryptoServiceProvider (RSA .NET) использовать SHA256 для шифрования (без подписи) вместо SHA1? - PullRequest
11 голосов
/ 25 февраля 2011

При шифровании может ли RSACryptoServiceProvider (или любой другой шифратор RSA, доступный в .NET) использовать SHA256 вместо SHA1?

SHA1 представляется жестко запрограммированным без возможности его изменения.Например, RSACryptoServiceProvider.SignatureAlgorithm трудно закодировать для возврата "http://www.w3.org/2000/09/xmldsig#rsa-sha1".

Если нет способа заставить RSACryptoServiceProvider использовать SHA256, каковы альтернативы?


Обновление

Следующий код работает отлично, но я хотел бы изменить OAEPWithSHA1AndMGF1Padding на OAEPWithSHA256AndMGF1Padding. Что требуется на стороне C #, чтобы иметь возможность шифрования с использованием SHA256, а не SHA1?

Шифрование выполняется в C # с использованием:

var parameters = new RSAParameters();
parameters.Exponent = new byte[] {0x01, 0x00, 0x01};
parameters.Modulus = new byte[] {0x9d, 0xc1, 0xcc, ...};
rsa.ImportParameters(parameters);

var cipherText = rsa.Encrypt(new byte[] { 0, 1, 2, 3 }, true);

Расшифровка выполняется на Java с использованием:

Cipher cipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
byte[] cipherText = ...;
byte[] plainText = cipher.doFinal(cipherText);

Ответы [ 7 ]

11 голосов
/ 27 июня 2012

RSACryptoServiceProvider работает с сигнатурами на основе SHA2, но вы должны вложить в него определенные усилия.

Когда вы используете сертификат для получения RSACryptoServiceProvider, действительно важно, что является основным поставщиком CryptoAPI.По умолчанию, когда вы создаете сертификат с помощью 'makecert', это «RSA-FULL», который поддерживает только хэши SHA1 для подписи.Вам нужен новый "RSA-AES", который поддерживает SHA2.

Итак, вы можете создать свой сертификат с дополнительной опцией: -sp "Microsoft Enhanced RSA и AES Cryptographic Provider" (или эквивалентный -sy 24) и тогда ваш код будет выглядеть (в .NET 4.0):

var rsa = signerCertificate.PrivateKey as RSACryptoServiceProvider;
//
byte[] signature = rsa.SignData(data, CryptoConfig.CreateFromName("SHA256"));

Если вы не можете изменить способ выдачи сертификата, существует полулегитимный обходной путь, основанный на фактечто по умолчанию RSACryptoServiceProvider создается с поддержкой SHA2.Итак, следующий код также будет работать, но он немного уродлив: (что делает этот код, это создает новый RSACryptoServiceProvider и импортирует ключи из того, который мы получили из сертификата)

var rsa = signerCertificate.PrivateKey as RSACryptoServiceProvider;
// Create a new RSACryptoServiceProvider
RSACryptoServiceProvider rsaClear = new RSACryptoServiceProvider();
// Export RSA parameters from 'rsa' and import them into 'rsaClear'
rsaClear.ImportParameters(rsa.ExportParameters(true));
byte[] signature = rsaClear.SignData(data, CryptoConfig.CreateFromName("SHA256"));
2 голосов
/ 25 февраля 2011

Если нет способа заставить RSACryptoServiceProvider обрабатывать OAEP-with-SHA-256 (ответы от других, похоже, говорят об этом), то вы все равно можете реализовать эту операцию самостоятельно.Речь идет о части encryption , которая использует только открытый ключ.Открытый ключ, ну, в общем, открытый, что означает, что вы можете экспортировать его (на самом деле, в вашем коде у вас уже есть модуль и экспонента в виде массива байтов), и нет никаких проблем с утечкой секретных данных через небрежную реализацию,поскольку здесь нет секретного ключа.

Реализация OAEP влечет за собой следующее:

  • Follow PKCS # 1 , раздел 7.1.Это преобразует данные для шифрования в последовательность байтов той же длины, что и модуль RSA.Вам понадобится реализация SHA-256 (будет хорошо System.Security.Cryptography.SHA256Managed) и источник alea криптографического качества (System.Security.Cryptography.RandomNumberGenerator).
  • Декодируйте полученную последовательность в большое целое, выполните модульное возведение в степень (по модулю n (модуль RSA) и закодировать результат в другую последовательность байтов той же длины, что и модуль.Правила кодирования: байты с прямым порядком байтов, без знакового бита и фиксированного размера (если это 1024-битный ключ RSA, то есть 2 1023 <= n <2 <sup>1024 , тогда зашифрованное сообщение всегда будет иметь длину ровно 128 байтов, даже если числовое значение поместилось бы меньше, например, 127 или 126 байтов).

.NET 4.0 и далее обеспечиваетSystem.Numerics.BigInteger с нужным кодом (метод ModPow()).Для предыдущих версий вам придется использовать пользовательскую реализацию;Есть несколько лежащих вокруг, Google, как всегда, ваш друг.Здесь вам не нужна абсолютная производительность: RSA шифрование быстрое, потому что открытый показатель мал (17 бит в вашем примере кода).

2 голосов
/ 25 февраля 2011

Начиная с .NET 3.5 с пакетом обновления 1 (SP1) на любой операционной системе Windows Server 2003 и более поздних версиях, да, RSACryptoServiceProvider поддерживает RSA-SHA256 для подписания , но не шифрования.

Из сообщения блога Использование RSACryptoServiceProvider для подписей RSA-SHA256 :

byte[] data = new byte[] { 0, 1, 2, 3, 4, 5 };
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
    byte[] signature = rsa.SignData(data, "SHA256");

    if (rsa.VerifyData(data, "SHA256", signature))
    {
        Console.WriteLine("RSA-SHA256 signature verified");
    }
    else
    {
        Console.WriteLine("RSA-SHA256 signature failed to verify");
    }
}

Вы должны прочитать оригинальный пост, так как есть некоторые ошибки, о которых нужно знать.

1 голос
/ 14 декабря 2011

Bounty Castle C # был обновлён до 1.7 после того, как на этот вопрос был задан и дан ответ.Для дальнейшего использования вы можете рассмотреть это, он добавляет множество криптоалгоритмов, хэшей, подписей, которые Bouncy Castle делает доступными для Java.Нажмите на ссылку, найдите «Примечания к выпуску для 1.7» и «Текущий список функций:».

0 голосов
/ 11 июня 2018

Только для справки: Как изменить CSP в .p12 или .pfx (сертификат с закрытым ключом).Вам необходим пароль для закрытого ключа в .pfx, чтобы выполнить следующие шаги:

Шаг 1: Преобразовать файл в открытый формат temp.pem

openssl pkcs12 -in myCert.p12 -out temp.pem -passin pass:myPassword -passout pass:temppwd

или openssl pkcs12-in myCert.pfx -out temp.pem -passin pass: myPassword -passout pass: temppwd

Шаг 2: Создать файл myCert2.pfx, содержащий ссылку CSP, необходимую для Windows

openssl pkcs12 -export -in temp.pem -out myCert2.pfx -CSP "Microsoft Enhanced RSA and AES Cryptographic Provider" -passin pass:temppwd -passout pass:myPassword

Шаг 3: Удалить temp.pem.Больше не нужно.

del temp.pem

Шаг 4: Убедитесь, что все сделано правильно

openssl pkcs12 -info -nodes -in myCert2.pfx -passin pass:myPassword

Это должно показать Microsoft CSP Name: Microsoft Enhanced RSA and AES Cryptographic Provider

С таким измененным сертификатом вы можетеиспользуйте 1-й код в ответе Касторского.

0 голосов
/ 07 апреля 2017

Все остальные ответы здесь о подписи, а не шифровании с SHA256. Я собираюсь ответить на заданный вопрос.

Любые алгоритмы SHA-2 или выше предназначены для хеширования, не обязательно шифрования / дешифрования, но это не означает, что вы не можете генерировать ключи с использованием этих алгоритмов, а затем шифровать / дешифровать их. Технически, я буду предупреждать об этом тех, кто не согласен с этим ответом, это не «шифрование с помощью SHA256», но оно позволяет RSA использовать хешированный ключ, сгенерированный с использованием этого алгоритма. Пусть ваша конкретная организация решит, достаточно ли этого, чтобы соответствовать NIST / FIPS, если это будет вашей причиной, как это было мое при исследовании этого вопроса.

Для шифрования (с использованием RSA или другого алгоритма асимметричного шифрования) просто требуется открытый ключ (для шифрования) и закрытый ключ (для дешифрования). Создав ключи с использованием этого хэша, вы можете зашифровать / расшифровать их.

Я собираюсь собрать воедино некоторые исследования, которые я провел, чтобы показать пару путей, по которым вы можете пойти, чтобы добиться этого, используя ключ, созданный с использованием хэша SHA-256, который вы затем шифруете / дешифруете. Вы можете сгенерировать ключ SHA-256, создав сертификат или предоставив ему RSACryptoServiceContainer.

Метод сертификата

Создайте свой сертификат с этими строками в командной строке:

makecert -r -pe -n "CN=MyCertificate" -a sha256 -b 09/01/2016 -sky exchange C:\Temp\MyCertificate.cer -sv C:\Temp\MyCertificate.pvk
pvk2pfx.exe -pvk C:\Temp\MyCertificate.pvk -pi "MyP@ssw0rd" -spc C:\Temp\MyCertificate.cer -pfx C:\Temp\MyCertificate.pfx -po "MyP@ssw0rd"

Затем импортируйте сертификат в локальное корневое хранилище полномочий и используйте этот код:

string input = "test";
string output = string.Empty;

X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);

X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindBySubjectName, "MyCertificate", false);

X509Certificate2 certificate = collection[0];

using (RSACryptoServiceProvider cps = (RSACryptoServiceProvider)certificate.PublicKey.Key)
{
    byte[] bytesData = Encoding.UTF8.GetBytes(input);
    byte[] bytesEncrypted = cps.Encrypt(bytesData, false);
    output = Convert.ToBase64String(bytesEncrypted);
}

store.Close();

Если вы хотите использовать SHA512, вы просто измените этот параметр sha256 на sha512 при создании сертификата.

Ссылка : https://social.msdn.microsoft.com/Forums/en-US/69e39ad0-13c2-4b5e-bb1b-972a614813fd/encrypt-with-certificate-sha512?forum=csharpgeneral

Использование RSACryptoServiceProvider для генерации ключей

private static string privateKey = String.Empty;

private static void generateKeys()
{
    int dwLen = 2048;
    RSACryptoServiceProvider csp = new RSACryptoServiceProvider(dwLen);
    privateKey = csp.ToXmlString(true).Replace("><",">\r\n");
}

public static string Encrypt(string data2Encrypt)
{
    try
    {
        generateKeys();
        RSAx rsax = new RSAx(privateKey, 2048);
        rsax.RSAxHashAlgorithm = RSAxParameters.RSAxHashAlgorithm.SHA256;
        byte[] CT = rsax.Encrypt(Encoding.UTF8.GetBytes(data2Encrypt), false, true); // first bool is for using private key (false forces to use public), 2nd is for using OAEP
        return Convert.ToBase64String(CT);
    }
    catch (Exception ex) 
    { 
        // handle exception
        MessageBox.Show("Error during encryption: " + ex.Message);
        return String.Empty;
    }
}

public static string Decrypt(string data2Decrypt)
{
    try
    {
        RSAx rsax = new RSAx(privateKey, 2048);
        rsax.RSAxHashAlgorithm = RSAxParameters.RSAxHashAlgorithm.SHA256;
        byte[] PT = rsax.Decrypt(Convert.FromBase64String(data2Decrypt), true, true); // first bool is for using private key, 2nd is for using OAEP
        return Encoding.UTF8.GetString(PT);
    }
    catch (Exception ex) 
    { 
        // handle exception
        MessageBox.Show("Error during encryption: " + ex.Message);
        return String.Empty;
    }
}

Если вы хотите использовать SHA512, вы можете изменить RSAxHashAlgorithm.SHA256 на RSAxHashAlgorithm.SHA512.

Эти методы используют библиотеку DLL с именем RSAx.DLL , созданную с использованием исходного кода https://www.codeproject.com/Articles/421656/RSA-Library-with-Private-Key-Encryption-in-Csharp, которая не принадлежит мне (автор: Арпан Джати), но я использовал ее и он доступен для сообщества разработчиков под CodeProject Open Source License . Вы также можете просто добавить 3 класса из этого проекта: RSAx.cs, RSAxParameters.cs, RSAxUtils.cs

Код будет принимать этот пост за предел в 30000 символов, поэтому я просто опубликую RSAx, чтобы вы могли видеть, что происходит, но все 3 класса обязательны. Вы должны изменить пространство имен и ссылаться на сборку System.Numerics.

RSAx.cs

// @Date : 15th July 2012
// @Author : Arpan Jati (arpan4017@yahoo.com; arpan4017@gmail.com)
// @Library : ArpanTECH.RSAx
// @CodeProject: http://www.codeproject.com/Articles/421656/RSA-Library-with-Private-Key-Encryption-in-Csharp  

using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Numerics;
using System.Linq;
using System.Text;
using System.IO;

namespace ArpanTECH
{
    /// <summary>
    /// The main RSAx Class
    /// </summary>
    public class RSAx : IDisposable
    {
        private RSAxParameters rsaParams;
        private RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

        /// <summary>
        /// Initialize the RSA class.
        /// </summary>
        /// <param name="rsaParams">Preallocated RSAxParameters containing the required keys.</param>
        public RSAx(RSAxParameters rsaParams)
        {
            this.rsaParams = rsaParams;
            UseCRTForPublicDecryption = true;
        }

        /// <summary>
        /// Initialize the RSA class from a XML KeyInfo string.
        /// </summary>
        /// <param name="keyInfo">XML Containing Key Information</param>
       /// <param name="ModulusSize">Length of RSA Modulus in bits.</param>
       public RSAx(String keyInfo, int ModulusSize)
       {
            this.rsaParams = RSAxUtils.GetRSAxParameters(keyInfo, ModulusSize);
            UseCRTForPublicDecryption = true;
        }

        /// <summary>
        /// Hash Algorithm to be used for OAEP encoding.
        /// </summary>
        public RSAxParameters.RSAxHashAlgorithm RSAxHashAlgorithm
        {
            set
            {
                rsaParams.HashAlgorithm = value;
            }
        }

        /// <summary>
        /// If True, and if the parameters are available, uses CRT for private key decryption. (Much Faster)
        /// </summary>
        public bool UseCRTForPublicDecryption
        {
            get;  set;
        }

        /// <summary>
        /// Releases all the resources.
        /// </summary>
        public void Dispose()
        {
            rsaParams.Dispose();
        }

        #region PRIVATE FUNCTIONS

        /// <summary>
        /// Low level RSA Process function for use with private key.
        /// Should never be used; Because without padding RSA is vulnerable to attacks.  Use with caution.
        /// </summary>
        /// <param name="PlainText">Data to encrypt. Length must be less than Modulus size in octets.</param>
        /// <param name="usePrivate">True to use Private key, else Public.</param>
        /// <returns>Encrypted Data</returns>
        public byte[] RSAProcess(byte[] PlainText, bool usePrivate)
        {

            if (usePrivate && (!rsaParams.Has_PRIVATE_Info))
            {
                throw new CryptographicException("RSA Process: Incomplete Private Key Info");
            }

            if ((usePrivate == false) && (!rsaParams.Has_PUBLIC_Info))
            {
                throw new CryptographicException("RSA Process: Incomplete Public Key Info");
            }            

            BigInteger _E;
            if (usePrivate)
                _E = rsaParams.D; 
            else
                _E = rsaParams.E;

            BigInteger PT = RSAxUtils.OS2IP(PlainText, false);
            BigInteger M = BigInteger.ModPow(PT, _E, rsaParams.N);

            if (M.Sign == -1)
                return RSAxUtils.I2OSP(M + rsaParams.N, rsaParams.OctetsInModulus, false);            
            else
                return RSAxUtils.I2OSP(M, rsaParams.OctetsInModulus, false);                   
        }

        /// <summary>
        /// Low level RSA Decryption function for use with private key. Uses CRT and is Much faster.
        /// Should never be used; Because without padding RSA is vulnerable to attacks. Use with caution.
        /// </summary>
        /// <param name="Data">Data to encrypt. Length must be less than Modulus size in octets.</param>
        /// <returns>Encrypted Data</returns>
        public byte[] RSADecryptPrivateCRT(byte[] Data)
        {
            if (rsaParams.Has_PRIVATE_Info && rsaParams.HasCRTInfo)
            {
                BigInteger C = RSAxUtils.OS2IP(Data, false);

                BigInteger M1 = BigInteger.ModPow(C, rsaParams.DP, rsaParams.P);
                BigInteger M2 = BigInteger.ModPow(C, rsaParams.DQ, rsaParams.Q);
                BigInteger H = ((M1 - M2) * rsaParams.InverseQ) % rsaParams.P;
                BigInteger M = (M2 + (rsaParams.Q * H));

                if (M.Sign == -1)
                    return RSAxUtils.I2OSP(M + rsaParams.N, rsaParams.OctetsInModulus, false);
                else
                    return RSAxUtils.I2OSP(M, rsaParams.OctetsInModulus, false); 
            }
            else
            {
                throw new CryptographicException("RSA Decrypt CRT: Incomplete Key Info");
            }                             
        }        

        private byte[] RSAProcessEncodePKCS(byte[] Message, bool usePrivate)
        {
            if (Message.Length > rsaParams.OctetsInModulus - 11)
            {
                throw new ArgumentException("Message too long.");
            }
            else
            {
                // RFC3447 : Page 24. [RSAES-PKCS1-V1_5-ENCRYPT ((n, e), M)]
                // EM = 0x00 || 0x02 || PS || 0x00 || Msg 

                List<byte> PCKSv15_Msg = new List<byte>();

                PCKSv15_Msg.Add(0x00);
                PCKSv15_Msg.Add(0x02);

                int PaddingLength = rsaParams.OctetsInModulus - Message.Length - 3;

                byte[] PS = new byte[PaddingLength];
                rng.GetNonZeroBytes(PS);

                PCKSv15_Msg.AddRange(PS);
                PCKSv15_Msg.Add(0x00);

                PCKSv15_Msg.AddRange(Message);

                return RSAProcess(PCKSv15_Msg.ToArray() ,  usePrivate);
            }
        }

        /// <summary>
        /// Mask Generation Function
        /// </summary>
        /// <param name="Z">Initial pseudorandom Seed.</param>
        /// <param name="l">Length of output required.</param>
        /// <returns></returns>
        private byte[] MGF(byte[] Z, int l)
        {
            if (l > (Math.Pow(2, 32)))
            {
                throw new ArgumentException("Mask too long.");
            }
            else
            {
                List<byte> result = new List<byte>();
                for (int i = 0; i <= l / rsaParams.hLen; i++)
                {
                    List<byte> data = new List<byte>();
                    data.AddRange(Z);
                    data.AddRange(RSAxUtils.I2OSP(i, 4, false));
                    result.AddRange(rsaParams.ComputeHash(data.ToArray()));
                }

                if (l <= result.Count)
                {
                    return result.GetRange(0, l).ToArray();
                }
                else
                {
                    throw new ArgumentException("Invalid Mask Length.");
                }
            }
        }


        private byte[] RSAProcessEncodeOAEP(byte[] M, byte[] P, bool usePrivate)
        {
            //                           +----------+---------+-------+
            //                      DB = |  lHash   |    PS   |   M   |
            //                           +----------+---------+-------+
            //                                          |
            //                +----------+              V
            //                |   seed   |--> MGF ---> XOR
            //                +----------+              |
            //                      |                   |
            //             +--+     V                   |
            //             |00|    XOR <----- MGF <-----|
            //             +--+     |                   |
            //               |      |                   |
            //               V      V                   V
            //             +--+----------+----------------------------+
            //       EM =  |00|maskedSeed|          maskedDB          |
            //             +--+----------+----------------------------+

            int mLen = M.Length;
            if (mLen > rsaParams.OctetsInModulus - 2 * rsaParams.hLen - 2)
            {
                throw new ArgumentException("Message too long.");
            }
            else
            {
                byte[] PS = new byte[rsaParams.OctetsInModulus - mLen - 2 * rsaParams.hLen - 2];
                //4. pHash = Hash(P),
                byte[] pHash = rsaParams.ComputeHash(P);

                //5. DB = pHash||PS||01||M.
                List<byte> _DB = new List<byte>();
                _DB.AddRange(pHash);
                _DB.AddRange(PS);
                _DB.Add(0x01);
                _DB.AddRange(M);
                byte[] DB = _DB.ToArray();

                //6. Generate a random octet string seed of length hLen.                
                byte[] seed = new byte[rsaParams.hLen];
                rng.GetBytes(seed);

                //7. dbMask = MGF(seed, k - hLen -1).
                byte[] dbMask = MGF(seed, rsaParams.OctetsInModulus - rsaParams.hLen - 1);

                //8. maskedDB = DB XOR dbMask
                byte[] maskedDB = RSAxUtils.XOR(DB, dbMask);

                //9. seedMask = MGF(maskedDB, hLen)
                byte[] seedMask = MGF(maskedDB, rsaParams.hLen);

                //10. maskedSeed = seed XOR seedMask.
                byte[] maskedSeed = RSAxUtils.XOR(seed, seedMask);

                //11. EM = 0x00 || maskedSeed || maskedDB.
                List<byte> result = new List<byte>();
                result.Add(0x00);
                result.AddRange(maskedSeed);
                result.AddRange(maskedDB);

                return RSAProcess(result.ToArray(), usePrivate);
            }
        }


        private byte[] Decrypt(byte[] Message, byte [] Parameters, bool usePrivate, bool fOAEP)
        {
            byte[] EM = new byte[0];
            try
            {
                if ((usePrivate == true) && (UseCRTForPublicDecryption) && (rsaParams.HasCRTInfo))
                {
                    EM = RSADecryptPrivateCRT(Message);
                }
                else
                {
                    EM = RSAProcess(Message, usePrivate);
                }
            }
            catch (CryptographicException ex)
            {
                throw new CryptographicException("Exception while Decryption: " + ex.Message);
            }
            catch
            {
                throw new Exception("Exception while Decryption: ");
            }

            try
            {
                if (fOAEP) //DECODE OAEP
                {
                    if ((EM.Length == rsaParams.OctetsInModulus) && (EM.Length > (2 * rsaParams.hLen + 1)))
                    {
                        byte[] maskedSeed;
                        byte[] maskedDB;
                        byte[] pHash = rsaParams.ComputeHash(Parameters);
                        if (EM[0] == 0) // RFC3447 Format : http://tools.ietf.org/html/rfc3447
                        {
                            maskedSeed = EM.ToList().GetRange(1, rsaParams.hLen).ToArray();
                            maskedDB = EM.ToList().GetRange(1 + rsaParams.hLen, EM.Length - rsaParams.hLen - 1).ToArray();
                            byte[] seedMask = MGF(maskedDB, rsaParams.hLen);
                            byte[] seed = RSAxUtils.XOR(maskedSeed, seedMask);
                            byte[] dbMask = MGF(seed, rsaParams.OctetsInModulus - rsaParams.hLen - 1);
                            byte[] DB = RSAxUtils.XOR(maskedDB, dbMask);

                            if (DB.Length >= (rsaParams.hLen + 1))
                            {
                                byte[] _pHash = DB.ToList().GetRange(0, rsaParams.hLen).ToArray();
                                List<byte> PS_M = DB.ToList().GetRange(rsaParams.hLen, DB.Length - rsaParams.hLen);
                                int pos = PS_M.IndexOf(0x01);
                                if (pos >= 0 && (pos < PS_M.Count))
                                {
                                    List<byte> _01_M = PS_M.GetRange(pos, PS_M.Count - pos);
                                    byte[] M;
                                    if (_01_M.Count > 1)
                                    {
                                        M = _01_M.GetRange(1, _01_M.Count - 1).ToArray();
                                    }
                                    else
                                    {
                                        M = new byte[0];
                                    }
                                    bool success = true;
                                    for (int i = 0; i < rsaParams.hLen; i++)
                                    {
                                         if (_pHash[i] != pHash[i])
                                        {
                                            success = false;
                                            break;
                                        }
                                    }

                                    if (success)
                                    {
                                        return M;
                                    }
                                    else
                                    {
                                        M = new byte[rsaParams.OctetsInModulus]; //Hash Match Failure.
                                        throw new CryptographicException("OAEP Decode Error");
                                    }
                                }
                                else
                                {// #3: Invalid Encoded Message Length.
                                    throw new CryptographicException("OAEP Decode Error");
                                }
                            }
                            else
                            {// #2: Invalid Encoded Message Length.
                                throw new CryptographicException("OAEP Decode Error");
                            }
                        }
                        else // Standard : ftp://ftp.rsasecurity.com/pub/rsalabs/rsa_algorithm/rsa-oaep_spec.pdf
                        {//OAEP : THIS STADNARD IS NOT IMPLEMENTED
                            throw new CryptographicException("OAEP Decode Error");
                        }
                    }
                    else
                    {// #1: Invalid Encoded Message Length.
                        throw new CryptographicException("OAEP Decode Error");
                    }
                }
                else // DECODE PKCS v1.5
                {
                    if (EM.Length >= 11)
                    {
                        if ((EM[0] == 0x00) && (EM[1] == 0x02))
                        {
                            int startIndex = 2;
                            List<byte> PS = new List<byte>();
                            for (int i = startIndex; i < EM.Length; i++)
                            {
                                if (EM[i] != 0)
                                {
                                    PS.Add(EM[i]);
                                }
                                else
                                {
                                    break;
                                }
                            }

                            if (PS.Count >= 8)
                            {
                                int DecodedDataIndex = startIndex + PS.Count + 1;
                                if (DecodedDataIndex < (EM.Length - 1))
                                {
                                    List<byte> DATA = new List<byte>();
                                    for (int i = DecodedDataIndex; i < EM.Length; i++)
                                    {
                                        DATA.Add(EM[i]);
                                    }
                                    return DATA.ToArray();
                                }
                                else
                                {
                                    return new byte[0];
                                    //throw new CryptographicException("PKCS v1.5 Decode Error #4: No Data");
                                }
                            }
                            else
                            {// #3: Invalid Key / Invalid Random Data Length
                                throw new CryptographicException("PKCS v1.5 Decode Error");
                            }
                        }
                        else
                        {// #2: Invalid Key / Invalid Identifiers
                            throw new CryptographicException("PKCS v1.5 Decode Error");
                        }
                    }
                    else
                    {// #1: Invalid Key / PKCS Encoding
                        throw new CryptographicException("PKCS v1.5 Decode Error");
                    }

                }
            }
            catch (CryptographicException ex)
            {
                throw new CryptographicException("Exception while decoding: " + ex.Message);
            }
            catch
            {
                throw new CryptographicException("Exception while decoding");
            }


        }

        #endregion

        #region PUBLIC FUNCTIONS

        /// <summary>
        /// Encrypts the given message with RSA, performs OAEP Encoding.
        /// </summary>
        /// <param name="Message">Message to Encrypt. Maximum message length is (ModulusLengthInOctets - 2 * HashLengthInOctets - 2)</param>
        /// <param name="OAEP_Params">Optional OAEP parameters. Normally Empty. But, must match the parameters while decryption.</param>
        /// <param name="usePrivate">True to use Private key for encryption. False to use Public key.</param>
        /// <returns>Encrypted message.</returns>
        public byte[] Encrypt(byte[] Message, byte[] OAEP_Params, bool usePrivate)
        {
            return RSAProcessEncodeOAEP(Message, OAEP_Params, usePrivate);
        }

        /// <summary>
        /// Encrypts the given message with RSA.
        /// </summary>
        /// <param name="Message">Message to Encrypt. Maximum message length is For OAEP [ModulusLengthInOctets - (2 * HashLengthInOctets) - 2] and for PKCS [ModulusLengthInOctets - 11]</param>
        /// <param name="usePrivate">True to use Private key for encryption. False to use Public key.</param>
        /// <param name="fOAEP">True to use OAEP encoding (Recommended), False to use PKCS v1.5 Padding.</param>
        /// <returns>Encrypted message.</returns>
        public byte[] Encrypt(byte[] Message, bool usePrivate, bool fOAEP)
        {
            if (fOAEP)
            {
                return RSAProcessEncodeOAEP(Message, new byte[0], usePrivate);
            }
            else
            {
                return RSAProcessEncodePKCS(Message, usePrivate);
            }
        }

        /// <summary>
        /// Encrypts the given message using RSA Public Key.
        /// </summary>
        /// <param name="Message">Message to Encrypt. Maximum message length is For OAEP [ModulusLengthInOctets - (2 * HashLengthInOctets) - 2] and for PKCS [ModulusLengthInOctets - 11]</param>
        /// <param name="fOAEP">True to use OAEP encoding (Recommended), False to use PKCS v1.5 Padding.</param>
        /// <returns>Encrypted message.</returns>
        public byte[] Encrypt(byte[] Message,  bool fOAEP)
        {
            if (fOAEP)
            {
                return RSAProcessEncodeOAEP(Message, new byte[0], false);
            }
            else
            {
                return RSAProcessEncodePKCS(Message, false);
            }
        }

        /// <summary>
        /// Decrypts the given RSA encrypted message.
        /// </summary>
        /// <param name="Message">The encrypted message.</param>
        /// <param name="usePrivate">True to use Private key for decryption. False to use Public key.</param>
        /// <param name="fOAEP">True to use OAEP.</param>
        /// <returns>Encrypted byte array.</returns>
        public byte[] Decrypt(byte[] Message, bool usePrivate, bool fOAEP)
        {
            return Decrypt(Message, new byte[0], usePrivate, fOAEP);
        }

        /// <summary>
        /// Decrypts the given RSA encrypted message.
        /// </summary>
        /// <param name="Message">The encrypted message.</param>
        /// <param name="OAEP_Params">Parameters to the OAEP algorithm (Must match the parameter while Encryption).</param>
        /// <param name="usePrivate">True to use Private key for decryption. False to use Public key.</param>
        /// <returns>Decrypted byte array.</returns>
        public byte[] Decrypt(byte[] Message, byte[] OAEP_Params, bool usePrivate)
        {
            return Decrypt(Message, OAEP_Params, usePrivate, true);
        }

        /// <summary>
        /// Decrypts the given RSA encrypted message using Private key.
        /// </summary>
        /// <param name="Message">The encrypted message.</param>
        /// <param name="fOAEP">True to use OAEP.</param>
        /// <returns>Decrypted byte array.</returns>
        public byte[] Decrypt(byte[] Message,  bool fOAEP)
        {
            return Decrypt(Message, new byte[0], true, fOAEP);
        }
        #endregion
    }
}
0 голосов
/ 25 февраля 2011

Согласно Microsoft MVP (Роб Тейшейра), нет.Вы можете использовать стороннюю библиотеку, такую ​​как Security.Cryptography.dll

...