【问题标题】:Failure to decrypt RSA encrypted content(By Client) on Server无法在服务器上解密 RSA 加密内容(由客户端)
【发布时间】:2021-09-22 20:35:27
【问题描述】:

我们有一个客户端服务器系统,其中客户端(Android 手机)和服务器(spring)都使用 java.security.KeyFactory 来获取 java.security.KeyFactory 的实例,如下所示:

KeyFactory factory = KeyFactory.getInstance("RSA");

但是如果我们这样做,当我们使用这个工厂加密数据时,服务器会给出不同的输出,客户端会给出不同的输出。当我们检查供应商时,服务器端是 SunRsaSign,客户端是 OpenSSLRSA。所以我们尝试使用以下方法在客户端上设置相同的内容:

KeyFactory factory = KeyFactory.getInstance("RSA", "SunRsaSign");

但是我们得到 java.security.NoSuchProviderException 错误。同样,当我们尝试在服务器上设置 OpenSSLRSA 时,它们也面临同样的错误。

完整的加密代码在服务器和客户端上是相同的:

String pubKey = "<key here>"
byte[] keyData = DatatypeConverter.parseHexBinary(pubKey);
System.out.println("key data" + Arrays.toString(keyData));
KeyFactory factory = KeyFactory.getInstance("RSA");
//System.out.println("provide = " + factory.getProvider());
PublicKey pub = factory.generatePublic(new X509EncodedKeySpec(keyData));
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, pub);
byte[] secretMessageBytes = msg.getBytes(StandardCharsets.UTF_8);
System.out.println("secret msg" +Arrays.toString(secretMessageBytes));
byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);
System.out.println("enc data" +Arrays.toString(encryptedMessageBytes));

生成的encryptedMessageBytes 不同。这会是个问题吗?我认为这是因为不同平台使用了不同的 Provider。

有人可以帮助我如何设置 KeyFactory 的提供程序或如何删除解密错误(javax.crypto.BadPaddingException)?

【问题讨论】:

  • 您究竟将工厂用于什么,用于密钥导入?你有多确定问题真的出在工厂?也许您应该发布双方导入和加密的代码。您使用的是哪个 Android 版本?
  • 另请注意,RSA 加密会为相同的输入数据生成不同的密文。仅此一点并不表示存在问题。
  • @user9014097 添加了加密代码。
  • 也可以试试Cipher.getInstance("RSA/ECB/PKCS1Padding")。每边可能有不同的填充默认值。
  • 我已经详细说明了我的评论并将其发布为答案。

标签: java android kotlin encryption rsa


【解决方案1】:

在 Android 和 Java/Spring 端都使用的发布代码仅指定算法而不是实例化密码时的填充:

Cipher.getInstance("RSA")

如果没有明确指定填充,则使用双方提供者的默认填充。然而,不同的提供者通常定义不同的默认填充(例如NoPaddingPKCS1PaddingOAEPPadding)。不同的填充会导致解密失败,因为成功解密的先决条件是使用与加密相同的填充。

为避免此类情况,应始终在实例化密码时指定填充,尤其是在跨平台环境中,例如:

Cipher.getInstance("RSA/ECB/PKCS1Padding")

左边是算法,右边是填充。注意中间部分(ECB)对RSA没有意义(它是使用对称加密方案的神器,中间指定操作模式,非对称加密没有定义)。

用明确的填充规范解决问题证明填充确实是问题所在。


我只能推测您的环境中使用的默认填充。

我无法测试 OpenSSLRSA 提供程序,因为它在我的环境中不可用。在我的机器上,Android(API 级别 28,P)应用了 AndroidOpenSSL 提供程序(又名 Conscrypt)。这默认为NoPadding,而Java 的SunJCE 提供程序默认为PKCS1Padding。 Android 上的加密和 Java 上的解密将导致异常(或其他方向的未删除填充)。

您可以按如下方式确定环境的默认填充:使用默认填充进行加密(仅通过指定算法)并在解密时改变填充,直到解密成功并且原始明文被解密。

【讨论】:

    猜你喜欢
    • 2015-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-23
    相关资源
    最近更新 更多