¡Están en juego 10.000 puntos para el ganador!
Mi primera intervención va a ser para presentaros un algoritmo de cifrado que utilizo desde hace tiempo: TFTR. Las iniciales evocan a los tokamaks, ya sabéis: esas máquinas toroidales, donde se intenta confinar la fusión nuclear, transmutando el hidrógeno en helio; y ya se sabe que cifrar va de cambiar ciertas cosas por otras, a ser posible con algo circular implicado en ello.
Después de esto parece que este cifrado será algo muy complejo, pero no, al contrario: es sencillísimo, es un cifrado simétrico que usa una clave nemotécnica y creo que es bastante seguro: a ver qué opináis...
Normalmente utilizo la tabla ASCII, pero en este ejemplo utilizaré un alfabeto reducido, de 32 símbolos; así con 5 bits me funciona el operador XOR de VB.
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 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 _ . @ * ,
Por ejemplo, utlizamos la clave SANCHO para cifrar el primer párrafo del Quijote:
EN_UN_LUGAR_DE_LA_MANCHA,_DE_CUYO_NOMBRE_NO_QUIERO_ACORDARME,_NO_HA_MUCHO_TIEMPO_QUE_VIVIA_UN_HIDALGO_DE_LOS_DE_LANZA_EN_ASTILLERO,_ADARGA_ANTIGUA,_ROCIN_FLACO_Y_GALGO_CORREDOR.
Lo primero que hacemos es sumar los valores de los caracteres de la clave:
S A N C H O 19 + 0 + 13 + 2 + 7 + 15 = 56
Ahora sumamos los dígitos del resultado:
5 + 6 = 11
multiplicamos este resultado por el anterior:
56 * 11 = 616
Ahora obtenemos el módulo con la longitud del mensaje:
616 mod 177 = 85
Estas operaciones las realizamos para obtener la posición del caracter que vamos a cifrar; en este caso hemos obtenido la posición 85, que está ocupada por la letra V en el mensaje.
A continuación hacemos un XOR entre el valor del primer carácter de la clave (S) y V:
19 XOR 22 = 5
5 es el valor del carácter F que pasará a ocupar la posición 85 del texto cifrado.
Además, la primera posición de la clave se cambia por V: VANCHO
Proseguimos con esta lógica y recalculamos el valor de la clave:
22+0+13+27+15=59; 5+9=14; 59*14=826;826 mod 177=118
La posición 118 está ocupada por la E. Haciendo un XOR con la segunda posición de la clave tenemos:
0 XOR 4 = 4
En el caso de que la posición obtenida pertenezca a un carácter ya cifrado, buscaremos por la derecha la primera posición pendiente. Si nos "salimos" del mensaje, como siempre comenzaremos por el principio.
La posición 118 del texto cifrado será una E; además cambiaremos la segunda posición de la clave: VENCHO.
Una vez que lleguemos al final de la clave daremos la vuelta, utilizando la primera posición. De esta forma la clave varía continuamente durante el cifrado, utilizando los caracteres del texto en claro, tomados de una forma no consecutiva, por lo que (en mi inocencia) me parece un cifrado muy seguro; quizá entonces vosotros podáis sacarme de mi error. Además no es muy difícil de aplicar manualmente, con lápiz y papel.
El texto cifrado es:
,XJRLV*ZCUHVIEA@_ABLVEFA.TÑTAYÑTTTB.BZ@V_FOJ**L,YTAMSA*DUÑEBACCJXHL.*QV.OTTAADTNA@HLCFSNIN.QJAXDFQIJDPQQ_IHWSHMAJGÑBAJEOJ_SPLLTG,_PVAQI,@E.EGÑKAQU,PJZCI*JEE_VTTCY@EDETTYAEJ_XMRQ
Añado un módulo de visual basic, donde está implementado este algoritmo; como véis no es un proceloso programa de páginas y páginas, es bastante sencillo.
Bueno, ya me diréis...
Function cifrar(clave_i, entrada_i, cifrar_descifrar)
Dim mensaje() As String
Dim clave() As String
longitud = Len(entrada_i)
lclave = Len(clave_i)
ReDim mensaje(longitud)
ReDim clave(lclave)
For i = 1 To longitud
mensaje(i - 1) = Mid$(entrada_i, i, 1)
Next i
For i = 1 To lclave
clave(i - 1) = Mid$(clave_i, i, 1)
Next i
cifrado = String(longitud, "-")
ya_ocupada = String(longitud, "-")
posicion_clave = -1
For t = 1 To longitud
posicion_clave = posicion_clave + 1
posicion_clave = posicion_clave Mod lclave
x = sumar_clave(clave(), longitud)
Do
ya_cifrado = Mid$(ya_ocupada, x + 1, 1)
If ya_cifrado = "*" Then
x = x + 1
x = x Mod longitud
End If
Loop Until ya_cifrado <> "*"
letra = mensaje(x)
Mid$(ya_ocupada, x + 1, 1) = "*"
y = inv_caracter(clave(posicion_clave)) Xor inv_caracter(letra)
Mid$(cifrado, x + 1, 1) = caracter(y)
If cifrar_descifrar = "C" Then
clave(posicion_clave) = letra
Else
clave(posicion_clave) = caracter(y)
End If
Next t
cifrar = cifrado
End Function
Function sumar_clave(clave() As String, longitud)
total = 0
For i = 0 To UBound(clave) - 1
a = clave(i)
x = inv_caracter(a)
total = total + x
Next i
cadena = Format$(total, "000000")
resuma = 0
For i = 1 To Len(cadena)
resuma = resuma + CDbl(Mid$(cadena, i, 1))
Next i
total = total * resuma
total = total Mod longitud
sumar_clave = total
End Function
Function caracter(numero)
caracteres = Array("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", "_", ".", "@", "*", ",")
caracter = caracteres(numero)
End Function
Function inv_caracter(caracter)
caracteres = Array("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", "_", ".", "@", "*", ",")
For i = 0 To 31
If caracteres(i) = caracter Then inv_caracter = i: Exit Function
Next i
End Function
Tengo un ataque pero no acabo de obtener resultados
LlamameX13 Septiembre 2011 - 4:27pm
Tftr no es invulnerable. Tiene una debilidad de base y es por ahí por donde le estoy royendo las patas, a ver si cae.
El problema que tiene es la suma de las posiciones de las letras de la clave. Dicho valor, aparte de ser pequeño (23*31=713 en el caso del reto), al tratarse de sumas de variables discretas (con las probabilidades de La regenta) sigue una distribución normal, con lo que en un rango de sólo (de nuevo con los 23 carácteres de la clave del reto) unos 220 valores alrededor del 356 (si no he calculado mal) se dan el 90% de los casos. Eso permite suponer que la suma de la clave inicial ha de andar por ahí, con lo que tenemos sólo que probar esos valores. Llamemos a esa suma Si; 246 < i < 466.
A partir de ahí podemos empezar a suponer los primeros carácteres de la clave. Imaginemos que empieza por K0 y decodificamos A0 en la posición Pi (calculada como producto de Si por la suma de sus dígitos módulo 512) como A0 = K0 XOR C[Pi]. A continuación calculamos la nueva Sj para la posición de K1 como Sj = Si - K0 + A0 (sustituimos K0 por A0) y lanzamos una hipótesis para K1. Seguimos con las sucesivas Ki.
Lo que necesitamos ahora es un test para saber si vamos bien con las hipótesis de las Ki. Yo estoy usando los valores de aparición en la Regenta, asumiendo que los caracteres decodificados deben seguirla también. Hasta ahora uso series muy cortas 5-6 carácteres y busco el descarte. Cogiendo los 12 primeros en frecuencia suman un 80% del total, con lo que la probabilidad de que en 5 caráctares haya 3 o más de ellos és de un 92%.
El problema es el altísimo número de falsos positivos que obtengo que me está impidiendo aún avanzar. Cada nuevo dígito es un nuevo factor 32 y necesito recortar más. Ahí se apreciarían colaboraciones.
Bien
tokamak13 Septiembre 2011 - 5:07pm
Miu bien, ¿has hecho algún test con un texto cifrado una una clave conocida?. Si existe alguna convergencia hacia la solución, a medida que se completa la clave, tal vez puedas probar con un AG. Eso si: yo no te lo voy a hacer, jejeje. Por cierto voy a probarlo.
Creo que no converge
LlamameX13 Septiembre 2011 - 6:11pm
Pensaba que podría hacerlo e irse refinando de bloque en bloque, pero en las pruebas que he hecho pequeñas variaciones al inicio desencadenan cambios muy grandes.
En referencia al algoritmo
ElCojo25 Julio 2011 - 1:36pm
En referencia al algoritmo, si lo he pillado bien, es indiferente que al terminar la clave empieces por el principio ya que es un caracter diferente sacado del mensaje, corrigeme si me equivoco, la clave a efectos practicos se va alargando por la derecha y al final tienes una clave igual de larga que el mensaje. Si estoy en lo cierto el espacio de la clave igual que el del mensaje y no se puede determinar la interaccion de esta en el texto. Voy bien?
Tanbien deduzco que cuanto mas % de texto cifrado llevas, inevitablemente mas caracteres cifrados te encuentras, y logicamente busca en posiciones vacias probablemente consecutivas mas veces cuanto mas al final esta. Eso pienso que puede tener que ver con los caracteres repetidos que comentaba sqrmatrix. Estoy en lo cierto?
No pretendo descifrar el reto (no me alcanzan las neuronas) solo tomarle el pulso al algoritmo y si sale algun bug que puedas corregirlo.
Y ahora que lo pienso
ElCojo25 Julio 2011 - 3:31pm
Cuando se encuentra un caracter ya cifrado, entiendo que empieza la busqueda de izda. a dcha. hasta encontrar uno pendiente de cifrar. Creo que obtendrias mejor dispersion del texto si lo hicieras de forma dicotomica, y, de paso mejorarias el tiempo de cifrado. Pero no he comprobado si seria reversible, lo has probado?
Dispersión
tokamak25 Julio 2011 - 10:30pm
Hola: sí. La dispersión es algo a mejorar, tengo casi a punto una versión 2.0 del algoritmo que resulta aún más simple que ésta (para mi cuanto más sencillo es el algoritmo, tanto más bello, si va acompañado de eficiencia claro) y que se basa en ordenaciones sucesivas, y sin utilizar bloques, para conseguir una gran dispersión de los caracteres cifrados, pero esa será otra historia...
Clave a partir del texto
tokamak12 Julio 2011 - 11:03am
Está bien, quizá se pueda combinar con una búsqueda de texto supuesto, aunque no sé como, pues ese texto tendría que ser tan largo como uno de los bloques...
Creo que seria suficiente con la longitud de la clave
LlamameX27 Julio 2011 - 9:39am
Puesto que a partir de ahi puede la nueva clave ya se habrá cargado con el resultado de la decodificación y podrá comprobarse si sigue generando texto válido.
Aún así sigue siendo un trabajo ingente.
Obtener la clave a partir del texto y el criptograma
sqrmatrix11 Julio 2011 - 9:04pm
Aquí voy a explicar cómo obtener la clave de un criptograma teniendo el texto claro.
Vamos a suponer que conocemos la suma de los caracteres de la clave. Utilizando el ejemplo de La Regenta que nos dejó tokamak, tenemos la clave "MAGISTRAL", cuya suma de caracteres es 94.
El proceso para extraer la clave es simple. Calculamos la posición donde se encriptaría/descriptaría la letra. En este caso, calculamos 94*(9+4)=1222, que módulo 512 queda 198. Leemos en estas posiciones la letra tanto del texto como la del criptograma. En este caso, la letra del texto es T="E", y la del criptograma es C="I". Tenemos que calcular la letra de la clave, K. Como en la encriptación se hizo C=T xor K, ahora tendremos que hacer K=C xor T. En este caso, K="E" xor "I", que es K=5 xor 9=12="M".
Así, tenemos que la primera letra de la clave es "M"=12. Tenemos que seguir, porque la suma de las letras de la clave no es aún 94.
Para obtener la siguiente letra de la clave, lo que hacíamos al encriptar/descriptar era sustituir la letra que utilizamos en la encriptación anterior por la letra del texto en la posición en la que encriptamos, y luego calcular la siguiente posición.
Todavía no tenemos la clave, pero eso no es problema. Como la posición la vamos a calcular a partir de la suma de las letras de la clave, esta operación de sustitución puede hacerse con el valor que tenemos de la clave, que en este momento es 94. La sustitución de la letra de la clave por la letra del texto consiste en retirar la letra de la clave en cuestión (en este caso la "M" que acabamos de calcular) y añadir la letra del texto, que en este caso es la "E". Esto es equivalente a restar al valor de la clave el valor de la letra de la clave que acabamos de calcular ("M"=12) y sumarle el valor de la letra del texto ("E"=5). Nos queda, pues, como nuevo valor de la suma de caracteres de la clave: 94-12+5=87.
Repetimos el proceso, pero ahora utilizando el valor 87. En cada paso vamos obteniendo una nueva letra de la clave.
La finalización de este proceso se producirá cuando la suma de las letras de la clave sea mayor al valor de partida, en este caso 94. No salimos si es igual por una excepción que paso a explicar enseguida. Si esta suma fuera mayor, entonces no hemos encontrado la clave, y la suma de caracteres de la clave dada al comienzo es errónea.
En caso de que la suma de caracteres de la clave calculada coincida con la suma dada al comienzo, no podemos afirmar que hayamos encontrado la clave. Para saber que hemos encontrado la clave basta con descifrar el criptograma con dicha clave, y ver si lo que obtenemos es idéntico al texto en claro. Si lo es, hemos encontrado la clave y podemos finalizar el procedimiento.
La excepción a la que hice referencia antes es que puede que la clave termine en "A", o en varias "A". En este caso, el valor que se añade al valor de la suma de caracteres de la clave es nulo. El problema está en que si la clave termina en "A", la suma de estos caracteres ya coincide con el de partida antes de leer esta "A", pero la clave no está calculada aún. Esto se resuelve fácilmente. Basta con comprobar, en el proceso anterior, si la suma de caracteres de la clave calculada coincide con el de partida. Si es así, comprobamos si la clave es la correcta (descriptando y comparando con el texto original). Si no es así, repetimos el proceso de lectura explicado antes. En caso de que en esa lectura no leamos otra "A", el proceso finalizará (con error) porque se sumará un valor no nulo a la suma de caracteres, quedando entonces una suma de caracteres superior a la dada al comienzo. Si se leyera "A", este proceso se repetirá de nuevo, y así hasta que obtengamos la clave correcta, o hasta que la suma de caracteres supere al dado al comienzo.
En todo caso, siempre que añadimos un carácter distinto de "A", sumamos un valor a la suma de caracteres de la clave calculada, lo que nos garantiza que siempre alcanzaremos el valor del comienzo, y lo superaremos en caso de error. Y en el caso de que se añadan letras "A", estas letras no suman nada a la suma de caracteres de la clave, pero estas letras pertenecen al texto, por lo que tarde o temprano se recibirá un carácter distinto (salvo que el texto sea todo "A"), que se sumará, por lo que también tenemos garantizado en este caso la finalización del proceso.
Este es el procedimiento conociendo la suma de caracteres de la clave. Si no conocemos este dato, basta realizar este proceso indicando los valores 0, 1, 2, ..., hasta encontrar la clave, o hasta superar un valor razonable. El procedimiento es rápido, y los valores que hay que probar son relativamente pocos (para una clave de 100 caracteres, habrá que probar sólo hasta 32*100=3200).
He aplicado este procedimiento al ejemplo de La Regenta, y la clave se obtiene en menos de 1 segundo, probando todos los valores del 0 al 100, en lenguaje Java.
Esto sólo será útil si alguien logra determinar el texto que generó el criptograma, sin la clave. Pero de todas formas, y como suelo decir, quizá esto dé alguna idea a alguien para atacar a este engendro.
Podríamos tener algo de texto claro
LlamameX14 Julio 2011 - 9:37pm
Si es como en Torner, la versión reducida de éste, el último bloque se habrá completado hasta los 512 con carácteres de relleno, concretamente en los ejemplos anteriores se usaba el ".".
No es mucho pero igual puede ser el hilo que desenreda el ovillo.
Relleno
tokamak15 Julio 2011 - 8:40am
Bueno, pues ors doy otra pista: esta vez no hay rellenos, así podéis centrar más el tiro, en vez de iros por als ramas...
Un pequeño intento fallido
sqrmatrix4 Julio 2011 - 1:31am
Lo que he visto en este cifrario es que es equivalente a un cifrario XOR con la clave tan larga como el criptograma, y que dicha clave tiene alguna que otra racha de caracteres iguales, de corta longitud. Llamaré a esta clave "clave equivalente XOR". Para el ejemplo de La Regenta, he encontrado una única racha de 6 caracteres "_" (los espacios, los más frecuentes) en la posición 1094, una única racha de 5 caracteres "_" en la posición 2492, y varias rachas de 4 ó menos caracteres. Con mucha suerte, una de estas rachas será suficientemente larga y coincidirá en la posición de una palabra clave que nos dé una pista sobre el texto encriptado. Para obtener esta palabra, bastará descriptar el criptograma con el algoritmo XOR, y como clave una letra del alfabeto, y buscar en el resultado devuelto alguna palabra o porción de palabra con sentido. Las rachas cuyo carácter coincida con el de la clave empleada serán descriptadas correctamente, y serán las que hay que buscar. El problema es que normalmente la longitud de estas rachas será insuficiente, que contendrán normalmente el final de una palabra y el comienzo de otra, separadas por un espacio, y que la palabra encontrada (si tenemos la suerte de que esté dentro de la racha) no dará ninguna pista del mensaje original.
Ya he probado con el reto utilizando como clave "_", pero no he encontrado nada significativo, aunque se me puede haber pasado. Lo he hecho a mano, porque la automatización de búsqueda de palabras la tengo pendiente, y por eso se me podría haber pasado (de todas formas, las palabras que pueden dar pistas del contenido del texto suelen ser nombres propios, que no aparecen en diccionarios, por lo que la automatización se complica).
Parece que estas rachas son más largas para los caracteres más frecuentes. También es fácil encontrar, en la clave equivalente XOR, secuencias de vocales diferentes. Todo esto lo he hecho con el ejemplo de La Regenta, y puede que en otros casos no se cumpla.
Mezclando retos
AgustínB3 Julio 2011 - 1:19pm
Mira que soy burro!
Igual sonaba la flauta y deducía la clave, pero me parece que va a ser que no.
El ataque de fuerza bruta por diccionario creo que lo descarto. Me puse a leer varias cosas a la vez, e interpreté que podía usar una clave aproximada pero de la misma longitud y que podría salir parte del texto.
Pero eso es Lapyznos.
Pues yo no descarto un ataque de diccionario (o casi)
LlamameX3 Julio 2011 - 8:34pm
Pero no contra la clave sinó contra el texto cifrado. Estoy estudiando una vía para el ataque contra el segundo bloque, más que nada para mirar de reducir el número de posiciones a probar.
La idea base es la de suponer una clave con una distribución de carácteres tipo regenta como resultado del cifrado del primer bloque, puesto que estará enteramente compuesta por letras del texto en claro. Eso nos da una serie de posiciones probables para los primeros carácteres del segundo bloque.
Elegimos un número determinado de dichas posiciones como las candidatas a primera hasta una alcanzar una probabilidad razonable (pongamos un 70%) y a partir de ellas probamos diferentes sustituciones de los carácteres de la clave profundizando mientras encontremos una compatibilidad de diccionario. Esta compatibilidad podemos obtenerla de tablas de digramas o trigramas (o se elabora por ejemplo con La Regenta).
Será muy pesado y si no se profundiza mucho obtendremos muchos falsos positivos, pero es de momento la única vía que se me ocurre.
El código por bloques
AgustínB3 Julio 2011 - 12:45pm
Por si a alguien le interesa ponerlo en una hoja de cálculo, adjunto el código a ver si admin lo pone bonito. No recuerdo el tag que había que poner pero como requiere aprobación ;-)
Creo que no hay fallos, lo he probado con La Regenta y si no me he confundido creo que cifra y descifra correctamente.
Por cierto, no es ni
ELECTROENCEFALOGRAFISTA, ni
ELECTRO-ENCEFALOGRAFICO, ni tampoco
NEMETON_CALLAECIA_RISIT
CALLAECIA_RISIT_NEMETON
NEMETON@CALLAECIA_RISIT
TOKAMAK@CALLAECIA_RISIT
TOKAMAK_CALLAECIA_RISIT
que casualmente son de longitud 23
Bueno, el código
Const intTam_Blo As Integer = 512 Function cifrar(clave_i, entrada_i, cifrar_descifrar) Dim strBloque_Cif, strBloqueACifrar, strUltima_Clave As String Dim intB As Integer intB = 0 strBloqueACifrar = Mid(entrada_i, (intTam_Blo * intB) + 1, intTam_Blo) cifrar = "" strUltima_Clave = clave_i Do clave_i = strUltima_Clave strBloque_Cif = cifrarbloque(clave_i, strBloqueACifrar, cifrar_descifrar, strUltima_Clave) cifrar = cifrar + strBloque_Cif intB = intB + 1 strBloqueACifrar = Mid(entrada_i, (intTam_Blo * intB) + 1, intTam_Blo) Loop Until strBloqueACifrar = "" End Function Function cifrarbloque(clave_i, entrada_i, cifrar_descifrar, ultima_clave) Dim mensaje() As String Dim clave() As String longitud = Len(entrada_i) lclave = Len(clave_i) ReDim mensaje(longitud) ReDim clave(lclave) For i = 1 To longitud mensaje(i - 1) = Mid$(entrada_i, i, 1) Next i For i = 1 To lclave clave(i - 1) = Mid$(clave_i, i, 1) Next i cifrado = String(longitud, "-") ya_ocupada = String(longitud, "-") posicion_clave = -1 For t = 1 To longitud posicion_clave = posicion_clave + 1 posicion_clave = posicion_clave Mod lclave x = sumar_clave(clave(), longitud) Do ya_cifrado = Mid$(ya_ocupada, x + 1, 1) If ya_cifrado = "*" Then x = x + 1 x = x Mod longitud End If Loop Until ya_cifrado <> "*" letra = mensaje(x) Mid$(ya_ocupada, x + 1, 1) = "*" y = inv_caracter(clave(posicion_clave)) Xor inv_caracter(letra) Mid$(cifrado, x + 1, 1) = caracter(y) If cifrar_descifrar = "C" Then clave(posicion_clave) = letra Else clave(posicion_clave) = caracter(y) End If Next t cifrarbloque = cifrado ultima_clave = "" For i = 1 To lclave ultima_clave = ultima_clave & clave(i - 1) Next i End Function Function sumar_clave(clave() As String, longitud) Total = 0 For i = 0 To UBound(clave) - 1 a = clave(i) x = inv_caracter(a) Total = Total + x Next i cadena = Format$(Total, "000000") resuma = 0 For i = 1 To Len(cadena) resuma = resuma + CDbl(Mid$(cadena, i, 1)) Next i Total = Total * resuma Total = Total Mod longitud sumar_clave = Total End Function Function caracter(numero) caracteres = Array("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", "_", ".", "@", "*", ",") caracter = caracteres(numero) End Function Function inv_caracter(caracter) caracteres = Array("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", "_", ".", "@", "*", ",") For i = 0 To 31 If caracteres(i) = caracter Then inv_caracter = i: Exit Function Next i End FunctionCódigo
tokamak4 Julio 2011 - 9:59am
Hola Agustín: ya había puesto el 15 de mayo como reformar el programa para operar con bloques, pero el que tú has puesto aquí funciona perfectamente: con la clave correcta descifra el reto con pelos y señales ;)
Otra cosa: no perdáis el tiempo en ataques con diccionario a la clave, aunque no sea necesariamente aleatoria, nunca la encontraréis así.
Un primer vistazo
sqrmatrix2 Julio 2011 - 7:22pm
Lo que voy a explicar no es gran cosa, y puede que no ayude al reto, pero por algo se empieza.
Puesto que la posición del carácter a cifrar viene dado por el valor de la suma de las letras de la clave multiplicado por la suma de los dígitos de dicho valor, se me ocurrió ver si había, dentro del bloque a codificar, posiciones inalcanzables, es decir, posiciones que nunca serían resultado de la operación anterior. Y resultó que así es. Para un bloque de 512 caracteres, y una clave de 23 letras, hay 166 posiciones que no serán alcanzadas por el cálculo anterior. Esto significa que los caracteres codificados en estas posiciones son caracteres que se iban a codificar en posiciones ocupadas y que han tenido que desplazarse a la derecha. Y esto es válido para todo el proceso de encriptación de cada bloque.
El listado de estas posiciones es muy largo para ponerlo aquí, así que adjunto enlaces que permitirán descargarlos:
Resultados bloque 512.txt
Resultados bloque 356.txt
El primero es para bloques de 512 caracteres y claves de 23 caracteres. El segundo es para el último bloque del reto, que será de 356 caracteres, y clave de 23 caracteres.
Cada línea está escrita de la forma:
64 (8) [8,48,196,288,320,400,484,704] {64,576,3136,5184,1600,1600,7744,7744}
El primer número indica la posición dentro del bloque. El número entre paréntesis indica el número de resultados (de la suma de letras de la clave multiplicada por la suma de dígitos) que hacen referencia a esa posición. Los números entre corchetes son la lista de las sumas de las letras de las claves que hacen referencia a esa posición. Los números entre llaves son el producto del correspondiente número de la lista entre corchetes por la suma de sus dígitos. En este ejemplo, tenemos la posición 64 dentro del bloque codificado. Sabemos que hay 8 sumas diferentes que, haciendo las operaciones correspondientes, van a dar como resultado la posición 64 (en la que estamos). Sabemos que las sumas de las letras de una clave que van a dar como resultado este valor 64 son 8, 48, 196, 288, 320, 400, 484, 704. Y sabemos que estos valores multiplicados por la suma de sus dígitos van a dar como resultado, respectivamente, los valores 64 (=8*(8)), 576 (=48*(4+8)), 3136 (=196*(1+9+6)), 5184 (=288*(2+8+8)), 1600 (=320*(3+2+0)), 1600 (400*(4+0+0)), 7744 (=484*(4+8+4)), 7744 (=704*(7+0+4)). Estos últimos valores son los que nos van a dar la posición 64 (haciendo módulo 512, pues este ejemplo es de un bloque de 512 caracteres).
Las líneas están ordenadas por el número diferente de sumas de claves que hacen referencia a cada posición, de forma que se ve fácilmente las posiciones que nunca serán ocupadas por el primer carácter cifrado, y que sólo serán ocupadas cuando la posición calculada ya esté ocupada, al desplazarse a la derecha hasta encontrar una posición libre.
Incluyo a continuación el código Java que he utilizado para realizar los cálculos, por si a alguien le interesa, y por si acaso he cometido un error y alguien puede corregirme:
import java.util.*; public class prueba1 { public static void main(String[] args) { int longitudClave=23; int máximoValorLetra=31; int longitudBloque=512; clsValorFrecuencia[] array=new clsValorFrecuencia[longitudBloque]; for(int i=0;i<array.length;i++) array[i]=new clsValorFrecuencia(i); for(int i=0;i<=longitudClave*máximoValorLetra;i++) { int a=(int)(i/100); int b=((int)(i/10)) % 10; int c=i % 10; int v=i*(a+b+c); int vmod=v % longitudBloque; array[vmod].incFrecuencia(); array[vmod].suma(v); array[vmod].enteroGenerador(i); } Arrays.sort(array); for(int i=0;i<array.length;i++) System.out.println(array[i]); } private static class clsValorFrecuencia implements Comparable<clsValorFrecuencia> { private int valor; private int frecuencia; private final ArrayList<Integer> listaEnterosGeneradores=new ArrayList<Integer>(); private final ArrayList<Integer> listaSumas=new ArrayList<Integer>(); public clsValorFrecuencia(int valor) { this.valor=valor; frecuencia=0; } public int valor() { return valor; } public int frecuencia() { return frecuencia; } public void incFrecuencia() { frecuencia++; } public void suma(int suma) { listaSumas.add(suma); } public void enteroGenerador(int enteroGenerador) { listaEnterosGeneradores.add(enteroGenerador); } public int compareTo(clsValorFrecuencia o) { return frecuencia-o.frecuencia; } public String toString() { String cadena=valor+" ("+frecuencia+")"; if(listaEnterosGeneradores.size()>0) { cadena+=" ["; for(int i=0;i<listaEnterosGeneradores.size()-1;i++) cadena+=listaEnterosGeneradores.get(i)+","; cadena+=listaEnterosGeneradores.get(listaEnterosGeneradores.size()-1)+"]"; } if(listaSumas.size()>0) { cadena+=" {"; for(int i=0;i<listaSumas.size()-1;i++) cadena+=listaSumas.get(i)+","; cadena+=listaSumas.get(listaSumas.size()-1)+"}"; } return cadena; } } }El algoritmo es simple. El máximo valor que tomará la suma de las letras de la clave será 23*31, pues la clave tiene una longitud de 23 caracteres, y el máximo valor que pueden tomar los caracteres es 31. Se recorren todos los valores comprendidos entre 0 y 23*31=713, se calcula el producto de cada valor por la suma de sus dígitos, y se calcula su valor módulo 512. Ésta es la posición de cifrado. Esto se almacena en una lista que va contando el número de veces que se hace referencia a la posición, además de almacenar el valor que generó esa posición, y el resultado de multiplicar dicho valor por la suma de sus dígitos. Terminado el proceso, se ordenan por el número de veces que se hace referencia a cada posición, y se muestra la lista en pantalla.
Bueno, esto no es gran cosa, pero quién sabe si no puede dar alguna idea a alguien para atacar a este criptosistema.
Me uno al ataque
sqrmatrix1 Julio 2011 - 7:19pm
Como nos hemos quedado sin ACYNOS, y me preguntaba qué bicho atacar, LlamameX me recomendó éste. Como muy bien decía, es grande y peludo, y vaya si lo es. Así que aquí estoy, a ver si consigo algo.
Me gusta el algoritmo, es bastante ingenioso. A ver qué tal se nos da. Como de costumbre, mis aportaciones serán normalmente esporádicas por falta de tiempo y/o resultados, pero estaré pensando en el bicho en busca de algún punto débil.
¿El código vb del TFTR es correcto?
AgustínB2 Julio 2011 - 7:55pm
Hola,
Muerto ACYNOS, seguimos por orden y me pregunto si el código basic entregado es correcto.
Lo he puesto en una hoja de cálculo y en dos celdas he puesto los 7451 caracteres de La Regenta, el cifrado y el descifrado proporcionado, y no me sale.
Celda A2 = MAGISTRAL
Celda B2 = 7451 caracteres cifrados de La Regenta
Celda C2 = cifrar(A2;B2;"D") --> No descifra correctamente el texto saca (pongo los primeros 50 caracteres de los 7451)
L.BBHI.ZTOKINRXDMCABBR_IUWJAA.VZHXJAQPDPJMROZAXF,ICelda B3 = cifrar(A2;C3;"C")
Celda C3 = 7451 caracteres de La Regenta --> El cifrado es distinto comienza por
,UISEÑTSYL_YOQQOLYDTPE@D_I_X.ZI_T_W_,XSR_PNIT,XÑEWEdito: Perdón, leo de nuevo todo el reto igual ha sido culpa mía. El código proporcionado para cifrar inicio de "El Quijote" con la palabra SANCHO, funciona correctamente entonces voy a ver si he cometido yo algún error.
Re-edito: Veo que nuestro amigo puede que esté de vacaciones y no contesta. Ya he visto donde se indica lo de los bloques de 512 pero aún así considero que si se tiene el código porque se ha cifrado y descifrado La Regenta se debería proporcionar correctamente todo el código y no por trozos e incompleto. Me lo voy a hacer yo entonces y ver si consigo por lo menos el cifrado y descifrado correcto de "La Regenta". El texto del RETO.txt entiendo que sigue el mismo algoritmo y que no hay introducido ningún otro cambio.
Por cierto, que como la clave de longitud 23 sea una palabra del dicionario, en el lemario que proporcionó en su día Agustín tenemos sólo una;
electroencefalografista
y de 22 tenemos las tres siguientes:
electroencefalográfico
esternocleidomastoideo
in pártibus infidélium
Si a la primera le ponemos un guión tenemos otra potencial de 23
electro-encefalográfico
Lo comento, porque ya me estoy montando un ataque por fuerza bruta de diccionario.
PD: Está curioso este reto del que creo Astur
http://es.wikipedia.org/wiki/Nemeton
Y buscando Callaecia Risit
http://www.celtiberia.net/articulo.asp?id=260&cadena=
Hay que hacer ingeniería social para ver por donde pueden ir los tiros del texto cifrado y/o la clave ;-)
Código
tokamak4 Julio 2011 - 10:06am
Bueno, aquí lo tienes:
Function cifrar(clave_i, entrada_i, cifrar_descifrar, ultima_clave) Dim mensaje() As String Dim clave() As String longitud = Len(entrada_i) lclave = Len(clave_i) ReDim mensaje(longitud) ReDim clave(lclave) For i = 1 To longitud mensaje(i - 1) = Mid$(entrada_i, i, 1) Next i For i = 1 To lclave clave(i - 1) = Mid$(clave_i, i, 1) Next i CIFRADO = String(longitud, "-") ya_ocupada = String(longitud, "-") posicion_clave = -1 For t = 1 To longitud posicion_clave = posicion_clave + 1 posicion_clave = posicion_clave Mod lclave x = sumar_clave(clave(), longitud) Do ya_cifrado = Mid$(ya_ocupada, x + 1, 1) If ya_cifrado = "*" Then x = x + 1 x = x Mod longitud End If Loop Until ya_cifrado <> "*" letra = mensaje(x) Mid$(ya_ocupada, x + 1, 1) = "*" y = inv_caracter(clave(posicion_clave)) Xor inv_caracter(letra) Mid$(CIFRADO, x + 1, 1) = caracter(y) If cifrar_descifrar = "C" Then clave(posicion_clave) = letra Else clave(posicion_clave) = caracter(y) End If Next t cifrar = CIFRADO ultima_clave = "" For i = 1 To lclave ultima_clave = ultima_clave & clave(i - 1) Next i End Function Function sumar_clave(clave() As String, longitud) total = 0 For i = 0 To UBound(clave) - 1 a = clave(i) x = inv_caracter(a) total = total + x Next i cadena = Format$(total, "000000") resuma = 0 For i = 1 To Len(cadena) resuma = resuma + CDbl(Mid$(cadena, i, 1)) Next i total = total * resuma total = total Mod longitud sumar_clave = total End Function Function caracter(numero) caracteres = Array("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", "_", ".", "@", "*", ",") caracter = caracteres(numero) End Function Function inv_caracter(caracter) caracteres = Array("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", "_", ".", "@", "*", ",") For i = 0 To 31 If caracteres(i) = caracter Then inv_caracter = i: Exit Function Next i End FunctionA esta función hay que irle enviando los segmentos de 512 bytes para que los vaya procesando. Para codificar o decodificar un segmento utilizamos la clave anterior, devuelta en ultima_clave, salvo la primera vez.
Otra cosa: la ingeniería social tampoco os dará la clave del reto, no soy ese astur del enlace.
Mi bestezuela peluda
tokamak30 Junio 2011 - 6:39pm
Siempre creí que ACYNOS era mucho más sólido, al menos lo parecía, en fin: SIC TRANSIT GLORIA MUNDI.
Bueno, ahora le toca el turno a TFTR un cifrado tan sencillo que parece broma, hasta se puede hacer manualmente sin mucho problema (sin usar los discos con los que el señor Torner quería pegarsela al embajador alemán, claro). Para mí simplemente que fuese muy difícil de atacar ya sería una sorpresa tan grande como también lo fue para mí la vulnerabilidad de ACYNOS.
Si necesitáis más textos, o lo que sea, aquí estamos.
Análisis de vías de ataque
LlamameX30 Junio 2011 - 11:55am
Tras Torner he vuelto a TFTR a ver si le ve cojear por alguna parte. Mis conclusiones tienden a que no. Por lo que veo como posibilidades de ataque:
A favor:
En contra:
A ver si ahora que ha caído Acynos podemos prestarle algo de atención a TFTR, que creo que se la merece.
¿Porqué 26^23?
AgustínB3 Julio 2011 - 1:04pm
¿No son combinaciones de 23 caracteres de un alfabeto de 32 caracteres?
A ver...
LlamameX4 Julio 2011 - 10:28am
uy pues si. XD
Aunque la idea es la misma. Un número una burrada de grande.
Esfuerzos
tokamak23 Mayo 2011 - 4:19pm
Se agradece el esfuerzo, auque no haya llegado la primera sangre, y se barrunta muy lejos... Sobre ACYNOS he intentado utilizar un Algoritmo Genético, utilizando como función de coste la concurrencia de caracteres en la misma posición entre el texto obtenido y el texto en claro, sobre el párrafo ejemplo de la Regenta, para ver si detectaba algún asomo de convergencia, pero nada. Yo creo que es más sólido que RC4.
Hombre, gracias.
Agustín23 Mayo 2011 - 6:15pm
Desde el punto de vista de la fuerza bruta, RC4 es algo más fuerte. Con semillas de 10 decimales, la fuerza de ACYNOS es de 10^10*10^10 = 10^20, mientras que con un alfabeto de 28 caracteres, RC4 tiene una fuerza de 28! = 3. * 10^29, si no fallan mis cuentas.
Ataque
tokamak23 Mayo 2011 - 12:12pm
Como dice LlamameX, aunque la clave no aproveche toda su entropía para generar posiciones de substitución, sí la utiliza para efectuar las substituciones de caracteres. Pero en fín... ¿nadie se anima a desencadenar un ataque general contra el cifrado TFTR?
Aunque le teno bastante confianza, siempre he pensado que es imposible que algo tan, tan simple sea también tan seguro, por eso lo traje a estas páginas...¿o voy a tener que patentarlo?
Le estuve dando unas cuantas vueltas
LlamameX23 Mayo 2011 - 3:55pm
Y le vi pocos flancos de ataque. Lo más prometedor es que hay una fuerte dependencia de la distribución de los carácteres del lenguaje y que el cifrado es un XOR de letras con esas frecuencias. Poco más. El uso de bloques de 512 nos quita esperanzas de encontrar grupos de letras consecutivas al final del texto, aunque puede haber suerte en las posiciones con probabilidad 0 cerca de posiciones con probabilidad "alta" (si es que a 9/512 se le puede considerar alta).
La última aproximación que se me ocurrió (antes de volver a Acynos no sea que me riña Agustín) fue considerar sólo las posiciones probables y sus vecinas (las primeras que deberían llenarse). A partir de ahí coger grupos de 22 (la longitud de clave que conocemos menos 1) y ver para cada uno que letra nos hacia falta incorporar para llegar a otros elementos del grupo. Con eso podríamos determinar que letras hemos ido xoreando e ir sacando la posible clave.
Desde ahí se podría seguir.
Paciencia
Agustín23 Mayo 2011 - 12:38pm
Debes tener un poco de paciencia, que atacar es muy difícil y, además, la gente está tratando de romper un código más antiguo. De todas maneras, puedes patentarlo, si la licencia CC no te parece suficiente.
Re: Entropía de la clave
tokamak23 Mayo 2011 - 12:14am
Ya lo sé, Alenog, no es ningún fallo, lo que aquí muestro difiere un poco de la implementación real que utilizo, (vgr.se pueden usar pesos) pero aún así poco importa, el algoritmo resulta más sencillo así y utilizando una clave de 10 o 15 caracteres, que no sea una única palabra, no me parece que se le pueda meter mano, a despecho de la gran sencillez del procedimiento, una especie cifrado con libreta de un sólo uso, en el que la "libreta".. ¡es el propio mensaje!.
La idea es buena
Agustín23 Mayo 2011 - 3:11am
Aunque no es totalmente nueva:
http://en.wikipedia.org/wiki/Autokey_cipher
Con menos sofisticación que el cifrado TFTR, podríamos imaginar una especie de Vigénere en el que en vez de repetir cíclicamente la clave de partida, que es su punto débil, se incorporaran a la clave los bytes del texto plano. Es decir, que si la longitud de la clave es L, el elemento K(L+1) sería P(1), el primer carácter del texto plano. En general, tendríamos
K(L+i) = P(i)
Voilà, una cierta forma de OTP. La debilidad -en este caso, no me refiero a TFTR- estriba en que los caracteres Pi no son aleatorios, como en un verdadero OTP, sino que tendrán la estructura interna del lenguaje, y podrían ser inferidos a partir de hipótesis estadísticas sobre él. Esto puede mejorarse si los caracteres plaos se incorporan a la clave después de haber sido modificados, mediante un cifrado previo. Precisamente hay una versión posterior de ACYNOS que hace algo asi, modestia aparte. No la voy a presenar, tranquilos.
Si, y también
LlamameX23 Mayo 2011 - 10:20am
puedes hacer un Vignere con longitud de clave variable (recortando/añadiendo carácteres al final/inicio) según lo que vayas codificando, con lo que también rompes todas las estadísticas y sigue siendo lo suficientemente sencillo para hacerlo con lápiz y papel.
Entropía de la clave
Alenog22 Mayo 2011 - 7:33pm
El primer fallo que veo es que no aprovechas toda la entropía de la clave.
Resulta equivalente usar como clave SANCHO, CAZON que CHASCZ. Con la consiguiente facilidad para quien quiera averiguarla.
No es asi
LlamameX23 Mayo 2011 - 12:16am
Si codificas con SANCHO la siguiente clave puede ser, por ejemplo, PANCHO y la tercer PONCHO. Aunque CAZON te de la misma posición de sustitución para el primer carácter, la clave que obtendrás será ahora PAZON, con lo que la siguiente sustitución ya será distinta.
Es bastante más sólido de lo que a primera vista puede parecer.
Posiciones bloque
tokamak16 Mayo 2011 - 4:12pm
Yo lo veo más fácil: Con una clave de 23 caracteres, el valor más alto de la suma será:
Pero el valor de la clave más alto es
A estas cantidades hay que aplicarles módulo 512, para saber el caracter que codificarán del bloque. Al bloque siguiente sólo se pasa cuando se termina de cifrar el primero.
Más información
LlamameX16 Mayo 2011 - 3:29pm
Asumiento un máximo de 999, las posiciones del bloque de 512 que pueden ser resultado del producto (a+b+c)*(100a+10b+c) son las siguientes (el número indica las veces que se obtiene esa posición. Sólo hay dos A's que corresponden a 10 veces en hexadecimal).
Sabemos que de los 999 valores sólo se usarán 512 (luego se pasará al bloque siguiente). Con longitudes de clave de 23 carácteres, además, el númeró máximo será (clave todo "*") 896, dejando el rellenado como
Podemos asumir también que habrá una desviación respecto a este rellenado por el tema de las probabilidades de las letras. Estoy preparando un modelo (tipo montecarlo) para encontrar algo más fino.
Los valores
LlamameX17 Mayo 2011 - 12:13pm
Tras 1.000.000 de generaciones de claves de 23 carácteres asumiendo una distribución tipo "La Regenta" (recordemos que el orden no es relevante), los valores más probables para una posición en un bloque de 512 (los que están por encima del 1%, que son el 31,27% del total) son
Tabla Xor
tokamak16 Mayo 2011 - 1:21pm
la función Xor funciona con 8 bits, es sobre la tabla ASCII, por eso se te va de rango de la forma en que la empleas.
pero (y esto ya lo comentaba al princio del post: empleando 5 bits, para lo cual me limito a 32 caracteres, también funciona)
Mira: haz esto y sacarás en un fichero la tabla Xor de equivalencias, verás como va bien (en un cifrado manual se usaría esta tabla, pero mostrando las equivalencias de caracteres)
xors = "c:\xors.txt" Open xors For Output As #1 For i = 0 To 31 For j = 0 To 31 k = i Xor j Print #1, i; "xor"; j; "="; k Next j Next i Close #1Cosas relativas al XOR
LlamameX16 Mayo 2011 - 12:37pm
Que se esté haciendo XOR de las posiciones en el alfabeto para codificar tiene varias implicaciones:
Xor
tokamak16 Mayo 2011 - 11:26am
Bueno yo utilizo, utilizo 5 bits:
1 xor 31:
Si ves la rutina inv_caracter, los caracteres se numeran desde 0 a 31, de esta forma no necesito hacer módulo 32:
31 xor 31:
Así funciona bien.
Ok
LlamameX16 Mayo 2011 - 1:03pm
Cierto. Era un problema de declaración de los límites de las variables. Óbviamente al trabajar bit a bit nunca podría salirse de rango.
No veo el XOR
LlamameX16 Mayo 2011 - 10:49am
Hola
Tal y como trata VB el XOR parece que vas a desbordar "caracteres" puesto que, por ejemplo, 1 XOR 32 = 33. No veo que ese XOR lo hagas módulo 32 para corregir eso.
No te olvides
Agustín16 Mayo 2011 - 2:50am
No te olvides de recordarle a admin que tu foro se ha convertido en un reto, para que provea el incentivo de los puntos.
Grande complication
tokamak15 Mayo 2011 - 3:16pm
Que va Agustín, no menosprecio en nada ACYNOS, todo lo contrario, basta ver la espectación que concita entre la concurrencia. Yo mismo, que acabo de entrar por la puerta, le he dedicado algunas horas, incluso he implementado el algoritmo en VB para ver como meterle mano (pero nada); la rutina pseudoaleatoria y el numero Godel de la clave, me parecen métodos elegantes, de hecho Grande Complication es como se conoce a unos relojes muy bonitos, de esos que enseñan las ruedecitas...
¡Ah!
Agustín16 Mayo 2011 - 12:47am
Alors, merci, et pardonne-moi mon ignorance
RETO
tokamak15 Mayo 2011 - 2:57am
Bueno, supongo que si las altas torres de esa grande complication llamada ACYNOS (me he puesto a leer algo, pero sólo llegué a crearme un programa que cifra y descifra) están a punto de caer, descifrar un mensaje con el algoritmo TFTR, que se puede aplicar con papel y lápiz perfectamente, tiene que ser más fácil...¿o no?.
El cifrado se realiza en bloques de 512 bytes, y cuando se termina de cifrar un bloque la última clave utilizada se emplea para cifrar el siguiente.
(En condiciones reales uso bloques de 4096 y calculo el producto de sus componentes, no la suma, pero queda más bonito con la suma, hace más fácil el cálculo manual)
Aquí hay un ejemplo más extenso de cifrado, los primeros 7451 caracteres de La Regenta:
(La clave utilizada es: MAGISTRAL)
Texto plano de la Regenta
La Regenta cifrada
Y finalmente, aquí está el reto: son 21348 caracteres:
Reto
Creo que con este repertorio se tendría que poder descifrar, (si es que es descifrable), por si acaso doy otra pista: la longitud de la clave es de 23 caracteres.
Eso de los bloques, las sumas y los productos
LlamameX15 Mayo 2011 - 12:24pm
¿Afecta en algo al algoritmo anterior?. Entiendo que no. De todas maneras a ver si lo implemento (que manía, ¿no?) para ver si lo he pillado todo bien.
No, no afecta
tokamak15 Mayo 2011 - 2:17pm
Pues eso, que no afecta al algoritmo anterior. Eso si: cuando se cifra un nuevo bloque, se utiliza la última clave que quedó al cifrar el bloque anterior; si acaso, dependiendo de como implementes el algoritmo, afectaría en que tras cada cifrado de bloque hay que guardar la clave para el proceso siguiente, por ejemplo puedes ponerlo así:
Y así emplear ultima_clave para cifrar el bloque de 512 bytes siguiente.
No sé
Agustín15 Mayo 2011 - 2:13pm
No sé qué estás haciendo aquí, en vez de estar contribuyendo a desmochar al vetusto ACYNOS, que le habéis dejado toda la faema al probre mellon. Debería darte vergüenza.
Es broma, claro.
Tengo las orejas coloradas
LlamameX15 Mayo 2011 - 4:24pm
Tanto por el tirón como por la vergüenza XDD
La verdad es que estoy a la espectativa. No se me ocurre nada mejor de lo que ya está haciendo Mellon salvo algún ajuste en los tests para ahorrar ciclos, pero dado que el ataque está en marcha estoy (estamos creo) a la espera de los resultados. Si los resultados (espero que no) no son positivos nos volveremos a volcar con la bestia.
Por otro lado este nuevo algoritmo parece también tener cuernos y pezuñas y oler a azufre. En primera instancia parecía atacable facilmente pero eso de los bloques me desarma bastante, ya que agota todo un espacio de posiciones antes de pasar al siguiente y deja poco espacio para cadenas consecutivas.
Las únicas debilidades que le veo son las siguientes:
Y tranqui por Acynos, sique saliendo en mis pesadillas XDD