BouncyCastle RSAPrivateKey for .NET RSAPrivateKey

I am creating a certificate distribution system to track clients and more.

What's happening:

  • Client sends CSR to server
  • Server verifies and signs the certificate
  • The server sends the signed certificate to the client.
  • The client puts the signed certificate plus the private key in the Windows store.

So, on the client this happens:

//Pseudo Server Object: Server s = new Server(); //Requested Certificate Name and things X509Name name = new X509Name("CN=Client Cert, C=NL"); //Key generation 2048bits RsaKeyPairGenerator rkpg = new RsaKeyPairGenerator(); rkpg.Init(new KeyGenerationParameters(new SecureRandom(), 2048)); AsymmetricCipherKeyPair ackp = rkpg.GenerateKeyPair(); //PKCS #10 Certificate Signing Request Pkcs10CertificationRequest csr = new Pkcs10CertificationRequest("SHA1WITHRSA", name, ackp.Public, null, ackp.Private); //Make it a nice PEM thingie StringBuilder sb = new StringBuilder(); PemWriter pemwrit = new PemWriter(new StringWriter(b)); pemwrit.WriteObject(csr); pemwrit.Writer.Flush(); s.SendRequest(sb.ToSting()); 

Good. So, I will skip the server. Just trust me that the server signs the certificate and sends it to the client. That's where I get the action.

 PemReader pr = new PemReader(new StringReader(b.ToString())); X509Certificate cert = (X509Certificate)pr.ReadObject(); //So lets asume I saved the AsymmetricCipherKeyPair (ackp) from before //I have now the certificate and my private key; //first I make it a "Microsoft" x509cert. //This however does not have a PrivateKey thats in the AsymmetricCipherKeyPair (ackp) System.Security.Cryptography.X509Certificates.X509Certificate2 netcert = DotNetUtilities.ToX509Certificate(cert); //So here comes the RSACryptoServerProvider: System.Security.Cryptography.RSACryptoServiceProvider rcsp = new System.Security.Cryptography.RSACryptoServiceProvider(); //And the privateKeyParameters System.Security.Cryptography.RSAParameters parms = new System.Security.Cryptography.RSAParameters(); //now I have to translate ackp.PrivateKey to parms; RsaPrivateCrtKeyParameters BCKeyParms = ((RsaPrivateCrtKeyParameters)ackp1.Private); //D is the private exponent parms.Modulus = BCKeyParms.Modulus.ToByteArray(); parms.P = BCKeyParms.P.ToByteArray(); parms.Q = BCKeyParms.Q.ToByteArray(); parms.DP = BCKeyParms.DP.ToByteArray(); parms.DQ = BCKeyParms.DQ.ToByteArray(); parms.InverseQ = BCKeyParms.QInv.ToByteArray(); parms.D = BCKeyParms.Exponent.ToByteArray(); parms.Exponent = BCKeyParms.PublicExponent.ToByteArray(); //Now I should be able to import the RSAParameters into the RSACryptoServiceProvider rcsp.ImportParameters(parms); //<em><b>not really</b></em> This breaks says "Bad Data" and not much more. I'll Post the //stacktrace at the end //I open up the windows cert store because thats where I want to save it. //Add it and save it this works fine without the privkey. X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser); store.Open(OpenFlags.MaxAllowed); store.Add(netcert); store.Close(); 

Now you probably think that there should be something wrong on the server side. Well, this is what I thought, too, but when I made a pfx file from this certificate and imported it manually, it worked fine ....

Somehow there is a difference between the .NET RSA private key and the BouncyCastle RSA private key, and I can't put it on it.

You probably suggest importing pfx, and then get the private key to it through the X509Store. I tried .: S And failed. As soon as I try ExportParameters(true) , true means the inclusion of private parameters. He says: "The key is not valid for use in the specified state." See Complete Exclusion at the End.

I hope some of you killed this pig earlier or could help me.

 ***Exceptions:*** System.Security.Cryptography.CryptographicException was unhandled Message="Key not valid for use in specified state.\r\n" Source="mscorlib" StackTrace: at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr) at System.Security.Cryptography.Utils._ExportKey(SafeKeyHandle hKey, Int32 blobType, Object cspObject) at System.Security.Cryptography.RSACryptoServiceProvider.ExportParameters(Boolean includePrivateParameters) InnerException: ***And the other one:*** System.Security.Cryptography.CryptographicException was unhandled Message="Bad Data.\r\n" Source="mscorlib" StackTrace: at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr) at System.Security.Cryptography.Utils._ImportKey(SafeProvHandle hCSP, Int32 keyNumber, CspProviderFlags flags, Object cspObject, SafeKeyHandle& hKey) at System.Security.Cryptography.RSACryptoServiceProvider.ImportParameters(RSAParameters parameters) InnerException: 
+14
cryptography rsa csr bouncycastle
Jun 04 '09 at 10:28
source share
5 answers

The answer (on behalf of the user) indicates the right direction: addition .

The latest version of goun's Bouncy-castle 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 is not in the nuget (2011) version of bouncy castle, or in most code samples RSA parameters were simply copied.

This code is different from the code that you can see elsewhere, which basically copies / pastes key parameters and does not perform an additional filling step.

+7
Feb 07 '15 at 21:37
source share

FYI, I added this functionality to the Org.BouncyCastle.Security.DotNetUtilities class; It will be available soon in release 1.6.

+7
Feb 02 2018-10-02T00
source share

I found him!

Or at least part of it :)

As for PrivateKey.ExportToParameters(true) Still not working, but it has something that with the key was 2048 bits. Because when I changed it to 1024bit, it worked. Therefore, if anyone finds out why should I keep me posted.

So let's go again.

 //BouncyCastle 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 a full certificate to my store :)

+6
Jun 04 '09 at 14:26
source share

I think I found a solution to this problem. It has nothing to do with the per key, 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);

Therefore, make sure that you pass the exportable flag in the X509Certificate2 constructor in this method. In my situation, I needed to sign some data using the private key located in the 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);

NTN

Stephen

+4
Feb 13 '10 at 22:51
source share

None of the solutions worked for me. But I noticed that an 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 than its neighbor:

 DP, DQ, InverseQ, P, Q 

or double size:

 D, Modulus 

For each of these two groups, I calculated the maximum length and added extra zeros at the beginning of each array to make them the same length (the same for each group). This works, I believe that ImportParameters checks that they are the same length (unfortunately, I do not have access to the ImportParameters code, it seems like it is calling some native library).

I am using BouncyCastle.Crypto.dll ver 1.7

+2
May 28 '12 at 16:00
source share



All Articles