如何在Android中使用C#生成的RSA公钥?

9

我希望在无法使用HTTPS的情况下,确保Android应用程序和C# ASP.NET服务器之间的消息隐私。

我想使用RSA加密一个对称密钥,该密钥在Android设备首次联系服务器时传输。

RSA密钥对已在服务器上生成,私钥存储在服务器上。 该密钥对是使用C#生成的:

// Create a new instance of RSACryptoServiceProvider
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
// Ensure that the key doesn't get persisted
rsa.PersistKeyInCsp = false;
RSAParameters parameters = rsa.ExportParameters(false);
string modulus = Convert.ToBase64String(parameters.Modulus);
string exponent = Convert.ToBase64String(parameters.Exponent);
string xmlKeys = rsa.ToXmlString(true);

尝试硬编码(从Visual Studio复制到Eclipse)嵌入公钥是不起作用的。代码会在rsaCipher.doFinal()方法调用时抛出org.bouncycastle.crypto.DataLengthException:RSA密码过于庞大的异常。
// Generate a new AES key
byte[] key = null;
try {
    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    keygen.init(128);            
    key = keygen.generateKey().getEncoded();
}
catch (NoSuchAlgorithmException e) {}

// Set up modulus and exponent
String mod = "qgx5606ADkXRxndzurIRa5GDxzDYg5Xajeym7I8BXG1HBSzaaGmX+rjQfZK1h4JtQU+Xaowsc81mgJU8+gwneQa56r1bl6/5jFue4FsdXKfpau5az8rY2SAHKcOeyHAOsT9ZqcNa1x6cL/jl9P3cBtOzMk51Hk/w6VNoQ5JJo/0m/eAJzlhVKr2xbOYFhd0xp3qUgRuK8TN4TsSvfc+R1LOWc8+3H22Zj3vhBxSqSgeXxdxi7ThiGiAl6HUwMf8ph7FHNJvoUQq+QPL6dx77pu6xVFiHv1JOfpbKcOubn0VSPLYKY3QPKCzNMYQ6pxUDqzpGtydHR1xaX5K0FGTraw==";

String ex = "AQAB";
BigInteger modulus = new BigInteger(Base64.decode(mod, Base64.DEFAULT));
BigInteger exponent = new BigInteger(Base64.decode(ex, Base64.DEFAULT));

// Encrypt the AES key
PublicKey pubKey;
byte[] cipherData;
try {
    pubKey = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpe(modulus, exponent));
    Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");     
    rsaCipher.init(Cipher.ENCRYPT_MODE, pubKey);
    // The following line fails with:
    // org.bouncycastle.crypto.DataLengthException
    cipherData = rsaCipher.doFinal(key);     
}
catch (InvalidKeySpecException e) {}
catch (NoSuchAlgorithmException e) {}
catch (InvalidKeyException e) {}
catch (NoSuchPaddingException e) {}
catch (BadPaddingException e) {}
catch (IllegalBlockSizeException e) {}

我怀疑我错误地解码了模数字符串,因为在Android中生成公钥成功加密了该密钥。我使用了以下代码:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");     
kpg.initialize(1024);     
KeyPair kpa = kpg.genKeyPair();     
pubKey = kpa.getPublic();   

那么,我做错了什么?


你应该明白,像这样在未加密的流量中传输安全密钥意味着任何人都可以获取它,对吧?如果你正在使用Mono for Android,我们需要更多信息才能帮助你。 - Security Hound
澄清一下:我在使用Java / Eclipse开发Android应用。安全密钥并没有以未加密的方式发送。Java代码中嵌入的RSA公钥用于加密AES对称密钥。加密后的AES密钥被发送到服务器,服务器使用其(私有的)RSA私钥解密,并用其加密服务器响应给Android客户端。 - Richard Keeble
1个回答

7
尝试使用new BigInteger(1, modulus)。BigIntegers是有符号的,由于模数以第一个位设置为1开始,因此它总是被解释为负数。

你只能在负模数中存储负数据 :) - Maarten Bodewes
BigInteger(1, modulus)解决了问题。你救了今天,非常感谢。 - Richard Keeble

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接