c# RSA中有了私钥对d和n怎么解密啊,

时间:2022-08-27 21:34:32
现在有了私钥对(n,d)怎么对密文解密啊,求指导,RSACryptoServiceProvider不行吧

8 个解决方案

#1


理论上n和d就足够了:
m = pow(c,d) mod n
其中c为秘文,m为明文。pow为计算c的d次方。

但是,DotNet的实现可能用了一些快速算法(比如中国剩余定理),因此如果你要用RSACryptoServiceProvider的话,那些P,Q等也需要。

#2


引用 1 楼 gomoku 的回复:
理论上n和d就足够了:
m = pow(c,d) mod n
其中c为秘文,m为明文。pow为计算c的d次方。

但是,DotNet的实现可能用了一些快速算法(比如中国剩余定理),因此如果你要用RSACryptoServiceProvider的话,那些P,Q等也需要。
能给个详细一点的算法么,我弄的好像不是很对哎,谢谢啦,

#3


引用 1 楼 gomoku 的回复:
理论上n和d就足够了:
m = pow(c,d) mod n
其中c为秘文,m为明文。pow为计算c的d次方。

但是,DotNet的实现可能用了一些快速算法(比如中国剩余定理),因此如果你要用RSACryptoServiceProvider的话,那些P,Q等也需要。
如果pq那些都有的话怎么初始化啊,网上看了好像没明白怎么用这些值初始化

#4


求指导啊   。。。。。。。。。。。。。。。。。

#5


注意BigInteger在DotNet4或以上才正式支持,需要添加System.Numerics引用。

using System;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Numerics;                   // <--
using System.Security.Cryptography;

class Program
{
    static string key =
    @"<RSAKeyValue>
      <Modulus>qjWim96tKp7fMgYtAKZRnLW1dOhbUAsWnzD1MMgtXC9WQYa72/riPTEUM+woW0lMHQKwKUKNVmwZ0TuSAzXAuX8frWU9g/iTL/wxqkql8fCzuGA21+4bvsu3RfuRM4mHY2A9hwLw6pugvz8sogao0x+j/HRUlnpwD7z/CQenats=</Modulus>
      <Exponent>AQAB</Exponent>
      <P>1xrSggP33Z3zi2pR6y86xCtJxZoDSCm382f0BZRgBv9FXPb2NU+jhS2hstIEED69Xr2t2jSwsXOlnw9wS/zgEw==</P>
      <Q>ypHBK9N6Z9O6n83saF+zWsSG9ZPgKwWAWbLnEhEQzbcDCHivz1OZInBqPb2wieAh1uzFywtXpdy7nWoWux9zGQ==</Q>
      <DP>hdTLWlcrtTfb2kbZFvF4p6qjKI1NM225ZHit63bIVDIortF8l+invWmJrF9cZdsTKUnsS9HyiUWBqzgIz05S/w==</DP>
      <DQ>ZAv4zBx2qDD6S1L5H9OkUYAe58tRO+5LpgGl/lZPZkqtRNHWgx9W0puS3UuClZYNIIlwZwgDEfgi8WwkLecqgQ==</DQ>
      <InverseQ>DmS5UXVYYSRcIrgyMf8ZX/4fidDPeIEz834gmjx9VuPQhgL0wXbXog7rpsAQ9+3m1/BvoXyB1okg76BEdg52RQ==</InverseQ>
      <D>c2zZ7+/q6LtCSq8rd4RSVf5Xpocn3TkXxy6xJ7qoIBqt2NPgs4YIREzzEV714ynqpsW65tAN/uxh+aT3GJwsK8POGUNowVoDwAASFOhEQD/RJVaiowB1Q6O6uTYFHE34e95XHVv3G58c8bG+87cmOjWSFfewTc993Z2kbAuoR5E=</D>
    </RSAKeyValue>";

    static void Main(string[] args)
    {
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(key);

        byte[] encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes("hello"), false);
        byte[] decrypted = MyRSADecrypted(encrypted, false);

