【问题标题】:Convert Java.Security.KeyPair to .NET RSACryptoServiceProvider将 Java.Security.KeyPair 转换为 .NET RSACryptoServiceProvider
【发布时间】:2014-03-06 04:29:21
【问题描述】:

如何对 Java 生成的 RSA 私有(和公共)密钥进行编码,以便在 .NET 中对其进行解码,以便在 RSACryptoServiceProvider 中使用?

我试过这段代码:

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

我正在使用 Xamarin.Android 编写 C#,但“本机”Java RSA 密钥生成器比单声道生成器快得多。所以我想使用 Java 的,但我仍然需要能够与 Windows 人员交换公钥和/或私钥,以便与RSACryptoServiceProvider 一起使用。

所以最终我可能想要/需要双向(JavaRSACryptoServiceProvider)。有没有人指点一下?

谢谢。

【问题讨论】:

    标签: java android cryptography xamarin rsa


    【解决方案1】:

    C# 具有来自 RSA Crypto Provider 的 xml 函数的负载。试试下面的方法:

    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;
            }
        }
    

    始终让您在 java 端使用 UTF-8 编码读取/写入字节数组,因为 Java 默认使用 Unicode 编码,而 C# 使用 UTF-8。

    Java 中的字节数组也是有符号的,而在 C# 中它们是无符号的。因此,如果您必须在 C# 端解析从 Java 代码发送的二进制数据,请在 sbyte 数组中读取它。

    【讨论】:

    • 谢谢,但这不起作用。在一个上加密并在另一个上解密的消息无法正确解密,就好像它们的密钥错误一样。
    • 你要加解密的字符串两边都应该是UTF-8格式。因此,您将字符串作为 UTF-8 字符串读入 java 端的字节数组。这是因为 java 默认使用 Unicode 作为字符串编码,而 C# 使用 UTF-8。
    • 我根本不传输字符串。我正在传输一个缓冲区 (byte[] {1,2,3}) 以使事情变得非常简单。缓冲区现在在另一边完全错误。
    • 另外请记住,默认情况下,字节在 java 端是有符号的,而 C# 字节是无符号的。在 C# 端将数组读入 sbyte。
    • 感谢您的提示。但是,我不确定该怎么做。无论有符号还是无符号,我希望 byte[] 的 base64 编码表示(在 C# 或 Java 中)是相同的。如果没有,我不确定我应该做什么。 sbyte[] 不是我需要的,也不是 Convert.Frombase64string() 给我的。
    【解决方案2】:

    我在 PvkConvert.java 文件中找到了答案,我已将其(在相关部分)重写为 C#,以便在 Xamarin.Android 应用程序中使用 PvkConvert.cs

    我了解到RSACryptoServiceProvider 的本机文件格式(当您使用 ExportCspBlob 时)称为 PRIVATEKEYBLOB 或 PUBLICKEYBLOB(取决于是否包含私钥)。将 Java IPrivateKey 编码为 PRIVATEKEYBLOB 需要一些字段,这些字段显然仅在最初生成的 IPrivateKey 实例上可用(从存储中反序列化的字段不会转换为必要的 IRSAPrivateCrtKey 接口。)

    【讨论】:

      猜你喜欢
      • 2018-08-15
      • 2018-11-14
      • 2015-01-21
      • 2019-12-12
      • 1970-01-01
      • 2017-07-26
      • 1970-01-01
      • 2016-04-18
      • 2011-11-08
      相关资源
      最近更新 更多