RSA es
uno de los sistemas de cifrado (encriptación) asimétricos, más exitosos en la
actualidad. Originalmente descubierto 1973 por la agencia de inteligencia
británica GCHQ, Government Communications Headquarters (GCHQ), recibió la
clasificación de alto secreto “Top Secret”.
El
algoritmo fue descrito en 1977 y es propiedad de los criptólogos Ron
Rivest, Adi Shamir y Leonard Adleman, del Instituto Tecnológico de
Massachusetts (MIT) - RSA sol las letras iniciales de sus apellidos.
El
algoritmo fue patentado por MIT en 1983 y no fue revelado hasta 1997. A
diferencia de los sistemas de codificación simétrica tradicionales, RSA trabaja
con dos claves diferentes: una clave "pública", y otra
"privada". Ambas son complementarias entre sí (trabajan de manera
conjunta) así que un mensaje cifrado con una de ellas sólo puede ser descifrado
por su contraparte. Dado que la clave privada no se puede calcular a partir de
la clave pública, esta última queda generalmente queda a disposición del
público. Estas propiedades permiten que los cripto-sistemas asimétricos sean
utilizados en una amplia variedad de funciones, tales como las firmas
digitales.
Algoritmo RSA:
El Algoritmo RSA Consta de 3
partes, la primera hace referencia a la generación de las claves o
llaves que serán usadas para la encriptación del mensaje, la segunda
el proceso de encriptado y la tercera el proceso de desencriptar el mensaje.
Generación de las Llaves
(Pública y Privada).
Para generar un par de claves (KP ; Kp), en primer lugar se eligen aleatoriamente dos números primos grandes, p y q (de unas 200 cifras cada uno, por ejemplo). Después se calcula el producto n = p.q Escogeremos ahora un número e primo relativo con (p-1) y con (q-1). Este par de números (e,n) pueden ser conocidos por cualquiera, y constituyen la llamada clave pública e por tanto debe tener un inverso módulo (p-1)(q-1), al que llamamos d. Por supuesto se cumple que ed ≡ 1 mod((p-1)(q-1)), que es lo mismo que decir que ed = 1+k (p-1)(q-1) para algún entero k. La clave privada será el par (d,n). Este número d debe mantenerse secreto y sólo será conocido por el propietario del par de claves.
Proceso de Encriptación y
Desencriptación del Mensaje
Ejemplo Aplicativo:
Implementación
Clase Conversor
public class Conversor { public int numero(String a){ int C=-666; if(a.equals(" ")){ C=-555; }else if(a.equals("a")||a.equals("A")){ C=0; }else if(a.equals("b")||a.equals("B")){ C=1; }else if(a.equals("c")||a.equals("C")){ C=2; }else if(a.equals("d")||a.equals("D")){ C=3; }else if(a.equals("e")||a.equals("E")){ C=4; }else if(a.equals("f")||a.equals("F")){ C=5; }else if(a.equals("g")||a.equals("G")){ C=6; }else if(a.equals("h")||a.equals("H")){ C=7; }else if(a.equals("i")||a.equals("I")){ C=8; }else if(a.equals("j")||a.equals("J")){ C=9; }else if(a.equals("k")||a.equals("K")){ C=10; }else if(a.equals("l")||a.equals("L")){ C=11; }else if(a.equals("m")||a.equals("M")){ C=12; }else if(a.equals("n")||a.equals("N")){ C=13; }else if(a.equals("o")||a.equals("O")){ C=14; }else if(a.equals("p")||a.equals("P")){ C=15; }else if(a.equals("q")||a.equals("Q")){ C=16; }else if(a.equals("r")||a.equals("R")){ C=17; }else if(a.equals("s")||a.equals("S")){ C=18; }else if(a.equals("t")||a.equals("T")){ C=19; }else if(a.equals("u")||a.equals("U")){ C=20; }else if(a.equals("v")||a.equals("V")){ C=21; }else if(a.equals("w")||a.equals("W")){ C=22; }else if(a.equals("x")||a.equals("X")){ C=23; }else if(a.equals("y")||a.equals("Y")){ C=24; }else if(a.equals("z")||a.equals("Z")){ C=25; } return C; } public String numeroletra(int a){ String C=null; if(a==-555){ C=" "; }else if(a==0){ C="00"; }else if(a==1){ C="01"; }else if(a==2){ C="02"; }else if(a==3){ C="03"; }else if(a==4){ C="04"; }else if(a==5){ C="05"; }else if(a==6){ C="06"; }else if(a==7){ C="07"; }else if(a==8){ C="08"; }else if(a==9){ C="09"; }else if(a==10){ C="10"; }else if(a==11){ C="11"; }else if(a==12){ C="12"; }else if(a==13){ C="13"; }else if(a==14){ C="14"; }else if(a==15){ C="15"; }else if(a==16){ C="16"; }else if(a==17){ C="17"; }else if(a==18){ C="18"; }else if(a==19){ C="19"; }else if(a==20){ C="20"; }else if(a==21){ C="21"; }else if(a==22){ C="22"; }else if(a==23){ C="23"; }else if(a==24){ C="24"; }else if(a==25){ C="25"; } return C; } public String letranumero(int a){ String C=null; if(a==-555){ C=" "; }else if(a==0){ C="A"; }else if(a==1){ C="B"; }else if(a==2){ C="C"; }else if(a==3){ C="D"; }else if(a==4){ C="E"; }else if(a==5){ C="F"; }else if(a==6){ C="G"; }else if(a==7){ C="H"; }else if(a==8){ C="I"; }else if(a==9){ C="J"; }else if(a==10){ C="K"; }else if(a==11){ C="L"; }else if(a==12){ C="M"; }else if(a==13){ C="N"; }else if(a==14){ C="O"; }else if(a==15){ C="P"; }else if(a==16){ C="Q"; }else if(a==17){ C="R"; }else if(a==18){ C="S"; }else if(a==19){ C="T"; }else if(a==20){ C="U"; }else if(a==21){ C="V"; }else if(a==22){ C="W"; }else if(a==23){ C="X"; }else if(a==24){ C="Y"; }else if(a==25){ C="Z"; } return C; } }
Clase Euclides
public class Euclides { public long[] euclidesExtendido(long a, long b) { long[] resp = new long[3]; long x=0,y=0,d=0; if(b==0) { resp[0] = a; resp[1] = 1; resp[2] = 0; } else { long x2 = 1, x1 = 0, y2 = 0, y1 = 1; long q = 0, r = 0; while(b > 0) { q = (a/b); r = a - q*b; x = x2-q*x1; y = y2 - q*y1; a = b; b = r; x2 = x1; x1 = x; y2 = y1; y1 = y; } resp[0] = a; resp[1] = x2; resp[2] = y2; } return resp; } }
Clase Exponenciación
public int CalcularExp(int a,int k,int z) { int exp=1; int xp=a%z; while(k > 0) { if((k%2)!=0) { exp=(exp*xp)%z; } xp=(xp*xp)%z; k=k/2; } return exp; }
Clase Inverso
public class Inverso { public double CalcularInverso(long n,long z) { long mcd[] =new long[3]; int x=0,y = 0; Euclides obj = new Euclides(); if(n > z) { mcd=obj.euclidesExtendido(n,z); } if(n < z) { mcd=obj.euclidesExtendido(z,n); } if(mcd[0] > 1) { System.out.println("EL INVERSO NO EXISTE"); y=0; } else { y=(int) mcd[2]; if(y < 0) { y=(int) (y+z); } } return y; } }
Clase RSA
import java.util.ArrayList; public class RSA { private long n, q, p; private long fi,e,d; private String mensaje; private String cifrado; private String MensajeLimpio; private String num_letra; private String CadenaDescifradaNumeros; public RSA() { //this.p=43; //this.q=59; //this.e=13; GenerarKey(); } public String getCadenaDescifradaNumeros() { return CadenaDescifradaNumeros; } public String getNum_letra() { return num_letra; } public String getMensajeLimpio() { return MensajeLimpio; } public long getN() { return n; } public long getQ() { return q; } public long getP() { return p; } public long getFi() { return fi; } public long getE() { return e; } public long getD() { return d; } public String getMensaje() { return mensaje; } public String getCifrado() { return cifrado; } public void RecibirMensaje(String m) { this.mensaje=m; } public void RecibirCifrado(String c) { this.cifrado=c; } public boolean primo(int n) { for(int i=2;i < n;i++) { if(n%i==0) { return false; } } return true; } public void GenerarPrimos() { Boolean resP,resQ; do { p = (int)(Math.random()*(100-10+1)+10); q = (int)(Math.random()*(100-10+1)+10); resP=primo((int) p); resQ=primo((int) q); }while((p==q)||(resP==false)||(resQ==false)); System.out.println("P:"+p); System.out.println("Q:"+q); } public int GenerarE() { Boolean resE; long mcd[]= new long[3]; Euclides euclides = new Euclides(); do { e = (int)(Math.random()*(100-1+1)+1); resE=primo((int) e); mcd=euclides.euclidesExtendido(e, fi); }while((e > =fi)||(mcd[0]!=1)||(resE==false)); return (int) e; } public void GenerarKey() { GenerarPrimos(); Inverso inverso= new Inverso(); n=p*q; fi=(p-1)*(q-1); e=GenerarE(); d=(long) inverso.CalcularInverso(e,fi); if(d < 0) { d=d+fi; } System.out.println("n: "+n); System.out.println("fi: "+fi); System.out.println("e: "+e); System.out.println("d: "+d); } public String EliminarEspaciosCaracteresEspeciales() { //Eliminando los espacios y caracteres especiales String AlfabetoValido="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; String aux_mensaje=""; int contador=0; for(int i=0;i < mensaje.length();i++) { for(int j=0;j < AlfabetoValido.length();j++) { if(!String.valueOf(mensaje.charAt(i)).equals(String.valueOf(AlfabetoValido.charAt(j)))) { contador++; } } if(contador > =AlfabetoValido.length()) { //AL EVALUAR EL CARACTER CON TODOS LOS ELEMENTOS DE LA CADENA UNA DEBE DE COINCIDIR POR LO QUE EL VALOR DEL CONTADOR DEBE SER UNO MENOS QUE //EL DEL TAMAÑO DE ALFABETOVALIDO, SI SON IGUALES O ES MAYOR SIGNIFICA QUE ESE CARACTER NO ES VALIDO Y DEBE SER IGNORADO } else { aux_mensaje=aux_mensaje+mensaje.charAt(i);//CREANDO UNA NUEVA CADENA SIN ESPACIOS } contador=0; } //En el caso de que falten caracteres para la agrupacion de 4, se completan con un x if(aux_mensaje.length()%2!=0) { aux_mensaje=aux_mensaje+"X"; } return aux_mensaje; } public String ConvertirNumeros(String mensaje_sin_espacios) { int aux_num_letra; num_letra =""; Conversor letras= new Conversor(); for(int i=0;i < mensaje_sin_espacios.length();i++) { //Realizando la conversion a numeros aux_num_letra=letras.numero(String.valueOf(mensaje_sin_espacios.charAt(i))); num_letra=num_letra+letras.numeroletra(aux_num_letra); } return num_letra; } public String ConvertirCadena(String cadenacifrada) { Conversor letras= new Conversor(); int inicioC=0,finalC=2; String TextoCifrado="",aux_TextoCifrado; for(int i=0;i < cadenacifrada.length();i++) { aux_TextoCifrado=cadenacifrada.substring(inicioC,finalC); if(Integer.parseInt(aux_TextoCifrado) > 25) { aux_TextoCifrado=String.valueOf(Integer.parseInt(aux_TextoCifrado)%26); } TextoCifrado=TextoCifrado+letras.letranumero(Integer.parseInt(aux_TextoCifrado));//CREANDO UNA NUEVA CADENA SIN ESPACIOS inicioC=finalC; finalC=finalC+2; i=inicioC; } return TextoCifrado; } public String Cifrar(String num_letra) { Exponenciacion expo= new Exponenciacion(); ArrayList < String > Cifrado = new ArrayList < > (); int inicioC=0,finalC=4,rexpo = 0; String auxiliar; for(int i =0 ;i < num_letra.length();i++) { auxiliar=num_letra.substring(inicioC,finalC); System.out.println("SUBCADENA ANTES DE CIFRAR: "+auxiliar); //Realizando operacion de encriptado rexpo=expo.CalcularExp(Integer.parseInt(auxiliar),(int)e,(int)n); System.out.println("YA ME CIFRARON: "+rexpo); //ALMACENANDO if(String.valueOf(rexpo).length()==1) { Cifrado.add("000"+String.valueOf(rexpo)); } if(String.valueOf(rexpo).length()==2) { Cifrado.add("00"+String.valueOf(rexpo)); } if(String.valueOf(rexpo).length()==3) { Cifrado.add("0"+String.valueOf(rexpo)); } if(String.valueOf(rexpo).length()==4) { Cifrado.add(String.valueOf(rexpo)); } inicioC=finalC; finalC=finalC+4; i=inicioC; } //Guardando todo en una sola cadena String cadena=""; for(int i=0;i < Cifrado.size();i++) { cadena=cadena+Cifrado.get(i); } System.out.println("A MI TIENEN QUE DESCIFRARME: "+cadena); RecibirCifrado(cadena);//SALVANDO C , QUE SERA USADO PARA DESENCRIPTAR return cadena; } public String Descifrar() { Exponenciacion expo= new Exponenciacion(); ArrayList < String > Descifrado = new ArrayList < > (); int inicioC=0,finalC=4,rexpo = 0; String auxiliar; System.out.println("SOY EL MENSAJE CIFRADO: "+cifrado); for(int i =0 ;i < cifrado.length();i++) { auxiliar=cifrado.substring(inicioC,finalC); System.out.println("SOY UNA SUBCADENA DEL MENSAJE CIFRADO ANTES DE SER DESCIFRADO: "+auxiliar); //Realizando operacion de encriptado rexpo=expo.CalcularExp(Integer.parseInt(auxiliar),(int)d,(int)n); System.out.println("ME DESCIFRARON: "+rexpo); //ALMACENANDO if(String.valueOf(rexpo).length()==1) { Descifrado.add("000"+String.valueOf(rexpo)); } if(String.valueOf(rexpo).length()==2) { Descifrado.add("00"+String.valueOf(rexpo)); } if(String.valueOf(rexpo).length()==3) { Descifrado.add("0"+String.valueOf(rexpo)); } if(String.valueOf(rexpo).length()==4) { Descifrado.add(String.valueOf(rexpo)); } inicioC=finalC; finalC=finalC+4; i=inicioC; } //Guardando todo en una sola cadena String cadena=""; for(int i=0;i < Descifrado.size();i++) { cadena=cadena+Descifrado.get(i); } return cadena; } public String OperacionRSAEncriptar() { //Generando llaves - ESTE PROCESO SE REALIZA EN EL METODO CONSTRUCTOR , AQUI SOLO LO INDICAMOS //Eliminando espacios y caracteres especiales MensajeLimpio=EliminarEspaciosCaracteresEspeciales(); //Realizando conversion de texto a numeros System.out.println("SOY EL MENSAJE LIMPIO: "+MensajeLimpio); num_letra=ConvertirNumeros(MensajeLimpio); System.out.println("CADENA ANTERIOR PERO EN NUMEROS: "+num_letra); //Cifrando String cadena; cadena=Cifrar(num_letra); System.out.println("Soy el cifrado"+this.cifrado); //Realizando conversion de numeros a letras String TextoFinal; TextoFinal=ConvertirCadena(cadena); return TextoFinal; } public String OperacionRSADesencriptar() { CadenaDescifradaNumeros=Descifrar(); String TextoFinal; TextoFinal=ConvertirCadena(CadenaDescifradaNumeros); return TextoFinal; } }
RESULTADOS: