El post del otro día

Hace ya tiempo que venía pensando en poner un post cifrado (GPG con clave simétrica) en Security Art Work para ver quién era capaz de romperlo, pero esto me planteaba dos problemas: si nadie lo rompía -que confío en que sea lo normal-, todos íbamos a decir que vaya reto más complicado… y si alguien era capaz de descifrarlo me empezaría a asustar :) Así que decidí incorporar algún tipo de pista que hiciera fácil el romper el post cifrado. Para no andar con adivinanzas raras, del tipo «la clave es la fecha de nacimiento de Phil Zimmermann XOReada con el número de seguidores del blog a fecha 15/04/2009 y restándole 3«, pensé que lo mejor era meter la clave de cifra en el propio mensaje cifrado. Pero esto tenía una complicación: dado un texto en claro y una clave de cifra, yo no sé si el mensaje cifrado contendrá una cadena concreta, en este caso la correspondiente a la clave… ¿o sí?

La verdad es que hace muchos años, tras leer el «Applied Cryptography» de Bruce Schneier, me dí cuenta de que ni tenía ni seguramente jamás conseguiría la base matemática suficiente para aprender criptografía «en serio»; era un tema que me interesaba pero, dentro de la seguridad, no era para mí lo más apasionante… Por tanto, a partir de ese momento he sido un simple usuario de aplicaciones de cifrado, con unos conocimientos básicos de criptografía o criptoanálisis para poder hablar del tema tomando un café pero por supuesto sin poder ir más allá. Vamos, que cuando Jorge Ramió habla de ataques complejos sobre el algoritmo lo-que-sea me quedo con la boca abierta :) Así, tras más de quince años usando PGP/GPG, la verdad es que jamás me había planteado nada más allá de su uso habitual: cifra, firma, anillos, confianzas y demás… pero nunca es tarde :)

Vamos allá. ¿Cómo meter la propia clave de cifra en el mensaje cifrado usando GPG? El RFC 1991 define los formatos de intercambio de mensajes PGP; para el formato ASCII Armor, el que iba a usar, se marcan seis campos:

  • Línea de cabecera (cinco guiones, «-«, la cadena «BEGIN PGP MESSAGE» y cinco guiones más en nuestro caso).
  • Cabeceras (versión de la aplicación y similares, en nuestro caso algo del tipo «Version: GnuPG v1.4.6 (GNU/Linux)»).
  • Línea en blanco.
  • Datos cifrados con formato ASCII-Armored.
  • Checksum.
  • Línea de fin (en nuestro caso, cinco guiones, «-«, la cadena «END PGP MESSAGE» y cinco guiones más).

Los campos que a priori desconocemos son únicamente los correspondientes a los propios datos cifrados y al checksum del mensaje; por tanto, para usar como clave de cifra algo que sepa de antemano que estará en el mensaje cifrado, no tengo más que elegir una clave ubicada los restantes campos: «END PGP», «—–«, «P MESSAGE-«, «nuPG v1.4» o similares… Demasiado fácil, ¿no? Si me planteo un ataque, con elegir claves de longitud variable a partir de estos campos tengo más que suficiente…

Lo siguiente sería conseguir una clave de cifra que esté en los propios datos cifrados; los ocho primeros caracteres de este campo son «adivinables», ya que marcan detalles como protocolo de cifra, versión, etc. necesarios para el descrifrado (por cierto, si alguien tiene información de qué es cada uno de los campos, le agradecería que me la enviara, que tengo curiosidad y en San Google no he encontrado nada «digerible» ;) También muy fácil seleccionar claves de esta cadena y empezar a probar por fuerza bruta… Lo interesante es meter la clave de cifra en los datos del cuerpo/checksum no predecibles -al menos por mí-. ¿Cómo? Pues también por fuerza bruta :)

Tenemos un texto -sí, el del post del otro día, bastante antiguo- en un fichero «monkeys»:

$ cat monkeys
I LIKE MONKEYS
I like monkeys.

