Descifrado de cifrado RSA en Android
public-key-encryption encryption (5)
Estoy implementando una demostración para encriptación y descifrado RSA en Android. Puedo realizar el cifrado muy bien, pero en el descifrado recibo una excepción: >>java.security.InvalidKeyException: unknown key type passed to RSA
.
KeyPairGenerator kpg;
KeyPair kp;
PublicKey publicKey;
PrivateKey privateKey;
byte [] encryptedBytes,decryptedBytes;
Cipher cipher,cipher1;
String encrypted,decrypted;
public String RSAEncrypt (final String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedBytes = cipher.doFinal(plain.getBytes());
encrypted = new String(encryptedBytes);
System.out.println("EEncrypted?????"+encrypted);
return encrypted;
}
public String RSADecrypt (final String result) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
cipher1=Cipher.getInstance("RSA");
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
decryptedBytes = cipher1.doFinal(result.getBytes());
decrypted = new String(decryptedBytes);
System.out.println("DDecrypted?????"+decrypted);
return decrypted;
}
Y estoy llamando a la función desde aquí:
encrypt.setOnClickListener(new OnClickListener()
{
public void onClick(View arg0)
{
try
{
RSAEncrypt rsaencrypt=new RSAEncrypt();
rsaencrypt.RSAEncrypt(name);
result=rsaencrypt.RSAEncrypt(name);
Toast.makeText(getBaseContext(), result.toString(),Toast.LENGTH_SHORT).show();
System.out.println("Result:"+result);
}
catch(Exception e)
{
e.printStackTrace();
Toast.makeText(getBaseContext(), e.toString(),Toast.LENGTH_LONG).show();
}
}
});
decrypt.setOnClickListener(new OnClickListener()
{
public void onClick(View arg0)
{
{
try
{
RSAEncrypt rsadecrypt=new RSAEncrypt();
rsadecrypt.RSADecrypt(result);
ans=rsadecrypt.RSADecrypt(result);
System.out.println("Result is"+ans);
Toast.makeText(getBaseContext(), ans.toString(),Toast.LENGTH_LONG).show();
}
catch(Exception e)
{
e.printStackTrace();
Toast.makeText(getBaseContext(), e.toString(),Toast.LENGTH_LONG).show();
System.out.println("Exception is>>"+e);
}
}
});
Aquí hay un ejemplo para Android de:
- generando un par de claves RSA privadas / públicas
- Encriptar una cadena
- descifrar la cadena encriptada
Estos métodos tratan con toda la codificación / decodificación de base 64.
public void TestEncryptData(String dataToEncrypt) {
// generate a new public/private key pair to test with (note. you should only do this once and keep them!)
KeyPair kp = getKeyPair();
PublicKey publicKey = kp.getPublic();
byte[] publicKeyBytes = publicKey.getEncoded();
String publicKeyBytesBase64 = new String(Base64.encode(publicKeyBytes, Base64.DEFAULT));
PrivateKey privateKey = kp.getPrivate();
byte[] privateKeyBytes = privateKey.getEncoded();
String privateKeyBytesBase64 = new String(Base64.encode(privateKeyBytes, Base64.DEFAULT));
// test encryption
String encrypted = encryptRSAToString(dataToEncrypt, publicKeyBytesBase64);
// test decryption
String decrypted = decryptRSAToString(encrypted, privateKeyBytesBase64);
}
public static KeyPair getKeyPair() {
KeyPair kp = null;
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
kp = kpg.generateKeyPair();
} catch (Exception e) {
e.printStackTrace();
}
return kp;
}
public static String encryptRSAToString(String clearText, String publicKey) {
String encryptedBase64 = "";
try {
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKey.trim().getBytes(), Base64.DEFAULT));
Key key = keyFac.generatePublic(keySpec);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(clearText.getBytes("UTF-8"));
encryptedBase64 = new String(Base64.encode(encryptedBytes, Base64.DEFAULT));
} catch (Exception e) {
e.printStackTrace();
}
return encryptedBase64.replaceAll("(//r|//n)", "");
}
public static String decryptRSAToString(String encryptedBase64, String privateKey) {
String decryptedString = "";
try {
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKey.trim().getBytes(), Base64.DEFAULT));
Key key = keyFac.generatePrivate(keySpec);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
// encrypt the plain text using the public key
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptedBytes = Base64.decode(encryptedBase64, Base64.DEFAULT);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
decryptedString = new String(decryptedBytes);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedString;
}
Creo que el problema es que debes usar el mismo par de claves para encriptar y descifrar el cifrado. En referencia a JavaDoc:
genKeyPair() This will generate a new key pair every time it is called.
En RSA, debe usar la clave pública para el cifrado y la clave privada para el descifrado.
El código de muestra utiliza para encriptar y desencriptar la clave pública; esto no puede funcionar.
Por lo tanto, en la parte de descifrado debe inicializar el cifrado de esta manera:
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
Además, tu código tiene un segundo error importante:
Está convirtiendo una matriz de bytes con contenido binario en una Cadena.
¡Nunca convierta datos binarios a String!
Las cadenas son para caracteres de cadena, no datos binarios. Si desea empaquetar datos binarios en un String, codifíquelos para caracteres imprimibles, por ejemplo, usando Hex o Base64.
El siguiente ejemplo utiliza el codificador hexadecimal del paquete org.apache.common.codec : se debe instalar una biblioteca de terceros.
public byte[] RSAEncrypt(final String plain) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedBytes = cipher.doFinal(plain.getBytes());
System.out.println("EEncrypted?????" + new String(org.apache.commons.codec.binary.Hex.encodeHex(encryptedBytes)));
return encryptedBytes;
}
public String RSADecrypt(final byte[] encryptedBytes) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
cipher1 = Cipher.getInstance("RSA");
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
decryptedBytes = cipher1.doFinal(encryptedBytes);
decrypted = new String(decryptedBytes);
System.out.println("DDecrypted?????" + decrypted);
return decrypted;
}
Mi clase:
package com.infovale.cripto;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
public class RSA {
KeyPairGenerator kpg;
KeyPair kp;
PublicKey publicKey;
PrivateKey privateKey;
byte[] encryptedBytes, decryptedBytes;
Cipher cipher, cipher1;
String encrypted, decrypted;
public String Encrypt (String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedBytes = cipher.doFinal(plain.getBytes());
encrypted = bytesToString(encryptedBytes);
return encrypted;
}
public String Decrypt (String result) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
cipher1=Cipher.getInstance("RSA");
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
decryptedBytes = cipher1.doFinal(stringToBytes(result));
decrypted = new String(decryptedBytes);
return decrypted;
}
public String bytesToString(byte[] b) {
byte[] b2 = new byte[b.length + 1];
b2[0] = 1;
System.arraycopy(b, 0, b2, 1, b.length);
return new BigInteger(b2).toString(36);
}
public byte[] stringToBytes(String s) {
byte[] b2 = new BigInteger(s, 36).toByteArray();
return Arrays.copyOfRange(b2, 1, b2.length);
}
}
cuando usa el método RSAEcvypt, rellena PublicKey y clave privada. Y cuando descifras tu byte generado [], tu publicKey y privateKey son NULL. Por eso obtienes este error.
Debes usar tus claves estáticas;
enter code here
KeyPairGenerator kpg;
KeyPair kp;
static PublicKey publicKey;
static PrivateKey privateKey;
byte [] encryptedBytes,decryptedBytes;
Cipher cipher,cipher1;
String encrypted,decrypted;