我正在尝试手动设置RSAParameters
的属性,但是在尝试加密,解密甚至实例化RSACryptoServiceProvider
时遇到各种错误。
如果仅设置指数和模量,则可以对消息进行加密;但是当我尝试解密它时,我得到了Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'Key does not exist
如果我设置了所有属性,则会得到一个System.Security.Cryptography.CryptographicException: 'The specified RSA parameters are not valid; both Exponent and Modulus are required fields.'
我的问题是为什么?我的参数出了什么问题?
我显然不对字段使用随机值;我从另一个项目中复制粘贴了它们的字符串表示形式。
下面是我编写的代码,它针对.Net Core 2.1。 我对其进行了更新,以包含此length restrictions
namespace PlayingWithCryptography {
using System;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
public static class Program {
private static void Main(string[] args) {
var msg = "lol";
var encodedMessage = Encoding.ASCII.GetBytes(msg);
var parameters = new RSAParameters();
parameters.P = BigInteger.Parse("14299623962416399520070177382898895550795403345466153217470516082934737582776038882967213386204600674145392845853859217990626450972452084065728686565928113").ToByteArray();
parameters.Q = BigInteger.Parse("7630979195970404721891201847792002125535401292779123937207447574596692788513647179235335529307251350570728407373705564708871762033017096809910315212884101").ToByteArray();
parameters.D = BigInteger.Parse("46730330223584118622160180015036832148732986808519344675210555262940258739805766860224610646919605860206328024326703361630109888417839241959507572247284807035235569619173792292786907845791904955103601652822519121908367187885509270025388641700821735345222087940578381210879116823013776808975766851829020659073").ToByteArray();
parameters.Modulus = BigInteger.Parse("109120132967399429278860960508995541528237502902798129123468757937266291492576446330739696001110603907230888610072655818825358503429057592827629436413108566029093628212635953836686562675849720620786279431090218017681061521755056710823876476444260558147179707119674283982419152118103759076030616683978566631413").ToByteArray();
parameters.Exponent = BigInteger.Parse("65537").ToByteArray();
parameters.DP = BigInteger.Parse("11141736698610418925078406669215087697114858422461871124661098818361832856659225315773346115219673296375487744032858798960485665997181641221483584094519937").ToByteArray();
parameters.DQ = BigInteger.Parse("4886309137722172729208909250386672706991365415741885286554321031904881408516947737562153523770981322408725111241551398797744838697461929408240938369297973").ToByteArray();
parameters.InverseQ = BigInteger.Parse("5610960212328996596431206032772162188356793727360507633581722789998709372832546447914318965787194031968482458122348411654607397146261039733584248408719418").ToByteArray();
Console.WriteLine($"M[0]={parameters.Modulus[0]}");
Console.WriteLine($"D.Length={parameters.D.Length}");
Console.WriteLine($"M.Length={parameters.Modulus.Length}");
Console.WriteLine($"E={parameters.Exponent[0]}");
Console.WriteLine($"P.Length={ parameters.P.Length}");
Console.WriteLine($"Q.Length={ parameters.Q.Length}");
Console.WriteLine($"DP.Length={ parameters.DP.Length}");
Console.WriteLine($"DQ.Length={ parameters.DQ.Length}");
Console.WriteLine($"InverseQ.Length={ parameters.InverseQ.Length}");
// Adding zeros coz https://stackoverflow.com/questions/42098493/decrypting-with-rsa-encryption-in-vb-net/42117655#42117655
parameters.D = new byte[] { 0 }.Concat(parameters.D).ToArray();
parameters.DQ = new byte[] { 0 }.Concat(parameters.DQ).ToArray();
parameters.InverseQ = new byte[] { 0 }.Concat(parameters.InverseQ).ToArray();
Console.WriteLine();
Console.WriteLine($"M[0]={parameters.Modulus[0]}");
Console.WriteLine($"D.Length={parameters.D.Length}");
Console.WriteLine($"M.Length={parameters.Modulus.Length}");
Console.WriteLine($"E[0]={parameters.Exponent[0]}");
Console.WriteLine($"P.Length={ parameters.P.Length}");
Console.WriteLine($"Q.Length={ parameters.Q.Length}");
Console.WriteLine($"DP.Length={ parameters.DP.Length}");
Console.WriteLine($"DQ.Length={ parameters.DQ.Length}");
Console.WriteLine($"InverseQ.Length={ parameters.InverseQ.Length}");
var csp = RSACryptoServiceProvider.Create();
csp.ImportParameters(parameters);
var encrypted = csp.Encrypt(
data: encodedMessage,
padding: RSAEncryptionPadding.OaepSHA256);
var decrypted = csp.Decrypt(
data: encrypted,
padding: RSAEncryptionPadding.OaepSHA256);
var decoded = Encoding.ASCII.GetString(decrypted);
Console.WriteLine(decoded);
Console.WriteLine("Done!");
}
}
}
回答对于处于类似情况的任何人,请阅读(并投票)James K Polk的答案,然后阅读answer for this question
答案 0 :(得分:1)
用户bartonjs(也是同名的stackoverflow用户)在“反馈”部分的页面底部给出了RSAParameters
字段的外观详细信息。这是他的评论的副本:
RSAParameters值的数组的完整规则如下:
其他字段必须全部为空(公用密钥参数)或全部非空(专用密钥参数)。当值不为空时:
示例:对于KeySize值为2056且标准公共指数值为0x010001的RSA密钥,数组长度为:
公钥:
私钥:
请注意,BigInteger.ToByteArray()
返回little-endian表示形式。必须颠倒此顺序才能获得RSAParameters
所要求的big-endian表示形式。
答案 1 :(得分:1)
我现在暂时不回答其他问题,但是我有理由怀疑其中引用的限制。对于问题中的参数,我的另一个答案表明RSAParameters.P
必须正好是64个字节。但这不可能,因为问题中的P至少需要65个字节才能表示。
相反,我建议您使用RSA.FromXMLString()
方法导入RSA公钥和私钥。这似乎是基于称为XML Signature Syntax and Processing Version 1.1的外部标准,尤其是this section和更多详细信息here。基本思想是将整数编码为最小长度的Big-endian字节数组-没有前导零-然后对其进行base64编码。
这里有一些经过严格测试的代码可以完成它。请注意,C#和.NET并不是我的强项,因此可以随时进行改进。请注意,在我的平台上,OAEPSha1是唯一受支持的OAEP填充。
using System;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
namespace PlayingWithCryptography
{
public static class ConvertToRSAParameters
{
public static string ConvertXML(BigInteger e, BigInteger n)
{
var xml = new StringBuilder();
xml.AppendLine(WrapTags(BigToBase64(n), "Modulus"));
xml.AppendLine(WrapTags(BigToBase64(e), "Exponent"));
WrapTags(xml, "RSAKeyValue");
return xml.ToString();
}
public static string ConvertXML(BigInteger e, BigInteger n, BigInteger p, BigInteger q,
BigInteger d, BigInteger dp, BigInteger dq, BigInteger inverseQ)
{
var xml = new StringBuilder();
xml.AppendLine(WrapTags(BigToBase64(n), "Modulus"));
xml.AppendLine(WrapTags(BigToBase64(e), "Exponent"));
xml.AppendLine(WrapTags(BigToBase64(p), "P"));
xml.AppendLine(WrapTags(BigToBase64(q), "Q"));
xml.AppendLine(WrapTags(BigToBase64(d), "D"));
xml.AppendLine(WrapTags(BigToBase64(dp), "DP"));
xml.AppendLine(WrapTags(BigToBase64(dq), "DQ"));
xml.AppendLine(WrapTags(BigToBase64(inverseQ), "InverseQ"));
WrapTags(xml, "RSAKeyValue");
return xml.ToString();
}
private static string BigToBase64(BigInteger val)
{
var valBytes = val.ToByteArray();
int len = valBytes.Length;
while (valBytes[len - 1] == 0)
{
--len;
if (len == 0)
{
break;
}
}
Array.Resize(ref valBytes, len);
Array.Reverse(valBytes);
return System.Convert.ToBase64String(valBytes);
}
private static string WrapTags(string target, string tag)
{
return String.Format("<{0}>{1}</{0}>", tag, target);
}
private static StringBuilder WrapTags(StringBuilder target, string tag)
{
return target.Insert(0, String.Format("<{0}>", tag)).AppendFormat("</{0}>", tag);
}
private static void Main(string[] args)
{
var msg = "lol";
var encodedMessage = Encoding.ASCII.GetBytes(msg);
Console.WriteLine();
var publicRsa = RSA.Create();
publicRsa.FromXmlString(
ConvertToRSAParameters.ConvertXML(
BigInteger.Parse("65537"),
BigInteger.Parse("109120132967399429278860960508995541528237502902798129123468757937266291492576446330739696001110603907230888610072655818825358503429057592827629436413108566029093628212635953836686562675849720620786279431090218017681061521755056710823876476444260558147179707119674283982419152118103759076030616683978566631413")
)
);
var privateRsa = RSA.Create();
privateRsa.FromXmlString(
ConvertToRSAParameters.ConvertXML(
BigInteger.Parse("65537"),
BigInteger.Parse("109120132967399429278860960508995541528237502902798129123468757937266291492576446330739696001110603907230888610072655818825358503429057592827629436413108566029093628212635953836686562675849720620786279431090218017681061521755056710823876476444260558147179707119674283982419152118103759076030616683978566631413"),
BigInteger.Parse("14299623962416399520070177382898895550795403345466153217470516082934737582776038882967213386204600674145392845853859217990626450972452084065728686565928113"),
BigInteger.Parse("7630979195970404721891201847792002125535401292779123937207447574596692788513647179235335529307251350570728407373705564708871762033017096809910315212884101"),
BigInteger.Parse("46730330223584118622160180015036832148732986808519344675210555262940258739805766860224610646919605860206328024326703361630109888417839241959507572247284807035235569619173792292786907845791904955103601652822519121908367187885509270025388641700821735345222087940578381210879116823013776808975766851829020659073"),
BigInteger.Parse("11141736698610418925078406669215087697114858422461871124661098818361832856659225315773346115219673296375487744032858798960485665997181641221483584094519937"),
BigInteger.Parse("4886309137722172729208909250386672706991365415741885286554321031904881408516947737562153523770981322408725111241551398797744838697461929408240938369297973"),
BigInteger.Parse("5610960212328996596431206032772162188356793727360507633581722789998709372832546447914318965787194031968482458122348411654607397146261039733584248408719418")
)
);
var encrypted = publicRsa.Encrypt(
data: encodedMessage,
padding: RSAEncryptionPadding.OaepSHA1);
var decrypted = privateRsa.Decrypt(
data: encrypted,
padding: RSAEncryptionPadding.OaepSHA1);
var decoded = Encoding.ASCII.GetString(decrypted);
Console.WriteLine(decoded);
Console.WriteLine("Done!");
}
}
}