繁体   English   中英

如何使用手动设置的RSA参数加密和解密字符串? 为什么RSACryptoServiceProvider抛出?

[英]How to encrypt and decrypt a string with manually set RSA parameters? Why RSACryptoServiceProvider is throwing?

我正在尝试手动设置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.'得到System.Security.Cryptography.CryptographicException: 'The specified RSA parameters are not valid; both Exponent and Modulus are required fields.' System.Security.Cryptography.CryptographicException: 'The specified RSA parameters are not valid; both Exponent and Modulus are required fields.'

我的问题是为什么? 我的参数有什么问题?

我显然没有在字段中使用随机值; 我从另一个项目中复制粘贴了它们的字符串表示形式。

下面是我编写的代码,它针对.Net Core 2.1。 我更新了它以包括此长度限制

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!");
        }

    }
}

类似的情况回答任何人,请阅读(投)两詹姆斯·诺克斯·波尔克的答案,然后回答这个问题

bartonjs用户(也是同名的stackoverflow用户)在“反馈”部分的页面底部给出了RSAParameters字段必须为什么样的详细信息。 这是他的评论的副本:

RSAParameters值的数组的完整规则如下:

  • 模量:RSA模量值的无符号大端表示。 模数[0]的值不能为0x00。
  • 指数:RSA公共指数值的无符号big-endian表示形式。 指数[0]的值不能为0x00。

其他字段必须全部为空(公用密钥参数),或全部非空(专用密钥参数)。 当值不为空时:

  • D:RSA私有指数值的无符号big-endian表示形式。 该数组的长度必须等于Modulus值的长度,并根据需要在低索引处插入0x00值字节。
  • P:RSA素数p的无符号大尾数表示。 该数组的长度必须等于Modulus值长度的一半(如有必要,向上取整),并根据需要在低索引处插入0x00值字节。
  • 问:RSA素数q的无符号大尾数表示。 该数组的长度必须等于Modulus值长度的一半(如有必要,向上取整),并根据需要在低索引处插入0x00值字节。 DP:RSA CRT参数dp的无符号大端格式表示。 该数组的长度必须等于Modulus值长度的一半(如有必要,向上取整),并根据需要在低索引处插入0x00值字节。
  • DQ:RSA CRT参数dq的无符号大尾数表示。 该数组的长度必须等于Modulus值长度的一半(如有必要,向上取整),并根据需要在低索引处插入0x00值字节。
  • InverseQ:RSA CRT参数qInverse的无符号大端表示。 该数组的长度必须等于Modulus值长度的一半(如有必要,向上取整),并根据需要在低索引处插入0x00值字节。

示例:对于具有2056的KeySize值和标准公共指数值0x010001的RSA密钥,数组长度为:

公钥:

  • 模数:257字节
  • 指数:3个字节
  • D,P,Q,DP,DQ,InverseQ:空值。

私钥:

  • 模数:257字节
  • 指数:3个字节
  • D:257字节
  • P:129字节
  • Q:129个字节
  • DP:129个字节
  • DQ:129个字节
  • InverseQ:129个字节

请注意, BigInteger.ToByteArray()返回little-endian表示形式。 必须颠倒此顺序以获得RSAParameters所需的big-endian表示形式。

我现在暂时不回答其他问题,但是我有理由怀疑其中引用的限制。 对于问题中的参数,我的另一个答案建议RSAParameters.P必须恰好是64个字节。 但是,这可能行不通,因为问题中的P至少需要65个字节才能表示。

相反,我建议您使用RSA.FromXMLString()方法导入RSA公钥和私钥。 这似乎是基于称为XML签名语法和处理版本1.1的外部标准的,尤其是本节此处有更多详细信息。 基本思想是将整数编码为最小长度的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!");
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM