Использование открытого ключа RSA для расшифровки строки, зашифрованной с помощью закрытого ключа RSA.

Это дубликат вопроса без ответа здесь: Использование открытого ключа RSA для расшифровки строки, зашифрованной с помощью закрытого ключа RSA

Вы можете видеть, что автор нашел решение, используя код отсюда: http://www.codeproject.com/KB/security/PrivateEncryption.aspx

Использование кода из этой ссылки выглядит очень многообещающе. Единственное, чего не хватает, так это набивки. Обычно я использую заполнение PKCS1.5, которое используется по умолчанию для OpenSSL RSA.

Я знаю, что ответ на этот вопрос очень близок. Я знаю, что единственное, что сдерживает расшифровку, — это заполнение pkcs1.5 в зашифрованном зашифрованном тексте openssl.

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

Я также активно пытался использовать RSACryptoServiceProvider для проверки хэша, полученного в результате шифрования с использованием OpenSSL. Например, я бы выполнил шифрование с закрытым ключом, используя хэш открытого текста SHA256, а затем попытался выполнить проверку этой подписи с помощью RSACryptoServiceProvider, и это не сработало. Я думаю, что то, как MS делает это, нестандартно, и, возможно, для этого есть специальные настройки.

Итак, альтернативой является этот вопрос, который просто берет зашифрованный текст с закрытым ключом и использует С# для его расшифровки, таким образом, проверяя его подлинность. Хэши могут быть включены для создания простой системы проверки подписи для объектов данных, подписанных сервером и проверенных на клиенте.

Я просмотрел RFC PKCS1, исходный код OpenSSL rsa и другие проекты, я не могу получить четкого ответа о том, как учитывать заполнение PKCS1 при выполнении RSA Decrypt. Я не могу найти, где в исходном коде OpenSSL они обрабатывают заполнение PKCS1, иначе у меня уже может быть ответ.

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

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

Возможно, самым простым решением здесь является простая фильтрация зашифрованного текста для удаления элементов заполнения...

