Otra vez ando trasteando con los cuadernos de un solo uso.
Bueno, me he estado estrujando un poco el limón y repasando con interés en mi manual de cifrado los distintos algoritmos que había hace unos años. He tenido un par de ideas al respecto, pero francamente nada innovador, de forma que seguiré dándole vueltas.
Escribo esto, porque de alguna manera quiero implicar en el problema el proceso de generar cuadenos otp que ya os había presentado, ahora en una versión más avanzada. Lo usaría como punto de partida para lo que se me ocurra en el futuro, pero de momento le he incorporado una funcionalidad interesante y... que cifra un poquito!!! Al pie os pongo el link para descargarlo si os interesa...
El algoritmo trata de codificar un texto de hasta 100 caracteres dentro de un otp ya generado; va buscando dentro del otp de forma secuencial cada uno de los caracteres del texto-claro, y donde encuentra uno, pone una almoadilla "#" en la misma posición del cuaderno codificado y continúa el proceso del texto-claro en esa posición del otp. Si el caracter no coincide con el del texto-claro pone un espacio; así con todos los caracteres hasta terminarlos. Al final tenemos un cuaderno codificado con una almoadilla "#" en la posición donde estaba el primer carácter coincidente con el del texto-claro que se estaba procesando en ese momento.
Para decodificar va leyendo caracteres del otp y del cuaderno codificado, en paralelo. En el momento en que encuentra una almohadilla en el codificado, coge el correspondiente del otp y lo añade al texto-claro, y así hasta que se termina el cuaderno codificado.
Hasta aquí nada interesante; sólo la funcionalidad de generar otp's y poder codificarlos y descodificarlos, de forma automática, aunque ya es algo.
He pensado en darle una pincelada criptográfica incluyendo un parámetro de desplazamiento que permite indicar en qué posición del otp queremos que se inicie el proceso de codificar un texto, ya que como el proceso siempre se inicia en el primer carácter del cuaderno codificado, y al estar el texto-claro limitado a 100 símbolos, las marcas siempre tienden a estar al principio del cuaderno.
Aun así sería fácil de decodificar, pues las marcas de perforación saldrían alineadas verticalmente con el otp y bastaría desplazarlas en bloque hacia abajo para encontrar un texto congruente.
Por ese motivo el algoritmo "trima" el cuaderno codificado eliminando espacios en blanco iniciales y finales, de forma que ahora las marcas se sitúan al principio del cuaderno codificado, pero ya no están alineadas ni vertical ni horizontalmente. Luego el algoritmo
calcula y nos presenta el nuevo parámetro de desplazamiento que se obtiene tras el trimado y se necesita para situar de nuevo las marcas en su lugar.
De no tener dicho parámetro, no queda más recurso que la fuerza bruta, es decir ir desplazando la estructura de marcas sobre el otp y anotando, hasta encontrar algo congruente. Es un cifrado sin fuerza alguna, pero complicará un poco las cosas a un eventual vulnerador que tuviese tanto el otp como el mensaje codificado; además, dependiendo de la longitud, se pueden obtener varios mensajes en claro como probables.
Éste sería un punto de partida para un nuevo algoritmo aún sin definir, pero me gustaría saber vuestras opiniones, y qué otros enfoques le podría dar, pues como dije en un post anterior, lo que no quiero es idear la enésima máquina de cifrar con rodillos.
De paso pondréis a prueba la potencia de vuestro PC, pues si lleváis al máximo los punteros del generador veréis cómo se va ralentizando, ya que estará generando 22500 números pseudoaleatorios no determinísticos de 64 bits en cada ciclo (en mi PC más o menos un ciclo por segundo). En realidad he tenido que limitar los punteros verticales a 10, pues llegaba a bloquearse el hilo de proceso.
Aqui está. En windows basta pulsar para ejecutarlo. En Linux abrir una terminal y ejecutarlo con java -jar otp.jar:
Aqui la clase java que realiza los procesos indicados
ElCojo30 Julio 2011 - 7:36pm
/** * @author OpenYourMindSoftware at gmail.com */ class OtpProcesador { private static final String nlChar = System.getProperty("line.separator"); private String cuadOtp = ""; private String cuadPer = ""; private String cuadMsg = ""; private int cuaOffset = 0; // /** * Constructor del cuaderno para su proceso * @param Otp de claves */ OtpProcesador(String cuad) { cuadOtp = cuad; cuadPer = ""; cuadMsg = ""; cuaOffset = 0; }// // /** * * @return offset de este cuaderno */ public int getOffset() { return this.cuaOffset; }// // /** * @param mensaje claro * @param offset * @return Otp codificado */ public String codificar(String msgClaro, int offset) { String cuaCodif = ""; String strTmp = ""; msgClaro = msgClaro.toUpperCase(); int cuaLen = cuadOtp.length(); int msgLen = msgClaro.length(); int cuaPos = 0; int msgPos = 0; char msgChr = 0; char cuaChr = 0; char cuaSpc = 32; // Caracter espacio char cuaPer = 35; // Caracter perforacion // Sustituir caracteres no validos del mensaje claro (ascii 36 a 95) while (msgPos < msgLen) { msgChr = msgClaro.charAt(msgPos); if (msgChr < 36 || msgChr > 95) { strTmp = strTmp + cuaSpc; } else { strTmp = strTmp + msgChr; } msgPos++; } msgClaro = strTmp; strTmp = ""; msgPos = 0; msgChr = 0; // Aplicar offset si lo hay while (cuaPos < offset) { cuaChr = cuadOtp.charAt(cuaPos); // Comprobar si el caracter correspondiente del otp es de control if (cuaChr > 31) { // Si no lo es ponemos un espacio cuaCodif = cuaCodif + cuaSpc; } else { // Si lo es ponemos el de control cuaCodif = cuaCodif + cuaChr; } cuaPos++; } // Bucle para codificar mensaje while (msgPos < msgLen && cuaPos < cuaLen) { msgChr = msgClaro.charAt(msgPos); cuaChr = cuadOtp.charAt(cuaPos); // Comprobar si el caracter del mensaje coincide con el del otp if (msgChr == cuaChr) { // Si no es espacio ponemos una perforacion if (msgChr != cuaSpc) { cuaCodif = cuaCodif + cuaPer; } else { // Si es un espacio ponemos el espacio cuaCodif = cuaCodif + cuaSpc; } msgPos++; } else { // El caracter del mensaje no coincide con el del otp // Si no es un caracter de control ponemos un espacio if (cuaChr > 31) { cuaCodif = cuaCodif + cuaSpc; } else { // Si es un caracter de control lo ponemos cuaCodif = cuaCodif + cuaChr; } } cuaPos++; } // Guardar posicion primera perforacion cuaOffset = cuaCodif.indexOf(cuaPer); // Comprobar si el mensaje se ha codificado completamente if (msgPos < msgLen) { cuaCodif = cuaCodif + "!!! INCOMPLETO MSG > OTP !!!"; } else { // Si hay offset trimar el cuaderno codificado = cifrado if (offset > 0) { strTmp = cuaCodif.trim(); cuaCodif = strTmp; strTmp = ""; } } // Retornar cuaderno codificado return cuaCodif; }// // /** * @param mensaje codificado * @param offset * @return mensaje Decodificado */ public String decodificar(String msgCodif, int offset) { String msgClaro = ""; String msgTmp = ""; int cuaLen = cuadOtp.length(); int msgLen = msgCodif.length(); int cuaPos = 0; int msgPos = 0; char msgChr = 0; char cuaChr = 0; char cuaSpc = 32; // Caractere espacio char cuaPer = 35; // Caracter perforacion // Aplicar offset si lo hay saltandonos esos caracteres while (cuaPos < offset) { cuaPos++; } // Decodificar mensaje while (cuaPos < cuaLen) { // Coger el caracter correspondiente del otp cuaChr = cuadOtp.charAt(cuaPos); // Comprobar si el caracter a decodificar esta en el rango del // cuaderno codificado if (msgPos < msgLen) { // Si lo esta lo cogemos msgChr = msgCodif.charAt(msgPos); } else { // Si no lo esta cogemos un espacio msgChr = cuaSpc; } // Comprobar si hemos encontrado una perforacion en el cuaderno codificado if (msgChr == cuaPer) { // En tal caso ya tenemos el caracter decodificado y lo añadimos // al final del mensaje claro msgClaro = msgClaro + cuaChr; } // Incrementar punteros cuaPos++; msgPos++; } return msgClaro; }// }