Шифрование с открытым ключом с помощью RSACryptoServiceProvider

Некоторое время я читал статью в CodeProject, в которой объясняется, как шифровать и расшифровывать с помощью поставщика RSA:

Шифрование закрытого ключа RSA

В то время как старая версия 2009 года содержала ошибки, новая версия 2012 года (с поддержкой System.Numerics.BigInteger) кажется более надежной. Однако в этой версии отсутствует способ шифрования с помощью открытого ключа и дешифрования с помощью закрытого ключа.

Итак, я пробовал сам, но при расшифровке получаю мусор. Я не знаком с провайдером RSA, поэтому я здесь в неведении. Трудно найти дополнительную информацию о том, как это должно работать.

Кто-нибудь видит, что с этим не так? Следующее - Шифрование с ПУБЛИЧНЫМ ключом:

// Add 4 byte padding to the data, and convert to BigInteger struct
BigInteger numData = GetBig( AddPadding( data ) );
RSAParameters rsaParams = rsa.ExportParameters( false );
//BigInteger D = GetBig( rsaParams.D ); //only for private key
BigInteger Exponent = GetBig( rsaParams.Exponent );
BigInteger Modulus = GetBig( rsaParams.Modulus );
BigInteger encData = BigInteger.ModPow( numData, Exponent, Modulus );    
return encData.ToByteArray();

Я использую большую букву D от провайдера, когда это делаю? Вероятно, нет, поскольку это открытый ключ, у которого нет буквы «D».

Затем аналог (расшифровка с использованием ЧАСТНОГО ключа):

BigInteger numEncData = new BigInteger( cipherData );

RSAParameters rsaParams = rsa.ExportParameters( true );
BigInteger D = GetBig( rsaParams.D );
//BigInteger Exponent = GetBig( rsaParams.Exponent );
BigInteger Modulus = GetBig( rsaParams.Modulus );

BigInteger decData = BigInteger.ModPow( numEncData, D, Modulus );

byte[] data = decData.ToByteArray();
byte[] result = new byte[ data.Length - 1 ];
Array.Copy( data, result, result.Length );
result = RemovePadding( result );

Array.Reverse( result );
return result;

Нужна ли мне здесь "D" или экспонента?

Очевидно, мне нужно, чтобы криптовалюта работала в обоих направлениях: частное-государственное-государственное-частное. Любая помощь приветствуется!


person John    schedule 29.03.2013    source источник


Ответы (2)


вот вам пример:

    public static void rsaPlayground()
    {
        byte[] data = new byte[] { 1, 2, 3, 4, 5 };
        RSACryptoServiceProvider csp = new RSACryptoServiceProvider();//make a new csp with a new keypair
        var pub_key = csp.ExportParameters(false); // export public key
        var priv_key = csp.ExportParameters(true); // export private key

        var encData = csp.Encrypt(data, false); // encrypt with PKCS#1_V1.5 Padding
        var decBytes = MyRSAImpl.plainDecryptPriv(encData, priv_key); //decrypt with own BigInteger based implementation
        var decData = decBytes.SkipWhile(x => x != 0).Skip(1).ToArray();//strip PKCS#1_V1.5 padding

    }

    public class MyRSAImpl 
    {

        private static byte[] rsaOperation(byte[] data, BigInteger exp, BigInteger mod)
        {
            BigInteger bData = new BigInteger(
                data    //our data block
                .Reverse()  //BigInteger has another byte order
                .Concat(new byte[] { 0 }) // append 0 so we are allways handling positive numbers
                .ToArray() // constructor wants an array
            );
            return 
                BigInteger.ModPow(bData, exp, mod) // the RSA operation itself
                .ToByteArray() //make bytes from BigInteger
                .Reverse() // back to "normal" byte order
                .ToArray(); // return as byte array

            /*
             * 
             * A few words on Padding:
             * 
             * you will want to strip padding after decryption or apply before encryption 
             * 
             */
        }

        public static byte[] plainEncryptPriv(byte[] data, RSAParameters key) 
        {
            MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
            return rsaOperation(data, myKey.privExponent, myKey.Modulus);
        }
        public static byte[] plainEncryptPub(byte[] data, RSAParameters key)
        {
            MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
            return rsaOperation(data, myKey.pubExponent, myKey.Modulus);
        }
        public static byte[] plainDecryptPriv(byte[] data, RSAParameters key)
        {
            MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
            return rsaOperation(data, myKey.privExponent, myKey.Modulus);
        }
        public static byte[] plainDecryptPub(byte[] data, RSAParameters key)
        {
            MyRSAParams myKey = MyRSAParams.fromRSAParameters(key);
            return rsaOperation(data, myKey.pubExponent, myKey.Modulus);
        }

    }

    public class MyRSAParams
    {
        public static MyRSAParams fromRSAParameters(RSAParameters key)
        {
            var ret = new MyRSAParams();
            ret.Modulus = new BigInteger(key.Modulus.Reverse().Concat(new byte[] { 0 }).ToArray());
            ret.privExponent = new BigInteger(key.D.Reverse().Concat(new byte[] { 0 }).ToArray());
            ret.pubExponent = new BigInteger(key.Exponent.Reverse().Concat(new byte[] { 0 }).ToArray());

            return ret;
        }
        public BigInteger Modulus;
        public BigInteger privExponent;
        public BigInteger pubExponent;
    }
