Encriptar y Desencriptar con RSA en ANDROID

Ayer mostraba una clase java para cifrado y descifrado RSA en para Java SE ahora traigo la misma clase pero modificada para funcionar en una app en Android

Si quieren ver la version para Java SE pueden ir a Encriptar y Desencriptar con RSA en JAVA sino pueden seguir leyendo: Encriptar y Desencriptar con RSA en ANDROID

Les dejo el codigo fuente del ejemplo AndroidRSATest.zip

Ejemplo de como utilizar la clase para Android:

public class MainActivity extends AppCompatActivity {


    private TextView txtOrignal;
    private TextView txtEncode;
    private TextView txtDecode;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        txtOrignal = (TextView) findViewById(R.id.txtOriginal);
        txtEncode = (TextView) findViewById(R.id.txtEncode);
        txtDecode = (TextView) findViewById(R.id.txtDecoded);

        txtOrignal.setText("Este es el texto a cifrar");


    }

    public void crypt(View view) {

        try {

           //Obtenemos el texto desde el cuadro de texto 
            String original = txtOrignal.getText().toString();
            
            RSA rsa = new RSA();

            //le asignamos el Contexto
            rsa.setContext(getBaseContext());

            //Generamos un juego de claves
            rsa.genKeyPair(1024);

            //Guardamos en la memoria las claves
            rsa.saveToDiskPrivateKey("rsa.pri");
            rsa.saveToDiskPublicKey("rsa.pub");

            //Ciframos
            String encode_text = rsa.Encrypt(original);

            //Mostramos el texto cifrado
            txtEncode.setText(encode_text);

            
            //Creamos otro objeto de nuestra clase RSA
            RSA rsa2 = new RSA();

            //Le pasamos el contexto
            rsa2.setContext(getBaseContext());

            //Cargamos las claves que creamos anteriormente
            rsa2.openFromDiskPrivateKey("rsa.pri");
            rsa2.openFromDiskPublicKey("rsa.pub");

            //Desciframos
            String decode_text = rsa2.Decrypt(encode_text);

            //Mostramos el texto ya descifrado
            txtDecode.setText(decode_text);
        } catch (Exception e) {

        }


    }
}

También tenemos la opción de no guardarlas en disco para manejaras en memoria o en una base de datos por lo cual podemos asignarlas a variables

     //Guardamos las claves
     String publicKey = rsa.getPublicKeyString();
     String privateKey = rsa.getPrivateKeyString();
     

     //Las claves guardadas anteriormente las podemos
     //Aignar a otra clase para poder cifrar o descifrar
     rsa2.setPublicKeyString(publicKey);
     rsa2.setPrivateKeyString(privateKey);

Por ultimo la clase RSA.java

package uy.com.adl.androidrsatest;

import android.content.Context;
import android.util.Log;


