【问题标题】:RSA decryption with a public key使用公钥进行 RSA 解密
【发布时间】:2012-05-07 02:28:40
【问题描述】:

我的 Android 项目中有一些解密问题。

我得到一个用私钥签名的字符串,我必须用公钥验证(解密)它。 我想得到与使用 PHP 函数完全相同的结果 - openssl_public_decrypt (http://php.net/manual/pl/function.openssl-public-decrypt.php)

我必须在我的 Java 项目中这样做,这样我才能使用 Java 库(例如 BouncyCastle 或其他东西,有什么建议吗?)

有什么办法解决这个问题吗?

好的,这是我的代码。 我得到这样的公钥

PEMReader reader = new PEMReader(new InputStreamReader(ctx
                .getAssets().open("pubkey.pem")));
        Object obj;
        while ((obj = reader.readObject()) != null) {
             if (obj instanceof RSAPublicKey) {
                pubKey = (RSAPublicKey) obj;
                return pubKey;
            }
        }

而且我总是毫无问题地获得公钥。

Cipher c = Cipher.getInstance("RSA/NONE/NoPadding", "SC");
c.init(Cipher.DECRYPT_MODE, pubKey);
byte[] result = c.doFinal(data_to_decrypt.getBytes());

结果(将字节转换为字符串后)我得到022c06571c6a263b389fcd93159cb311abb880bddf51b7c916dd1ae...

php 函数返回的地方 sd8dsa348acvcx87|00454|OK|15000|CDE 这是正确的输出。

【问题讨论】:

  • 在公钥密码学中:您使用私钥签名和解密/解密;您验证(签名)并使用公钥加密/加密。你想做什么?
  • 就像我说的我正在尝试使用公钥解密数据
  • 不能用公钥解密数据,这是没有意义的(尽管 PHP 的命名选择很糟糕)。 “我得到一个用私钥加密的字符串”:这真的没有意义。最好是签了。当然,对于 RSA,它或多或少会是相同的操作(但对于 DSA,情况并非如此)。问题是消息的签名几乎肯定会涉及哈希,因此不可能获取原始消息。
  • 好的,假设该字符串已签名,我该如何验证呢?
  • 您对签名了解更多吗?使用了哪种哈希算法,例如RSAwithSHA1

标签: java php android rsa public-key


【解决方案1】:

Java 有 Java Cryptography Extension Framework,它就是为这些事情而设计的。

BouncyCastle 是该框架的密码学提供程序。这意味着,它为您的 Java Cryptography Extension 提供了加密算法的实现。

您可以在包java.securityjavax.crypto 中找到这方面的基本类

要使用公钥解密您的消息,您可以尝试以下操作:

// Use RSA/NONE/NoPadding as algorithm and BouncyCastle as crypto provider
Cipher asymmetricCipher = Cipher.getInstance("RSA/NONE/NoPadding", "BC");

// asume, that publicKeyBytes contains a byte array representing
// your public key
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);

KeyFactory keyFactory;
keyFactory = KeyFactory.getInstance(publicKeySpec.getFormat());
Key key = keyFactory.generatePublic(publicKeySpec);

// initialize your cipher
asymmetricCipher.init(Cipher.DECRYPT_MODE, key);
// asuming, cipherText is a byte array containing your encrypted message
byte[] plainText = asymmetricCipher.doFinal(cipherText);

请注意,此示例非常基本,缺少几个 try catch 块。此外,您不应该使用没有填充的非对称密码,因为这会使您容易受到重放攻击。您可能还会遇到密钥长度问题。在某些 Java 包中,允许的最大密钥长度受到限制。这可以通过使用无限强度策略文件来解决。

我希望这可以帮助您开始使用 Java 密码学。

【讨论】:

  • 感谢您的回答。我之前有一个类似的解决方案,它可以工作,但结果是这样的:022c06571c6a263b389fcd93159cb311abb880bddf51b7c916dd1ae...其中php函数返回解密字符串,哪里有问题?
  • 该方法返回一个字节数组。您是否将结果转换为字符串?我也只是认识到,我没有将 doFinal 方法的结果分配给变量...要编辑答案...
  • 我将结果转换为字符串,我之前的评论的输出是从字节数组转换而来的字符串
  • 我编辑了我的第一篇文章,并添加了一些代码,也许它会有助于找到解决方案。
  • 未找到 KeyFactory X.509 实现