BouncyCastle的RSAPrivateKey到.NET RSAPrivateKeyBouncyCastle、RSAPrivateKey、NET

2023-09-02 11:56:34 作者:青春奋斗

我要创建一个证书分发系统来跟踪客户和东西。

什么情况是:

在客户端发送CSR到服务器 服务器检查和标志证书 在服务器发送签名证书客户端 客户端放入Windows应用商店签名的证书以及私有密钥。

所以,在客户机上发生这种情况:

  //伪服务器对象:
服务器S =新服务器();

//请求的证书名称与事
X509Name名=新X509Name(CN =客户端证书,C = NL);

//密钥生成2048bits
RsaKeyPairGenerator rkpg =新RsaKeyPairGenerator();
rkpg.Init(新KeyGenerationParameters(新的SecureRandom(),2048));
AsymmetricCipherKeyPair ACKP = rkpg.GenerateKeyPair();

// PKCS#10证书签名请求
Pkcs10CertificationRequest CSR =新Pkcs10CertificationRequest(SHA1WITHRSA,姓名,ackp.Public,空,ackp.Private);

//使它成为一个很好的PEM的thingie
StringBuilder的SB =新的StringBuilder();
PemWriter pemwrit =新PemWriter(新的StringWriter(B));
pemwrit.WriteObject(CSR);
pemwrit.Writer.Flush();
s.SendRequest(sb.ToSting());
 

好了,所以我将跳过服务器端只要相信我的服务器签署证书,并将其发送回客户端。多数民众赞成在那里我会拿起行动。

  PemReader PR =新PemReader(新StringReader(b.ToString()));
x509证书证书=(x509证书)pr.ReadObject();

//因此,让asume我救了AsymmetricCipherKeyPair(ACKP)的前
//我现在有证书和我的私人钥匙;

//首先我使之成为微软x509cert。
//然而,这并不具有在AsymmetricCipherKeyPair当作PrivateKey这就是(ACKP)
System.Security.Cryptography.X509Certificates.X509Certificate2 netcert = DotNetUtilities.ToX509Certificate(证书);

//所以这里来的RSACryptoServerProvider:
System.Security.Cryptography.RSACryptoServiceProvider RCSP =新System.Security.Cryptography.RSACryptoServiceProvider();

//而privateKeyParameters
System.Security.Cryptography.RSAParameters PARMS =新System.Security.Cryptography.RSAParameters();

//现在我要翻译ackp.PrivateKey到PARMS;
RsaPrivateCrtKeyParameters BCKeyParms =((RsaPrivateCrtKeyParameters)ackp1.Private);

// D是私人指数
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();

//现在我应该能够在RSAParameters导入的RSACryptoServiceProvider
rcsp.ImportParameters(PARMS);

//< EM>< B>没有真正< / B>< / EM>这打破了说坏数据,而不是更多。我会后的
//堆栈跟踪在年底

//我打开窗户证书存储,因为多数民众赞成在我要保存它。
//添加它,将它保存这个工作正常没有的privKey。
的X509Store店=新的X509Store(StoreName.My,StoreLocation.CurrentUser);
store.Open(OpenFlags.MaxAllowed);
store.Add(netcert);
store.Close();
 

现在你可能在想一定有一些事情出错在服务器端。那么这就是我的想法太多,但我从这个证书做了一个PFX文件,并手动输入它它工作得很好......

不知怎的,有一个性差异bewteen一个.NET RSA privatekey和BouncyCastle的RSA privatekey,我不能把我的手指上。

恶意软件Cryptolocker已破解,受害者可以解密资料了

您可能会提示导入PFX,然后从它那里得到通过的X509Store私钥。我试过了。 :S与失败。当我尝试 ExportParameters(真)真正的看台上为包括privateparameters。它说:关键不适于在指定状态。。请参阅在年底完成例外。

我希望你们中的一些已经被杀害的这猪前或也许能帮助我。

  ***例外:***

System.Security.Cryptography.CryptographicException是未处理
  消息=键不适于在指定状态下使用。 r  N
  来源=mscorlib程序
  堆栈跟踪:
       在System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(的Int32小时)
       在System.Security.Cryptography.Utils._ExportKey(SafeKeyHandle的hKey,的Int32 blobType,对象cspObject)
       在System.Security.Cryptography.RSACryptoServiceProvider.ExportParameters(布尔includePrivateParameters)
  的InnerException:

***而另一种:***

System.Security.Cryptography.CryptographicException是未处理
  消息=坏数据。 r  N
  来源=mscorlib程序
  堆栈跟踪:
       在System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(的Int32小时)
       在System.Security.Cryptography.Utils._ImportKey(SafeProvHandle hCSP,的Int32 keyNumber,CspProviderFlags标志,对象cspObject,SafeKeyHandle和放大器;的hKey)
       在System.Security.Cryptography.RSACryptoServiceProvider.ImportParameters(RSAParameters参数)
  的InnerException:
 

解决方案

答案(由用户名)指向正确的方向:填充

快活,城堡的最新版本混帐具有以下code:

 公共静态RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters的privKey)
{
   RSAParameters RP =新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);
   返回RP;
}

私有静态的byte [] ConvertRSAParametersField(BigInteger的N,INT尺寸)
{
   byte []的BS = n.ToByteArrayUnsigned();
   如果(bs.Length ==大小)
      返回BS;
   如果(bs.Length>大小)
      抛出新的ArgumentException(指定尺寸太小,大小);
   byte []的填充=新的字节[尺寸]
   Array.Copy(BS,0,填充,大小 -  bs.Length,bs.Length);
   返回补齐;
}
 

注:此code。在不充气城堡的的NuGet版本(2011年),或在大多数code样品RSA参数直接复制

这code是从$ C $不同的C,你可以看到其他地方基本上复制/粘贴的关键参数,并且不执行额外的填充一步。

I'm creating a certificate distribution system to keep track of clients and stuff.

What happens is:

Client send CSR to Server Server checks and signs certificate Server sends Signed certificate to Client Client puts Signed certificate plus Private key in 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());

Ok So I'll skip serverside Just trust me the server signs the cert and send it back to the client. Thats where I'll pick up 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're probably thinking there must be something going wrong at the server side. Well thats what I thought too but When I made a pfx file from this cert and imported it by hand it worked fine ....

Somehow there's a diference bewteen a .NET RSA privatekey and a BouncyCastle RSA privatekey and I can't put my finger on it.

You will probably suggest to import the pfx and then get the private key from it via the X509Store. I tried. :S And failed. As soon as I try to ExportParameters(true) the true stands for including privateparameters. It says "Key not valid for use in specified state.". See for complete exception at the end.

I hope some of you have slain this pig before or might be able to help me.

***Exceptions:***

System.Security.Cryptography.CryptographicException was unhandled
  Message="Key not valid for use in specified state.rn"
  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.rn"
  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: 

解决方案

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.