        string str = Encoding.UTF8.GetString(decrypted);     //"hello"
    }

    private static BigInteger FromBytes(byte[] beBytes)
    {
        // 1、BigInteger的构造函数接受byte[]的格式是“低位在前(Litter Endian)”。所以以下两行是等价的:
        //    new BigInteger(new byte[]{1, 2, 3, 4})
        //    new BitInteger(new byte[]{1, 2, 3, 4, 0, 0, 0})
        // 2、BigInteger支持负数,如果byte[]的最高二进制位非零,则表示为负数,比如new byte[]{1,2,3, 0x80}就是负数。
        //    而RSA中的参数都是正整数,因此,Concat(0)用来保证正整数。
        // 3、如果输入的byte[]的格式是“高位在前(Big Endian)”,那么要先用Reverse翻转一次。
        return new BigInteger(beBytes.Reverse().Concat(new byte[] { 0 }).ToArray());
    }

    /// <summary>
    /// 只用n和d来进行RSA解密
    /// </summary>
    private static byte[] MyRSADecrypted(byte[] encrypted, bool fOAEP)
    {
        XElement keyXml = XElement.Parse(key);
        byte[] Modulus = Convert.FromBase64String((string)keyXml.Element("Modulus"));
        byte[] D = Convert.FromBase64String((string)keyXml.Element("D"));

        BigInteger c = FromBytes(encrypted);
        BigInteger n = FromBytes(Modulus);
        BigInteger d = FromBytes(D);
        BigInteger m = BigInteger.ModPow(c, d, n);  // 见公式

        var bytes = m.ToByteArray().Reverse();
        if (fOAEP) throw new NotImplementedException("TODO");
        else bytes = bytes.SkipWhile(b => b != 0).Skip(1); // 去掉PKCS#1 V1.5铺垫,省略检验。

        return bytes.ToArray();
    }
}


如果你已经有了PQ等等,可以直接用RSAParameters导入:
RSAParameters par = new RSAParameters();
par.Modulus = n;
par.D = d; 
par.Exponent = e;
par.P = ...;
...

#6


引用 5 楼 gomoku 的回复:
注意BigInteger在DotNet4或以上才正式支持,需要添加System.Numerics引用。

using System;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Numerics;                   // <--
using System.Security.Cryptography;

class Program
{
    static string key =
    @"<RSAKeyValue>
      <Modulus>qjWim96tKp7fMgYtAKZRnLW1dOhbUAsWnzD1MMgtXC9WQYa72/riPTEUM+woW0lMHQKwKUKNVmwZ0TuSAzXAuX8frWU9g/iTL/wxqkql8fCzuGA21+4bvsu3RfuRM4mHY2A9hwLw6pugvz8sogao0x+j/HRUlnpwD7z/CQenats=</Modulus>
      <Exponent>AQAB</Exponent>
      <P>1xrSggP33Z3zi2pR6y86xCtJxZoDSCm382f0BZRgBv9FXPb2NU+jhS2hstIEED69Xr2t2jSwsXOlnw9wS/zgEw==</P>
      <Q>ypHBK9N6Z9O6n83saF+zWsSG9ZPgKwWAWbLnEhEQzbcDCHivz1OZInBqPb2wieAh1uzFywtXpdy7nWoWux9zGQ==</Q>
      <DP>hdTLWlcrtTfb2kbZFvF4p6qjKI1NM225ZHit63bIVDIortF8l+invWmJrF9cZdsTKUnsS9HyiUWBqzgIz05S/w==</DP>
      <DQ>ZAv4zBx2qDD6S1L5H9OkUYAe58tRO+5LpgGl/lZPZkqtRNHWgx9W0puS3UuClZYNIIlwZwgDEfgi8WwkLecqgQ==</DQ>
      <InverseQ>DmS5UXVYYSRcIrgyMf8ZX/4fidDPeIEz834gmjx9VuPQhgL0wXbXog7rpsAQ9+3m1/BvoXyB1okg76BEdg52RQ==</InverseQ>
      <D>c2zZ7+/q6LtCSq8rd4RSVf5Xpocn3TkXxy6xJ7qoIBqt2NPgs4YIREzzEV714ynqpsW65tAN/uxh+aT3GJwsK8POGUNowVoDwAASFOhEQD/RJVaiowB1Q6O6uTYFHE34e95XHVv3G58c8bG+87cmOjWSFfewTc993Z2kbAuoR5E=</D>
    </RSAKeyValue>";