The pet store was selling them for five cents a piece. I thought that
odd since they were normally a couple thousand each. I decided not to
look a gift horse in the mouth. I bought 200. I like monkeys.

I took my 200 monkeys home. I have a big car. I let one drive. His
name was Sigmund. He was retarded. In fact, none of them were really
bright. They kept punching themselves in their genitals. I laughed.
Then they punched my genitals. I stopped laughing.

I herded them into my room. They didn't adapt very well to their new
environment. They would screech, hurl themselves off of the couch at
high speeds and slam into the wall. Although humorous at first, the
spectacle lost its novelty halfway into its third hour.

Two hours later I found out why all the monkeys were so inexpensive:
they all died. No apparent reason. They all just sorta' dropped dead.
Kinda' like when you buy a goldfish and it dies five hours later. Damn
cheap monkeys.

I didn't know what to do. There were 200 dead monkeys lying all over my
room, on the bed, in the dresser, hanging from my bookcase. It looked
like I had 200 throw rugs.

I tried to flush one down the toilet. It didn't work. It got stuck.
Then I had one dead, wet monkey and 199 dead, dry monkeys.

I tried pretending that they were just stuffed animals. That worked for
a while, that is until they began to decompose. It started to smell real
bad.

I had to pee but there was a dead monkey in the toilet and I didn't want
to call the plumber. I was embarrassed.

I tried to slow down the decomposition by freezing them. Unfortunately
there was only enough room for two monkeys at a time so I had to change
them every 30 seconds. I also had to eat all the food in the freezer so
it didn't all go bad.

I tried burning them. Little did I know my bed was flammable. I had to
extinguish the fire.

Then I had one dead, wet monkey in my toilet, two dead, frozen monkeys in
my freezer, and 197 dead, charred monkeys in a pile on my bed. The odor
wasn't improving.

I became agitated at my inability to dispose of my monkeys and to use the
bathroom. I severely beat one of my monkeys. I felt better.

I tried throwing them way but the garbage man said that the city wasn't
allowed to dispose of charred primates. I told him that I had a wet
one. He couldn't take that one either. I didn't bother asking about the
frozen ones.

I finally arrived at a solution. I gave them out as Christmas gifts. My
friends didn't know quite what to say. They pretended that they like
them but I could tell they were lying. Ingrates. So I punched them in
the genitals.

I like monkeys

$

¿Cómo cifrarlo con una cadena que esté en el texto cifrado? Pues vamos probando… meter una clave de un carácter es inmediato, y por supuesto conforme incrementamos la longitud, la cosa cuesta más:

$ cat encode
#!/bin/sh

if [ $# -ne 2 ]; then
echo "Uso: $0 fichero password"
exit -1
fi

/bin/false
while [ $? -ne 0 ]; do
if [ -f $1.asc ]; then
rm $1.asc
fi
gpg --batch --passphrase $2 -c -a $1
grep $2 $1.asc 2>&1 >/dev/null
done
$
$ time ./encode monkeys a

real 0m0.016s
user 0m0.008s
sys 0m0.000s
$ time ./encode monkeys a1

real 0m0.064s
user 0m0.036s
sys 0m0.028s
$ time ./encode monkeys a1j

real 0m0.177s
user 0m0.108s
sys 0m0.068s
$ time ./encode monkeys a1j6

real 0m29.941s
user 0m17.441s
sys 0m12.473s
$ time ./encode monkeys a1j69

real 10m13.857s
user 5m49.878s
sys 4m16.124s
$

Vemos que si usamos una clave de cinco caracteres ya cuesta generar el texto cifrado diez minutillos… ¿Qué tal si intentamos usar una clave de seis caracteres?

$ time ./encode monkeys a1j69c

real 340m52.839s
user 174m31.662s
sys 115m46.658s
^C
$

Me parece que la probabilidad ya empieza a ser muy baja… 340 minutos y siguiendo para bingo… mejor hacemos Control-C y nos quedamos con una clave de cinco caracteres…:) Esto nos da una idea de la longitud que más o menos puede tener la clave del post cifrado.

