使用RSA公钥解密使用RSA私钥加密的字符串
本文关键字:RSA 加密 字符串 私钥 密使 公钥 解密 使用 | 更新日期: 2023-09-27 18:18:17
这是一个未解问题的重复:使用RSA公钥解密使用RSA私钥加密的字符串
你可以看到作者找到了一个解决方案,使用一些代码从这里:http://www.codeproject.com/KB/security/PrivateEncryption.aspx
使用该链接中的代码看起来非常有希望。唯一缺少的是填充物。我通常使用PKCS1.5填充,这是OpenSSL RSA的默认值。
我知道这个问题的答案非常接近。我知道唯一阻碍解密的是加密的openssl密文上的pkcs1.5填充。我很惊讶地看到关于这个主题的信息是多么的少,因为在很多情况下,你需要一个服务器来加密一些东西,签署一些东西,等等,并有一个客户端应用程序验证,解密,等等与公钥。
我还广泛尝试使用RSACryptoServiceProvider来验证使用OpenSSL加密产生的哈希值。例如,我将使用明文的SHA256哈希进行私钥加密,然后尝试对该签名进行RSACryptoServiceProvider验证,但它不起作用。我认为微软这样做的方式是非标准的,可能有特殊的定制工作。
所以,另一种选择是这个问题,它只是简单地使用私钥加密的密文并使用c#对其解密,从而验证它的真实性。哈希可以被合并成一个简单的签名验证系统,用于由服务器签名并在客户端验证的数据对象。
我已经看过PKCS1 RFC, OpenSSL rsa源代码和其他项目,我无法得到关于如何在做rsa解密时解释PKCS1填充的可靠答案。我无法在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;
}
问题不在于填充。实际上,从解密的密文中删除填充值实际上非常简单。问题出在这个地方的软件上:您可以看到作者找到了一个解决方案,使用一些代码从这里:http://www.codeproject.com/KB/security/PrivateEncryption.aspx
并配合Microsoft的系统实现。不能处理更大的整数的数字…
为了解决这个问题,我查看了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];
}
它将使用rsautl实用程序或Perl Crypt:: openssl::RSA private_encrypt方法完美地解密由openssl创建的密文。
另一个大的变化是放弃了微软的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,并在合理的范围内加密/解密任何你想要的东西。它足以处理私钥加密,然后是公钥解密。
酷。
PublicDecryption函数中有一个问题:BigInteger numEncData = new BigInteger(cipherData);
应是:BigInteger numEncData = GetBig(密码数据);
这一行也应删除:
Array.Reverse(结果);你可能会遇到一些填充问题,但如果你能得到正确的数据,它应该很容易纠正。