Reto: EL GRIAL

Imagen de tokamak
Enviado por tokamak en

Foros: 

Por tokamak

Bueno, pues en este reto tendréis que romper la clave de un criptosistema basado en un generador de números aleatorios. Estos generadores suelen estar basados en funciones recurrentes del tipo:

f x(n+1)=(ax(n) + b) mod m

Las series generadas por estas funciones siempre caen en ciclos, pero es posible ajustar los parámetros para que estos ciclos sean de amplitud máxima. Podéis consultar Wikipedia para ver los detalles. Por ejemplo con a=3, b=5 y m=32 se obtiene un ciclo de amplitud máxima, como máximo m, sin repetirse ningún valor.

Lo interesante son las congruencias con ciclos amplísimos, de las que he encontrado algunos ejemplos aquí o aquí

Al final me he quedado con la siguiente:

a = 2862933555777941757
b = 3037000493
m = 2^64

Esa función tiene un período de 2^64, lo que nos servirá para implementar nuestro algoritmo de esta forma:

El alfabeto base es el estándar de Kriptópolis, con valores entre 0 y 31:

ABCDEFGHIJKLMNÑOPQRSTUVWXYZ_.,:;

0-) Ponemos la clave en el "bloque anterior"
1-) Tomamos un bloque de 8 bytes del texto claro.
2-) Tomamos el bloque anterior, del texto en claro
2-) Convertimos el bloque anterior en una cadena de números, con los valores numéricos de sus carácteres.
3-) Utilizamos ese valor para generar un número "aleatorio" con la función propuesta
4-) Tomamos los 16 valores más significativos de ese número. Si hay menos, anteponemos ceros hasta completar 16 bytes
4-) Repasamos ese número, cogiendo cifras de dos en dos y haciendo módulo 32
5-) Hacemos Xor con esos valores y con cada uno de los valores del bloque actual y generamos el bloque cifrado
6-) Así hasta el final del cifrado

Os pongo un ejemplo
Clave

SANCHO_P

Claro

EN_UN_LUGAR_DE_LA_MANCHA

Traza

Bloque anterior   Bloque actual  Cadena numérica         Aleatorio      Aleatorio mod 32     Cifrado
 
SANCHO_P          EN_UN_LU       1900130207152716      8144192868236447  1712192804230015     UBIJJMLZ
EN_UN_LU          GAR_DE_L       0413272113271121      1284083070662115  1220083006022115     UBIJJMLZKTZFFGÑE
GAR_DE_L          A_MANCHA       0600182703042711      9560860986001016  3128220922001016     UBIJJMLZKTZFFGÑE;HZJ_CNP

Ya se ve que que es un proceso sencillísimo, poco más que un Vigenère con autoclave; además como es difícil que cada secuencia de 8 bytes se repita en el texto y como cada una de ellas nos genera un número distinto que sumar al bloque, resulta que estamos incrementando mucho el nivel de dificultad. Sobre todo teniendo en cuenta que no es fácil compilar una lista exhaustiva de las permutaciones posibles de cada bloque, a causa del gran número (32^8) de ellas, lista con la que podríamos conocer las asignaciones "aleatorias" que corresponderían a cada bloque.

La única complicación técnica de este proceso es la dificultad para hacer cálculos con precisión de 16 dígitos pero, mira por donde, ya había salido el tema en otro post, y yo había localizado unas funciones muy útiles para ese propósito en esta monografía. Sqrmatryx también nos contó como se puee hacer en Java, por lo que creo que no va a ser ningún problema.

Lo he llamado EL GRIAL, por la maravillosa simplicidad de los algoritmos para cifrados basados en generadores aleatorios, que se acercan a mi ideal de criptosistema. Ahora bien: seguro que existe una metodología para atacar estos cifrados, porque si no...apaga y vámonos. Además, finalmente lo he hecho más simple de lo que inicialmente había pergueñado, para dar alguna oportunidad. Por ejemplo no hago un segundo Xor con la clave anterior, lo que ofuscaría más el texto. Hay una vulnerabilidad evidente que podéis explotar.

Bueno que lo disfrutéis, el reto está en un fichero que se puede bajar de aquí

