Cifrado Vigenère

El cifrado Vigenère es un cifrado basado en diferentes series de caracteres o letras del cifrado César formando estos caracteres una tabla, llamada tabla de Vigenère, que se usa como clave. El cifrado de Vigenère es un cifrado de sustitución simple polialfabético. – Wikipedia

¡Buenos días! Como habréis podido notar hoy vamos a hacer una implementación del cifrado de Vigenènere. Este cifrado polialfabético nos da un cifrado muy simple con el que intercambiar mensajes con nuestros amigos o proponerlo de reto a alguien en una carta. Además contiene la operación modulo que vimos en el anterior post.

Pero, ¿Qué quiere decir que es polialfabético? Quiere decir que para sustituir una letra por otra no solo se usa el alfabeto normal y un padding como en el cifrado cesar, sino que el alfabeto va cambiando según un criterio. En concreto nosotros tendremos 26 alfabetos. Por tanto lo primero será declarar un mapa que nos guarde esta relación de alfabeto-letraclave.

private final static Map<Character, List<Character>> _alfabeto = new TreeMap<>();

¿Y por qué un mapa de carácteres a lista de carácteres? En el cifrado Vigenère ciframos según una clave dada. Por ejemplo : ROSA. Para cada letra de nuestro texto en claro tomaremos una letra(iterativamente) de la clave y la sustituiremos con la que le corresponda en la lista de carácteres. La posición a sustituir es donde iría normalmente esa letra. Si tenemos una E (la quinta del abecedario), para la letra R de nuestra clave miraremos la quinta posición, que es la V. Por tanto la E se cifra con la V. Para la siguiente letra no usaremos la R sino la siguiente, la O, luego la S, luego la A, luego la R… y así con todo el texto con lo que obtenemos protección contra una análisis de frecuencia. Además, si la clave es igual de largo que el texto obtenemos cifrado de secreto perfecto.

¿Cuál es entonces la función que nos genera este mapa?

	static
	{
		List<Character> list;
		
		for (int i = 65, j = 0; i < 91; ++i, ++j){	
			list = new ArrayList<Character>();
			
			// Siempre de 0 a 26 + un padding j
			// Si nos pasamos de 26 al sumar el padding entonces volvemos al 0
			// Y a eso le sumamos 65, que es la letra 'A'
			// Por tanto siempre iremos de A hasta Z
			for(int x = 0; x < 26; ++x)
				list.add((char)(((x + j) % 26) + 65));
			
			_alfabeto.put((char) (i), list);
		}
	}

Como véis nos movemos de la A a la Z(sin la Ñ) generando una lista que empieza por la propia letra y ,de manera circular, va añadiendo una a una las subsiguientes a la lista. Seguro que muchos ya sabéis cómo se consigue moverse de manera circular,¿Verdad? Es justo esta linea:

list.add((char)(((x + j) % 26) + 65));

Aquí tenéis el resultado:

Key: A
[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]

Key: B
[B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A]

Key: C
[C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B]

Key: D
[D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C]

Key: E
[E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D]

Key: F
[F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E]

Key: G
[G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F]

Key: H
[H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G]

Key: I
[I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H]

Key: J
[J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I]

Key: K
[K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J]

Key: L
[L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K]

Key: M
[M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L]

Key: N
[N, O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M]

Key: O
[O, P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N]

Key: P
[P, Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O]

Key: Q
[Q, R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P]

Key: R
[R, S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q]

Key: S
[S, T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R]

Key: T
[T, U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S]

Key: U
[U, V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T]

Key: V
[V, W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U]

Key: W
[W, X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V]

Key: X
[X, Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W]

Key: Y
[Y, Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X]

Key: Z
[Z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y]

¡Ahora ya podemos empezar a codificar nuestros mensajes!

	public static String codificar(String texto, String clave)
	{
		texto = texto.replaceAll("(\\r|\\n| )", "").toUpperCase();
		clave = clave.replaceAll("(\\r|\\n| )", "").toUpperCase();
		
		StringBuilder sb = new StringBuilder();
		int diff;
		List<Character> list;
	
		char[] keys = clave.toCharArray();
		char[] txt = texto.toCharArray();
		
		for(int i = 0, j = 0; i < txt.length; ++i, j = (j+1) % keys.length)
		{
			diff = txt[i] - 65;
			list = _alfabeto.get(keys[j]);
			sb.append(list.get(diff));
		}
		
		return sb.toString();
	}

Las dos primeras lineas quitan los espacios y saltos de linea del texto en claro y de nuestra clave, ya que no estan contempladas en nuestro mapa.
Quizás lo más destacable de este simple código es esta línea:

j = (j+1) % keys.length

¡Pero esto no es más que un movimiento circular por la clave! Y a lo mejor alguien se pregunta por qué restamos 65 a la letra. ¡Simplemente para tener una relación de 0 a 26(Siendo 0 la A)! Mucho más cómodo de trabajar, ¿No?

¿Y para descifrar nuestros mensajes? No mucho más difícil que sumar 65 en vez de restar:

	public static String decodificar(String texto, String clave)
	{
		texto = texto.replaceAll("(\\r|\\n| )", "").toUpperCase();
		clave = clave.replaceAll("(\\r|\\n| )", "").toUpperCase();
		
		StringBuilder sb = new StringBuilder();
		List<Character> list;
	
		char[] keys = clave.toCharArray();
		char[] txt = texto.toCharArray();
		
		int aux;
		
		for(int i = 0, j = 0; i < txt.length; ++i, j = (j+1) % keys.length)
		{
			list = _alfabeto.get(keys[j]);
			
			aux = list.indexOf(txt[i]);
			sb.append((char)(65 + aux));
		}
		
		return sb.toString();
	}

Como resultado final tenemos:

Clave : ROSA
Texto en claro: El enemigo atacara al anochecer

Cifrado: VZWNVAAGFOLATOJARZSNFQZETSJ
Descifrado: ELENEMIGOATACARAALANOCHECER

Pues fijaós si es simple este cifrado que ya hemos acabado. Seguro que algunos queréis sacar algo más a este cifrado, como el uso de minusculas, tildes, etc… No es mucho más difícil y esta resuelto en dropbox junto a este ejercicio.

Un saludo.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s