문제

고객과 물건을 추적하기 위해 인증서 배포 시스템을 만들고 있습니다.

일어나는 일은 다음과 같습니다.

  • 클라이언트는 CSR을 서버로 보냅니다
  • 서버 확인 및 서명 인증서
  • 서버는 서명 된 인증서를 클라이언트에 보냅니다
  • 클라이언트는 Windows Store에 서명 된 인증서와 개인 키를 넣습니다.

따라서 클라이언트에서는 이런 일이 발생합니다.

//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());

좋아, 그래서 skip skip skip skip grose 서버 서버 서명을 신뢰하고 클라이언트로 다시 보냅니다. 그것이 내가 행동을 선택하는 곳.

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();

이제 당신은 아마도 서버 측에 무언가 잘못 될 것이라고 생각할 것입니다. 그게 나도 생각했지만이 인증서에서 PFX 파일을 만들어 손으로 가져 왔을 때 잘 작동했습니다 ....

어쨌든 .net rsa privatekey와 bouncycastle rsa privatekey가있는 차이가 있으며 손가락을 넣을 수 없습니다.

아마도 PFX를 가져온 다음 X509Store를 통해 PFX를 가져 오는 것이 좋습니다. 나는 시도했다. : S와 실패. 내가 시도하자마자 ExportParameters(true) 진실은 개인 파라 메테르를 포함하는 것을 나타냅니다. "지정된 상태에서 사용하는 데 유효하지 않음"이라고 말합니다. 마지막에 완전한 예외를 참조하십시오.

나는 여러분 중 일부 가이 돼지를 죽였거나 나를 도울 수 있기를 바랍니다.

***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: 
도움이 되었습니까?

해결책

답변 (사용자 이름에서)은 올바른 방향을 가리 킵니다. .

Git의 Bouncy-Castle의 최신 버전에는 다음 코드가 있습니다.

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 :이 코드는 Bouncy Castle의 Nuget 버전 (2011)에 있지 않거나 대부분의 코드 샘플에서 RSA 매개 변수가 간단하게 복사되었습니다.

이 코드는 기본적으로 키 매개 변수를 복사/붙여 넣기로 볼 수있는 다른 곳에서 볼 수 있으며 추가 패딩 단계를 수행하지 않는 코드와 다릅니다.

다른 팁

참고로,이 기능을 org.bouncycastle.security.dotnetutilities 클래스에 추가했습니다. 곧 릴리스 1.6에있을 예정입니다.

찾았어요!

또는 그것의 적당한 부분 :)

에 관해서 PrivateKey.ExportToParameters(true) 여전히 작동하지 않지만 키가 2048 비트라는 사실과 관련하여 할 일이 있습니다. 1024 비트로 변경했을 때 작동했기 때문입니다. 그래서 누군가 나를 계속 게시하는 이유를 찾는 사람이 있다면.

그래서 우리는 다시 간다.

//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);

이제 내 매장에 전체 인증서를 추가 할 수 있습니다 :)

이 문제에 대한 해결책을 찾았다 고 생각합니다. 키당 키와는 아무런 관련이 없지만 x509Certificate2 객체와는 오히려 x509keyStorageFlags.Exportable Flag로 만들어야합니다.

이 경우 x509certificate2는이 방법에 의해 생성되었습니다. System.Security.Cryptography.X509Certificates.X509Certificate2 netcert = DotNetUtilities.ToX509Certificate(cert);

따라서 해당 방법에서 X509Certificate2의 생성자에 내보낼 수있는 플래그를 전달하십시오. 저는 PFX 파일에있는 개인 키로 일부 데이터에 서명해야했기 때문에 다음을 작성해야했습니다.

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

이제 할 수 있습니다
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
RSAParameters rsaParam = rsa.ExportParameters(true);

HTH,

스테판

솔루션 중 어느 것도 나에게 효과가 없었습니다. 그러나 나는 다음 배열 중 하나 일 때 예외가 항상 발생한다는 것을 알았습니다.

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();

이웃과 크기가 다릅니다.

DP, DQ, InverseQ, P, Q

또는 이중 크기 :

D, Modulus

이 두 그룹 각각에 대해 각 배열의 시작 부분에 최대 길이를 계산하고 추가 길이를 추가하여 동일한 길이 (각 그룹에 대해 동일)를 추가했습니다. 이것은 작동합니다 ImportParameters 그들이 길이가 같은지 확인합니다 (불행히도 나는 액세스 할 수 없습니다. ImportParameters 코드, 일부 기본 라이브러리라고하는 것 같습니다).

Bouncycastle.crypto.dll ver 1.7을 사용하고 있습니다

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top