Y este es el código fuente, utilizable como siempre desde Excel.

El cifrado lo componen sólo las 4 primeras funciones, un código minimalista. El resto es la "biblioteca" para cálculos largos.

Public Function CoD(ByRef mensaje As Variant, clave As Variant, cd As Variant) As String
 
 Dim bloque_ant, bloque_8, letra, letra_clave, semilla, nuevo, suma
 Dim i, j, cifra, k, l
 
 CoD = ""
 bloque_ant = clave
 
 For i = 1 To Len(mensaje) Step 8
   bloque_8 = Mid$(mensaje, i, 8)
   semilla = ""
   For j = 1 To 8
     letra_clave = Mid(bloque_ant, j, 1)
     semilla = semilla & Format$(inv_caracter(letra_clave), "00")
   Next j
 
   nuevo = aleatorio(semilla) 'Convierte bloque anterior en nº "aleatorio"
 
   aux = "": k = 0
    For j = 1 To 16 Step 2
     k = k + 1
     cifra = CInt(Mid(nuevo, j, 2)) Mod 32
          '  nº aleatorio   letra bloque
     cifra = cifra Xor inv_caracter(Mid(bloque_8, k, 1))
     CoD = CoD & caracter(cifra)
     aux = aux & caracter(cifra)
   Next j
  If cd = "C" Then bloque_ant = bloque_8 Else bloque_ant = aux
 Next i
 
End Function
Public Function inv_caracter(caracter)
  Dim i, caracteres
  caracteres = "ABCDEFGHIJKLMNÑOPQRSTUVWXYZ_.,:;"
  i = InStr(caracteres, caracter)
  inv_caracter = i - 1
End Function
Public Function caracter(numero)
  Dim caracteres()
  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
 
Public Function aleatorio(semilla) As String
 
Dim x(2) As String
Dim y(2) As String
Dim z(2) As String
 
Dim CR() As String
 
'X = (2862933555777941757 * X + 3037000493) mod 2^64
Dim n As Integer, test As Double
 
Dim Potencia, producto, suma As String
 
n = Len(test) - 1
 
Potencia = "18446744073709551616" ' 2^64
 
y(1) = semilla
y(2) = "2862933555777941757"
producto = Multiplicar(y(), n)
 
x(1) = producto
x(2) = "3037000493"
suma = Sumar(x(), n)
 
z(1) = suma
z(2) = Potencia
 
CR() = DivisionEuclidea(z(), n)
 
aleatorio = CR(2)
 
If Len(aleatorio) > 16 Then aleatorio = Left(aleatorio, 16)
diferencia = 16 - Len(aleatorio)
If diferencia > 0 Then   aleatorio = String(diferencia, "0") & aleatorio
 
End Function

Aquí se puede enlazar al texto completo. Funciones de cálculos largos incluídas

Descargar código completo con biblioteca de cálculos largos

Post scríptum
EL GRIAL (FORTE)

Existe la posibilidad de incrementar poderosamente la seguridad de este cifrado, añadiendo un generador adicional pseudoaleatorio que inicializaremos también con el valor de clave, y que se irá alimentando recursivamente con los valores que vaya produciendo. Cada valor generado lo Xoreamos con el bloque actual, y después seguimos el mismo procedimiento que con EL GRIAL.

Como generador adicional podemos usar, por ejemplo:

a = 6364136223846793005
b = 1442695040888963407
m = 2^64

Y ésta sería la traza para cifrar el mismo texto:

 Cadena numérica  Aleatorio        Aleatorio mod 32 Semilla adicional Aleatorio adicional Adicional mod 32 Bloque cifra  
 1900130207152716 8144192868236447 1712192804230015 1900130207152716    1427708576476394 1427062112153130 _ZÑ.FDTE
 0413272113271121 1284083070662115 1220083006022115 1427708576476394    1781493185490403 1717173121170403 _FLZPWKH
 0600182703042711 9560860986001016 3128220922001016 1781493185490403    1813710054170517 1813070022170517 NK,JNSIB

No voy a publicar el fuente para no interferir con el reto. Quien quiera el código sólo tiene que pedirmelo.

Calificación A

