2013-07-23 104 views
1

我想解密我的Android应用程序中使用我的设备上生成的RSA密钥的字符串。加密由php服务完成,使用我的应用程序提供的公共rsa密钥。我的问题是解密,失败。Android RSA解密(失败)/服务器端加密(openssl_public_encrypt)

我做了以下内容:

  • 生成密钥对在Android(与KeyPairGenerator.getInstance( “RSA”)) - >确定

  • 两个密钥(公钥和私钥)保存到用Base64.encode(pubKey.getEncoded())编码后的文件和用私钥相同的文件。 - >确定

  • 当我打电话给我的web服务,我通过在变量后我的公钥(在基地64) - >确定

  • Web服务(PHP服务),使用公钥使用openssl_public_encrypt函数对短字符串进行加密。加密的字符串被转换为base64。 - >看起来好,函数不返回FALSE。

  • 应用程序检索该服务的结果,并对其进行解码(Base64.decode()) - >行(I已经检查中,接收到的字节与由openssl_public_encrypt()函数生成的一个原因)

  • 最后一件事是解密这个字符串,我正在做以下事情: - >不是OK

    Cipher cipher = Cipher.getInstance(“RSA”);

    cipher.init(Cipher.DECRYPT_MODE,privateKey);

    byte [] decryptedBytes = cipher.doFinal(cryptedBytes);

    String decryptedString = new String(decryptedBytes);

    System.out.println(decryptedString);

解密的结果与我的原始字符串不匹配。

我错过了什么?

+0

'密码。getInstance(“RSA”)默认为“教科书RSA” - 没有填充 - 根本不安全。我不知道PHP代码使用了什么样的填充,因为您没有显示它,但是您应该在两端将其更改为OAEP。 – ntoskrnl

+1

@ntoskrnl你可以把它变成我猜的答案。请注意,默认的“RSA/NONE/NoPadding”仅适用于Bouncy Castle,Java SE - 或更准确地说,Sun JCE - 默认为“RSA/ECB/PKCS1Padding”。 –

+0

@owlstead好点 - 也说明了显式声明模式的重要性,而不是依赖实现之间不同的默认值。 – ntoskrnl

回答

9

OpenSSL默认使用padding = OPENSSL_PKCS1_PADDING。所以要在双方都有相同的填充机制,你应该使用Cipher.getInstance("RSA/ECB/PKCS1Padding")。这也是您可以在Java SE中使用的。

请注意,依赖加密中的默认操作模式是非常危险的。许多实现具有不同的默认值,并且可能很难查找。因此,请始终尝试完全指定要使用的算法/模式。

你可以尝试其他的RSA填充模式,但是请注意 - 不幸的是 - Android已经禁用了很多来自他们改编的Bouncy Castle源代码的算法和别名。


[编辑]这是一个老的答案,OAEP填充强烈地受到现在使用RSA-KEM建议,或混合加密。

+0

谢谢@owlstead,使用'getInstance(“RSA/ECB/PKCS1Padding”)'我的服务器端脚本可以正确解密我的Android应用程序加密的内容。但是,如果我使用'getInstance(“RSA/None/PKCS1Padding”)'(在服务器端解密虽然不起作用),但我没有“异常的RSA数据块”异常。有任何想法吗? – ericn

+1

这似乎是混合加密的一个明确的例子。 RSA加密不应该单独使用;通常您应该加密一个新的随机生成的AES密钥,并使用该AES密钥对数据执行加密(例如使用CBC操作模式),这样您就可以加密几乎无限量的明文。 –

+0

@MaartenBodewes导致扎根的Android设备,我不想把解密密钥放在客户端,所以我怎么能解密在服务器端,在Android设备加密的文件?请参阅我的相关问题:http://stackoverflow.com/questions/30951805/protected-document-viewer –