使用具有给定模数和指数的RSA算法在Android中加密

时间:2013-03-07 12:08:22

标签: java android encryption rsa

我之前在C#中使用过RSACryptoServiceProvider来加密某些数据,现在我必须在Android程序中复制这种加密。我希望我的Android程序能够生成与我在C#程序中相同的结果。

公钥:

<RSAKeyValue>
    <Modulus>zz4qdc39y1BHyJgVXUkINJSbsUd1ZJPISyE9nNGjqgR+ZO1a4cE3ViVCSZCw+6dBdVMFNjzZPBxl0mT57GIq7rcuoT0scesZgxOftbMasPbxp0BGrh3HTpbBMJdCopgcYV98CZERakb8Pgbb0ne/DiW9Aq0kfTBE02/iEHRNuqMNfo1GFo55m0OKbxVoM6UBb8AITQ6lbdvfCgeIvMzRlVrHCwxUNrrX5cS6gurEfJ8Da+prKQmwWpFCkwDkPWje2W+bTSPUc9l6Ads0UimYE5sGs4Zsfz6Eocz4rJjR+qCiB8qt6HtdyjKo0auqYzyXIjdRv2950flc9tOh5bRlQQ==
    </Modulus>
    <Exponent>AQAB</Exponent>
</RSAKeyValue>

Java加密程序:

byte[] modulusBytes = Base64.decode(Modoutput.getBytes("UTF-8"),
        Base64.DEFAULT);
byte[] exponentBytes = Base64.decode(Expoutput.getBytes("UTF-8"),
        Base64.DEFAULT);
BigInteger e = new BigInteger(1, exponentBytes);
BigInteger m = new BigInteger(1, modulusBytes);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKeyn = fact.generatePublic(keySpec);

Log.i("Publickey", pubKeyn.toString());
Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, pubKeyn);
byte[] encryptedByteData = cipher.doFinal(byteData);
String outputEncrypted = Base64.encodeToString(encryptedByteData,
        Base64.NO_WRAP);

Log.i("Encrypteddata", outputEncrypted);

我尝试了上面的代码,但它提供了与C#完全不同的输出。谁能告诉我我的代码有什么问题?提前谢谢。


编辑 :根据要求,这是我尝试在Java中复制加密输出的C#代码:

public static string EncryptText(string text, int keySize,
        string publicKeyXml) {
    var encrypted = Encrypt(Encoding.UTF8.GetBytes(text), keySize,
            publicKeyXml);
    return Convert.ToBase64String(encrypted);
}

public static byte[] Encrypt(byte[] data, int keySize, string publicKeyXml) {
    if (data == null || data.Length == 0)
        throw new ArgumentException("Data are empty", "data");
    int maxLength = GetMaxDataLength(keySize);
    if (data.Length > maxLength)
        throw new ArgumentException(String.Format(
                "Maximum data length is {0}", maxLength), "data");
    if (!IsKeySizeValid(keySize))
        throw new ArgumentException("Key size is not valid", "keySize");
    if (String.IsNullOrEmpty(publicKeyXml))
        throw new ArgumentException("Key is null or empty", "publicKeyXml");

    using (var provider = new RSACryptoServiceProvider(keySize)) {
        provider.FromXmlString(publicKeyXml);
        return provider.Encrypt(data, _optimalAsymmetricEncryptionPadding);
    }
}

1 个答案:

答案 0 :(得分:4)

按定义加密会尝试隐藏有关纯文本的所有信息。这包括有关相同纯文本的信息。为此,它在各种填充模式中使用某种随机(例如,RSA的PKCS#1 v1.5兼容填充或OAEP填充)。因此,从加密的角度来看,如果您得到相同的结果,则实现已损坏

检查密文是否正确的方法是使用私钥解密。如果这导致您开始使用的纯文本,那么您的实现是正确的。

[编辑]请注意,您在C#代码中使用OAEP加密,而Java默认使用PKCS#1 v1.5兼容方案。您应该使用"RSA/None/OAEPWithSHA1AndMGF1Padding""RSA/ECB/OAEPWithSHA1AndMGF1Padding"。如果没有,请添加Bouncy Castle提供商。