Convert Java.Security.KeyPair to .NET RSACryptoServiceProvider

匿名 (未验证) 提交于 2019-12-03 09:06:55

问题:

How can I encode a Java-produced RSA private (and public) key such that it can be decoded in .NET for use within RSACryptoServiceProvider?

I have tried this code:

var keyGen = KeyPairGenerator.GetInstance("RSA"); keyGen.Initialize(2048); KeyPair keyPair = keyGen.GenerateKeyPair();  IPrivateKey privateKey = keyPair.Private; byte[] nativePrivateKey = privateKey.GetEncoded();  var nativeToRsa = new RSACryptoServiceProvider(); nativeToRsa.ImportCspBlob(nativePrivateKey); // throws a CryptographicException 

I'm using Xamarin.Android to write C#, but the "native" Java RSA key generator is much faster than the mono one. So I want to use the Java one, but I still need to be able to exchange the public and/or private keys with Windows folks to use with RSACryptoServiceProvider.

So ultimately I may want/need to go both ways (Java<->RSACryptoServiceProvider). Does anyone have any pointers?

Thanks.

回答1:

C# has a load from xml functionm for RSA Crypto Provider. Try the approach below:

JAVA

                KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");     keyGen.initialize(1024);     KeyPair keyPair = keyGen.generateKeyPair();     RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();     RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();     BigInteger mod_Int = publicKey.getModulus();     BigInteger exp_Int = publicKey.getPublicExponent();     byte[] mod_Bytes_Extra = mod_Int.toByteArray();     byte[] mod_Bytes = new byte[128];     System.arraycopy(mod_Bytes_Extra, 1, mod_Bytes, 0, 128);     byte[] exp_Bytes = exp_Int.toByteArray();     String modulus = Base64.encodeToString(mod_Bytes, Base64.DEFAULT);     String exponent = Base64.encodeToString(exp_Bytes, Base64.DEFAULT);     System.out.println(modulus);     System.out.println(exponent);     String public_Xml = "<BitStrength>0124</BitStrength><RSAKeyValue><Modulus>"+modulus+"</Modulus><Exponent>"+exponent+"</Exponent></RSAKeyValue>"; 

C#

class KeyBuilder     {         private RSACryptoServiceProvider rsa;          public RSACryptoServiceProvider CreateKey(string rsaKeyPair)         {             rsa = new RSACryptoServiceProvider();             StringBuilder output = new StringBuilder();             string xmlString = "<Key>" + rsaKeyPair + "</Key>";             rsa.FromXmlString(xmlString);             return rsa;         }     } 

Always make you read/write byte arrays with UTF-8 encoding on java side because Java by default uses Unicode encoding whereas C# uses UTF-8.

Also byte arrays in java are signed whereas in C# they are unsigned. So if you have to parse binary data sent from Java code in C# side read it in a sbyte array.



回答2:

I found the answer in the PvkConvert.java file, which I've rewritten (in the relevant parts) as C# for use in Xamarin.Android apps as PvkConvert.cs.

I learned that RSACryptoServiceProvider's native file format (when you use ExportCspBlob) is called PRIVATEKEYBLOB or PUBLICKEYBLOB (depending on whether the private key is included). Encoding a Java IPrivateKey as a PRIVATEKEYBLOB requires a few fields that evidently are only available on an originally generated IPrivateKey instance (one deserialized from storage does not cast to the necessary IRSAPrivateCrtKey interface.)



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