Yo le adjudico desde ya la calificación A. Si el PRNG no presenta repeticiones cíclicas, se trata de un Fake-OTP con autoclave. Quizás LlamameX haga una de las suyas, atacándolo por donde no está previsto. El problema del autoclave es el posible ataque sobre texto conocido, cuando hay alguna pista.

No obstante, no acabo de ver claro el número-aleatorio-mod-32. Sólo tiene 14 dígitos

17121928423015 = 17 12 19 28 42 30 15

y sale un valor 42 que no puede asignarse a ningún carácter del alfabeto.

Desde luego se podría complicar más, desordenando el alfabeto y también el bloque en claro, pero comprendo que no quieras que nos matemos.

SUGERENCIA:
El larguísimo código se podría poner enlazado a un fichero, para no dificultar la lectura del hilo.

Simple y elegante, como tiene

Simple y elegante, como tiene que ser un cifrario. Si no le hubieras quitado los 16 dígitos menos significativos a los resultados del generador... :)

Reedición:
---------------------
Ahora que me doy cuenta, sólo participan 2^32 valores de los posibles 2^64, lo que significa que puede ocurrir que dos claves distintas acaben generando, a partir de cierto punto, la misma secuencia, porque de los posibles 2^64 valores que puede devolver el generador, estás recortándolos a 2^32

A ver si lo he entendido...

Corrígeme si me equivoco, porque antes lo había entendido mal. Entiendo que el bloque anterior se utiliza para obtener un número aleatorio, que se utilizará para hacer XOR con el siguiente bloque. De ser así, si tenemos dos bloques repetidos en diferentes puntos del criptograma, ambos generarán la misma clave para el siguiente bloque. Y si resulta que tenemos dos bloques consecutivos duplicados en el texto en claro (es decir, bloque A seguido de bloque B, y este par de bloques consecutivos repetido en otro lugar del texto claro), cuando se codifiquen, el segundo bloque de ambos duplicados (B) se codificará de la misma manera. En caso de encontrarnos dos bloques idénticos en el criptograma, tendremos bastante certeza de que el texto original en ambos será el mismo, que el bloque anterior en ambos casos tendrá el mismo texto, aunque puede estar codificado de diferente manera, y que el siguiente bloque estará en ambos casos codificado con la misma clave. Si no me he equivocado en lo expuesto, esto puede ser una vulnerabilidad.

Bueno, entonces creo que lo

Bueno, entonces creo que lo voy entendiendo. Es que todavía no lo he implementado, y si no implemento un criptosistema, me cuesta más entenderlo. De todas formas, a primera vista parece complicado resolverlo. A ver cómo avanza la cosa.

Bloques obtenidos

Éstos son los bloques repetidos que he obtenido, y su posición en el criptograma, junto con el bloque anterior y el posterior. Hay altas probabilidades de que los bloques repetidos tengan el mismo texto y la misma clave, que los bloque primeros tengan el mismo texto, pero no la misma clave, y que los bloques últimos tengan la misma clave, pero no el mismo texto.

00720: OEJYKBÑT ZIL.HÑDM DD,GWHYQ
01064: FXGDGRMG ZIL.HÑDM DDYUWMGQ
 
04576: PRNZHAMY YPJBJAY. JYXQNCNY OH;R;KW,
32008: PSYRVZPG YPJBJAY. JYXQNCNY OBYNPZMA
 
04944: HSHLPZHG R,IKY.;T WCOR;_DN
37952: YMQRYR:B R,IKY.;T QZRRX_L_
 
09840: D,:LBGDI ÑFAGLEWD VÑOX.NYK
26528: FBHGQGSL ÑFAGLEWD YMO_J_I_
 
10672: KUE,,UAS XOWYSL;K CIOQ_ÑXJ
46144: MTPSVWYE XOWYSL;K CIRHCÑRF
 
10744: EQMHNP.C .QRLLTER FL,HMAFN
63400: YSÑGÑAFS .QRLLTER JGZMHBKA
 
18144: I.M,ZCAÑ V;TRHEC, VCVÑ;LKF
32696: W_RUL..E V;TRHEC, VFSGYNKJ
 
20104: _FNJL:ÑE CXSAZOXH W,ULWJLA
23152: GLF_BUGY CXSAZOXH ;BUOIAXB
 
