BouncyCastle RSAPrivateKey to .NET RSAPrivateKey

老子叫甜甜 提交于 2019-11-28 04:34:56
JB.

The answer (from username) points to the right direction: padding.

Bouncy-castle's latest version from git has the following code:

public static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey)
{
   RSAParameters rp = new RSAParameters();
   rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
   rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
   rp.P = privKey.P.ToByteArrayUnsigned();
   rp.Q = privKey.Q.ToByteArrayUnsigned();
   rp.D = ConvertRSAParametersField(privKey.Exponent, rp.Modulus.Length);
   rp.DP = ConvertRSAParametersField(privKey.DP, rp.P.Length);
   rp.DQ = ConvertRSAParametersField(privKey.DQ, rp.Q.Length);
   rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.Q.Length);
   return rp;
}

private static byte[] ConvertRSAParametersField(BigInteger n, int size)
{
   byte[] bs = n.ToByteArrayUnsigned();
   if (bs.Length == size)
      return bs;
   if (bs.Length > size)
      throw new ArgumentException("Specified size too small", "size");
   byte[] padded = new byte[size];
   Array.Copy(bs, 0, padded, size - bs.Length, bs.Length);
   return padded;
}

nb: This code in not in the nuget version (2011) of bouncy castle, or in most code samples were RSA parameters are simply copied.

This code is different from the code you can see anywhere else which basically copy/paste the key parameters, and does not perform the extra padding step.

FYI, I've added this functionality to the Org.BouncyCastle.Security.DotNetUtilities class; it will be in release 1.6, due soon.

I found it!

Or atleast part of it :)

As for the PrivateKey.ExportToParameters(true) Still doens't work but this has something todo with the fact that the key was 2048 bit. Because when I changed it to 1024bit it did work. So if anyone ever finds out why keep me posted.

So here we go again.

//BouncyCastle's Key objects
RsaPrivateCrtKeyParameters rpckp = ((RsaPrivateCrtKeyParameters)ackp.Private);

//.NET RSA Key objects
System.Security.Cryptography.RSACryptoServiceProvider rcsp = new System.Security.Cryptography.RSACryptoServiceProvider();
System.Security.Cryptography.RSAParameters parms = new System.Security.Cryptography.RSAParameters();

//So the thing changed is offcourse the ToByteArrayUnsigned() instead of
//ToByteArray()
parms.Modulus   = rpckp.Modulus.ToByteArrayUnsigned();
parms.P         = rpckp.P.ToByteArrayUnsigned();
parms.Q         = rpckp.Q.ToByteArrayUnsigned();
parms.DP        = rpckp.DP.ToByteArrayUnsigned();
parms.DQ        = rpckp.DQ.ToByteArrayUnsigned();
parms.InverseQ  = rpckp.QInv.ToByteArrayUnsigned();
parms.D         = rpckp.Exponent.ToByteArrayUnsigned();
parms.Exponent  = rpckp.PublicExponent.ToByteArrayUnsigned();

//So now this now appears to work.
rcsp.ImportParameters(parms);

So now I can add the complete Certificate to my store :)

I think I found the solution to this problem. It has nothing to do with the key per, but rather with the X509Certificate2 object which must be created with the X509KeyStorageFlags.Exportable flag.

In this case your X509Certificate2 was created by this method: System.Security.Cryptography.X509Certificates.X509Certificate2 netcert = DotNetUtilities.ToX509Certificate(cert);

So make sure you pass the exportable flag in the constructor of the X509Certificate2 in that method. I my situation I needed to sign some data with a private key located in a PFX file so I had to write this:

X509KeyStorageFlags flags = X509KeyStorageFlags.Exportable;
X509Certificate2 cert = new X509Certificate2("my.pfx", "somepass", flags);

Now I can do
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
RSAParameters rsaParam = rsa.ExportParameters(true);

HTH,

Stefan

Neither of the solutions worked for me. But I've noticed that the exception is always thrown when one of the following arrays:

parms.Modulus   = rpckp.Modulus.ToByteArrayUnsigned();
parms.P         = rpckp.P.ToByteArrayUnsigned();
parms.Q         = rpckp.Q.ToByteArrayUnsigned();
parms.DP        = rpckp.DP.ToByteArrayUnsigned();
parms.DQ        = rpckp.DQ.ToByteArrayUnsigned();
parms.InverseQ  = rpckp.QInv.ToByteArrayUnsigned();
parms.D         = rpckp.Exponent.ToByteArrayUnsigned();
parms.Exponent  = rpckp.PublicExponent.ToByteArrayUnsigned();

has a different size then its neighbor:

DP, DQ, InverseQ, P, Q

or double sized:

D, Modulus

For each of these two groups I have calculated the max length and added extra zeroes at the beginning of each array to make them the same length (the same for each group). This works, I suppose that ImportParameters checks that they are of the same length (unfortunately I don't have an access to the ImportParameters code, it seems that it calls some native library).

I'm using BouncyCastle.Crypto.dll ver 1.7

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!