Cifrado asimétrico en Java
Vamos a ver como encriptar y desencriptar de forma asimétrica texto o archivos en Java. Este tipo de cifrado utiliza 2 llaves para el proceso, por una parte tenemos una clave pública, que será la encargada de encriptar, y por otro lado tenemos la clave privada, que es la encargada de desencriptar el contenido encriptado con la llave pública. Por tanto la llave pública es la que compartiremos con otros usuarios para que nos envien la información cifrada, mientras que la llave privada permanece de forma segura con nosotros.

Para utilizar este tipo de cifrado en Java tenemos la clase KeyPairGenerator, que como su nombre indica, esta clase nos permite generar un juego de llaves, una llave privada y otra llave pública.
A continuación vamos a ver un ejemplo en el que vamos a encriptar una cadena de texto para ver como queda una vez encriptada y posteriormente procederemos a desencriptarla.
Para empezar crearemos un objeto de tipo KeyPairGenerator utilizando el algoritmo RSA, generaremos un par de llaves y vamos a declarar una cadena de texto que usaremos para encriptar y desencriptar.
/* Utilizamos el metodo estático getInstance() especificando el
* tipo de algoritmo que vamos a usar para crear el objeto
*/
KeyPairGenerator key = KeyPairGenerator.getInstance("RSA");
// Especificamos el tamaño de la llave en bits
key.initialize(1024);
// Generamos el par de llaves que se almacenan en el objeto KeyPair
KeyPair keyPair = key.generateKeyPair();
// Obtenemos ambas llaves por separado
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String msg = "Mensaje para encriptar y posteriormente desencriptar";
Lo siguiente que vamos a hacer es crear 2 métodos, uno se encargará de encriptar y el otro de desencriptar. Estos metodos utilizarán la clase Cipher para realizar la tarea de cifrado.
public static byte[] encriptar(byte[] inputBytes, PublicKey publicKey, String algorithm){
try {
/* Utilizamos el metodo estático getInstance() especificando el tipo de algoritmo que
* vamos a usar para crear el objeto, que será RSA.
*/
Cipher cipher = Cipher.getInstance(algorithm);
// Inicializamos el cipher en modo de encriptado y pasamos la llave pública
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
/* Por último le pasamos el texto en bytes, y nos devolverá el texto encriptado
* en bytes
*/
return cipher.doFinal(inputBytes);
} catch (Exception ex) {
System.out.print(ex);
}
return null;
}
public static byte[] desencriptar(byte[] inputBytes, PrivateKey privateKey, String algorithm){
try {
Cipher cipher = Cipher.getInstance(algorithm);
// Inicializamos el cipher en modo de desencriptado y pasamos la llave privada
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(inputBytes);
} catch (Exception ex) {
System.out.print(ex);
}
return null;
}
Una vez creados los métodos ya podemos proceder probar el encriptado y desencriptado de nuestro mensaje de prueba.
System.out.println("Texto sin encriptar -> " + msg);
byte[] msgEncryptedBytes = encriptar(msg.getBytes(), publicKey, key.getAlgorithm());
System.out.println("Texto encriptado -> " + new String(msgEncryptedBytes));
byte[] msgDecryptedBytes = desencriptar(msgEncryptedBytes, privateKey, key.getAlgorithm());
System.out.println("Texto desencriptado -> " + new String(msgDecryptedBytes));
Atención: Convertir datos encriptados de bytes a String no es una buena práctica ya que se puede perder información o corromper los datos en el proceso.
A continuación dejaré el código completo de la clase creada.
Código completo.
public class CifradoAsimetrico {
public static void main(String[] args) throws NoSuchAlgorithmException {
/* Utilizamos el metodo estático getInstance() especificando el tipo de algoritmo que
* vamos a usar para crear el objeto
*/
KeyPairGenerator key = KeyPairGenerator.getInstance("RSA");
// Especificamos el tamaño de la llave en bits
key.initialize(1024);
// Generamos el par de llaves que se almacenan en el objeto KeyPair
KeyPair keyPair = key.generateKeyPair();
// Obtenemos ambas llaves por separado
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String msg = "Mensaje para encriptar y posteriormente desencriptar";
System.out.println("Texto sin encriptar -> " + msg);
byte[] msgEncryptedBytes = encriptar(msg.getBytes(), publicKey, key.getAlgorithm());
System.out.println("Texto encriptado -> " + new String(msgEncryptedBytes));
byte[] msgDecryptedBytes = desencriptar(msgEncryptedBytes, privateKey, key.getAlgorithm());
System.out.println("Texto desencriptado -> " + new String(msgDecryptedBytes));
}
public static byte[] encriptar(byte[] inputBytes, PublicKey publicKey, String algorithm){
try {
/* Utilizamos el metodo estático getInstance() especificando el tipo de algoritmo que
* vamos a usar para crear el objeto, que será RSA.
*/
Cipher cipher = Cipher.getInstance(algorithm);
// Inicializamos el cipher en modo de encriptado y pasamos la llave pública
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
/* Por último le pasamos el texto en bytes, y nos devolverá el texto encriptado
* en bytes
*/
return cipher.doFinal(inputBytes);
} catch (Exception ex) {
System.out.print(ex);
}
return null;
}
public static byte[] desencriptar(byte[] inputBytes, PrivateKey privateKey, String algorithm){
try {
Cipher cipher = Cipher.getInstance(algorithm);
// Inicializamos el cipher en modo de desencriptado y pasamos la llave privada
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(inputBytes);
} catch (Exception ex) {
System.out.print(ex);
}
return null;
}
}