person DarkSquirrel42    schedule 29.03.2013
comment
элемент «D» не встречается в открытом ключе. он устанавливается только при использовании закрытого ключа для расшифровки, и поэтому ваш пример завершится ошибкой, если закрытый ключ не будет распространен вместе с приложением. - person Kraang Prime; 22.05.2015
comment
ммм ... это может быть факт, что вы не можете расшифровать с помощью закрытого ключа, когда у вас его нет ... да ... какое это имеет отношение к примеру расчета, который просто показывает, как это сделать математика RSA? - person DarkSquirrel42; 29.05.2015
comment
Неправильно, вы можете расшифровать данные, которые были зашифрованы с использованием закрытого ключа, используя ТОЛЬКО открытый ключ в процессе расшифровки. В приведенном выше примере требуется закрытый ключ, независимо от того, используется ли для расшифровки открытый или закрытый ключ. Взгляните на свой образец, и вы все поймете. Для всех вам требуются ОБЕ общедоступные и частные, чтобы любой из ваших методов дешифрования работал, что неверно. - person Kraang Prime; 30.05.2015
comment
В частности, MyRSAParams.fromRSAParameters ищет частную и публичную экспоненту. - значение D. - person Kraang Prime; 30.05.2015
comment
вздох ... так ... вы хотите сказать, что конструктор не уважает открытые ключи? ... напишите свой собственный ... это пример, который показывает, как делать математику и как читать ключевые компоненты ... без бесплатного копирования и вставки производственного кода с гарантиями ... не стесняйтесь размещать свой собственный ответ ... - person DarkSquirrel42; 01.06.2015
comment
Настоящая магия! Интересно, почему это после некоторого поиска в Google является единственным ответом на этот вариант использования. Кажется, это обычная проблема: предоставить некоторую информацию, которую могу предоставить только я (дистрибьютор, безопасно), и не доверять другой стороне (клиент, небезопасно). Хеш для этого не годится, поскольку клиент всегда может обойти проверку, поэтому единственный способ - иметь механизм для шифрования с помощью закрытого ключа и дешифрования с помощью открытого ключа, чтобы клиент не мог генерировать свои собственные секреты в будущее. - person Andreas Reiff; 20.03.2017
comment
Кроме того, похоже, что x == decrypt (encrypt (x)) == encrypt (decrypt (x)). Идеально! - person Andreas Reiff; 20.03.2017

Возьмите этот пример кодирования / декодирования

        byte[] toEncryptData = Encoding.ASCII.GetBytes("hello world");

        //Generate keys
        RSACryptoServiceProvider rsaGenKeys = new RSACryptoServiceProvider();
        string privateXml = rsaGenKeys.ToXmlString(true);
        string publicXml = rsaGenKeys.ToXmlString(false);

        //Encode with public key
        RSACryptoServiceProvider rsaPublic = new RSACryptoServiceProvider();
        rsaPublic.FromXmlString(publicXml);
        byte[] encryptedRSA = rsaPublic.Encrypt(toEncryptData, false);
        string EncryptedResult = Encoding.Default.GetString(encryptedRSA);


        //Decode with private key
        var rsaPrivate = new RSACryptoServiceProvider();
        rsaPrivate.FromXmlString(privateXml);
        byte[] decryptedRSA = rsaPrivate.Decrypt(encryptedRSA, false);
        string originalResult = Encoding.Default.GetString(decryptedRSA);
person Ivan Plyusnin    schedule 20.07.2013
comment
В исходном вопросе просили привести примеры обоих направлений. Ваш код показывает, как выполнять дешифрование только с закрытым ключом, а не как расшифровывать с помощью открытого ключа. - person Kraang Prime; 22.05.2015
comment
В случае RSA расшифровывать с помощью открытого ключа не нужно. За исключением того, что вы имеете в виду подписание RSA. - person Ivan Plyusnin; 25.05.2015
comment
Нет, я имею в виду расшифровать с помощью открытого ключа. Например, в php использование openssl_private_encrypt () - сохранение закрытого ключа PRIVATE на сервере в том виде, в каком он должен быть. Теперь в клиенте это нужно будет расшифровать с помощью открытого ключа (примером клиентов может быть программа, написанная на C # и подписанная с помощью AuthentiCode). Удобно иметь встроенный сертификат в программу (часть процесса подписи). А теперь представьте себе это с другой стороны - эпический провал. И создание хэша, который нужно проанализировать для проверки данных - так легко взломать. - person Kraang Prime; 26.05.2015
comment
Я скажу это, однако, это не ваша вина, что остальной мир сошел с ума и считает, что распространение закрытых ключей по клиентским приложениям - это разумный способ - или, что еще лучше, использование самозаверяющих закрытых ключей на стороне клиента и хранение тонна открытых ключей на сервере - которые легко подделать, и которые на 100% бесполезны для всего, что имеет действительно безопасный характер, например, для лицензирования программного обеспечения. - person Kraang Prime; 26.05.2015
comment
Возможно, мой ответ был поспешным. Я думаю, что у RSACryptoServiceProvider есть преднамеренное ограничение, чтобы избежать возможных ошибок при частном шифровании / публичном дешифровании. А для подписи мы можем использовать SignData / VerifyData. - person Ivan Plyusnin; 28.05.2015
comment
Не совсем уверен, почему багги Microsoft расшифровывают при использовании криптографии, но, к счастью, (довольно) тривиально использовать BigInteger в сочетании с параметрами экспорта криптографии, чтобы это произошло. Разумеется, есть использование публичного шифрования, частного дешифрования, такого как программа, которую вы распространяете клиентам, которая должна отправлять данные на сервер. Вообще говоря, с самого начала ключей pub / priv это был закрытый ключ для отправителя данных и открытый ключ для получателя (для расшифровки). Не уверен, когда и как люди это запутали. Даже Thawte до сих пор упоминает об этом способе. - person Kraang Prime; 28.05.2015
comment
Зачем нужно сгенерировать ключ снова? потому что у нас уже есть private_component и private exponent? Извините, я все еще в темноте. - person Sml004; 02.06.2016