使用RSA公钥来解密使用RSA被加密的字符串私钥
这是一个悬而未决的问题在这里的副本:Using an RSA Public Key to decrypt a string that was encrypted using RSA Private Key使用RSA公钥来解密使用RSA被加密的字符串私钥
你可以看到笔者发现使用一些代码的解决方案从这里: http://www.codeproject.com/KB/security/PrivateEncryption.aspx
使用该链接的代码看起来很有希望。唯一缺少的是填充。我通常使用PKCS1.5填充,这是OpenSSL RSA的默认填充。
我知道这个问题的答案非常接近。我知道唯一阻止解密的是加密的openssl密文上的pkcs1.5填充。
我很惊讶地发现这个主题上的信息很少,因为在很多情况下你需要一个服务器来加密某些东西,签署某些东西等等,并且让客户端应用程序验证,解密等等公钥。
我也广泛尝试使用RSACryptoServiceProvider来验证使用OpenSSL进行加密所产生的哈希结果。例如,我会使用明文的SHA256散列进行私钥加密,然后尝试对该签名执行RSACryptoServiceProvider验证,但它不起作用。我认为MS做这件事的方式并不标准,可能还有特殊的定制。
所以,另一种方法是这个问题,它只是采用私钥加密的密文并使用C#解密它,从而验证其真实性。哈希可以合并为一个简单的签名验证系统,用于由服务器签名并在客户端进行验证的数据对象。
我已经浏览了PKCS1 RFC,OpenSSL rsa源代码和其他项目,但是在做RSA解密时,我无法得到关于如何解释PKCS1填充的明确答案。我无法找到他们处理PKCS1填充的OpenSSL源代码的位置,否则,我现在可能会有答案。另外,这是我的第一个问题,我知道它是一个未答复的问题的重复,所以,该怎么办?我也搜索了这个,并没有发现任何东西。
我不明白的另一件事是为什么我的解密方法不起作用。由于填充在解密后被移除,我的解密数据应该类似于明文,并且它甚至不是很接近。所以,我几乎肯定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的实现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];
}
这将完全解密使用rsautl实用程序通过OpenSSL的创建的密文,或Perl的隐窝:: OpenSSL的:: RSA private_encrypt方法。
另一个重大变化是丢弃了Microsoft BitInteger库,它根本无法工作。我最终使用了代码项目文章中提到的一个,并在此处找到: 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实例,并使用bignumbers设置所有变量。下面是该代码:
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(cipherData);
该行也应该删除: Array.Reverse(result);
您可能会遇到一些填充问题,但如果您可以正确获取数据,则应该很容易对其进行纠正。
加密代码在哪里?有*两种* PKCS#1版本1.5填充:块类型(BT)1和块类型2填充。 BT 1用于你正在做的RSA签名,BT 2用于RSA加密。 –