Hasta ahora
estareis acostumbrados a encontrar programas y algoritmos que encriptan cosas.
Os piden un password, se lo dais, y ya está, os encriptan lo que sea. Luego,
cuando quereis recuperar la información necesitais el mismo password para poder
desencriptar. Estos programas se basan en criptografia de clave simétrica, o
sea, la clave que necesitas para encriptar y para desencriptar es la misma.
Afortunadamente, estos no son los únicos tipos de algoritmos de encriptación
que existen. Existen otros algoritmos de encriptación en los que la clave que
necesitas usar para encriptar y la que necesitas usar para desencriptar no son
la misma, y además no puedes calcular una a partir de la otra si no dispones de
datos adicionales. Este tipo de algoritmos son los llamados algoritmos de clave
pública.
Si tú quieres
comunicarte con un amigo que vive lejos usando un canal no seguro (por ejemplo,
internet, donde cualquiera te puede sniffar la conexion y ver los datos que
circulan) te puede interesar enviar las cosas encriptadas. Que pasa si encriptas
los datos a enviar con una clave simétrica? Pues que tu amigo necesita conocer
esta misma clave para poder desencriptar los datos que le lleguen... y... cómo
le haces llegar la clave de forma segura? :-? La única forma sería que se la
dieras tú en persona, así seguro que nadie la chafardea... pero muchas veces
eso no es posible (por ejemplo, a tus amigos del IRC no los ves nunca en
persona). Por eso se han desarrollado estos otros algoritmos de clave pública.
En este caso, tu amigo te enviaría su clave pública, tú encriptarias los
datos con la clave pública, y se los enviarías. Nadie, salvo quien tiene la
clave privada correspondiente a esa clave pública será capaz de desencriptar
los datos. Estos algoritmos se construyen de forma que dada una clave pública
sea IMPOSIBLE obtener la clave privada correspondiente. Así que si tu amigo se
ha guardado la clave privada bien guardada, los datos que tú le envies
encriptados con su clave pública sólo los podrá leer él, que es el único
que tiene la clave privada correspondiente. Con esto ya aseguras que sólo el
destinatario (tu amigo) puede leer lo que tú has encriptado para él. Y que
pasa si alguien captura la clave pública cuando tu amigo te la enviaba a ti?
pues nada, sólo podra enviar info encriptada a tu amigo pero a partir de la
clave pública no podrá calcular la clave privada y, por tanto, no podrá
desencriptar los datos que tú envíes a tu amigo. De esta forma, cualquiera que
tenga la clave pública de tu amigo (por ejemplo tú) le puede enviar datos sin
temor a que alguien los pueda chafardear, ya que el único que podrá ver los
datos será tu amigo... Y no necesitas un canal seguro para obtener la clave, ya
que la clave que te envia tu amigo sólo sirve para encriptar, y aunque la
capturen no podrán leer los datos que tú le envias a tu amigo...
Ahora os voy a presentar un mundo un poco extraño, donde las matemáticas que conoceis no funcionan como esperais... Es un mundo donde vamos a trabajar siempre "módulo n", o sea, un mundo donde se cuenta 0, 1, 2, 3, 4, ..., n-2, n-1, 0, 1, 2, 3, ... Como se opera en este mundo? Pues fácil:
(n-1)
+ 1 == n == 0
2 * (n-2) == 2n-4 ==
(n-4)
4 - 8 == -4 == (n-4)
42 == 16
(23)2
== 2(3*2) == 26 == 64
Si os fijais,
operar en este mundo es como hacerlo normalmente con los números enteros sólo
que cuando el número da más grande que n-1 o da más pequeño que 0, pues se
le suma o se le resta n tantas veces como sea necesario hasta que salga un número
comprendido en el rango [0..n-1]. Las propiedades de las operaciones +,-,*,/,^
se cumplen igualmente. Ah! y n es un número entero que fijaremos al principio.
Si no fijamos n no podemos hacer gran cosa ya que el mundo no estará
completamente definido... Este maravilloso mundo tiene un problema, y es... cómo
se divide? :-? imaginemos que queremos dividir 4/2... esto es sencillo, da 2.
Pero las cosas se complican si dividimos 4/3. Cuanto da eso? Pues bien, la forma
habitual de entender la división en este mundo es tratarla como el producto por
el inverso... el qué? el inverso, sí... el inverso de un número es aquel otro
número tal que el producto de ambos da 1. Por ejemplo, el inverso de 1 (yo lo
escribiré 1-1) es 1 ya que 1*1==1 pongamos que queremos encontrar el
inverso de 3 módulo 10... pues será aquel número t tal que (3 * t)
mod 10 = 1 ... veamos... mmmmm... t = 7! Comprobemoslo: 3*7==21==11==1
sip! 7 es 3-1 en el mundo "módulo 10"... Si en este mundo
queremos hacer 4/3 sólo hemos de hacer 4*(3-1) o sea, 4*7=28=18=8...
así que 4/3 en este mundo da 8. Quien lo iba a imaginar, eh? Ahora faltaria que
8*3 diera 4 para que se cumplan las propiedades que conocemos... a ver...
8*3==24==14==4 anda, pues sí!
Vale, ya sabemos
dividir... bueno, siempre que sepamos calcular el inverso de un número...
mmmmm... calcular inversos parece un problema complicado... realmente lo es?
pues... depende de las circunstancias... El inverso de un número depende del
mundo en el que estemos trabajando, o sea de la n del mundo "módulo
n" en el que juguemos... Para cada n, el inverso de un número
puede variar. Además, para calcular el inverso de un número en un mundo de
estos, la cosa puede ser muy muy complicada, ya que hasta el momento sólo se
sabe calcular el inverso de un número módulo n si n es primo o
si sabemos escribir n como producto de números primos. En cada mundo
"módulo n" existe un número f(n) tal que cualquier número
en el rango [0..n-1] elevado a f(n) es igual a 1, o sea, que para
todo x se tiene que xf(n) == 1 mod n. Si
nos fiajmos, tenemos que x * xf(n)-1 == 1, así
que parece que si multiplicamos x por xf(n)-1
obtenemos 1... y eso es precisamente lo que ha de cumplir un inverso! :-) Así
que si somos capaces de calcular f(n) podemos calcular el inverso de
cualquier número simplemente haciendo xf(n)-1... Qué
fácil, nop? :-) Pues bien, en caso de que n sea un número primo, no es
difícil calcular f(n). Simplemente, f(n)=n-1. Si n
lo podemos escribir como producto de números primos, hay un teorema (el teorema
chino de los restos) que nos permite obtener el inverso a partir de calcular el
inverso en cada uno de los mundos "módulo qi" donde
qi son los factores primos de n. Por ejemplo, si n
= p * q, se llega a que f(n)=(p-1)*(q-1). Sólo
hemos de conocer la descomposición de n en factores primos para calcular
f(n) y poder así calcular el inverso de cualquier número en ese mundo
"módulo n". En caso de que no sepamos factorizar n, la
única forma de encontrar el inverso de un número "módulo n"
es provando todos los números entre el 2 y el (n-1) a ver cuál de ellos
cumple que multiplicado por el número original el resultado sea 1 mod n.
Hasta aquí os
gusta el mundo?? ... no?? pues los algoritmos de clave pública existen gracias
a este mundo y otros similares. Ya que os habeis tragado todo este rollo matemático
voy a explicaros un algoritmo que funciona en ese mundo para conseguir que la
clave con la que encriptas y la clave con la que desencriptas sean diferentes.
Suponte que cojes
un número (m) y lo elevas a otro número (e):
me
== c mod n (n es primo)
c
es el resultado de esa operacion. A partir de c, como obtienes m??
pues veamos:
sabemos que (me)d == m(e*d)
vale, pues a partir de esto, si encontramos un d tal que e*d==1
mod n ya tenemos la forma de desencriptar: cd == (me)d
== m(e*d) == m1 == m
mod n o sea, elevamos c a d y obtenemos m... y d
y e son dos números tal que e*d==1 mod n, pero no
tienen por que ser iguales. Si m fuera un trozo de un mensaje que
queremos encriptar, el mensaje encriptado obtenido (c) se consigue usando
una clave (e) distinta de la clave que necesitamos para recuperar el
mensaje original (d).
Así que en este caso, m serian los datos a enviar, {e,n} la clave pública, {d,n} la clave privada, y c lo que envias por internet a tu amigo, o sea, el mensaje encriptado! :-) Como ves, d y e no son iguales! Así que aunque tu amigo te envie e y alguien lo vea, no pasa nada, porque no podrá obtener m a partir de tener c, e y n... necesita d! :-) y como calculamos d?? pues... en este caso es fácil: e*d == 1, o sea, d == 1/e, es decir, d == 1*(e-1) == e-1 si podemos calcular el inverso de e ya tenemos d... y el inverso de d se puede calcular fácilmente porque n es primo! :-) vaya... pero... yo sólo he necesitado n y e para calcularlo... así que... cualquiera lo puede calcular! :-( Eso no es lo que yo queria... Parece que cualquiera que pueda ver e podrá calcular d y entonces podrá descifrar mi mensaje c! :-( Eso no es lo que dije antes, verdad?? Dije que teniendo e no se tenia que poder calcular d... Así que todo lo que hemos hecho no sirve para nada?? Deberiamos tratar de arreglar un poco esto para que no sea tan fácil calcular d a partir de e! Y cómo hacemos para que sea más difícil el cálculo de d?? pues... haciendo que n no sea primo... :-) Hagamos que n sea realmente el producto de dos números primos p y q, y que nadie más que la persona que ha de recibir el mesaje conozca p y q... a partir de n sólo se puede encontrar p y q si factorizas, pero factorizar es un problema también muy difícil del que luego hablaré un poco. Ahora veamos cómo queda modificado el algoritmo que teníamos si n deja de ser primo:
como n no es primo, ya no es cierto que f(n)=n-1, y en su lugar, lo que se cumple es que f(n)=(p-1)*(q-1), así que suponiendo que c==me, hemos de conseguir un d tal que cd==m, o sea, que (me)d==m, o lo que es lo mismo, que m(e*d)==m, o sea, que e*d==f(n)+1 Y como obtenemos d?? pues fácil, e*d==1 mod f(n), así que d==1/e==e-1 mod f(n), y para calcular d ahora necesitamos pode calcular f(n)=(p-1)*(q-1), o sea, necesitamos conocer p y q, cosa que sólo conoce el receptor, ya que aunque n=p*q nadie es capaz de factorizar un número muy grande en sus dos factores, y si no te lo crees, intenta factorizar este pequeño n de sólo 20 cifras, y obtener sus dos factores p y q... ;-)
66024717357306257987
Por cierto, el
hecho de que se use un n producto de sólo dos números primos es porque
cuantos más factores tenga n, más fácil es de factorizar. Me explico,
si n=p*q se sabe que o bien p o bien q estará
por debajo de sqrt(n) (o sea, raíz cuadrada de n), en cambio si n=p*q*r
lo que se sabe es que alguno de los tres factores está por debajo la raiz cúbica
de n, que es un número aún menor que sqrt(n). Así que para
factorizar n basta con probar a dividirlo por números más pequeños que
ese límite que se conoce. Y el límite preferible es sqrt(n), que es
mayor que la raiz cúbica y, por tanto, obliga a hacer más pruebas para
factorizar n. Es por eso que se usa un n compuesto únicamente de
dos factores primos p y q.
Otra cuestión respecto a los números primos
escogidos para generar n es que han de estar muy separados, o sea, que (p-q)
sea un número grande ya que sino existen ataques que permiten factorizar n.
También es importante que p-1 y q-1 sean números que tengan
ambos por lo menos un factor primo muy grande ya que, en caso contrario, también
es muy sencillo factorizar n.
RSA es uno de estos algoritmos de clave pública que se basan en lo que os he explicado en el apartado anterior. Su funcionamiento es muy simple:
Se eligen 2 números primos, llamemosles p y q.
Se calcula n=p*q.
Se escoge un número
e en el rango [2..n-1] que cumpla ciertas cosas. Para que el inverso
de e sea difícil de calcular, e no puede valer 1 (el inverso
de 1 es 1) ni tampoco puede ser múltiplo de (p-1)*(q-1), ya
que calcularemos d como e-1 en el mundo "módulo
(p-1)*(q-1)", y si e es múltipo de (p-1)*(q-1)
tendriamos que e==0 en ese mundo, así que no podríamos calcular su
inverso! :-( [dime un número que multiplicado por 0 de 1 en el mundo módulo
(p-1)*(q-1), o lo que es lo mismo, dime cuanto vale 1/0 en ese
mundo...].
Ahora se
calcula d == e-1 mod ((p-1)*(q-1)).
Como os dije antes, hay un teorema que permite calcular esta d sin
problemas, sólo que necesitamos conocer p y q.
La clave pública
es {n,e} y la privada es {p,q,d} Así que tú
le pides a tu amigo, al que quieres enviar datos, su clave pública, y él te
envia {n,e} a tí... Tú ahora, codificas tu mensaje como una tira
de números entre 0 y n-1 y a cada número m le aplicas c =
me mod n y envias cada uno de esos números c
después de aplicarles la operación. Ahora tu amigo recibe cada número y hace m
= cd mod p*q (o sea, mod n ya que n=p*q)
y obtiene los números originales entre 0 y n-1 que son en realidad tu
mensaje desencriptado. Supongamos que en este proceso alguien captura lo que
circula por la red, o sea, {n,e} y c. Qué puede hacer??
:-? Pues realmente nada: Necesita d para poder desencriptar los datos c,
y para calcular d necesita tener e y saber los 2 factores en los
que se descompone n. O sino, puede intentar calcular m como la
raiz e-ésima de c módulo n, pero eso también es un
problema muy difícil. Así que, este sistema, en qué basa su seguridad?? pues
en 2 cosas:
Si tienes n que es producto de dos primos p y q, has de factorizar para poder obtener p y q, y factorizar es un proceso muy lento (has de ir provando a hacer divisiones y mirar si te da 0 de resto o no), así que si n es lo bastante grande, necesitarás millones de años y el ordenador más potente del mundo para encontrar los dos factores p y q.
Calcular la raiz e-ésima de c para obtener m en el mundo "módulo n" es algo también muy difícil, y sólo se saben calcular raices de una forma fácil si conoces la factorización de n o si n es primo.
Pues bien, este algoritmo que os he explicado es el RSA. Es un algoritmo que está patentado en USA (o sea, que para implementarlo y usarlo has de pagar derechos), pero que es libre en el resto del mundo, es decir, que si no vives en USA puedes usarlo sin problemas. Este algoritmo se lo inventaron tres señores cuyos apellidos eran Rivest, Shamir y Adleman, así que le pusieron de nombre las iniciales de sus apellidos: RSA. Como veis, eran muy poco originales! :-)
Hay varios programas que se basan en todo esto que he explicado para encriptar/desncriptar. El más popular es probablemente el PGP. PGP es un programa que te permite encriptar algo con la clave pública de los receptores a los que va destinado y desencriptar con la clave secreta si es que tú eres el receptor de un mensaje cifrado. Encriptar usando algoritmos de clave pública tiene 2 inconvenientes:
Es un proceso lento: Elevar un número a otro y luego hacer el módulo n es un proceso lento, muy lento, por tanto es mucho más rápido encriptar con métodos de clave simétrica.
Sólo un único destinatario podrá leer el mensaje: O sea, sólo la persona que tiene la clave privada necesaria será capaz de leer el mensaje, así que si quieres enviar un mismo mensaje a varios amigos, tendrás que encriptarlo una vez para cada uno de tus amigos con su clave pública y enviar a cada uno el mensaje encriptado que son capaces de desemcriptar.
Estos dos
inconvenientes se pueden solucionar fácilmente, tal y como lo hace el PGP. En
lugar de encriptar el mensaje con un algoritmo de clave pública, lo encripta
con un algoritmo de clave simétrica usando como clave simétrica algo
absolutamente aleatorio e impredecible. A continuación, encripta la clave simétrica
que ha generado para encriptar usando las claves públicas de los destinatarios.
El resultado es un mensaje encriptado con una clave que nadie conoce, seguido de
esa clave, pero encriptada con la clave pública del destinatario. Si hay más
de un destinatario, se añanade la clave simétrica encriptada tantas veces como
destinatarios haya, encriptandola cada vez con la clave pública de uno de los
destinatarios del mensaje. Con esto, uno de los destinatarios del mensaje puede
desencriptar la clave simétrica (una de las copias encriptadas que hay va
destinada a él así que está encriptada con su clave pública) y con la clave
simétrica puede desencriptar el mensaje completo. De esta forma conseguimos
acelerar el proceso (encriptar con clave simétrica es muy rápido, y con clave
pública sólo se encripta la clave simétrica que es algo muy corto), y además
permitimos que varias personas puedan desencriptar el mismo mensaje cifrado (ya
que la clave simétrica necesaria para desencriptar el mensaje está encriptada
con la clave pública de cada receptor, y añadida al final del mensaje
encriptado). Así que un documento encriptado con PGP está formado por varias
partes:
mensaje original encriptado con IDEA, usando una clave K generada aleatoriamente en el momento de encriptar el mensaje.
K
encriptada con la clave pública RSA del receptor 1.
K
encriptada con la clave pública RSA del receptor 2.
Ahora, si os
fijais, la seguridad del sistema no sólo depende de que no se pueda hayar la
clave privada de alguno de los receptores del mensaje sino también de que no se
pueda encontrar K. Para ello, el algoritmo de clave simétrica que usemos
ha de ser robusto y seguro, y lo que usa PGP 2.6.x (es decir, IDEA)
lo es... al menos de momento. Y también ha de ser realmente impredecible la K,
es decir, hemos de poder generar números realmente aleatorios para formar la
clave K y que esos números no sean predecibles. Respecto a las claves públicas,
existen métodos para factorizar un n de forma rápida, basados en
propiedades matemáticas extrañas. De todas formas, aumentando el tamaño del número
n se consigue hacer que estos métodos sean muy muy lentos. Por eso se
recomiendan claves públicas en las que n sea un número de 512 bits, 768
bits, 1024 bits, o incluso 2048 bits si usas PGP 2.6.3i. Mi recomendación es
que useis una clave de 2048 bits, ya que actualmente se han conseguido
factorizar números de 129 digitos (512 bits aprox.) y se espera que pronto
caigan los de 768 bits. En realidad, es posible que alguna agencia en USA ya sea
capaz de factorizar 768 bits, ya que todas ellas invierten millones de dollares
en investigación sobre estos temas cada año, y, al contrario que en las
universidades, no comparten sus resultados con el resto del mundo. A nivel
civil, se cree que se podrán factorizar números de 1024 bits en el 2004, y de
2048 bits en el 2014 si es que no se descubre nada nuevo que suponga una
revolución en este campo... Es de suponer que los militares, la CIA, el FBI,
etc... nos llevan ventaja, así que ponerse una clave de 2048 es bastante
recomendable.
A ver, he intentado mantener a las matemáticas lo más alejadas posible de este documento, así que no os he hablado de ciertas cosas y no os he demostrado algunas propiedades, ya que lo que me interesa es que entendais la idea de cómo y porqué funciona, no que saqueis un 10 en las asignturas de álgebra o matemática discreta. Eso quiere decir que me he comido algunos detalles y que no he justificado ciertas cosas. Entre los detalles que no he mencionado es la forma en la que hemos de escoger p y q. No cualquier pareja de números primos nos sirve, ya que si se cumplen ciertas cosas, es fácil factorizar n... :-( Así que ya sabeis, si queréis conocer más detalles, leed libros serios sobre criptografía en los que no se ahorren esos detalles, o sino, haced la carrera de matemáticas! X-D
Por último,
deciros que últimamente han salido por ahí PGP 5.0 y 5.5, que no son
compatibles con 2.6.x ya que no usan los mismo métodos de encriptación que
2.6.x (o sea, no usan ni IDEA ni RSA). En su lugar usan un problema conocido
como "El Gamal" y encima no lo hacen en el mundo que os he explicado
("módulo n") sino en un mundo montado sobre Curbas Elípticas. Esto
les permite conseguir la misma seguridad que antes pero usando claves más
cortas (de menos bits). Además, este algoritmo no está patentado así que se
puede usar en cualquier sitio sin pagar derechos a nadie. El problema es que el
mundo de las Curbas Elípticas no está aún muy estudiado, y cualquier día
descubriremos que es más fácil moverse en ese mundo de lo que ahora parece, y
los métodos criptográficos basados en ese mundo dejarán de ser seguros. Se
le han encontrado algunos problemas a las Curbas Elípticas, pero hasta ahora
nada serio que comprometa la seguridad de los algoritmos de encriptación... de
todas formas, se llevan estudiando demasiado poco tiempo como para asegurar que
no tienen truco, por lo que de momento creo que es preferible usar PGP 2.6.3i
mejor que PGP 5.0 o 5.5 ya que RSA ha soportado muchos y muy variados ataques
que se han probado, y el mundo de los cuerpos finitos está mucho más estudiado
y se conoce mucho más a fondo y desde hace más tiempo. Además, la seguridad
de "El Gamal" no reside en la imposibilidad de factorizar un número o
en el cálculo de raices e-ésimas sino en que no sabemos calcular el logaritmo
discreto de un número en ese mundo. El problema de calcular un logaritmo
discreto se supone igual de difícil que el problema de factorizar, pero en el
caso del logaritmo discreto se sabe que existen funciones en ciertos mundos que
tranforman ese cálculo en calcular simplemente un inverso, cosa muy sencilla,
ya que aquí no hay que factorizar nada, con lo que hay que escoger el cuerpo
sobre el que se trabaja de forma muy cuidadosa para no sea posible hallar una de
esas funciones. Y el cuerpo que se ha escogido es uno que no conocemos mucho, o
sea, uno sobre una Curva Elíptica... así que saca tú tus propias conclusiones
sobre la seguridad que te puede ofrecer PGP 5.x.
Y como siempre,
las sugerencias, consultas o críticas destructivas que tengais las podéis
enviar a z3b4l@iname.com.
Y aquí teneis mi clave pública PGP 2.6.3i de 2048
bits por si me quereis enviar algo encriptado para que solamente yo pueda
desencriptarlo.
Tipo Bits/Clave Fecha
Identificador
pub 2048/4AE73665 1998/07/19 Zebal
<z3b4l@iname.com>
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: 2.6.3i
mQENAzWyABwAAAEIALS8PuClNEaEnhAfUxaM+sh8mgZGpJTNXvWGBC/J4VrNvDlC
IDDoYLbRkG5Fbf6fNG89oUI3SiottK7FJysKI28ZR3D4mfy1KIEhuCchlsW8ll+5
uHbEcn9exlJ5VXQYuxCRXkMsNurK5b0TSzvcejuFo55kNCpua8/pqv3o7WS12DS6
kuhCArRyfRMbS34T3IxLpvKPb8bXvW4iaA9Hnp3jlYotVdryQovJzfoOmSU7r/ZB
tbAy/2zNInNasgNwFnH5IjxrKkNlb3kVcHSAfoPrHjuusuBagoJRUJEwm4vAQ9MD
cEkejAwgS8rNkpoc+I2q9YQMLu5EqqhHzkrnNmUABRG0F1plYmFsIDx6M2I0bEBp
bmFtZS5jb20+iQEVAwUQNbIAHqqoR85K5zZlAQEJDwf/ZgFUK5rWGRZlF4Vlln6P
bbu7jSPySIiH08OJQzaV+W1oNK7ebGlmN60kypsr5h3FoDNxxhJ+hA0H10tMLOSY
b3pNxA2OOnQ6yh7KKWKSnySrP5xl4nuj9l3ZBPBGs8S8dtGQauNKPVhdVL0920KN
HtUCH1R28SHImnEI+KhNA3w07k384m8+8rQ8HLDuJgt3wK4PnLFdmXZX3w1kZ/Vt
ibqXW2eqsRoXTgwMLDORhDEpMxZmf6KYhlTMHEv9yyxq9yhzccZO4FjeUlGztZ2f
m2bDRYU5SfCUrXC1BBYWa2yOQyQ9qZ/FGl9wUWcv2mjHrPdjnhs64JRo89Bb7dJP
bA==
=/mJT
-----END PGP PUBLIC KEY BLOCK-----
(Hispahack 22-7-98) By Zebal