    static void Main(string[] args)
    {
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(key);

        byte[] encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes("hello"), false);
        byte[] decrypted = MyRSADecrypted(encrypted, false);

        string str = Encoding.UTF8.GetString(decrypted);     //"hello"
    }

    private static BigInteger FromBytes(byte[] beBytes)
    {
        // 1、BigInteger的构造函数接受byte[]的格式是“低位在前(Litter Endian)”。所以以下两行是等价的:
        //    new BigInteger(new byte[]{1, 2, 3, 4})
        //    new BitInteger(new byte[]{1, 2, 3, 4, 0, 0, 0})
        // 2、BigInteger支持负数,如果byte[]的最高二进制位非零,则表示为负数,比如new byte[]{1,2,3, 0x80}就是负数。
        //    而RSA中的参数都是正整数,因此,Concat(0)用来保证正整数。
        // 3、如果输入的byte[]的格式是“高位在前(Big Endian)”,那么要先用Reverse翻转一次。
        return new BigInteger(beBytes.Reverse().Concat(new byte[] { 0 }).ToArray());
    }

    /// <summary>
    /// 只用n和d来进行RSA解密
    /// </summary>
    private static byte[] MyRSADecrypted(byte[] encrypted, bool fOAEP)
    {
        XElement keyXml = XElement.Parse(key);
        byte[] Modulus = Convert.FromBase64String((string)keyXml.Element("Modulus"));
        byte[] D = Convert.FromBase64String((string)keyXml.Element("D"));

        BigInteger c = FromBytes(encrypted);
        BigInteger n = FromBytes(Modulus);
        BigInteger d = FromBytes(D);
        BigInteger m = BigInteger.ModPow(c, d, n);  // 见公式

        var bytes = m.ToByteArray().Reverse();
        if (fOAEP) throw new NotImplementedException("TODO");
        else bytes = bytes.SkipWhile(b => b != 0).Skip(1); // 去掉PKCS#1 V1.5铺垫,省略检验。

        return bytes.ToArray();
    }
}


如果你已经有了PQ等等,可以直接用RSAParameters导入:
RSAParameters par = new RSAParameters();
par.Modulus = n;
par.D = d; 
par.Exponent = e;
par.P = ...;
...


非常非常感谢了,还是有一个问题,我添加了biginteger的引用了,但是总是提示biginteger并不包含modpow的定义,啥情况啊,我是.net 4.0的

#7


引用 5 楼 gomoku 的回复:
注意BigInteger在DotNet4或以上才正式支持,需要添加System.Numerics引用。

using System;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Numerics;                   // <--
using System.Security.Cryptography;

class Program
{
    static string key =
    @"<RSAKeyValue>
      <Modulus>qjWim96tKp7fMgYtAKZRnLW1dOhbUAsWnzD1MMgtXC9WQYa72/riPTEUM+woW0lMHQKwKUKNVmwZ0TuSAzXAuX8frWU9g/iTL/wxqkql8fCzuGA21+4bvsu3RfuRM4mHY2A9hwLw6pugvz8sogao0x+j/HRUlnpwD7z/CQenats=</Modulus>
      <Exponent>AQAB</Exponent>
      <P>1xrSggP33Z3zi2pR6y86xCtJxZoDSCm382f0BZRgBv9FXPb2NU+jhS2hstIEED69Xr2t2jSwsXOlnw9wS/zgEw==</P>
      <Q>ypHBK9N6Z9O6n83saF+zWsSG9ZPgKwWAWbLnEhEQzbcDCHivz1OZInBqPb2wieAh1uzFywtXpdy7nWoWux9zGQ==</Q>
      <DP>hdTLWlcrtTfb2kbZFvF4p6qjKI1NM225ZHit63bIVDIortF8l+invWmJrF9cZdsTKUnsS9HyiUWBqzgIz05S/w==</DP>
      <DQ>ZAv4zBx2qDD6S1L5H9OkUYAe58tRO+5LpgGl/lZPZkqtRNHWgx9W0puS3UuClZYNIIlwZwgDEfgi8WwkLecqgQ==</DQ>
      <InverseQ>DmS5UXVYYSRcIrgyMf8ZX/4fidDPeIEz834gmjx9VuPQhgL0wXbXog7rpsAQ9+3m1/BvoXyB1okg76BEdg52RQ==</InverseQ>
      <D>c2zZ7+/q6LtCSq8rd4RSVf5Xpocn3TkXxy6xJ7qoIBqt2NPgs4YIREzzEV714ynqpsW65tAN/uxh+aT3GJwsK8POGUNowVoDwAASFOhEQD/RJVaiowB1Q6O6uTYFHE34e95XHVv3G58c8bG+87cmOjWSFfewTc993Z2kbAuoR5E=</D>
    </RSAKeyValue>";