20352: VMPOWQQF DOIU::,N YHEJZS,M
22064: DJC._Q.Y DOIU::,N YHENZS,W
 
23928: VSQ_.YZD SMKEZQVQ GTYCYYQK
38648: IÑAYOPE; SMKEZQVQ JYYKCYUR
 
24360: ZÑ.RHUSR :GXLÑRB; PXPKQID,
62384: _BCAIWDL :GXLÑRB; PXPILNKN
 
26360: CUZNPREE JERÑL_SN ,AJ_YPNV
56600: I:_IOFUL JERÑL_SN ,AJ_;HYP
 
26544: YMO_J_I_ AQAB.DM, WMK__DB.
26880: ÑLCWGSPA AQAB.DM, WMK__JKL
 
27440: QLC:MFGM :JUKTMUP MGZÑV:;O
43680: TTIMH;II :JUKTMUP LQFITN;P
 
28336: YUIDOHTH EAON.APV E.CZÑK;Y
50312: V:ÑDNDZE EAON.APV DWEQH;ÑQ
 
28336: YUIDOHTH EAON.APV E.CZÑK;Y
51104: MA.:_OLG EAON.APV TLTÑSMAJ
 
32120: W:H:PZJO IWNRXDVÑ KWVCEPML
44792: _VPÑR,QJ IWNRXDVÑ KMÑÑRAZT
 
32120: W:H:PZJO IWNRXDVÑ KWVCEPML
47912: GLXL..RR IWNRXDVÑ GPÑKR.F;
 
32200: E;AF_X:Y PAÑI_AHT LQWU.MGW DJRDB:LA
36408: J;VCVGPC PAÑI_AHT LQWU.MGW CJCY:TEA
 
35920: J:Y:ALMJ CTCCVBUJ VVJNEVEZ
56232: CIZQJHF; CTCCVBUJ VVNNXCOL
 
37648: AXOAKV;U IV;MMRMY .D;XBY;Ñ
48680: ACERYHUG IV;MMRMY .IXZDK;Z
 
37816: V,JVFBNF K.IVKLMF R,HXT;IA
54464: LBCEBWZR K.IVKLMF R,BOPQWU
 
37880: ZSWJJENA A.NTY;WT LAQBHK:V ;SSJR:YR RJÑCFYHL
39632: _ELPL:NS A.NTY;WT LAQBHK:V ;SSJR:YR RJÑY::NQ
 
39216: WKPVRPYP EOI.XO_S LSMTSEES
41704: QFPFYYRF EOI.XO_S LSMTSE,D
 
39784: ISC.UPDÑ BOVKV:PW VQYHMJEZ
42480: RSYWCZNM BOVKV:PW ;FIX.WKN
 
42088: BBX;VVVQ TW;LWR:Q R:USBWCN
43824: ÑBMH.IEM TW;LWR:Q R:USBWC,
 
44672: NHVPULM; TCM_ÑYIG ETSCGÑ,M SJDKOJTR
53544: HZN;OWE_ TCM_ÑYIG ETSCGÑ,M USUGLGUR
 
44792: _VPÑR,QJ IWNRXDVÑ KMÑÑRAZT
47912: GLXL..RR IWNRXDVÑ GPÑKR.F;
 
45008: JYXQWX:Ñ OSVAZNBI VLBDRBZZ
47000: ETGEXVCO OSVAZNBI VL;OO;XZ
 
45240: XDH.DM.D HBV;VONQ BSBAOSEO
47072: LN_JNOXR HBV;VONQ BSBAOSEI
 
45240: XDH.DM.D HBV;VONQ BSBAOSEO
47768: EKÑP:O;G HBV;VONQ BSBAOSEI
 
45768: JCNYJC_W EOF,WMGK ,Z:FIBQ;
65432: LVÑFEQHX EOF,WMGK ,Z:FÑGKR
 
45944: VUPY:GAY R,QHNWGN TÑXNMFXN ZIZOJYMI
51040: KLPF.ZVN R,QHNWGN TÑXNMFXN ,D::ÑGDI
 
