RSA расшифрока по private exponent и modulus в C#

Рейтинг: 0Ответов: 1Опубликовано: 20.02.2023

Код на java:

        byte[] decode = Base64.getDecoder().decode(str);
        PrivateKey generatePrivate = KeyFactory.getInstance("RSA").generatePrivate(new RSAPrivateKeySpec(new BigInteger("test1", 16), new BigInteger("test2", 16)));
        Security.getProvider("BC");
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(2, generatePrivate);
        return new String(cipher.doFinal(decode), "UTF-8");

Код на C#

RSAParameters rsaparam = new RSAParameters();
            rsaparam.Modulus = StringToByteArray(modF);
            rsaparam.Exponent = StringToByteArray(privExpF);
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.ImportParameters(rsaparam);
            byte[] encryptedData = RSA.Decrypt(data, false);

Вопрос:

При одинаковых данных модуля и экспоненты. Java отрабатывает нормально, но в c# выдается ошибка "Плохие данные".

Ответы

▲ 0

Для операций RSA используются разные ключи.

  • Encrypt - открытый ключ (public key);
  • Verify - открытый ключ (public key);
  • Decrypt - закрытый ключ (private key);
  • Sign - закрытый ключ (private key).

В примере на Java генерируется новый закрытый ключ:

PrivateKey generatePrivate = KeyFactory.getInstance("RSA").generatePrivate(new RSAPrivateKeySpec(new BigInteger("test1", 16), new BigInteger("test2", 16)));

А в примере на С# ключ состоит из Modulus и Exponent:

RSAParameters rsaparam = new RSAParameters();
rsaparam.Modulus = StringToByteArray(modF);
rsaparam.Exponent = StringToByteArray(privExpF);

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

  • Modulus,
  • Exponent,
  • D - закрытый Exponent,
  • Q, P - пара ключей, P * Q = Modulus,
  • DP, DQ, InverseQ - промежуточные значения для увеличения производительности дешифровки.

Пример работы RSA в C# (.NET 6):

using System.Security.Cryptography;
using System.Text;

// генерируем параметры
RSAParameters privateKey;
RSAParameters publicKey;
RSAEncryptionPadding padding = RSAEncryptionPadding.Pkcs1;
using (RSACryptoServiceProvider provider = new(4096))
{
  privateKey = provider.ExportParameters(true);
  publicKey = provider.ExportParameters(false);
}

// шифрование
string message = "{ Some example of data }";
Console.WriteLine("Data: " + message);
byte[] data = Encoding.UTF8.GetBytes(message);
byte[] encrypted;
using (RSACryptoServiceProvider provider = new())
{
  provider.ImportParameters(publicKey);
  encrypted = provider.Encrypt(data, padding);
}
Console.WriteLine("Encrypted: " + string.Join("-", encrypted.Select(x => x.ToString("X"))));

// дешифровка
byte[] decrypted;
using (RSACryptoServiceProvider provider = new())
{
  provider.ImportParameters(privateKey);
  publicKey = provider.ExportParameters(false);
  decrypted = provider.Decrypt(encrypted, padding);
}
Console.WriteLine("Decrypted: " + Encoding.UTF8.GetString(decrypted));

// пример по modulus, exponent
byte[] publicModulus = publicKey.Modulus;
byte[] publicExponent = publicKey.Exponent;
RSAParameters test = new RSAParameters() { Modulus= publicModulus, Exponent = publicExponent };
using (RSACryptoServiceProvider provider = new())
{
  provider.ImportParameters(test);
  encrypted = provider.Encrypt(data, padding);
}

// дешифруем вручную
// источник https://stackoverflow.com/questions/15702718/public-key-encryption-with-rsacryptoserviceprovider
byte[] privateModulus = privateKey.Modulus.Reverse().Concat(new byte[] { 0 }).ToArray();
byte[] privateExponent = privateKey.D.Reverse().Concat(new byte[] { 0 }).ToArray();
byte[] encConv = encrypted.Reverse().Concat(new byte[] { 0 }).ToArray();
BigInteger intModulus = new BigInteger(privateModulus);
BigInteger intExponent = new BigInteger(privateExponent);
BigInteger intEncrypted = new BigInteger(encConv);
decrypted = BigInteger.ModPow(intEncrypted, intExponent, intModulus).ToByteArray().Reverse().ToArray();
decrypted = decrypted.SkipWhile(x => x != 0).Skip(1).ToArray();
Console.WriteLine("Decrypted: " + Encoding.UTF8.GetString(decrypted));