    static void Main(string[] args)
    {
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(key);

        byte[] encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes("hello"), false);
        byte[] decrypted = MyRSADecrypted(encrypted, false);

        string str = Encoding.UTF8.GetString(decrypted);     //"hello"
    }

    private static BigInteger FromBytes(byte[] beBytes)
    {
        // 1、BigInteger的构造函数接受byte[]的格式是“低位在前(Litter Endian)”。所以以下两行是等价的:
        //    new BigInteger(new byte[]{1, 2, 3, 4})
        //    new BitInteger(new byte[]{1, 2, 3, 4, 0, 0, 0})
        // 2、BigInteger支持负数,如果byte[]的最高二进制位非零,则表示为负数,比如new byte[]{1,2,3, 0x80}就是负数。
        //    而RSA中的参数都是正整数,因此,Concat(0)用来保证正整数。
        // 3、如果输入的byte[]的格式是“高位在前(Big Endian)”,那么要先用Reverse翻转一次。
        return new BigInteger(beBytes.Reverse().Concat(new byte[] { 0 }).ToArray());
    }

    /// <summary>
    /// 只用n和d来进行RSA解密
    /// </summary>
    private static byte[] MyRSADecrypted(byte[] encrypted, bool fOAEP)
    {
        XElement keyXml = XElement.Parse(key);
        byte[] Modulus = Convert.FromBase64String((string)keyXml.Element("Modulus"));
        byte[] D = Convert.FromBase64String((string)keyXml.Element("D"));

        BigInteger c = FromBytes(encrypted);
        BigInteger n = FromBytes(Modulus);
        BigInteger d = FromBytes(D);
        BigInteger m = BigInteger.ModPow(c, d, n);  // 见公式

        var bytes = m.ToByteArray().Reverse();
        if (fOAEP) throw new NotImplementedException("TODO");
        else bytes = bytes.SkipWhile(b => b != 0).Skip(1); // 去掉PKCS#1 V1.5铺垫,省略检验。

        return bytes.ToArray();
    }
}


如果你已经有了PQ等等,可以直接用RSAParameters导入:
RSAParameters par = new RSAParameters();
par.Modulus = n;
par.D = d; 
par.Exponent = e;
par.P = ...;
...


楼上的问题找到了,我之前用的另一个大数类,有点问题,换了vs的好了,话说那个解密的里面bool fOAEP是啥的标记

#8


bool fOAEP控制如何凑齐数据(输入数据要被加到128个字节长)。
如果是真,则用OAEP padding,
如果是假,则用PKCS#1 v1.5 padding。

其中PKCS#1 v1.5比较简单,它的形式如下:
0T PPPPPPPPPPPP 0DDDDDDDDDDDDDDDDDDDDD
总共128个字节,其中
第一个0是先导零,要来保证正整数;
T是凑齐方法,可以是0,1,或者2;
P就是填充数据;
第二个0是分隔符;
D就是原始数据。

而当
T=0: 所有的P都必须为0
T=1: 所有的P都必须为255
T=2: P是不为零的随机数。