import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class RSA {
	
	public PrivateKey PrivateKey = null;
	public PublicKey PublicKey = null;

	public Context context;

	public RSA()
	{
		

	}

	public Context getContext() {
		return context;
	}

	public void setContext(Context context) {
		this.context = context;
	}

	public void setPrivateKeyString(String key) throws NoSuchAlgorithmException, InvalidKeySpecException{
		byte[] encodedPrivateKey = stringToBytes(key);
		
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
		PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
		this.PrivateKey = privateKey;
	}

	public void setPublicKeyString(String key) throws NoSuchAlgorithmException, InvalidKeySpecException{
		
		byte[] encodedPublicKey = stringToBytes(key);
		
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey);
		PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
		this.PublicKey = publicKey;
	}

	public String getPrivateKeyString(){
		PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(this.PrivateKey.getEncoded());
	    return bytesToString(pkcs8EncodedKeySpec.getEncoded());
	}

	public String getPublicKeyString(){
		X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(this.PublicKey.getEncoded());
		return bytesToString(x509EncodedKeySpec.getEncoded());
	}
	
	
	public void genKeyPair(int size) throws NoSuchAlgorithmException,NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException  {
		
	    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
	    kpg.initialize(size);
	    KeyPair kp = kpg.genKeyPair();
	    
	    PublicKey publicKey = kp.getPublic();
	    PrivateKey privateKey = kp.getPrivate();
	    
	    this.PrivateKey = privateKey;
	    this.PublicKey = publicKey;
	}

	public String Encrypt(String plain) throws NoSuchAlgorithmException,NoSuchPaddingException, InvalidKeyException,IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException, NoSuchProviderException {

	    byte[] encryptedBytes; 
  
	    Cipher cipher = Cipher.getInstance("RSA");
	    cipher.init(Cipher.ENCRYPT_MODE, this.PublicKey);
	    encryptedBytes = cipher.doFinal(plain.getBytes());

	    return bytesToString(encryptedBytes);

	}

	public String Decrypt(String result) throws NoSuchAlgorithmException,NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {

	    byte[] decryptedBytes;

	    Cipher cipher = Cipher.getInstance("RSA");
	    cipher.init(Cipher.DECRYPT_MODE, this.PrivateKey);
	    decryptedBytes = cipher.doFinal(stringToBytes(result));
	    return new String(decryptedBytes);
	}

	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);
	}


	public void saveToDiskPrivateKey(String path){
		try {
			FileOutputStream outputStream = null;
			outputStream =  this.context.openFileOutput(path, Context.MODE_PRIVATE);
			outputStream.write(this.getPrivateKeyString().getBytes());
			outputStream.close();
		} catch (Exception e) {
			Log.d("RSA:","Error write PrivateKey");
		}
	}
	
	public void saveToDiskPublicKey(String path) {
		try {
			FileOutputStream outputStream = null;
			outputStream =  this.context.openFileOutput(path, Context.MODE_PRIVATE);
			outputStream.write(this.getPublicKeyString().getBytes());
			outputStream.close();
		} catch (Exception e) {
			Log.d("RSA:","Error write Public");
		}
	}

	public void openFromDiskPublicKey(String path) throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {
		String content = this.readFileAsString(path);
		this.setPublicKeyString(content);
	}
	
	public void openFromDiskPrivateKey(String path) throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {
		String content = this.readFileAsString(path);
		this.setPrivateKeyString(content);
	}


	private String readFileAsString(String filePath) throws IOException {

		BufferedReader fin = new BufferedReader(new InputStreamReader(context.openFileInput(filePath)));
		String txt = fin.readLine();
		fin.close();
		return txt;

    }
		
}

Alvaro DeLeon

Acerca de Alvaro DeLeon

Administrador de Sistemas,Programador,Docente y Blogger. Más de 20 años de experiencia en computación. Escribo más que nada sobre Linux, sistemas operativos, virtualización, seguridad y tecnología en general además de algunos artículos con opiniones muy personales e irrelevantes.
Esta entrada fue publicada en Desarrollo y etiquetada , , , , . Guarda el enlace permanente.

6 respuestas a Encriptar y Desencriptar con RSA en ANDROID

  1. Cinthia dijo:

    Excelente aporte, se que ya hace bastante tiempo fue publicada esta entrada pero considero que nuca es tarde para dar gracias ^^

    Muchas gracias! ♥

    • Gracias por tu comentario, me alegro que te haya servido, una de las razones por lo que lo escribí es porque nunca encontré algo sencillo y rápido de implementar y a muchos les debe pasar lo mismo porque este post y el otro de RSA en Java (no android) son de los más vistos del blog por lejos.

  2. andy dijo:

    lo eh usado y funciona pero no entiendo como puedo desifrar algo en otra clase

    • Hola Andy

      Para descifrar lo único que tienes que hacer es desde la otra clase crear una instancia del objeto RSA nuevamente, asignarle la clave privada que tienes que haber guardado cuando la cifraste, no crear llaves nuevas sino usar el par con el que fue cifrado, luego a la función RSA.Decrypt() pasarle el texto cifrado que te devolverá el texto descifrado.

      Saludos

  3. Christian Guantiva dijo:

    Hola buenos días, no entiendo como manejar las claves en una Base de Datos, tengo el problema de que cuando voy a desencriptar la información desde otro dispositivo, no lo hace. me podrías ayudar, por favor.

    GRACIAS

    • Hola Christian, para pasarle las claves que vengan de la base de datos puedes hacerlo mediante las funciones setPublicKeyString y setPrivateKeyString, lo deberías hacer en ambos dispositivos, solo te debes asegurar que las claves se estén guardando sin problemas, te debería funcionar, saludos

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *