RSA расшифрока по private exponent и modulus в C#
Код на 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# выдается ошибка "Плохие данные".
Ответы (1 шт):
Автор решения: Arkee
→ Ссылка
Для операций 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));