¿Cómo romper la cifra? Podemos intentar atacar al algoritmo CAST5, el usado por defecto por GPG para cifrado simétrico, pero no creo que esta línea sea muy provechosa… otra opción es atacar a las personas para obtener la clave, línea que directamente no recomiendo porque en este caso el afectado sería yo. Más sencillo: si alguien me hubiera pedido la clave se la habría dado… a fin de cuentas tampoco se esconde aquí ningún secreto. Pero por supuesto, lo realmente interesante del mensaje cifrado no era cómo romperlo, ya que con la pista de la clave metida en el post era más que suficiente (alguna otra era para despistar ;), sino simplemente pasar el rato y aprender un poquito más de GPG. Este script «rompe» la cifra en unos segundos, muchos menos de lo que cuesta generarla:


$ cat decode
#!/bin/sh
if [ $# -ne 1 ]; then
echo "Uso: $0 fichero.asc"
exit -1
fi
content=`cat $1|tr -d '\n\'`
len=`echo $content|wc -c`
for l in 1 2 3 4 5 6 7 8; do
i=1
while [ $i -le $len ]; do
KEY=`expr substr "$content" $i $l`
i=`expr $i + 1`
gpg --batch --passphrase $KEY -d $1 >$1.clear 2>/dev/null
if [ $? -eq 0 ]; then
##cat $1.clear
echo "CLAVE: $KEY"
exit 0
fi
done
done
$ time ./decode monkeys.asc
CLAVE: a1j69

real 1m17.165s
user 0m45.747s
sys 0m30.230s
$

En poco más de un minuto hemos averiguado la contraseña…Por eso el «premio» era sólo una cerveza ;) Espero que al menos se hayan entretenido una horita… para la próxima, si ponemos un mensaje cifrado con GPG sin pistas y alguien lo rompe, habrá una recompensa más importante (nuestra o de algún otro, seguro).

Comments

  1. Cierto que las pistas podian ayudar o no, ya que la clave de cifra no es ni siquiera una palabra propiamente dicha sino una cadena de carafteres, trampa :P

  2. Antonio Villalon says

    Hola xavitxus
    Yo no dije que la clave fuera una palabra, sólo que estaba en el post }:)

  3. Cierto, pido disculpas, un par de posts muy buenos lo que no acabo de comprender es como consigues emplear parte del texto cifrado como clave de cifra.

  4. Antonio Villalon says

    Hello Xavitxus
    Por fuerza bruta :)
    Selecciono una clave de cifra y voy cifrando con ella hasta que -aleatoriamente- la propia clave aparece en el texto cifrado… por eso con seis caracteres la probabilidad de «casualidad» ya empieza a ser bajita y me quedo con la de cinco :)
    Saludos
    T

  5. Creo, querido Toni, que no he sido el único que no entendió como consigues utilizar una parte del texto cifrado como clave de cifra, por lo que obviamente no se trata de un problema de comprensión lectora sino de expresión escrita ;)

  6. Vale Toni ya tengo claro como lo haces, otra duda que tengo es porque GPG te permitio usar claves de cifra menores de 5 caracteres ASCII pues el minimo para la clave de cifra de CAST5 son 40bits (5 caracteres ASCII).

  7. A mí me ha costado un buen rato entender como avanzaba el bucle while, hasta que me he dado cuenta que el texto cifrado cambia aunque se use la misma contraseña y el mismo texto. El algoritmo lo condimentará con algo de sal ;)

  8. Antonio Villalon says

    Hola xavitxus
    Con la longitud de la clave de cifra se hará algún tipo de padding o similar hasta completar la longitud mínima, no tengo claro el detalle pero seguro que está documentado; permite sin problemas claves de longitud menor.

    Saludos
    T

  9. Antonio Villalon says

    Hola José Luis
    Efectivamente, el texto cifrado cambia a pesar de usar una clave fija y un texto en claro fijo, para evitar así ciertos ataques :)

    Saludos
    T