Vamos pues a ver hoy cómo cifrar un mensaje en JAVA. En este caso se va utilizar el algoritmo de cifrado AES, pero existen multitud de estándares para el cifrado de la información. El cifrado AES es un esquema de cifrado por bloques en el que se utiliza una clave de 128,192 o 256 bits. Para saber más acerca de este tipo de cifrado:
http://es.wikipedia.org/wiki/Advanced_Encryption_Standard y
http://www.codeplanet.eu/files/flash/Rijndael_Animation_v4_eng.swf
Lo primero que se necesita para llevar a cabo el cifrado es una clave. En este caso la clave es de 128 bits, pero podría ser de 192 o 256 bits. Para generar la clave se hace uso de la clase keyGenerator.
private Cipher cifrado; // clase Cypher para cifrado/descifrado
private byte[] iv; // Vector de inicialización
private Cipher descifrado;
private ByteArrayOutputStream outputStream; //flujo de salida de datos encriptados/desencriptados
En el constructor de la clase:
KeyGenerator kgen; //clase Keygenerator para generar la clave
kgen = KeyGenerator.getInstance("AES"); //indicamos que se quiere utilizar AES
kgen.init(128); //se indica que se quieren utilizar 128 bits
SecretKey aesKey = kgen.generateKey(); //se genera la clave
Con esto ya se tiene creada nuestra clave, "aesKey". El siguiente paso es crear una clase Cipher para el cifrado y descifrado. Para el primer caso:
cifrado = Cipher.getInstance("AES/CBC/PKCS5Padding");
cifrado.init(Cipher.ENCRYPT_MODE, aesKey);
La primera línea indica que se quiere utilizar un cifrado AES en modo de cifrado de bloque (CBC) y puesto que es un cifrado de bloque, que se requiere de "padding" (relleno). La segunda linea indica que se quiere utilizar el modo de encriptación (cifrado) y se quiere utilizar la clave generada anteriormente.
Para descifrar podríamos utilizar la misma clase Cipher indicandole ahora que se quiere el modo descifrado, pero en este ejemplo se crea otra clase para verlo un poco más claro:
descifrado = Cipher.getInstance("AES/CBC/PKCS5Padding");
iv = cifrado.getIV();
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
descifrado.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
La diferencia ahora es que se utiliza un vector de bytes para el descifrado. Este vector iv es muy importante por motivos de seguridad, y su utilidad radica en que dada la misma clave y diferentes vectores de inicialización, el resultado es diferente. Más información aquí:
http://es.wikipedia.org/wiki/Vector_de_inicializaci%C3%B3n
Ahora que ya se tienen inicializadas las clases Cipher para cifrar y descifrar, se crean dos métodos para el cifrado y descifrado:
public byte[] cifrarMensaje(String mensaje){
String mensajeCifrado = null;
byte[] BytesEncriptados = null;
try {
outputStream = new ByteArrayOutputStream();
try (CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cifrado)) {
cipherOutputStream.write(mensaje.getBytes());
cipherOutputStream.flush();
}
BytesEncriptados = outputStream.toByteArray();
} catch (IOException ex) {
Logger.getLogger(ejemploCifrado.class.getName()).log(Level.SEVERE, null, ex);
}
return BytesEncriptados;
}
public String descifrarMensaje(byte[] mensaje){
outputStream = new ByteArrayOutputStream();
ByteArrayInputStream inStream = new ByteArrayInputStream(mensaje);
CipherInputStream cipherInputStream = new CipherInputStream(inStream, descifrado);
byte[] buf = new byte[1024];
int bytesRead;
try {
while ((bytesRead = cipherInputStream.read(buf)) >= 0) {
outputStream.write(buf, 0, bytesRead);
}
} catch (IOException ex) {
Logger.getLogger(ejemploCifrado.class.getName()).log(Level.SEVERE, null, ex);
}
return new String(outputStream.toByteArray());
}
La primera clase es la encargada del cifrado. Recibe el String a cifrar y devuelve un vector de bytes con el mensaje cifrado. Lo que se hace fundamentalmente es generar un ByteArrayInputStream que será el encargado de recibir los bytes encriptados y abrir un flujo de cifrado de bytes CipherOutputStream que se encargue de convertir el mensaje a bytes, cifrarlo y pasarselo al ByteArrayInputStream. Este último convierte el flujo de bytes obtenido a un vector de bytes.
La segunda hace el camino inverso: recibe un vector de bytes cifrado y devuelve el string descifrado.
IMPORTANTE: cada algoritmo de cifrado tiene sus propias características, por lo que si se cambia alguno de los parámetros es posible que no funcione. Es importante a la hora de añadir un tipo de cifrado especifico leer primero acerca de cómo funciona.
El código completo se encuentra aquí:
https://github.com/VicenteCantonPaterna/CifradoSimple
Está desarrollado en netbeans y por tanto habría que crear un proyecto para Android, pero se puede comprobar su funcionamiento fácilmente. El código no lo he implementado yo sino que estuve intentando montar este minitutorial y en una página encontré uno que no me daba demasiados errores:
http://stackoverflow.com/questions/15554296/simple-java-aes-encrypt-decrypt-example
En realidad lo único que hice fue comentarlo un poco para que se pudiera entender cómo funciona (más o menos).
Espero que os sirva de algo!