MyRSADecrypted(有错别字,改为MyRSADecrypt)目前只支持PKCS#1 v1.5填充。所以当fOAEP==true的时候,它将抛出‘尚未实现’异常。

#1


理论上n和d就足够了:
m = pow(c,d) mod n
其中c为秘文,m为明文。pow为计算c的d次方。

但是,DotNet的实现可能用了一些快速算法(比如中国剩余定理),因此如果你要用RSACryptoServiceProvider的话,那些P,Q等也需要。

#2


引用 1 楼 gomoku 的回复:
理论上n和d就足够了:
m = pow(c,d) mod n
其中c为秘文,m为明文。pow为计算c的d次方。

但是,DotNet的实现可能用了一些快速算法(比如中国剩余定理),因此如果你要用RSACryptoServiceProvider的话,那些P,Q等也需要。
能给个详细一点的算法么,我弄的好像不是很对哎,谢谢啦,

#3


引用 1 楼 gomoku 的回复:
理论上n和d就足够了:
m = pow(c,d) mod n
其中c为秘文,m为明文。pow为计算c的d次方。

但是,DotNet的实现可能用了一些快速算法(比如中国剩余定理),因此如果你要用RSACryptoServiceProvider的话,那些P,Q等也需要。
如果pq那些都有的话怎么初始化啊,网上看了好像没明白怎么用这些值初始化

#4


求指导啊   。。。。。。。。。。。。。。。。。

#5


注意BigInteger在DotNet4或以上才正式支持,需要添加System.Numerics引用。

using System;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Numerics;                   // <--
using System.Security.Cryptography;

class Program
{
    static string key =
    @"<RSAKeyValue>
      <Modulus>qjWim96tKp7fMgYtAKZRnLW1dOhbUAsWnzD1MMgtXC9WQYa72/riPTEUM+woW0lMHQKwKUKNVmwZ0TuSAzXAuX8frWU9g/iTL/wxqkql8fCzuGA21+4bvsu3RfuRM4mHY2A9hwLw6pugvz8sogao0x+j/HRUlnpwD7z/CQenats=</Modulus>
      <Exponent>AQAB</Exponent>
      <P>1xrSggP33Z3zi2pR6y86xCtJxZoDSCm382f0BZRgBv9FXPb2NU+jhS2hstIEED69Xr2t2jSwsXOlnw9wS/zgEw==</P>
      <Q>ypHBK9N6Z9O6n83saF+zWsSG9ZPgKwWAWbLnEhEQzbcDCHivz1OZInBqPb2wieAh1uzFywtXpdy7nWoWux9zGQ==</Q>
      <DP>hdTLWlcrtTfb2kbZFvF4p6qjKI1NM225ZHit63bIVDIortF8l+invWmJrF9cZdsTKUnsS9HyiUWBqzgIz05S/w==</DP>
      <DQ>ZAv4zBx2qDD6S1L5H9OkUYAe58tRO+5LpgGl/lZPZkqtRNHWgx9W0puS3UuClZYNIIlwZwgDEfgi8WwkLecqgQ==</DQ>
      <InverseQ>DmS5UXVYYSRcIrgyMf8ZX/4fidDPeIEz834gmjx9VuPQhgL0wXbXog7rpsAQ9+3m1/BvoXyB1okg76BEdg52RQ==</InverseQ>
      <D>c2zZ7+/q6LtCSq8rd4RSVf5Xpocn3TkXxy6xJ7qoIBqt2NPgs4YIREzzEV714ynqpsW65tAN/uxh+aT3GJwsK8POGUNowVoDwAASFOhEQD/RJVaiowB1Q6O6uTYFHE34e95XHVv3G58c8bG+87cmOjWSFfewTc993Z2kbAuoR5E=</D>
    </RSAKeyValue>";

    static void Main(string[] args)
    {
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(key);

        byte[] encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes("hello"), false);
        byte[] decrypted = MyRSADecrypted(encrypted, false);