46640: MXKT.QAR VTPMVRTB XG;BSXÑM
47208: O,IXMGE; VTPMVRTB XF;B;BBP
 
46640: MXKT.QAR VTPMVRTB XG;BSXÑM
47976: QGMGH.YR VTPMVRTB XCTDJXÑD
 
46816: :_LS.SGQ QW_GQF_Ñ ;ÑL:EHCN D:KIKIV;
49440: _IHBZMNF QW_GQF_Ñ ;ÑL:EHCN DXCM;:HG
 
47072: LN_JNOXR HBV;VONQ BSBAOSEI .NE_YR;Z
47768: EKÑP:O;G HBV;VONQ BSBAOSEI NY;DUR;Z
 
47168: AHVUTFUV :XBRNCSO KÑGÑMDBO LDXAX.MH
55640: GÑUNPWSL :XBRNCSO KÑGÑMDBO LDXAX.XB
 
47168: AHVUTFUV :XBRNCSO KÑGÑMDBO LDXAX.MH
65456: LBÑNBO.R :XBRNCSO KÑGÑMDBO LDXAX.XY
 
47208: O,IXMGE; VTPMVRTB XF;B;BBP
47976: QGMGH.YR VTPMVRTB XCTDJXÑD
 
47944: :E;O:ÑSU C_DR.UJA HDÑIXFÑY _:SNOS.X
52272: RK.EMXL; C_DR.UJA HDÑIXFÑY _:UF_ÑÑX
 
47952: C_DR.UJA HDÑIXFÑY _:SNOS.X
53640: ,_J;GQZS HDÑIXFÑY _:SHPPJH
 
50312: V:ÑDNDZE EAON.APV DWEQH;ÑQ
51104: MA.:_OLG EAON.APV TLTÑSMAJ
 
51968: BMQC.DKA VJIQKÑVO OXL;YQ,S
59112: Ñ:ZBJ:JD VJIQKÑVO OXL;YQO_
 
52280: C_DR.UJA HDÑIXFÑY _:UF_ÑÑX
53640: ,_J;GQZS HDÑIXFÑY _:SHPPJH
 
53360: BHJFMURI GNR,QBSZ FFZ,HNÑL
54096: VM;,TRAV GNR,QBSZ FFZ,TG,X
 
53360: BHJFMURI GNR,QBSZ FFZ,HNÑL
57944: YWQLOXPV GNR,QBSZ FFZ,TGHP
 
54096: VM;,TRAV GNR,QBSZ FFZ,TG,X
57944: YWQLOXPV GNR,QBSZ FFZ,TGHP
 
54200: PO_,I;.Q TNEHRKUC JUVXMXSS
54376: L:N.ZFAV TNEHRKUC ÑFYPHHKS
 
55640: GÑUNPWSL :XBRNCSO KÑGÑMDBO LDXAX.XB
65456: LBÑNBO.R :XBRNCSO KÑGÑMDBO LDXAX.XY
 
56904: VQF;ZTJO ZE,MSMBÑ DFKKO.TV
63056: JDYXQMEQ ZE,MSMBÑ DÑE:___O
 
58376: ;,OFX,LO D,:HZLZV K.C;XTBM VHA;IZKQ
62080: SF_LQXUY D,:HZLZV K.C;XTBM VHAYC.GÑ
 
62608: JCVUBNEU :GW,UÑÑ. JGY,CTIA
62720: VWMQCPUB :GW,UÑÑ. JGDÑJCXC
 
63568: G;YJKDNM JVNGEK,G WYSLB;PN
63808: ETPOLMME JVNGEK,G QJGN:G_N

Joer que estress!

Es que no se puede despistar uno. No se si meterme en esto pues antes que le de un tiento ya lo habrá masticado y deglutido Sqrmatrix.

Lo de los 2 (o n) generadores con ciclos distintos te lo iba a comentar como medio fácil de multiplicar por muchísimo la longitud del tuyo.

Tranquilidad, que ahora falta

