在PHP和Java Android问题之间使用RSA解密数据

我使用PHP服务器加密一些数据,然后将其解密到Android设备。 但是当我尝试在Android设备端解密时,我收到以下错误:

javax.crypto.BadPaddingException:错误:0407106B:rsa例程:RSA_padding_check_PKCS1_type_2:块类型不是02

当我在

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

我正在使用PHPSeclips库(此日期的最后一个github版本)加密PHP服务器上的值并签名。 这部分确实有效,因为已经习惯在Javacard程序上解码,所以错误实际上并不属于这里。

这是我在Android方面的方式:

 protected byte[] decryptData(String alias, byte[] data) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, BadPaddingException, IllegalBlockSizeException, UnsupportedOperationException { Log.i(TAG, "decryptData() Decrypt data " + HexStringConverter.byteArrayToHexString(data)); byte[] decryptedData = null; PrivateKey privateKey = getPrivateKey(alias); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privateKey); decryptedData = cipher.doFinal(data); Log.i(TAG, "decryptData() Decrypted data: " + HexStringConverter.byteArrayToHexString(decryptedData)); return decryptedData; } 

使用getPrivateKey()方法:

 protected RSAPrivateKey getPrivateKey(String alias) { try { KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); KeyStore.Entry entry = ks.getEntry(alias, null); if (!(entry instanceof KeyStore.PrivateKeyEntry)) { Log.w(TAG, "getPrivateKey() Not an instance of a PrivateKeyEntry"); } return (RSAPrivateKey) ((KeyStore.PrivateKeyEntry) entry).getPrivateKey(); } catch (NoSuchAlgorithmException e) { Log.w(TAG, "getPrivateKey() ", e); } catch (KeyStoreException e) { Log.w(TAG, "getPrivateKey() ", e); } catch (CertificateException e) { Log.w(TAG, "getPrivateKey() ", e); } catch (IOException e) { Log.w(TAG, "getPrivateKey() ", e); } catch (UnrecoverableEntryException e) { Log.w(TAG, "getPrivateKey() ", e); } return null; } 

以及如何在PHP端加密:

 //Function for encrypting with RSA function rsa_encrypt($string, $key) { require_once(__DIR__ . '/../phpseclib/Crypt/RSA.php'); //Create an instance of the RSA cypher and load the key into it $cipher = new Crypt_RSA(); $cipher->loadKey($key); //Set the encryption mode $cipher->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); //Return the encrypted version return $cipher->encrypt($string); } //Function for decrypting with RSA function rsa_sign($string, $key) { require_once(__DIR__ . '/../phpseclib/Crypt/RSA.php'); //Create an instance of the RSA cypher and load the key into it $cipher = new Crypt_RSA(); $cipher->loadKey($key); //Set the signature mode $cipher->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); //Return the signed message return $cipher->sign($string); } 

更新(2014年7月3日)对于那些犯同样错误的人,我建议您查看以下页面: http : //hustoknow.blogspot.ca/2013/01/rsa-block-type-is-not-02-的error.html

事实上,这让我找到了解决问题的正确方法。

引发的错误告诉解密密钥与用于加密的密钥不匹配,因此我查看了用于此交换的每个公钥。 因为我使用1024密钥大小,我正在解析输入消息(模数+公共指数),每个都有相应的大小。 我注意到,与Android设备上显示的模数相比,未完全接收到模数。 所以这是错误,当您使用KeyPairGenerator对象生成密钥时,Android默认使用2048密钥大小。 只需手动将密钥大小设置为1024即可解决此问题。

例:

 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore"); Calendar notBefore = Calendar.getInstance(); Calendar notAfter = Calendar.getInstance(); notAfter.add(Calendar.YEAR, 1); KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(mContext) .setAlias(alias) .setKeySize(1024) .setSubject( new X500Principal(String.format("CN=%s, OU=%s", alias, mContext.getPackageName()))) .setSerialNumber(BigInteger.ONE).setStartDate(notBefore.getTime()) .setEndDate(notAfter.getTime()).build(); keyPairGenerator.initialize(spec); KeyPair kp = keyPairGenerator.generateKeyPair(); 

希望这有帮助。

您可能需要define('CRYPT_RSA_PKCS15_COMPAT', true)

以下注释块详细说明:

https://github.com/phpseclib/phpseclib/blob/a8c2ff0fb013169193c649adab512cafef5068cf/phpseclib/Crypt/RSA.php#L2272

基本上,OpenSSL(很可能也是Java)实现了PKCS#1 v1.5,而phpseclib实现了PKCS#1 v2.1。 PKCS#1 v2.1修改PKCS1样式加密以使用随机填充,因此没有两个密文将是相同的。