        string str = Encoding.UTF8.GetString(decrypted);     //"hello"
    }

    private static BigInteger FromBytes(byte[] beBytes)
    {
        // 1、BigInteger的构造函数接受byte[]的格式是“低位在前(Litter Endian)”。所以以下两行是等价的:
        //    new BigInteger(new byte[]{1, 2, 3, 4})
        //    new BitInteger(new byte[]{1, 2, 3, 4, 0, 0, 0})
        // 2、BigInteger支持负数,如果byte[]的最高二进制位非零,则表示为负数,比如new byte[]{1,2,3, 0x80}就是负数。
        //    而RSA中的参数都是正整数,因此,Concat(0)用来保证正整数。
        // 3、如果输入的byte[]的格式是“高位在前(Big Endian)”,那么要先用Reverse翻转一次。
        return new BigInteger(beBytes.Reverse().Concat(new byte[] { 0 }).ToArray());
    }

    /// <summary>
    /// 只用n和d来进行RSA解密
    /// </summary>
    private static byte[] MyRSADecrypted(byte[] encrypted, bool fOAEP)
    {
        XElement keyXml = XElement.Parse(key);
        byte[] Modulus = Convert.FromBase64String((string)keyXml.Element("Modulus"));
        byte[] D = Convert.FromBase64String((string)keyXml.Element("D"));

        BigInteger c = FromBytes(encrypted);
        BigInteger n = FromBytes(Modulus);
        BigInteger d = FromBytes(D);
        BigInteger m = BigInteger.ModPow(c, d, n);  // 见公式

        var bytes = m.ToByteArray().Reverse();
        if (fOAEP) throw new NotImplementedException("TODO");
        else bytes = bytes.SkipWhile(b => b != 0).Skip(1); // 去掉PKCS#1 V1.5铺垫,省略检验。

        return bytes.ToArray();
    }
}


如果你已经有了PQ等等,可以直接用RSAParameters导入:
RSAParameters par = new RSAParameters();
par.Modulus = n;
par.D = d; 
par.Exponent = e;
par.P = ...;
...

#6


引用 5 楼 gomoku 的回复:
注意BigInteger在DotNet4或以上才正式支持,需要添加System.Numerics引用。

using System;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Numerics;                   // <--
using System.Security.Cryptography;

class Program
{
    static string key =
    @"<RSAKeyValue>
      <Modulus>qjWim96tKp7fMgYtAKZRnLW1dOhbUAsWnzD1MMgtXC9WQYa72/riPTEUM+woW0lMHQKwKUKNVmwZ0TuSAzXAuX8frWU9g/iTL/wxqkql8fCzuGA21+4bvsu3RfuRM4mHY2A9hwLw6pugvz8sogao0x+j/HRUlnpwD7z/CQenats=</Modulus>
      <Exponent>AQAB</Exponent>
      <P>1xrSggP33Z3zi2pR6y86xCtJxZoDSCm382f0BZRgBv9FXPb2NU+jhS2hstIEED69Xr2t2jSwsXOlnw9wS/zgEw==</P>
      <Q>ypHBK9N6Z9O6n83saF+zWsSG9ZPgKwWAWbLnEhEQzbcDCHivz1OZInBqPb2wieAh1uzFywtXpdy7nWoWux9zGQ==</Q>
      <DP>hdTLWlcrtTfb2kbZFvF4p6qjKI1NM225ZHit63bIVDIortF8l+invWmJrF9cZdsTKUnsS9HyiUWBqzgIz05S/w==</DP>
      <DQ>ZAv4zBx2qDD6S1L5H9OkUYAe58tRO+5LpgGl/lZPZkqtRNHWgx9W0puS3UuClZYNIIlwZwgDEfgi8WwkLecqgQ==</DQ>
      <InverseQ>DmS5UXVYYSRcIrgyMf8ZX/4fidDPeIEz834gmjx9VuPQhgL0wXbXog7rpsAQ9+3m1/BvoXyB1okg76BEdg52RQ==</InverseQ>
      <D>c2zZ7+/q6LtCSq8rd4RSVf5Xpocn3TkXxy6xJ7qoIBqt2NPgs4YIREzzEV714ynqpsW65tAN/uxh+aT3GJwsK8POGUNowVoDwAASFOhEQD/RJVaiowB1Q6O6uTYFHE34e95XHVv3G58c8bG+87cmOjWSFfewTc993Z2kbAuoR5E=</D>
    </RSAKeyValue>";