Вот мой метод расшифровки:

    public static byte[] PublicDecryption(this RSACryptoServiceProvider rsa, byte[] cipherData)
    {
        if (cipherData == null)
            throw new ArgumentNullException("cipherData");

        BigInteger numEncData = new BigInteger(cipherData);

        RSAParameters rsaParams = rsa.ExportParameters(false);
        BigInteger Exponent = GetBig(rsaParams.Exponent);
        BigInteger Modulus = GetBig(rsaParams.Modulus);

        BigInteger decData = BigInteger.ModPow(numEncData, Exponent, 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;
    }

    private static byte[] RemovePadding(byte[] data)
    {
        byte[] results = new byte[data.Length - 4];
        Array.Copy(data, results, results.Length);
        return results;
    }

person Damian Patrick    schedule 12.06.2013    source источник
comment
Где код шифрования? Существует два вида заполнения PKCS #1 версии 1.5: заполнение блочного типа (BT) 1 и блочного типа 2. BT 1 используется для подписей RSA, что вы и делаете, BT 2 — для шифрования RSA.   -  person President James K. Polk    schedule 13.06.2013


Ответы (2)


Проблема не в прокладке. На самом деле удалить значения заполнения из расшифрованного зашифрованного текста на самом деле очень просто. Проблема была с программным обеспечением в этом месте: вы можете видеть, что автор нашел решение, используя некоторый код отсюда: http://www.codeproject.com/KB/security/PrivateEncryption.aspx

А с реализацией Microsoft System.Numeric, которая просто не может обрабатывать большие целые числа...

Чтобы решить эту проблему, я просмотрел предыдущие версии кода на сайте codeproject и остановился на этом методе PublicDecrypt.

    public static byte[] PublicDecryption(this RSACryptoServiceProvider rsa, byte[] cipherData)
    {
        if (cipherData == null)
            throw new ArgumentNullException("cipherData");

        BigInteger numEncData = new BigInteger(cipherData);
        RSAParameters rsaParams = rsa.ExportParameters(false);
        BigInteger Exponent = new BigInteger(rsaParams.Exponent);
        BigInteger Modulus = new BigInteger(rsaParams.Modulus);

        BigInteger decData2 = numEncData.modPow(Exponent, Modulus);
        byte[] data = decData2.getBytes();
        bool first = false;
        List<byte> bl = new List<byte>();
        for (int i = 0; i < data.Length; ++i)
        {
            if (!first && data[i] == 0x00)
            {
                first = true;
            }
            else if (first)
            {
                if (data[i] == 0x00)
                {
                    return bl.ToArray();
                }
                bl.Add(data[i]);
            }
        }
        if (bl.Count > 0)
            return bl.ToArray();
        return new byte[0];
    }

Это отлично расшифрует зашифрованный текст, созданный openssl, с помощью утилиты rsautl или метода Perl Crypt::OpenSSL::RSA private_encrypt.

Другим большим изменением стало удаление библиотеки Microsoft BitInteger, которая просто не работала. В итоге я использовал тот, который упоминается в статье Code Project, и нашел здесь: http://www.codeproject.com/Articles/2728/C-BigInteger-Class

Ключевым моментом здесь является установка maxintsize в библиотеке на значение, которое больше в зависимости от того, насколько большой размер ключа вы используете. Для 4096 бит значение 500 работало нормально (приблизительная длина модуля).

Вот метод вызова:

            var encmsg3 = "JIA7qtOrbBthptILxnurAeiQM3JzSoi5WiPCpZrIIqURKfVQMN1BrondF9kyNzbjTs1DaEKEuMBVwKExZe22yCvXXpm8pwcEGc9EHcVK2MPqNo89tIF8LJcaDqBMwLvxdaa/QgebtpmOVN/TIWfuiV8KR+Wn07KwsgV+3SALbNgbOIR3RtCx3IiQ3tZzybJb08+ZKwJEOT011uwvvGmtJskQgq9PC8kr1RPXMgaP6xMX7PHFJ8ORhkuWOFfCh+R4NhY1cItVhnRewKpIC2qVlpzUYRAgKIKdCXuZDqUQdIponR29eTovvLb0DvKQCLTf9WI1SzUm6pKRn0vLsQL7L3UYHWl43ISrTpDdp+3oclhgRF3uITR4WCvoljephbGc6Gelk5z3Vi6lN0oQaazJ7zIen+a/Ts7ZX3KKlwPl4/lAFRjdjoqu7u4IAK7O7u1Jf2xDiGw18C/eGt8UHl09zU4qQf9/u+7gtJ+10z2NERlLSaCDjVqslwmmxu81pG2gCv8LfpR4JlPaFfBZMGfGBihyGryWhJwizUXXo8wgdoYbHRXe8/gL19qro0ea5pA9aAhDjTpX1Zzbwu2rUU7j6wtwQtUDJOGXXCw1VOHsx6WXeW196RkqG72ucVIaSAlx5TFJv8cnj6werEx1Ung5456gth3gj19zHc8E/Mwcpsk=";
            byte[] enc = Convert.FromBase64String(encmsg3);
            var dec = rsa2.PublicDecryption(enc);
            Debug.Print("PLAINTEXT: " + Encoding.UTF8.GetString(dec));

Единственное, что кому-то нужно будет полностью воспроизвести, это получить закрытый ключ в формате openssl, чтобы они могли передавать закрытый и открытый ключи туда и обратно между openssl и C#.

Я использовал openssl.net, создал экземпляр RSA и установил все переменные, используя большие числа. Вот код для этого:

        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(Properties.Resources.RSAParameters);

        RSAParameters par = rsa.ExportParameters(true); // export the private key


        using (OpenSSL.Crypto.RSA rsaos = new OpenSSL.Crypto.RSA())
        using (BigNumber bnmod = BigNumber.FromArray(par.Modulus))
        using (BigNumber bnexp = BigNumber.FromArray(par.Exponent))
        using (BigNumber bnD = BigNumber.FromArray(par.D))
        using (BigNumber bnP = BigNumber.FromArray(par.P))
        using (BigNumber bnQ = BigNumber.FromArray(par.Q))
        using (BigNumber bnDmodP = BigNumber.FromArray(par.DP))
        using (BigNumber bnDmodQ = BigNumber.FromArray(par.DQ))
        using (BigNumber bnInverse = BigNumber.FromArray(par.InverseQ))
        {
            rsaos.PublicExponent = bnexp;
            rsaos.PublicModulus = bnmod;

            rsaos.IQmodP = bnInverse;
            rsaos.DmodP1 = bnDmodP;
            rsaos.DmodQ1 = bnDmodQ;
            rsaos.SecretPrimeFactorP = bnP;
            rsaos.SecretPrimeFactorQ = bnQ;
            rsaos.PrivateExponent = bnD;
            string privatekey = rsaos.PrivateKeyAsPEM;   
            string publickey = rsaos.PublicKeyAsPEM
        }

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

Прохладный.

person Damian Patrick    schedule 12.06.2013

Проблема в строке функции PublicDecryption: BigInteger numEncData = new BigInteger(cipherData);

это должно быть: BigInteger numEncData = GetBig(cipherData);

Эта строка также должна быть удалена: Array.Reverse(result);

Вы можете столкнуться с некоторыми проблемами заполнения, но если вы сможете правильно ввести данные, это будет легко исправить.

person Rex    schedule 08.01.2014