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.