EDA

Anuncio
Proyecto de Criptografía
EDA
Encriptación y desencriptación de Archivos
Karina Escobar Vázquez
1. Introducción.
EDA es una aplicación que permite cifrar y descifrar archivos utilizando el algoritmo
AES. EDA esta implementada en el lenguaje java. Se selecciono razón por la que se
selecciono java como lenguaje de implementación es debido a que java nos
proporciona portabilidad ya es un lenguaje independiente de la plataforma.
AES (Advanced Encryption Standard) es un algoritmo simétrico con bloques de 128
bits y con llaves de 128 192 o 256 bits.
AES es el algoritmo que sustituye a DES. En 1976 el Gobierno de Estados Unidos
declaró a DES (Data Encryption Standard) como el algoritmo de encriptación
estándar para toda comunicación de datos no sensitivos, fue desarrollado por IBM
con la ayuda de la NSA (National Security Agency). Actualmente DES es el
algoritmo más utilizado. A mediados de 1998 una fundación en los Estado Unidos
denominada EFF (Electronic Frontiers Foundation) construyó un ordenador capaz
de descubrir la clave de DES en un tiempo promedio de 5 días.
Estos son algunas razones por la que NIST (National Institute of Standards and
technology) público las especificaciones para el algoritmo AES a finales de 1997. Los
participantes de esta competencia tenían que escribir código en los lenguajes de
programación ANSI-C y Java. NITS explico que los criterios para escoger el
algoritmo ganador serían en orden de prioridad las siguientes:
 Seguridad.
 Velocidad.
 Sencillez del diseño.
