Descriptografar dados usando o RSA entre problema PHP e Java Android
Estou usando um servidor PHP para criptografar alguns dados e descriptografá-los em um dispositivo Android. Mas quando tento descriptografá-lo no lado do dispositivo Android, recebo o seguinte erro:
javax.crypto.BadPaddingException: erro: 0407106B: rotinas rsa: RSA_padding_check_PKCS1_type_2: o tipo de bloco não é 02
Quando eu estou
Cipher.getInstance("RSA/ECB/PKCS1Padding");
Estou criptografando o valor em um servidor PHP usando a PHPSeclips Library (última versão do github nesta data) e assinando também. Esta parte realmente funciona porque já era decodificada em um programa Javacard, portanto, o erro não pertence aqui.
É assim que procuro no lado do 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;
}
Com o método 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;
}
E como é criptografado no lado do 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);
}
ATUALIZAÇÃO (3/7/14) Para aqueles que cometerem os mesmos erros, recomendo que você veja a seguinte página:http://hustoknow.blogspot.ca/2013/01/rsa-block-type-is-not-02-error.html
De fato, isso me colocou no caminho certo para descobrir qual era o problema.
O erro gerado informa que a chave de descriptografia não corresponde à chave usada para criptografá-la. Por isso, observei todas as Chaves Públicas usadas para essa troca. Como usei o tamanho da chave 1024, estava analisando a mensagem de entrada (módulo + expoente público) com o tamanho relevante de cada uma. E notei que o módulo não foi totalmente recebido em comparação com o exibido no dispositivo Android. Então, aqui está o erro: o Android, por padrão, usa o tamanho da chave 2048 quando você usa o objeto KeyPairGenerator para geração de chave. Basta definir manualmente o tamanho da chave como 1024 para corrigir esse problema.
Exemplo:
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();
Espero que esta ajuda.