Tranquilidad, que ahora falta lo más difícil, y me da que va a ser muy difícil. De momento no se me ocurre cómo utilizar estos datos para romper el cifrado. Lo que sí observo, que no me dí cuenta antes, es que los últimos bloques a veces tienen sus primeras letras coincidentes, y es lógico, ya que el texto repetido puede continuar algunas letras en estos bloques, y como están codificados con la misma clave, su codificación coincidirá, lo que nos da una pista de hasta dónde llega el texto. Por otro lado, los primeros bloques tienen el texto idéntico, y posiblemente en algún caso el bloque anterior tenga parte de ese texto coincidente, pero seguramente no coincidan en nada así cifrados y no podamos extraer nada de ellos

Sabemos el XOR de los carácteres en claro

Es evidente que los bloques posteriores a un bloque común difieren por que los carácteres en claro lo hacen. Xoreados entre ellos eliminamos la parte que corresponde al elemento aleatorio que coincidirá y obtenemos el XOR de los carácteres en claro.

Dado que sólo hay que encontrar grupos de texto castellano que xoreados nos den ese resultado para poder descifrar desde ahí, no debería ser demasiado dificil encontrarlos.

O estoy pecando de optimista (siempre lo hago al principio de un ataque)

Es muy diferente del FOTP

De entrada no hay alfabeto derivado con lo que podemos operar con los caracteres y después es texto estructurado castellano. Creo que debería caer con mi test de trigramas puesto que ambos bloques, el que se pruebe y el que se obtenga por XOR habrán de cumplirlos. Además hay una segunda verificación posible y es descifrar desde un bloque coincidente hasta completar los dos elementos iguales (la siguiente pareja de bloques iguales) siguientes y comprobar si coinciden.

Otros temas que resuelves

Es que al usar sólo la clave para el cifrado del primer bloque (los demás los cifras con el texto claro), aparecen los siguientes problemas:

- Dos cifrados distintos, aún con claves distintas, si tienen un bloque en claro en común podrán usarse entre ellos para un descifrado parcial de ambos textos.
- Un recifrado del mismo texto en claro con otra clave coincidirá en todo con el primer cifrado a partir del tercer bloque haciéndolo identificable y tremendamente atacable pudiendo ir a buscar directamente la clave.
- Juntando ambos casos, si dos textos en claro, cifrados con claves distintas, aunque no coincidan totalmente, empiezan por los mismos bloques estamos fritos.

Muy, muy difícil

A partir del bloque recien descifrado obtenemos por XOR la modificación (16 dígitos significativos módulo 32) de la parte "aleatoria" que la cifró. Es en teoría posible aunque complicado encontrar los posibles elementos de la secuencia que pudieran generar ese valor y, desde él, los generadores que podrían corresponder al bloque anterior. El proceso habría que repetirlo hacia atrás para cada bloque que se averigüe.

Casi va a ser más fácil atacar por fuerza bruta la clave (que es cortita) directamente que eso. De momento habrá que conformarse con el descifrado parcial.

El PRNG y la periodicidad

La periodicidad de los PRNGs aparece antes o después cuando el resultado de una generación se toma como semilla para la siguiente. Pero en el caso que nos ocupa, si lo he entendido bien, la semilla se forma con cada bloque de texto (la primera vez con la clave), de manera que quizá no haría falta utilizar un número tan grande (2**64) para hacer la congruencia, lo que eliminaría la necesidad de herramientas que manejen enteros largos, y aumentaría la eficiencia. Corregidme si me equivoco.

Más probable es que encontremos bloques dobles repetidos en el texto, como bien señala sqrmatrix

Una posible mejora

Es desligar la clave del tamaño del bloque o incrementar éste. Para ello habría que cambiar la conversión a numérico del bloque. En lugar de concatenar cifras (otra vulnerabilidad puesto que los dígitos pares -desde 0- serán siempre sólo 0,1,2 o 3) puede usarse fórmulas como Suma((K[i]+1)*10**i)=K[0]+1 + 10*(K[1]+1) + 100*(K[2]+1) +...+ 10**L*(K[L]+1), que nos permitan claves (y por tanto bloques) arbitrariamente más largos.

opinar

Texto puro

  • No se permiten etiquetas HTML.
  • Las direcciones de las páginas web y las de correo se convierten en enlaces automáticamente.
  • Saltos automáticos de líneas y de párrafos.
By submitting this form, you accept the Mollom privacy policy.