De los algoritmos que se recibieron fue elegido “Rijndael” que es un algoritmo
basado en el algoritmo SQUARE. Esto hace que Rijndael sea el nuevo algoritmo de
encriptación estándar para toda comunicación de datos no sensitivos como son:
dinero electrónico, negocios por Internet, correo electrónico por mencionar algunos.
Por esto se selecciono a AES como el algoritmo de Encriptación de EDA.
Rijndael presenta las siguientes ventajas:
Aspectos de implementación:
Puede ser implementado en Smart Card e una pequeña cantidad de código,
usando una pequeña cantidad de memoria Ram y tomando un pequeño número
de ciclos. Además con unos pequeños cambios se pude implementar en
memorias ROM.
Las rondas de transformación están diseñadas para su ejecución en paralelo,
esta es una ventaja importante ya que se podrá utilizar hardware dedicado.
Como el cifrado no se realiza usando operaciones aritméticas, este no tiene
predisposición hacia grandes o pequeñas arquitecturas de procesadores .
Simplicidad del diseño:
El cifrador no hace uso de otros componentes criptográficos, cajas S de otros
cifradores de buena reputación, obtención aleatoria de bits de tablas, dígitos de
, ya que el cifrador es completo y totalmente autocontenido.
El cifrador no basa su seguridad o parte de esta en el desconocimiento del
algoritmo o no entender la iteración entre las operaciones aritméticas, basándose
en la nueva filosofía de encriptación.
El fuerte diseño del cifrador no nos proporciona facilidades para esconder una
puerta trasera.
Extensiones:
El diseño permite la variación de la longitud del bloque y la longitud de la llave.
En un rango de 128 a 256 en variaciones de 32 bits.
2. Diseño.
2.1 Descripción
EDA es una aplicación que nos permite cifrar y descifrar archivos basándose en
una llave. Utiliza el algoritmo de encriptación AES. Ya que AES requiere una llave
para cifrar y descifrar se necesitan administrar las llaves de las personas con las
que se comparte la información, además de permitirnos generar llaves. La longitud
de llaves que maneja EDA es de 128 bits.
Para proporcionar una mejor seguridad EDA no guarda directamente el password
de los usuarios en su tabla, si no utiliza el password para generar después cifra un
plaintext predeterminado y el resultado de este cifrado es lo que guarda y se utiliza
para verificación del password. Con esto, cada vez que el usuario aceda al sistema
lo que se compara es la cifra obtenida con el cifrado del plaintext con el password
ingresado como llave, y lo que se guardo al momento de agregar al usuario al
sistema.
Diagrama de clases
EDA se diseño utilizando el paradigma de programación Orientada a Objetos esta
formada principalmente por los objetos EDA, criptógrafo, estado y llavero; la
forma en que interactúan estas clases se pueden visualizar en su arquitectura. La
arquitectura de EDA se realizó utilizando el diagrama de clases.
AES
private
private
private
private
EDA
private Llavero llaves;
private AES cripto;
private FILE out;
private FILE in;
public int valida(user, password);
public void cifra(user, password, arch);
public void descifra(user, password,
arch, salida);
public void agrega(user,password);
public void guardausuarios();
public void elimina(user,password);
public static void main( args) ;
public void obtenllave(user);
public void agregallave(user,arch);
byte[16] m ;
byte[4][44] w;
byte[4][44] dw;
byte[4][44] s;
public void iniciam(m);
public void iniciall(ll);
public byte[] eqinvcipher()
public byte[] invcipher()
private void shiftrows();
private void invshiftrows();
private void subbytes();
private void invsubbytes();
private void mixcolumns();
private void invmixcolumns( ronda);
private void addroundkey(ronda);
private void expansionkey();
private byte[] subword(a)
private byte multi( a, b);
SBOX
private byte[16][16] sbox;
private byte[16][16] invsbox;
public byte sboxvalor(ren, col);
public byte sboxinvvalor( ren,col);
private calculainv();
Llavero
private Hashtable usuarios;
private Hashtable llavero;
private AES cripto;
public int alta(user, password)
public int baja( user,password)
public byte[] obllave(user,password)
public agregallave(user,ll)
public int valida(user,password)
private boolean cmp (a,b)
Diagrama de clases de EDA
2.3.Cartas CRC (Clases-Responsabilidades- Colaboración)
Las cartas CRC nos permite ver la responsabilidad de cada clase y, que
clases son las que colaboran con ella para que cumpla con estas
responsabilidades. A continuación de muestra la carta CRC de cada una
de las clases que forman la aplicación EDA.
EDA
Responsabilidad
Cifra: cifra un archivo.
Descifra: descifra un archivo.
Valida: Valida un usuario.
Agrega: Agrega un usuario a la tabla de
usuarios.
Elimina: Elimina un usuario de la tabla de
usuarios.
Obllave: Obtiene la llave del usuario que
ingreso al programa.
Agregallave: Agrega una llave al llavero del
usuario.
Guardausuarios: Guarda la tabla de usuario
en disco.
Main: programa principal
Colaboración
AES
AES
Llavero
Llavero
Llavero
Llavero
Llavero
Ninguna
Ninguna
Carta CRC de EDA
AES
Responsabilidad
Iniciam:Inicia mensaje de 16 bytes
Iniciall:Inicia llave de 16 bytes
Cipher:Cifra un mensaje utilizando el
algoritmo AES
Eqinvcipher:Descifra mensaje utilizando
algoritmo equivalente a cifrado de AES
Invcipher:Descifra el mensaje utilizando
el algoritmo inverso del cifrado de AES
Shiftrows:Realiza el corrimiento de
columna para la implementación del
algoritmo AES
InvShiftrows:Realiza el inverso del
corrimiento de columnas para la
implementación del algoritmo AES.
Subbytes: Realiza la substitución de caja S
para la implementación del algoritmo AES.
Invsubbytes:Realiza la substitucion de
bytes con la caja inversa de S para la
implementación del algoritmo AES.
Mixcolumns: Realiza la mezcla de
columnas para la implementación del
algoritmo AES.
Invmixcolumns: Realiza el procedimiento
inverso de la mezcla de columnas.
Addroundkey: Realiza un xor de la matriz
estado con la sub-llave de la ronda.
Colaboración
Ninguna
Ninguna
Ninguna
Ninguna
Ninguna
Ninguna
Ninguna
SBOX
SBOX
Ninguna
Ninguna
Ninguna
Expansionkey: Realiza la expansión de la
llave para obtener las sub-llaves.
Subword:Reliza la sustitución de caja S
para la expansión de llave.
Rotword: Realiza una rotación de bytes
para la caja S.
multi: Realiza la multiplicación de dos
número en el campo binario 28.
Ninguna
Reduce: Reduce modulo x8+x4+x3+x+1
un número
Ninguna
SBOX
Ninguna
Ninguna
Carta CRC de Criptógrafo
Llavero
Responsabilidad
Alta: Da de alta a un usuario en la tabla de
usuarios y le genera su llave.
Baja: Da de baja a un usuario de la tabla
de usuarios y elimina su llavero.
Valida: Verifica si un existe un usuario en
la tabla de usuarios y verifica su password.
Obllave:Obtiene la llave de un usuario.
Agregallave: Agrega una llave al llavero
del usuario.
Cmp: Compara dos arreglos de bytes
Agregallave: Agrega llave al llavero del
usuario que esta utilizando el sistema.
Bajaotro: Elimina una llave del usuario
usuario que esta utilizando el sistema
Imprimellavero: Muestra el llavero del
usuario que acceso al sistema.
Imprimellavero: Muestra el llavero
principal
Obllaveotro:Obtiene la llave que
corresponde al identificador. La obtiene
del llavero del usuario
Colaboración
AES
Ninguna
AES
AES
Ninguan
Ninguna
Ninguna
Ninguna
Ninguna
Ninguna
Ninguna
Carta CRC de Llavero
SBOX
Responsabilidad
Sboxvalor: Regresa el valor
correspondiente a renglón, columna de la
caja S.
Sboxinvvalor:Regresa el valor
correspondiente a renglón, columna de la
caja inversa de S.
Colaboración
Ninguna
Ninguna
Calculasbox: Calcula la caja S.
Calculainvsbox: Calcula la caja inversa S.
Ninguna
Ninguna
Carta CRC de Estado
3. Implementación de EDA
En esta sección se muestran el pseudo código para cada método de las clases que
conforman EDA.
3.1 Clase EDA
Métodos:
Cifra()
1. Recibe el usuario, password y archivo a cifrar
2. Forma el nombre del archivo de salida arch.eda
3. Obtiene la llave del usuario
4. Carga la llave a la clase AES
5. Mientras (!EOF)
5.1 lee m de arch
5.2 aes.iniciam(m);
5.3 cifrado=aes.cipher();
5.4 escribe cifrado a arch.eda
6. Regresa.
Descifra()
1. Recibe usuario, password, archivo a descifrar, archivo de salida
2. Obtiene llave de usuario
3. Carga la llave a la clase AES
4. Mientras (!EOF)
4.1 lee m de arch
4.2 aes.iniciam(m);
4.3 descifrado=aes.invcipher();
4.4 escribe descifrado a salida
5. Regresa.
Agregar()
1. Recibe nombre de usuario y password
2. Da de alta al llavero llaves.alta(user,password)
3. regresa
Valida()
1. Recibe el nombre de usuario y password
2. int resul;
3. Llama a resul=llaves.valida(user,password);
4. regresa resul.
Obtenllave()
1. Recibe nombre del usuario al que pertenece la llave y nombre del archivo
donde se encuentra la llave.
2. Lee la llave del archivo
3. llaves.agregallave(usuario,llave);
4. regresa
Agregallave()
1. Recibe nombre del usuario del que se quiere obtener la llave
2. Obtiene la llave del llavero
3. Guarda la llave a un archivo
4. regresa
Elimina()
1. Recibe usuario y password
2. Elimina el usuario del llavero llaves.baja(user,password);
Regresa
Guardausuarios()
1. Escribe a disco el objeto llaves.
2. Regresa.
Nota: Si no se realiza esta operación los cambio hechos durante la sesión se perderán.
Main()
1. Recibe el usuario y password
2. Si usuarios valido
a. Muestra menú
i. Cifra archivo con mi llave
ii. Descifra archivo con mi llave
iii. Cifra Archivo con otra llave
iv. Descifra Archivo con otra llave
v. Elimina mi usuario
vi. Agrega llave a mi llavero
vii. Exporta mi llave
viii. Elimina una llave de mi llavero
ix. Imprime mi llavero
b. Obtiene opción
c. Ejecuta opción
3. Si el usuario no existe pregunta si se desea agregar
a. Si, agrega usuario
b. No, regresa
4. Si el password es incorrecto
a. Despliega mensaje informando que el password es incorrecto
b. Regresa
3.2 Clase AES
Métodos:
iniciam(m)
1. Recibe m
2. for i=0 to 3 i++
a. for j=0 to 3 j++
i. s[i][j]=m[4*j]
3. regresa
iniciall(ll)
1. Recibe ll
2. for i=0 to 3 i++
a. w[0][i]=ll[i*4]
b. w[1][i]=ll[i*4+1]
c. w[2][i]=ll[i*4+2]
d. w[3][i]=ll[i*4+3]
3. ExpansionKey()
4. Regresa
Cipher()
1. addroundkey(0,1)
2. for ronda=1 to 9 ronda++
a. subbytes()
b. shiftrows
c. mixcolumns()
d. addroundkey(ronda)
3. subbytes()
4. shiftrows()
5. addroundkey(10)
6. for (i=0 to 3 i++)
a. for (j=0 to 3 j++)
i. mcipher[I+4*j]=s[i][j]
7. regresa mpcipher
eqinvcipher()
1. addrounkey(10)
2. for (ronda=9 to 1 ronda--)
a. invsubbytes()
b. invshiftrows()
c. invmixcolumns()
d. addroundkey(ronda)
3. invsubbytes()
4. invshiftrows()
5. addrounfkey(0)
6. for (i=0 to 3 i++)
a. for (j=0 to 3 j++)
i. plaintext[I+4*j]=s[i][j]
7. regresa plaintext
Invcipher()
1. addroundkey(10);
2. for ( ronda=9; to ronda=1; ronda--)
a. invshiftrows()
b. invsubbytes()
c. addroundkey(ronda,1)
d. invmixcolumns()
3. invshiftrows()
4. invsubsytes()
5. addroundkey(0)
6. for (i=0 to 3 i++)
b. for (j=0 to 3 j++)
i. plaintext[I+4*j]=s[i][j]
7. regresa plaintext
shiftrows()
1. for (int i=1 to i<=3 i++)
a. for (int j=0 to j<i j++)
i. tem[j]=s[i][j];
b. for(int j=0 to j<(4-i) j++)
i. s[i][j]=s[i][i+j];
c. for(int j=0 to j<i j++)
i. s[i][4-i+j]=tem[j]
2. regresa
invshiftrows()
1. for (int i=1 to i<4 i++)
a. for (int j=0 toj<(4-i) j++)
i. tem[j]=s[i][j]
b. for(int j=0 toj<i j++)
i. s[i][j]=s[i][4-i+j]
c. for(int j=0 to j<(4-i) j++)
i. s[i][i+j]=tem[j]
2. Regresa
Subbytes()
1. for(int i=0 to i<=3 i++)
2. for (int j=0 to j=3 j++)
a. Obtenmos la parte baja col=s[i][j]& 0x0F;
b. Obtenemos la parte baja ren=(s[i][j]>>4) & 0x0F
c. Substituimos por el valor de la caja s, s[i][j]=box.sboxvalor(ren,col)
3. regresa
invsubbytes()
1. for(int i=0 to i<4 i++)
2. for (int j=0 to j<4 j++)
a. col=s[i][j]& 0x0F;
b. iren=(s[i][j]>>4) & 0x0F
c. s[i][j]= box.sboxinvvalor(ren,col)
4. regresa
mixcolumns()
1. for (int i=0 to i<4 i++)
a. ss[0]=((multi(2, s[0][i]))+(multi(3, s[1][i]))+ s[2][i]+ s[3][i])
b. ss[1]=(s[0][i]+(multi(2, s[1][i]))+(multi(3, s[2][i]))+ s[3][i])
c. ss[2]= (s[0][i]+s[1][i]+(multi(2, s[2][i]))+(multi(3, s[3][i])))
d. ss[3]= ((multi(3, s[0][i]))+s[1][i]+ s[2][i]+(multi(2, s[3][i])))
e. for (int j=0 to j<4 j++)
i. s[j][i]=ss[j];
2. regresa
invmixcolumns(ronda)
1. Recibe la ronda
2. for (int i=0;i<4;i++)
a. ss[0]=(byte)((multi(e,dw[0][ronda*4+i])) + (multi(b,dw[1][ronda*4+i]))+
multi(d,dw[2][ronda*4+i])) + (multi(9,dw[3][ronda*4+i])))
b. ss[1]=(byte)((multi(9,dw[0][ronda*4+i])) + (multi(e,dw[1][ronda*4+i]))+
(multi(b,dw[2][ronda*4+i]))+ (multi(d,dw[3][ronda*4+i])))
c. ss[2]=(byte)((multi(d,dw[0][ronda*4+i])) + (multi(9,dw[1][ronda*4+i]))+
(multi(e,dw[2][ronda*4+i])) + (multi(b,dw[3][ronda*4+i])))
d. ss[3]=(byte)((multi(b,dw[0][ronda*4+i])) + (multi(d,dw[1][ronda*4+i]))+
(multi(9,dw[2][ronda*4+i])) + (multi(e,dw[3][ronda*4+i])))
e. for (int j=0 to j<4 j++)
i. s[j][i]=ss[j];
3. regresa
addroundkey(ronda)
1. Recibe la ronda
2. for (int c=0 toc<4 c++)
a. for (int r=0 to r<4 r++)
i. s[r][c]=(s[r][c]+w[r][ronda*4+c]); /*xor de la matriz s con la
subllave*/
3. Regresa
expansionkey()
1. byte[][] rcon={{1,0,0,0},{2,0,0,0}, {4,0,0,0},{8,0,0,0},{10,0,0,0},{20,0,0,0},
{40,0,0,0},{80,0,0,0},{0x1B,0,0,0},{36,0,0,0}};
2. for (int i=4 to i<44 i++)
a. tem[0]=w[0][i-1] ;
b. tem[1]=w[1][i-1] ;
c. tem[2]=w[2][i-1] ;
d. tem[3]=w[3][i-1] ;
e. if ((i mod 4)=0)
i. tem=subword(rotword(tem));
ii. tem[0]=(tem[0] + rcon[(i/4)-1][0]);
iii. tem[1]=(tem[1]+ rcon[(i/4)-1][1]);
iv. tem[2]=(tem[2]+ rcon[(i/4)-1][2]);
v. tem[3]=(tem[3] + rcon[(i/4)-1][3]);
f. w[0][i]=(w[0][i-4]+ tem[0]);
g. w[1][i]=(w[1][i-4]+ tem[1]);
h. w[2][i]=(w[2][i-4]+ tem[2]);
i. w[3][i]=(w[3][i-4]+tem[3]);
3. for(int i=0 to i<4 i++)
a. for(int j=0 to j<44 j++)
i. dw[i][j]=w[i][j];
4. for (int ronda=1 to ronda=9 ronda++)
a. invmixcolumns(ronda);
5. regresa
rotword(a)
1. b[0]=a[1]
2. b[1]=a[2]
3. b[2]=a[3]
4. b[3]=a[0]
5. regresa b
subword(a)
1. for (int i=0 to i<4 i++)
a. Obtenemos la parte baja del a col=a[i]& 0x0F
b. Obtenemos la parte alta de a ren=(a[i]>>4) & 0x0F
c. Substituimos por el valor de caja S b[i]=box. Sboxvalor (ren,col)
2. regresa b
multi(a,b)
1. Cargo B
a.tem=b r=0
b.for (int i=0 to i<8 i++)
i. mulB[i]=tem & 0x01
ii. tem=tem>>1
2.Cargo A
a. for (int i=0 to i<8 i++)
i. tem=a;
b. for (int j=I to j<(i+8) j++)
i. mulA[j][i]=tem & 0x01;
ii. tem=tem>>1;
3. Multiplica
a. for(int i=0 to i<15 i++)
i. for (int j=0 to j<8 j++)
i.i c[i]=(mulA[i][j] &mulB[j] )^ c[i]
4. Convierte a numero el arreglo
a. for(int i=0;i<15;i++)
i. tem=c[i]<<i
ii. r=r|tem
5. r=reduce(r)
6. regresa r
reduce(c)
1. tem=(int)0x4000;
2. pol=(int)0x46C0;
3. while((c>>8)!=0)
a. while((c & tem)=0){
i. tem=tem>>1
ii. pol=pol>>1
b. c= c ^ pol
c. tem=tem>>1
d. pol=pol>>1
8. regresa c
3.3 Clase Llavero
Métodos:
Alta()
1. Si el usuario no esta
a. verificamos la longitud del password si es menor de 16 realizamos
paddindg
b. Cargamos el password como llave aes.iniciall(password.getBytes())
c. Cargamos el plaintext por default aes.iniciam(m)
d. Ciframos cifer=aescipher()
e. Guardamos el usuario y el cifrado
f. Generamos la llave
g. Verificamos que no se repita y guardamos de otra manera, si se repite
hacemos f
2. regresamos
baja()
1. Verficamos si existe el usuario
a. Verificamo que sea usuario valido y password correcto
Si
i. Eliminamos usuario de la tabla de usuarioa
ii. Elimnamos llaves del usuario de la tabla de llaves
3. regresamos
agregallave()
1. Recibe el usuario, el identificador de la llave y la llave
2. Busca el llavero del usuario
3. agrega la llave etiquetandolo con el identificador
4. regresa
bajaotro()
1. Recibe el usuario, el identificador de la llave
2. Busca el llavero del usuario
3. Elimina la lleva con el identificado llave
4. regresa
imprimellavero()
1. Recibe como parámetro el usuario
2. Busca el llavero del usuario
3. Imprime el llavero
4. regresa
imprimellavero(usuario)
1. Imprime el llavero principal
obllaveotro()
1. Recibe el nombre del usuario
2. Busca el llavero del usuario
3. Busca el identificador de la llave
4. regresa la llave
obtenllave()
1. Verificamos que exista el usuario
2. Validamos datos
3. Si son correctos
a. Obtenemos llave del llavero llavero.get(usuario)
4. regresamos
valida()
1. Verificamos que exista el usario
2. Si el password < 16 realizamos padding
3. Cargamos la llave
4. Cargamos el plaintext por defaul
5. Ciframos el cifrado=plaintext
6. Obtenemos el plaintext guardado en el llavero del usuario en c
7. Si cifrado=c
a. Si Usuario valido
a. No password incorrecto
8. regresamos
4. Documentación
Documentación de las clases de EDA
5. Resultados y Conclusiones
La pruebas finales se realizaron utilizando un archivo prueba.doc con un tamaño
de 28K.
Se creo el usuario kescobar con password “password” y se cifro el archivo prueba.doc
generando el archivo prueba.eda que contiene el texto cifrado.
Imagen que muestra la ejecución del programa.
Se salio del programa para posteriormente entrar al con el usuario kescobar y se
procedió a descifrar el archivo. El resultado obtenido fue el texto que en un principio se
tenía en el archivo que se suministro como archivo de salida (salida.doc).
Imagen que muestra la pantalla de la ejecución de programa
Tiempos obtenidos
La toma de tiempo se realizo en una lapto con un procesador a 333 MB , 64 K de RAM,
sistema operativo windows 98 y jdk1.3.1 de java sun.
Se realizaron varias pruebas para obtener lo tiempos promedios a continuación se
muestra una tabla con algunos tiempos .
Archivo
Prueba.doc
Book.xls
Computación.doc
Tamaño
26k
60 k
19 k
Cifrado(en
milisegundos)
22190
45790
13380
Descifrado(en
milisegundos)
409910
86860
25510
Equi-cifrado(en
milisegundos)
391740
87750
26510
Se puede observar que la implementación del algoritmo de descifrado equivalente al
cifrado presenta mejor desempeño. Eda cifra 10 k en 7.8 seg , descifra utilizando el
algoritmo inverso10 K en 13.49 seg y descifra utilizando el algoritmo equivalente al
cifrado en 10 K en 12.43 seg.
Conclusiones
Podemos concluir que Eda es una aplicación que nos permite manejar diferentes
usuarios sin problemas de que puedan descifrar archivos que no les pertenecen, ya que a
cada usuario se le asigna una llave diferente. Además, presenta una mejor seguridad en
el manejo de sus passwords ya que no los almacena directamente en la tabla, en caso de
que alguna persona pueda obtener esta tabla no podrá obtener los password por que
estos no se encuentran directamente almacenados, si no se utilizan como llave para
cifrar un plaintext predeterminando.
A consecuencia de que se necesita invocar a la máquina virtual de java para ejecutar el
programa, el cifrado y descifrado es lento. A esto se le agrega que el algoritmo utilizado
para realizar la multiplicación en el campo binario 28 es el algoritmo clásico egradando
el desempeño del programa.
Eda nos proporciona una manera de proteger los archivos a los que solo deseamos que
ciertas personas pueden endentar, esto se logra al compartir nuestra llave con esas
personas.
6. Referencias.
 The Rijndael Block Cipher document versión 2, date 03/09/99,
JoanDaemen y Vicent Rijmen.
 Specification for the ADVANCE ENCRYPTION STANDARD (AES),
Noviembre 26 2001, Federal Information Processing Standards
publication 197
 Introduction to Cryptography with Coding Theory.Wade trappe,
Lawrence C. Washington. Prentice Hall, 2002.
Descargar