    static void Main(string[] args)
    {
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(key);

        byte[] encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes("hello"), false);
        byte[] decrypted = MyRSADecrypted(encrypted, false);

        string str = Encoding.UTF8.GetString(decrypted);     //"hello"
    }

    private static BigInteger FromBytes(byte[] beBytes)
    {
        // 1、BigInteger的构造函数接受byte[]的格式是“低位在前(Litter Endian)”。所以以下两行是等价的:
        //    new BigInteger(new byte[]{1, 2, 3, 4})
        //    new BitInteger(new byte[]{1, 2, 3, 4, 0, 0, 0})
        // 2、BigInteger支持负数,如果byte[]的最高二进制位非零,则表示为负数,比如new byte[]{1,2,3, 0x80}就是负数。
        //    而RSA中的参数都是正整数,因此,Concat(0)用来保证正整数。
        // 3、如果输入的byte[]的格式是“高位在前(Big Endian)”,那么要先用Reverse翻转一次。
        return new BigInteger(beBytes.Reverse().Concat(new byte[] { 0 }).ToArray());
    }

    /// <summary>
    /// 只用n和d来进行RSA解密
    /// </summary>
    private static byte[] MyRSADecrypted(byte[] encrypted, bool fOAEP)
    {
        XElement keyXml = XElement.Parse(key);
        byte[] Modulus = Convert.FromBase64String((string)keyXml.Element("Modulus"));
        byte[] D = Convert.FromBase64String((string)keyXml.Element("D"));

        BigInteger c = FromBytes(encrypted);
        BigInteger n = FromBytes(Modulus);
        BigInteger d = FromBytes(D);
        BigInteger m = BigInteger.ModPow(c, d, n);  // 见公式

        var bytes = m.ToByteArray().Reverse();
        if (fOAEP) throw new NotImplementedException("TODO");
        else bytes = bytes.SkipWhile(b => b != 0).Skip(1); // 去掉PKCS#1 V1.5铺垫,省略检验。

        return bytes.ToArray();
    }
}


如果你已经有了PQ等等,可以直接用RSAParameters导入:
RSAParameters par = new RSAParameters();
par.Modulus = n;
par.D = d; 
par.Exponent = e;
par.P = ...;
...


非常非常感谢了,还是有一个问题,我添加了biginteger的引用了,但是总是提示biginteger并不包含modpow的定义,啥情况啊,我是.net 4.0的

#7


引用 5 楼 gomoku 的回复:
注意BigInteger在DotNet4或以上才正式支持,需要添加System.Numerics引用。

using System;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Numerics;                   // <--
using System.Security.Cryptography;

class Program
{
    static string key =
    @"<RSAKeyValue>
      <Modulus>qjWim96tKp7fMgYtAKZRnLW1dOhbUAsWnzD1MMgtXC9WQYa72/riPTEUM+woW0lMHQKwKUKNVmwZ0TuSAzXAuX8frWU9g/iTL/wxqkql8fCzuGA21+4bvsu3RfuRM4mHY2A9hwLw6pugvz8sogao0x+j/HRUlnpwD7z/CQenats=</Modulus>
      <Exponent>AQAB</Exponent>
      <P>1xrSggP33Z3zi2pR6y86xCtJxZoDSCm382f0BZRgBv9FXPb2NU+jhS2hstIEED69Xr2t2jSwsXOlnw9wS/zgEw==</P>
      <Q>ypHBK9N6Z9O6n83saF+zWsSG9ZPgKwWAWbLnEhEQzbcDCHivz1OZInBqPb2wieAh1uzFywtXpdy7nWoWux9zGQ==</Q>
      <DP>hdTLWlcrtTfb2kbZFvF4p6qjKI1NM225ZHit63bIVDIortF8l+invWmJrF9cZdsTKUnsS9HyiUWBqzgIz05S/w==</DP>
      <DQ>ZAv4zBx2qDD6S1L5H9OkUYAe58tRO+5LpgGl/lZPZkqtRNHWgx9W0puS3UuClZYNIIlwZwgDEfgi8WwkLecqgQ==</DQ>
      <InverseQ>DmS5UXVYYSRcIrgyMf8ZX/4fidDPeIEz834gmjx9VuPQhgL0wXbXog7rpsAQ9+3m1/BvoXyB1okg76BEdg52RQ==</InverseQ>
      <D>c2zZ7+/q6LtCSq8rd4RSVf5Xpocn3TkXxy6xJ7qoIBqt2NPgs4YIREzzEV714ynqpsW65tAN/uxh+aT3GJwsK8POGUNowVoDwAASFOhEQD/RJVaiowB1Q6O6uTYFHE34e95XHVv3G58c8bG+87cmOjWSFfewTc993Z2kbAuoR5E=</D>
    </RSAKeyValue>";

    static void Main(string[] args)
    {
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(key);

        byte[] encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes("hello"), false);
        byte[] decrypted = MyRSADecrypted(encrypted, false);

        string str = Encoding.UTF8.GetString(decrypted);     //"hello"
    }

    private static BigInteger FromBytes(byte[] beBytes)
    {
        // 1、BigInteger的构造函数接受byte[]的格式是“低位在前(Litter Endian)”。所以以下两行是等价的:
        //    new BigInteger(new byte[]{1, 2, 3, 4})
        //    new BitInteger(new byte[]{1, 2, 3, 4, 0, 0, 0})
        // 2、BigInteger支持负数,如果byte[]的最高二进制位非零,则表示为负数,比如new byte[]{1,2,3, 0x80}就是负数。
        //    而RSA中的参数都是正整数,因此,Concat(0)用来保证正整数。
        // 3、如果输入的byte[]的格式是“高位在前(Big Endian)”,那么要先用Reverse翻转一次。
        return new BigInteger(beBytes.Reverse().Concat(new byte[] { 0 }).ToArray());
    }

    /// <summary>
    /// 只用n和d来进行RSA解密
    /// </summary>
    private static byte[] MyRSADecrypted(byte[] encrypted, bool fOAEP)
    {
        XElement keyXml = XElement.Parse(key);
        byte[] Modulus = Convert.FromBase64String((string)keyXml.Element("Modulus"));
        byte[] D = Convert.FromBase64String((string)keyXml.Element("D"));

        BigInteger c = FromBytes(encrypted);
        BigInteger n = FromBytes(Modulus);
        BigInteger d = FromBytes(D);
        BigInteger m = BigInteger.ModPow(c, d, n);  // 见公式

        var bytes = m.ToByteArray().Reverse();
        if (fOAEP) throw new NotImplementedException("TODO");
        else bytes = bytes.SkipWhile(b => b != 0).Skip(1); // 去掉PKCS#1 V1.5铺垫,省略检验。

        return bytes.ToArray();
    }
}


如果你已经有了PQ等等,可以直接用RSAParameters导入:
RSAParameters par = new RSAParameters();
par.Modulus = n;
par.D = d; 
par.Exponent = e;
par.P = ...;
...


楼上的问题找到了,我之前用的另一个大数类,有点问题,换了vs的好了,话说那个解密的里面bool fOAEP是啥的标记

#8


bool fOAEP控制如何凑齐数据(输入数据要被加到128个字节长)。
如果是真,则用OAEP padding,
如果是假,则用PKCS#1 v1.5 padding。

其中PKCS#1 v1.5比较简单,它的形式如下:
0T PPPPPPPPPPPP 0DDDDDDDDDDDDDDDDDDDDD
总共128个字节,其中
第一个0是先导零,要来保证正整数;
T是凑齐方法,可以是0,1,或者2;
P就是填充数据;
第二个0是分隔符;
D就是原始数据。

而当
T=0: 所有的P都必须为0
T=1: 所有的P都必须为255
T=2: P是不为零的随机数。

MyRSADecrypted(有错别字,改为MyRSADecrypt)目前只支持PKCS#1 v1.5填充。所以当fOAEP==true的时候,它将抛出‘尚未实现’异常。