jueves, 30 de julio de 2015

CIFRADO DE RABIN

El criptosistema de Rabin es una técnica criptográfica asimétrica cuya seguridad, al igual que RSA, se basa en la complejidad de la factorización. Sin embargo, la ventaja del criptosistema de Rabin es que se ha demostrado que la complejidad del problema en el que se basa es tan duro como la factorización de enteros, cosa que se desconoce si es cierto en el caso del RSA simple. El inconveniente que tiene es que cada salida de la función de Rabin puede ser generado por 4 posibles entradas, y si cada salida es un texto cifrado se requiere un tiempo extra en el descifrado para identificar cual de las 4 posibles entradas era el correcto texto en claro. El algoritmo se publicó en enero de 1979 por Michael O. Rabin.
El sistema de llave asimétrica de Rabin se basa en el problema de calcular raíces cuadradas módulo un número compuesto. Este problema se ha demostrado que es equivalente al de la factorización de dicho número.

ALGORITMO DE RABIN

GENERACIÓN DE LLAVES
Escogemos dos números primos, p y q, ambos congruentes con 3 módulo 4.Estos primos son la clave privada.
La clave pública es su producto, n=p*q.

CIFRAR MENSAJE

  • Cabe aclarar  que para cifrar el mensaje este debe de estar en forma de cadena de bits con una longitud de 16 bits , en el caso de que falten se cogen las ultimas cifras de la cadena para completar los 16 bits. 
  • Se realiza una conversión de binario a decimal de la cadena ingresada (m) .
  • Para codificar un mensaje , simplemente se calcula:

DESCIFRAR MENSAJE
Para desencriptar el mensaje solo se deben obtener las 4 raíces de:

C (mod n)

Una de las raíces convertida a binario hará referencia al mensaje cifrado.

EJEMPLO APLICATIVO:
Generando llaves:


Sea:
  • p=277
  • q=331
Entonces n= p*q = 91687

  • Clave Publica=(p=277,q=331)
  • Clave Privada=(n=91687)

Cifrando:

Cadena Ingresada: 1001111001 , como no cumple con la cantidad maxima de 16 caracteres se cogen las ultimas  6 cifras para completar, obteniendo nuestra nueva cadena:1001111001111001.
Pasando a decimal nuestra cadena, obteniendo m= 40569.
Ahora procedemos a cifrar: aplicando :
C=40569 mod 91687  =  62111

Descifrando:
Para descifrar el mensaje lo único que debemos hacer es aplicar la raíz cuadrada de C(mod n) , en este ejemplo obtendríamos:

m1 = 69654   = > 10001000000010110
m2 = 22033   = > 101011000010001
m3 = 40569   = > 1001111001111001
m4 = 51118   = > 1100011110101110

Podemos observar que la raíz m3 corresponde al mensaje antes de cifrar.


Implementación
Se hace recordar que en la implementacion hace uso de algoritmos que ya hemos visto con anterioridad , por lo que recomendamos se pase por el siguiente post:




Clase Rabin:

public class Rabin {
    private String mensaje;
    private long n, q, p;
    private String cifrado;
    private String CadenaCompleta;
    private int m,c;

    public int getM() {
        return m;
    }

    public int getC() {
        return c;
    }

    public String getCadenaCompleta() {
        return CadenaCompleta;
    }
    
    public String getMensaje() {
        return mensaje;
    }

    public long getN() {
        return n;
    }

    public long getQ() {
        return q;
    }

    public long getP() {
        return p;
    }

    public String getCifrado() {
        return cifrado;
    }
    
    public void setMensaje(String mensaje) {
        this.mensaje = mensaje;
    }
    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()*(1000-100+1)+100); 
            q = (int)(Math.random()*(1000-100+1)+100); 
            resP=primo((int) p);
            resQ=primo((int) q);
        }while((p< q)||(p==q)||(resP==false)||(resQ==false)||((p-3)%4!=0)||((q-3)%4!=0));
        
        System.out.println("P:"+p);
        System.out.println("Q:"+q);
    }
    public void GenerarKey()
    {
        GenerarPrimos();
        n=p*q;
        System.out.println("n: "+n);
    }
    public String CompletarCadena()
    {
        String nuevo_mensaje,aux;
        int tam=mensaje.length();
        int diferencia=tam-(16-tam);
        System.out.println("diferencia: "+diferencia);
        if(tam< 16)
        {
            aux=mensaje.substring(diferencia,tam);
            nuevo_mensaje=mensaje+aux;
        }
        else
        {
            nuevo_mensaje=mensaje;
        }
        return nuevo_mensaje;
    }
    public String Encriptar()
    {
        //Completando Cadena en el caso de que no cumplan los 16 bits   
        CadenaCompleta=CompletarCadena();
        //Pasando la cadena a decimal para poder encriptar
        Binario objBinario= new Binario();
        m=objBinario.BinarioDecimal(CadenaCompleta);
        //Encriptando
        Exponenciacion expo= new Exponenciacion();
        c=expo.CalcularExp(m, 2, (int) n);
        //Pasando a Binario el mensaje cifrado
        cifrado=objBinario.decimalABinario(c);
        return cifrado;
    }
    public String[] Desencriptar(int m,int c)
    {
        RaizCompuesta obj = new RaizCompuesta();
        int raices[]=new int[4];
        Binario objBinario= new Binario();
        String Descifrado[]= new String[4];
        raices=obj.CalcularRaizCompuesta(m,c);
        if(raices==null)
        {
            JOptionPane.showMessageDialog(null, "NO EXISTEN RAICES");
        }
        else
        {
            
            Descifrado[0]=objBinario.decimalABinario(raices[0]);
            Descifrado[1]=objBinario.decimalABinario(raices[1]);
            Descifrado[2]=objBinario.decimalABinario(raices[2]);
            Descifrado[3]=objBinario.decimalABinario(raices[3]);
        }
        return Descifrado;
    }
}


Clase Binario:
public class Binario {
    int decimal;
    public int BinarioDecimal(String numero)
    {
        decimal= Integer.parseInt(numero,2);
        return decimal;
    }
    public String decimalABinario(int numeroDecimal){
    int temp = numeroDecimal;
    String resultado="";
    while (temp != 0){
     if(temp % 2 == 0)
     {
         resultado="0"+resultado;
     }
     else
     {
         resultado="1"+resultado;
     }
     temp = temp/2;
    }
    return resultado;
   }
}

Resultados:




miércoles, 29 de julio de 2015

CIFRADO DE HILL

Fue Inventado por Lester S. Hill en 1929, y fue el primer sistema criptográfico polialfabético que era práctico para trabajar con mas de tres símbolos simultáneamente.
Este sistema es polialfabético pues puede darse que un mismo caracter en un mensaje a enviar se encripte en dos caracteres distintos en el mensaje encriptado.

Se trabaja con un alfabeto de 26 letras (A=0, B=1, ... ,Z=25).

Todas las operaciones aritméticas se realizan en la forma módulo 26, es decir que 26=0, 27=1, 28=2 etc.







Implementación
#include< conio.h >
#include < math.h >
#include < string.h >
#include < stdio.h >
#include < stdlib.h >
#include< iostream >
using namespace std;
int *euclidesExtendidoMCD(int a, int b);
int inversoMultiplicativo(int a, int z);
char *preMatriz(char *clave,char *letras,char *textCpy);
void ingresarMatriz(int d,int M[][100]);
void mostrarMatriz(int d, int M[][100]);
void multiplicarMatriz(int M[][100],int P[][100], int C[][100], int m,int p,int n);
int subMatriz(int i, int j, int M[][100],int temp[][100],int d);
int determinanteMatriz(int M[][100],int d);
void algoCifradoHill(char *text, int M[][100], int d);
void desencriHill(char *text, int M[][100], int d);
char *agrupar(char *text,char *textAgru,int d);
bool comparar(char *clave,char a,int k);
int *euclidesExtendidoMCD(int a, int b){
 
 int d,x,y;
 int x1,x2,y1,y2;
 int q,r;
 int *rpts=new int[3];
 
 if(b==0){
  d=a;
  x=1;
  y=0; 
  
  rpts[0]=d; rpts[1]=x; rpts[2]=y;
  return rpts;
 }
 x1=0; x2=1;
 y1=1; y2=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;    
 }
 //d=a;
 rpts[0]=a; rpts[1]=x2; rpts[2]=y2;
 
 return rpts;
}

int inversoMultiplicativo(int a, int z){
 
 int *resp;
 int inver;     
 
 resp=euclidesExtendidoMCD(a,z);
 
 if(resp[0]==1){
  if(resp[1]< 0)
   inver=z+resp[1];
  else if(resp[1] >0)
   inver=resp[1];    
  delete(resp);
  return inver;
 }       
 else {            
  delete(resp);
  return -1;
 }
 
}

void ingresarMatriz(int d,int M[][100]){
 
 cout< < "\n";
 for(int i=0;i< d;i++)
  for(int j=0;j< d;j++){
   do{
    
    cout< < "\t\tMatriz ["< < i+1< < "]["< < j+1< < "]: ";
    cin > >M[i][j];
    if(M[i][j]< 0 || M[i][j] >25){
     cout< < "\n\t\tDebe ingresar los numeros en el rango de 0 a 25\n";
    }
    
   }while(M[i][j]< 0 || M[i][j] >25);   
   
  }
 
}

void mostrarMatriz(int d, int M[][100]){
 
 for(int i=0;i< d;i++){
  cout< < "|";
  for(int j=0;j< d;j++)
   cout< < M[i][j]< < " ";
  cout< < "|\n";
 }
}

void multiplicarMatriz(int M[][100],int P[][100], int C[][100], int m,int p,int n){
 int s;  
 
 for (int i=0;i< m;i++){
  for(int j=0;j< n;j++){
   s=0;          
   for(int k=0;k< p;k++){
    s+=M[i][k]*P[k][j];
   }
   C[i][j]=s;
  }
 }
}

int subMatriz(int i, int j, int M[][100],int temp[][100],int d){
 
 int fil=0;
 int col=0;
 
 for(int k=0;k< d;k++){
  if(k!=i){
   col=0;
   for(int l=0;l< d;l++){
    if(l!=j){
     temp[fil][col]=M[k][l];
     col++;
    }
    
   }
   fil++;   
  }
  
 }
 return determinanteMatriz(temp,d-1);
}
int determinanteMatriz(int M[][100],int d){
 
 int temp[100][100];
 
 if(d==2){
  int deter=M[0][0]*M[1][1]-M[1][0]*M[0][1]; 
  
  return deter;
 }else{
  int deter=0;
  
  for(int j=0;j< d;j++){      
   subMatriz(0,j,M,temp,d);
   deter=deter+pow(-1,0+j)*M[0][j]*determinanteMatriz(temp,d-1);
   
  }
  
  return deter;
 }
 
}
bool comparar(char *clave,char a,int k){
 
 for(int i=0;i< k;i++){
  if(clave[i]==a)
   return false;
 }
 
 return true;
}

char *preMatriz(char *clave,char *letras,char *textCpy){
 
 int k=0,i=0; 
 bool band=true;  
 
 while(k< 25){  
  
  if(clave[k]=='j')
   clave[k]='i'; 
  
  if(clave[k]!='\0' && band==true){ 
   if(clave[k]!=' ' && clave[k] >96 && clave[k]< 123){      
    if(comparar(clave,clave[k],k)){
     textCpy[i]=clave[k];
     i++;                          
    }  
   }
  }
  else{
   if(band==true)
    k=0;
   band=false;
   if(comparar(textCpy,letras[k],i)){
    textCpy[i]=letras[k];
    i++;                          
   }
  }     
  
  k++;
 }
 textCpy[25]='\0';
 //cout< < "i: "< < i;
 return textCpy;
}

void algoCifradoHill(char *text, int M[][100], int d){
 
 char textAgru[500]; 
 
 int P[100][100],p=0;
 int C[100][100];
 int inver,deter,verfInver;
 int k=0,m=0,ini=0,tam;
 
 deter=determinanteMatriz(M,d)%26; 
 
 if(deter< 0){
  verfInver=deter+26;
  //cout< < "\n\t\tDeterminante: "< < verfInver< < "\n";
 }
 else{ 
  verfInver=deter;
  //  cout< < "\n\t\tDeterminante: "< < verfInver< < "\n";
 }
 inver=inversoMultiplicativo(verfInver,26); 
 //cout< < "\n\t\tinverso("< < verfInver< < ",26) = "< < inver< < "\n";
 
 if(deter!=0 && inver!=-1){
  strcpy(textAgru,agrupar(text,textAgru,d));
  
  tam=strlen(textAgru);
  
  cout< < "\n\t\tTexto: "< < textAgru;
  
  while(k< =tam){   
   
   if(p< d){          
    P[p][0]=textAgru[k]-97; 
    //cout< < P[p][0]< < " " ;
    p++; 
   }else{      
    multiplicarMatriz(M,P,C,d,p,1);
    for(int i=ini;i< k;i++){
     textAgru[i]=(C[m][0]%26)+97;    
     m++;
     
    }            
    ini=k+1;
    m=0;
    p=0;
    
   }  
   k++;
  }
  
  cout< < "\n\t\tTexto Encriptado: "< < textAgru;
 }else
  cout< < "\n\t\tCon la clave matrices ingresada no se puede encriptar el mensaje";
 
}

void desencriHill(char *text, int M[][100], int d){
 
 int inver,deter,verfInver; 
 int resul,tam,ini=0,p=0,k=0,m=0;
 
 int P[100][100];
 int C[100][100]; 
 int A[100][100];
 int temp[100][100];
 
 deter=determinanteMatriz(M,d)%26; 
 
 if(deter< 0){
  verfInver=deter+26;
  cout< < "\n\t\tDeterminante: "< < verfInver< < "\n";
 }
 else{ 
  verfInver=deter;
  cout< < "\n\t\tDeterminante: "< < verfInver< < "\n";
 }
 inver=inversoMultiplicativo(verfInver,26); 
 cout< < "\n\t\tinverso("< < verfInver< < ",26) = "< < inver< < "\n";
 
 if(deter!=0 && inver!=-1){
  
  for(int i = 0; i <  d; i++) 
   for(int j = 0; j <  d ;j++)               
    A[j][i] = pow(-1,i+j)*subMatriz(i,j,M,temp,d);
  
  for(int i = 0; i <  d; i++){    
   for(int j = 0; j <  d ;j++){
    resul=A[i][j]*inver;             
    if(resul< 0)
     A[i][j]=(resul%26)+26;
    else   
     A[i][j]=resul%26;
   }               
   
  } 
  tam=strlen(text); 
  
  cout< < "\n\t\tTexto: "< < text;
  
  while(k< =tam){   
   
   if(p< d){          
    P[p][0]=text[k]-97; 
    //cout< < P[p][0]< < " " ;
    p++; 
   }else{      
    multiplicarMatriz(A,P,C,d,p,1);
    for(int i=ini;i< k;i++){
     text[i]=(C[m][0]%26)+97;    
     m++;
     
    }            
    ini=k+1;
    m=0;
    p=0;
    
   }  
   k++;
  }
  
  cout< < "\n\t\tTexto Desencriptado: "< < text;
  
  
 }else
  {cout< < "\n\t\tCon la clave matrices ingresada no se puede desencriptar el mensaje";}
 cout< < endl;
 system("pause");
 
 
}
char *agrupar(char *text,char *textAgru,int d){
 
 int k=0,i=0;
 int cont=0;
 
 
 while(text[k]!='\0'){
  
  if(text[k]!=' '){
   if(cont!=d){
    textAgru[i]=text[k];
    cont++;
    i++;
   }
   else{         
    textAgru[i]=' ';
    textAgru[i+1]=text[k];
    i+=2;
    cont=1;
   }
   
  } 
  k++; 
 }
 
 while(cont< d){
  textAgru[i]='x';
  cont++;
  i++;
 }
 textAgru[i]='\0';
 
 return textAgru;
}

int main(int argc, char *argv[]) {
 char text[500];
 int M[100][100];
 int d;   
 int opcion;
 while(1)
 {
  system("cls");
  cout< < "\n\t\t\tALGORITMOS DE ENCRIPTACION HILL\n";
  cout< < "1. ENCRRIPTAR\n";
  cout< < "2. DESENCRRIPTAR\n";
  cout< < "INGRESE OPCION: ";
  cin > >opcion;
  switch(opcion)
  {
   case 1:
   {
    system("cls");
    cout< < "\n\t\t\tALGORITMOS DE ENCRIPTACION HILL - ENCRIPTACION\n";
    cout< < "\n\t\tINGRESE TEXTO: ";
    fflush(stdin);
    gets(text);
    strcpy(text,strlwr(text));
    cout< < "\n\t\tINGRESE TAMAÑO DE MATRIZ DXD: ";
    cin > >d; 
    ingresarMatriz(d,M);
    algoCifradoHill(text,M,d);
    cout< < endl;
    system("pause");
    break;
   }
   case 2:
   {
    system("cls");
    cout< < "\n\t\t\tALGORITMOS DE ENCRIPTACION HILL - DESENCRIPTACION\n";
    cout< < "\n\t\tINGRESE TEXTO: ";
    fflush(stdin);
    gets(text);
    strcpy(text,strlwr(text));
    cout< < "\n\t\tINGRESE TAMAÑO DE MATRIZ DXD: ";
    cin > >d; 
    ingresarMatriz(d,M);
    desencriHill(text,M,d);
    cout< < endl;
    system("pause");
    break; 
   }
  }
 }
 return 0;
}

ANÁLISIS DE LA COMPLEJIDAD DE MÉTODOS DE ORDENACIÓN Y SU IMPLEMENTACIÓN

La tarea de la programación esta ligada al objetivo de obtener algoritmos que resuelvan un problema con la mayor eficiencia posible; de hecho es sorprendente comprobar las múltiples formas como podemos resolver un mismo problema y las ventajas que conseguimos , en términos de eficiencia , al buscar soluciones alternativas a las ya conocidas o consideradas como evidentes.
Para comparar y analizar la eficiencia de los algoritmos , estos los consideramos escritos en un lenguaje de programación de alto nivel , pero aun empleando la misma representación , establecer una medida precisa de la eficiencia de un algoritmo no es fácil.En efecto , fijémonos en que una definición de eficiencia podría ser el numero de instrucciones que tiene el programa ; sin embargo esto no se correspondería , con el concepto intuitivo que tenemos de eficiencia(según el cual,el algoritmo mas eficiente seria aquel que tardase menos tiempo en resolver el problema sobre una misma maquina), dado que todas las instrucciones no utilizan el mismo tiempo de procesador aun realizando la misma función.

MÉTODOS DE ORDENACIÓN:
En computación y matemáticas un algoritmo de ordenamiento es un algoritmo que pone elementos de una lista o un vector en una secuencia dada por una relación de orden, es decir, el resultado de salida ha de ser una permutación  o reordenamiento de la entrada que satisfaga la relación de orden dada. Los ordenamientos eficientes son importantes para optimizar el uso de otros algoritmos (como los de búsqueda y fusión) que requieren listas ordenadas para una ejecución rápida. También es útil para poner datos en forma canónica y para generar resultados legibles por humanos.



MÉTODO DE ORDENAMIENTO BURBUJA:

Este es uno de los métodos de ordenamiento mas usados .aunque no de los mas eficaces.
Consiste en recorrer la lista de valores a ordenar y compararlos dos a dos.Si los elementos están bien ordenados, pasamos al siguiente , hasta llegar al final de la lista.El proceso completo se repite hasta que la lista este ordenada.




Algoritmo:
DESDE I=1 hasta N-1 hacer
    DESDE J=1 hasta N-1 hacer
          Si v[J]>V[J+1] entonces
                Aux= V[J]
                V[J]=V[J+1]
                V[J+1]=Aux
           FIN SI
     FIN DESDE
FIN DESDE

Análisis de Complejidad:











El ciclo interno se ejecuta n veces para una lista de n elementos. El ciclo externo también se ejecuta n veces. Es decir, la complejidad es n * n = O(n2). El comportamiento del caso promedio depende del orden de entrada de los datos, pero es sólo un poco mejor que el del peor caso, y sigue siendo O(n2).

Implementación
public int burbuja(int[] arreglo)
    {  
        int aux,num_intercambios=0;  
        for(int i=1;i <  arreglo.length;i++)
        {  
            for (int j=0 ; j <  arreglo.length- 1; j++)
            {  
                if (arreglo[j] > arreglo[j+1])
                {  
                    aux = arreglo[j];  
                    arreglo[j] = arreglo[j+1];  
                    arreglo[j+1] = aux;  
                    num_intercambios++;
                }  
            }  
        }  
        //Nos retorna el numero de operaciones que hace referencia a la complejidad
        //Si desea obtener la lista de valores ordenados , recuperar este valor a través de un método get
        return num_intercambios;
    }  

MÉTODO DE ORDENACIÓN INSERCIÓN:
La idea de este algoritmo de ordenación consiste en ir insertando un elemento de la lista o un arreglo en la parte ordenada de la misma, asumiendo que el primer elemento es la parte ordenada, el algoritmo ira comparando un elemento de la parte desordenada de la lista con los elementos de la parte ordenada, insertando el elemento en la posición correcta dentro de la parte ordenada, y así sucesivamente hasta obtener la lista ordenada. Para explicarlo mejor nos basaremos en el siguiente enunciado:
“Para cada elemento de la lista después del primero, comparar los elementos con los anteriores desplazando una posición a la derecha a todos los elementos anteriores que cumplan con la comparación y luego colocar el elemento en la posición del último elemento anterior desplazado.”

Algoritmo:
for (i=1; i<TAM; i++)
      aux = array[i];
      j = i - 1;
      while ( (array[j] > aux) && (j >= 0) )
          array[j+1] = array[j];
           j--;
      array[j+1] = aux;

Análisis de la Complejidad:


Para una lista de n elementos el ciclo externo se ejecuta n-1 veces. El ciclo interno se ejecuta como máximo una vez en la primera iteración, 2 veces en la segunda, 3 veces en la tercera, etc. Esto produce una complejidad O(n2).

Implementación:
//METODO DE ORDENACION : INSERCION
    public int Insercion(int[] array){
        int aux,num_intercambios=0;
        for (int i = 1; i <  array.length; i++) {
            aux = array[i];
            for (int j = i-1; j   > =0 && array[j]  > aux; j--) {
                array[j+1]=array[j];
                array[j]=aux;
                num_intercambios++;
            }
        }
        //Nos retorna el numero de operaciones que hace referencia a la complejidad
        //Si desea obtener la lista de valores ordenados , recuperar este valor a través de un método get
return num_intercambios; }

MÉTODO DE ORDENACIÓN QUICKSORT:


Sin duda, este algoritmo es uno de los más eficientes. Este método es el más rápido gracias a sus llamadas recursivas, basándose en la teoría de divide y vencerás.
Lo que hace este algoritmo es dividir recursivamente el vector en partes iguales, indicando un elemento de inicio, fin y un pivote (o comodín) que nos permitirá segmentar nuestra lista. Una vez dividida, lo que hace, es dejar todos los mayores que el pivote a su derecha y todos los menores a su izquierda Al finalizar el algoritmo, nuestros elementos están ordenados.
Por ejemplo, si tenemos 3 5 4 8 básicamente lo que hace el algoritmo es dividir la lista de 4 elementos en partes iguales, por un lado 3, por otro lado 4 8 y como comodín o pivote el 5. Luego pregunta, 3 es mayor o menor que el comodín? Es menor, entonces lo deja al lado izquierda Y como se acabaron los elementos de ese lado, vamos al otro lado. 4 Es mayor o menor que el pivote? Menor, entonces lo tira a su izquierda. Luego pregunta por el 8, al ser mayor lo deja donde está, quedando algo así: 3 4 5 8.
En esta figura se ilustra de mejor manera un vector con más elementos, usando como pivote el primer elemento:


Algoritmo

// Inicialización de variables
    elem_div = lista[sup];
    i = inf - 1;
    j = sup;
    cont = 1;
    
    // Verificamos que no se crucen los límites
    if (inf >= sup)
          retornar;
    
    //  Clasificamos la sublista
    while (cont)
          while (lista[++i] < elem_div);
          while (lista[--j] > elem_div);
         if (i < j)
              temp = lista[i];
              lista[i] = lista[j];
              lista[j] = temp;
         else
              cont = 0;
   
   // Copiamos el elemento de división
   // en su posición final
    temp = lista[i];
    lista[i] = lista[sup];
    lista[sup] = temp;
   
   // Aplicamos el procedimiento
   // recursivamente a cada sublista
    OrdRap (lista, inf, i - 1);
    OrdRap (lista, i + 1, sup);

Análisis de la Complejidad:

Caso promedio: La complejidad para dividir una lista de n es O(n). Cada sublista genera en promedio dos sublistas más de largo n/2. Por lo tanto la complejidad se define en forma recurrente como:
f(1) = 1
f(n) = n + 2 f(n/2)
La forma cerrada de esta expresión es:
f(n) = n log2n
Es decir, la complejidad es O(n log2n).
El peor caso ocurre cuando la lista ya está ordenada, porque cada llamada genera sólo una sublista (todos los elementos son menores que el elemento de división). En este caso el rendimiento se degrada a O(n2). 
Implementación

//METODO DE ORDENACION: QUICKSORT
    public  int ordenacionRapida(int[] v) {
        final int N = v.length;
        quicksort(v,0,N-1);
        return num_intercambios_qs;
    }
 
    public void quicksort(int A[], int izq, int der) {
    int pivote=A[izq]; // tomamos primer elemento como pivote
    int i=izq; // i realiza la búsqueda de izquierda a derecha
    int j=der; // j realiza la búsqueda de derecha a izquierda
    int aux;

    while(i< j){            // mientras no se crucen las búsquedas
       while(A[i]< =pivote && i< j) i++; // busca elemento mayor que pivote
       while(A[j] > pivote) j--;         // busca elemento menor que pivote
       if (i< j) {                      // si no se han cruzado                      
           aux= A[i];                  // los intercambia
           A[i]=A[j];
           A[j]=aux;
       }
       num_intercambios_qs++;
        
     }
     A[izq]=A[j]; // se coloca el pivote en su lugar de forma que tendremos
     A[j]=pivote; // los menores a su izquierda y los mayores a su derecha
     if(izq< j-1)
        quicksort(A,izq,j-1); // ordenamos subarray izquierdo
     if(j+1 < der)
        quicksort(A,j+1,der); // ordenamos subarray derecho
    }
    

MÉTODO DE ORDENACIÓN MERGESORT:
Este algoritmo consiste básicamente en dividir en partes iguales la lista de números y luego mezclarlos comparándolos, dejándolos ordenados.
Si se piensa en este algoritmo recursivamente, podemos imaginar que dividirá la lista hasta tener un elemento en cada lista, luego lo compara con el que está a su lado y según corresponda, lo sitúa donde corresponde.
En la siguiente figura podemos ver cómo funciona:



Análisis de la Complejidad:












La complejidad para dividir una lista de n es O(n). Cada sublista genera en promedio dos sublistas más de largo n/2. Por lo tanto la complejidad se define en forma recurrente como:
f(1) = 1
f(n) = n + 2 f(n/2)
La forma cerrada de esta expresión es:
f(n) = n log2n
Es decir, la complejidad es O(n log2n).




Implementación:

//METODO DE ORDENACION: MERGESORT     
    public int MergeSort(int a[], int iMin, int iMax) 
    {
        mergeSort (a,iMin,iMax) ;
        return num_intercambios_ms;
    }
    public void mergeSort (int a[], int iMin, int iMax) 
    {
        // Caso Base
    if(iMin  >= iMax) 
        {
            return;
    }
    // Cortamos para aplicar mergeSort recursivamente
    int k = (iMin+iMax) / 2;
    mergeSort(a, iMin, k);
    mergeSort(a, k+1, iMax);
    // Utilizamos un arreglo temporal
    int l = iMax-iMin+1;
    int temp[] = new int[l];
    for(int i = 0; i <  l; i++)
        {
        temp[i] = a[iMin+i];
        }
    // Mezclamos
    int i1 = 0;
    int i2 = k-iMin+1;
    for(int i = 0; i <  l; i++) 
        {
            if(i2 < = iMax-iMin) 
            {
                if(i1 < = k-iMin) 
                {
                    if(temp[i1]  > temp[i2]) 
                    {
                        a[i+iMin] = temp[i2++];
                    }
                    else
                    {
                        a[i+iMin] = temp[i1++];
                    }
                }
                else
                {
                    a[i+iMin] = temp[i2++];
                }
                
                num_intercambios_ms++;
            }
            else 
            {
                a[i+iMin] = temp[i1++];
                
                num_intercambios_ms++;
            }
        }
    }

MÉTODO DE ORDENACIÓN HEAPSORT


Este algoritmo consiste en almacenar todos los elementos del vector a ordenar en un montículo (heap), y luego extraer el nodo que queda como nodo raíz del montículo (cima) en sucesivas iteracciones obteniendo el conjunto ordenado. Basa su funcionamiento en una propiedad de los montículos, por la cual, la cima contiene siempre el menor elemento (o el mayor, según se haya definido el montículo) de todos los almacenados en él. El algoritmo, después de cada extracción, re coloca en el nodo raíz o cima, la última hoja por la derecha del último nivel. Lo cual destruye la propiedad heap del árbol. Pero, a continuación realiza un proceso de "descenso" del número insertado de forma que se elige a cada movimiento el mayor de sus dos hijos, con el que se intercambia. Este intercambio, realizado sucesivamente "hunde" el nodo en el árbol restaurando la propiedad montículo del árbol y dejando paso a la siguiente extracción del nodo raíz.


Análisis de Complejidad:





Implementación:


 // METODO DE ORDENACION: HEAP SORT
    public int ordenacionMonticulos(int[] v) 
    {
        final int N = v.length;
        for(int nodo = N/2; nodo >=0; nodo--) hacerMonticulo(v, nodo, N-1);
        for(int nodo = N-1; nodo >=0; nodo--) {
            int tmp = v[0];
            v[0]    = v[nodo];
            v[nodo] = tmp;
            hacerMonticulo(v, 0, nodo-1);
        }
        return num_intercambios_hs;
    }
    public void hacerMonticulo(int[] v, int nodo, int fin)
    {
        int izq = 2*nodo+1;
        int der = izq+1;
        int may;
        if(izq >fin) return;
        if(der >fin) 
        {
            may=izq;  
            num_intercambios_hs++;
        }
        else
        {
            if(v[izq] >v[der])
                may= izq;
            else
                may=der; 
            num_intercambios_hs++;
        }
        if(v[nodo] <  v[may]) 
        {
            int tmp = v[nodo];
            v[nodo] = v[may];
            v[may]  = tmp; 
            num_intercambios_hs++;
            hacerMonticulo(v, may, fin); 
            num_intercambios_hs++;
        }
    }
Fuente Teóricas: Wikipedia, algunos documentos de Prezzi, apuntes de Clase.

sábado, 25 de julio de 2015

CIFRADO DE PLAYFAIR

El cifrado de Playfair es un ejemplo de sustitución digrámica, donde un par de letras de un texto en claro (mensaje sin codificar) se convierten en otro par distinto, para de esta forma codificar información que no deseamos sea leída.
El cifrado de Playfair trabaja con una matriz de 5x5 letras, cifrando por digramas (bloques de a dos caracteres).










IMPLEMENTACIÓN:

#include  < iostream > 
#include  < string.h > 
#include  < stdio.h > 
#include  < stdlib.h > 
#include < conio.h > 
using namespace std;

bool comparar(char *clave,char a,int k){
   
   for(int i=0;i < k;i++){
       if(clave[i]==a)
    return false;
   }
   
   return true;
}

char *preMatriz(char *clave,char *letras,char *textCpy){
 
 int k=0,i=0; 
 bool band=true;  
 
 while(k < 25){  
    
    if(clave[k]=='j')
     clave[k]='i'; 
     
    if(clave[k]!='\0' && band==true){ 
      if(clave[k]!=' ' && clave[k] > 96 && clave[k] < 123){      
      if(comparar(clave,clave[k],k)){
         textCpy[i]=clave[k];
      i++;                          
      }  
     }
    }
    else{
       if(band==true)
         k=0;
       band=false;
       if(comparar(textCpy,letras[k],i)){
          textCpy[i]=letras[k];
       i++;                          
       }
       }     
        
      k++;
 }
 textCpy[25]='\0';
 //cout <  < "i: " <  < i;
    return textCpy;
}

char *agrupar(char *text,char *textAgru){
 
 int k=0,i=0;
 int cont=0;
 
 while(text[k]!='\0'){
  
  if(text[k]=='j')
     text[k]='i';
  
  if(text[k]!=' '){
   if(cont!=2){
    textAgru[i]=text[k];
    cont++;
    i++;
   }
   else{
     if(textAgru[i-2]==textAgru[i-1]){
      textAgru[i-1]='x';
      textAgru[i]=' ';
            textAgru[i+1]=text[k-1];
            k--;
         i+=2;
         cont=1;
     } 
     else{     
         textAgru[i]=' ';
            textAgru[i+1]=text[k];
         i+=2;
         cont=1;
     }
    }     
  } 
  k++; 
 }
 //cout <  < "i: " <  < i <  < "\n";
 if(textAgru[i-2]==' '){ 
    textAgru[i]='x';
    textAgru[i+1]='\0';
    }
 else   
     textAgru[i]='\0';
     
 return textAgru;
}

void algoCifradoPlaySyFair(char *text,char *clave,char *letras){
 
 char textCpy[25];
 char textAgru[500]; 
 char matriz[5][5];
 int k=0,m=0,sum1,sum2;
 int f1,f2,c1,c2;
 bool band1=true,band2=true;
 
 strcpy(textCpy,preMatriz(clave,letras,textCpy));
 
 for(int i=0;i < 5;i++){
  for(int j=0;j < 5;j++){
   matriz[i][j]=textCpy[k];
   k++;
  }
 }
 
 strcpy(textAgru,agrupar(text,textAgru));
 
 cout <  < "\n" <  < textAgru;
 
 while(textAgru[m]!='\0'){
  
  for(int i=0;i < 5;i++){
   for(int j=0;j < 5;j++){
    if(matriz[i][j]==textAgru[m] && band1==true){     
     f1=i;
     c1=j;
     band1=false;
    }           
    if(matriz[i][j]==textAgru[m+1] && band2==true){     
     f2=i;
     c2=j;
     band2=false;
    }
   }
  }
  
  if(f1==f2){
   sum1=c1+1;
   sum2=c2+1;
   if(sum1 > 4)
      textAgru[m]=matriz[f1][0];
            else
               textAgru[m]=matriz[f1][c1+1];
               
            if(sum2 > 4)
      textAgru[m+1]=matriz[f2][0];
   else   
      textAgru[m+1]=matriz[f2][c2+1];
  }
  else if(c1==c2){
      sum1=f1+1;
      sum2=f2+1;
      
      if(sum1 > 4)
        textAgru[m]=matriz[0][c1];
      else
        textAgru[m]=matriz[f1+1][c1];
      
      if(sum2 > 4)
        textAgru[m+1]=matriz[0][c2];   
      else    
        textAgru[m+1]=matriz[f2+1][c2];   
  }else{
   textAgru[m]=matriz[f1][c2];  
            textAgru[m+1]=matriz[f2][c1];
  }
    
   m=m+3;
   band1=true;
   band2=true;
 }
 
 cout <  < "\n\n";
 for(int i=0;i < 5;i++){
  for(int j=0;j < 5;j++)
   cout <  < matriz[i][j] <  < " ";   
  cout <  < endl;
 }
 
 cout <  < "\n" <  < textAgru;
 
}

void descifradoPlaySyFair(char *text,char *clave,char *letras){
 
 char textCpy[25];
 char textAgru[500]; 
 char matriz[5][5];
 int k=0,m=0,sum1,sum2;
 int f1,f2,c1,c2;
 bool band1=true,band2=true;
 
 strcpy(textCpy,preMatriz(clave,letras,textCpy));
 
 for(int i=0;i < 5;i++){
  for(int j=0;j < 5;j++){
   matriz[i][j]=textCpy[k];
   k++;
  }
 }
 
 strcpy(textAgru,agrupar(text,textAgru));
 
 cout <  < "\n" <  < textAgru;
 
 while(textAgru[m]!='\0'){
  
  for(int i=0;i < 5;i++){
   for(int j=0;j < 5;j++){
    if(matriz[i][j]==textAgru[m] && band1==true){     
     f1=i;
     c1=j;
     band1=false;
    }           
    if(matriz[i][j]==textAgru[m+1] && band2==true){     
     f2=i;
     c2=j;
     band2=false;
    }
   }
  }
  
  if(f1==f2){
   sum1=c1-1;
   sum2=c2-1;
   if(sum1 < 0)
      textAgru[m]=matriz[f1][4];
            else
               textAgru[m]=matriz[f1][c1-1];
               
            if(sum2 < 0)
      textAgru[m+1]=matriz[f2][4];
   else   
      textAgru[m+1]=matriz[f2][c2-1];
  }
  else if(c1==c2){
      sum1=f1-1;
      sum2=f2-1;
      
      if(sum1 < 0)
        textAgru[m]=matriz[4][c1];
      else
        textAgru[m]=matriz[f1-1][c1];
      
      if(sum2 < 0)
        textAgru[m+1]=matriz[4][c2];   
      else    
        textAgru[m+1]=matriz[f2-1][c2];   
  }else{
   textAgru[m]=matriz[f1][c2];  
            textAgru[m+1]=matriz[f2][c1];
  }
    
   m=m+3;
   band1=true;
   band2=true;
 }
 
 cout <  < "\n\n";
 for(int i=0;i < 5;i++){
  for(int j=0;j < 5;j++)
   cout <  < matriz[i][j] <  < " ";   
  cout <  < endl;
 }
 
 cout <  < "\n" <  < textAgru;
 
 
 
}

int main()
{ 
 char letras[25]={'a','b','c','d','e',
                  'f','g','h','i','k',
      'l','m','n','o','p',
      'q','r','s','t','u',
      'v','w','x','y','z'}; 
 char text[500];
 char clave[250];
 int n;
 int opcion;
 cout <  < "\t\tALGORITMO PLAYFAIR";
 while(1)
 {
  system("cls");
  cout <  < "\n\t\tALGORITMO DE VERNAM\n\n";
  cout <  < "1. ENCRIPTAR\n";
  cout <  < "2. DESENCRIPTAR\n";
  cout <  < "INGRESE OPCION: ";
  cin >  > opcion;
  switch(opcion)
  {
  case 1: 
   {
    system("cls");
    cout <  < "\t\tALGORITMO PLAYFAIR - CIFRAR\n";
    cout <  < "INGRESAR TEXTO(SIN ESPACIOS): ";
    fflush(stdin);
    gets(text);
    
    cout <  < "INGRESE CLAVE: ";
    fflush(stdin);
    gets(clave);
    algoCifradoPlaySyFair(text,clave,letras);
    getch(); 
    break;
   }
  case 2:
   {
    system("cls");
    cout <  < "\t\tALGORITMO PLAYFAIR - DESCIFRAR\n";
    cout <  < "INGRESAR TEXTO(SIN ESPACIOS): ";
    fflush(stdin);
    gets(text);
    
    cout <  < "INGRESE CLAVE: ";
    fflush(stdin);
    gets(clave);
    descifradoPlaySyFair(text,clave,letras);
    getch(); 
    break;
   }
  }
 }
 system("pause");
 
}

CIFRADO DE VERNAM

El cifrado de Vernam también llamado máscara desechable es parecido al cifrado de Vigenère solo que aquí la clave es aleatoria y tan larga como el mensaje, además se debe utilizar una sola vez. Claude Shannon en su trabajo “Teoría de las comunicaciones secretas” demostró que estas características hacen que este cifrado sea perfectamente seguro ya que no hay manera de criptoanalizarlo (es matemáticamente complicado).
En este criptosistema tanto el texto plano, el texto cifrado y la clave son números modulo 2 (binario).
El método de cifrado y descifrado utilizan la función lógica XOR.

La longitud del texto (plano o cifrado) es obligatoriamente igual a la longitud de la clave.



Implementación
#include  < iostream > 
#include  < bitset > 
#include  < string.h > 
#include  < stdio.h > 
#include  < stdlib.h > 
#include < conio.h > 
using namespace std;

void algorCifraVernam(char *cadena, char *clave){
 
 char textEn[100];
 
 int tamCad,tamCla,cad,clav;
    int output[100][100];
 
 tamCad=strlen(cadena);
   tamCla=strlen(clave);
   
   strcpy(textEn,cadena);
       
    if(tamCad==tamCla){
     
  for(int i=0;i < tamCad;i++){
   for(int j=0;j < 7;j++){
    cad=(cadena[i] >  > (6-j))&1;
    clav=(clave[i] >  > (6-j))&1;
    output[i][j]=cad^clav;
   }
  }
  cout <  < "TEXTO CIFRADO: ";
  for(int i=0;i < tamCad;i++){
   for(int j=0;j < 7;j++)
    if(j==6)
    {cout <  < output[i][j];}
  }
  cout <  < "\n";
 }else
   cout <  < "LA LONGUITUD DE LA CADENA Y LA CLAVE DEBE DE SER LA MISMA";
}


void descripVernam(char *cadena, char *clave){
 
 char textEn[100];
 
 int tamCad,tamCla;
    int output[100];
 
 tamCad=strlen(cadena);
   tamCla=strlen(clave);
   
   strcpy(textEn,cadena);
       
    if(tamCad==tamCla){
     
  for(int i=0;i < tamCad;i++){      
   output[i]=cadena[i]^clave[i];
  }
  cout <  < "TEXTO DESCIFRADO: ";
  for(int i=0;i < tamCad;i++){   
    cout <  < output[i];   
  }
  cout <  < "\n";
 }else
  cout <  < "LA LONGUITUD DE LA CADENA Y LA CLAVE DEBE DE SER LA MISMA";
 
}

int main()
{
 char cadena[100];
 char clave[100];
 int opcion;
 while(1)
 {
  system("cls");
  cout <  < "\n\t\tALGORITMO DE VERNAM\n\n";
  cout <  < "1. ENCRIPTAR\n";
  cout <  < "2. DESENCRIPTAR\n";
  cout <  < "INGRESE OPCION: ";
  cin >  > opcion;
  switch(opcion)
  {
  case 1: 
   {
    system("cls");
    cout <  < "\n\t\tALGORITMO DE VERNAM  -  CIFRADO \n\n";
    cout <  < "INGRESE TEXTO: ";
    fflush(stdin);
    gets(cadena);
    
    cout <  < "INGRESE CLAVE: ";
    fflush(stdin);
    gets(clave);
    algorCifraVernam(cadena,clave);
    getch(); 
    break;
   }
  case 2:
   {
    system("cls");
    cout <  < "\n\t\tALGORITMO DE VERNAM  -  DESCIFRADO \n\n";
    cout <  < "INGRESE TEXTO: ";
    fflush(stdin);
    gets(cadena);
    cout <  < "INGRESE CLAVE: ";
    fflush(stdin);
    gets(clave);
    descripVernam(cadena,clave);
    getch(); 
    break;
   }
  }
 }
 system("pause");
}


CIFRADO DE VIGENERE

Este cifrado soluciona la debilidad del cifrado del César en que una letra se cifra siempre igual. Se usa una clave K de longitud L y se cifra carácter a carácter sumando módulo n el texto en claro con los elementos de esta clave.


Implementación:

#include  < iostream > 
#include  < cstdlib > 
#include  < string.h > 
#include < conio.h > 
using namespace std;

string alfabeto = "abcdefghijklmnopqrstuvwxyz";

void encriptardoVigenere (){
 string texto, clave, encriptar;
 cout <  < "\n\n\t INGRESE TEXTO(SIN ESPACIO): ";cin >  > texto;
 cout <  < "\n\n\t INGRESE CLAVE: ";cin >  > clave;
 
 int tamtexto = texto.size(); 
 int tamclave = clave.size(); 
 int postexto , posclave;
 if ( tamtexto  >  tamclave){
  for ( int i = 0; i  <  texto.size(); i++){
   clave += clave [i];
   //cout <  < " " <  < clave [i];
  }
  for ( int i = 0; i  <  texto.size(); i++){
  postexto = alfabeto.find(texto[i]);
  posclave = alfabeto.find(clave[i]); 
        encriptar += alfabeto[(postexto + posclave)%26];
  }
 }else {
  for ( int i = 0; i  <  texto.size(); i++){
   postexto = alfabeto.find(texto[i]);
   posclave = alfabeto.find(clave[i]); 
         encriptar += alfabeto[(postexto + posclave)%26];
  }
 }
 // mostrar texto encriptado
 cout <  < "\n\n\t TEXTO ENCRIPTADO:  ";
    for (int i = 0 ; i  <  texto.size() ; i++){
        cout <  < encriptar[i];
    } 
}

void desencriptar(){
 string texto, clave, desencriptar;
 int resultado;
 
 cout <  < "\n\n\t INGRESE TEXTO(SIN ESPACIO): ";cin >  > texto;
 cout <  < "\n\n\t INGRESE CLAVE: ";cin >  > clave;
 
 int tamtexto = texto.size(); 
 int tamclave = clave.size(); 
 int postexto , posclave;
 
 if ( tamtexto  >  tamclave){
  for ( int i = 0; i  <  texto.size(); i++){
   clave += clave [i];
   //cout <  < " " <  < clave [i];
  }
  for ( int i = 0; i  <  texto.size(); i++){
   postexto = alfabeto.find(texto[i]);
   posclave = alfabeto.find(clave[i]); 
   resultado = postexto - posclave;
   if ( resultado  <  0){
    resultado = 26 + resultado;
    desencriptar += alfabeto[resultado%26];
   }
   else{
    desencriptar += alfabeto[resultado%26];
   }         
  }
 }else {
  for ( int i = 0; i  <  texto.size(); i++){
   postexto = alfabeto.find(texto[i]);
   posclave = alfabeto.find(clave[i]); 
   resultado = postexto - posclave;
   if ( resultado  <  0){
    resultado = 26 + resultado;
    desencriptar += alfabeto[resultado%26];
   }
   else{
    desencriptar += alfabeto[resultado%26];
   }
  }
 } 
    cout <  < "\n\n\t TEXTO DESENCRIPTADO:  ";
    for (int i = 0 ; i  <  texto.size() ; i++){
        cout <  < desencriptar[i];
    }
}
int main (void)
{
     
 string alfabeto = "abcdefghijklmnopqrstuvwxyz";
 int opcion;
 cout <  < "\n\n\t\t CIFRADO DE VIGENERE";
 cout <  < endl;
 cout <  < endl;
 cout <  < "1. ENCRIPTAR ";
 cout <  < endl;
    cout <  < "2. DESENCRIPTAR";
    cout <  < endl;
    cout <  < endl;
    cout <  < "INGRESAR OPCION: ";
    cin >  > opcion;
    
    switch(opcion)
    {
     
  case 1:
  {
          
   encriptardoVigenere ();
   getch(); 
   break;
  }
  case 2:
  {
          
         desencriptar();
         getch(); 
         break;
        }
  system("pause");
 }
}

CIFRADO AFIN

El cifrado afín también se le llama cifrado de transformación afín o cifrado monoalfabético genérico. Es un tipo de cifrado por sustitución en el que cada símbolo del alfabeto en claro (el alfabeto del texto en claro) es sustituido por un símbolo del alfabeto cifrado (el alfabeto del texto cifrado) siendo el número de símbolos del alfabeto en claro igual que el número de símbolos del alfabeto cifrado. Para hallar el símbolo del alfabeto cifrado que sustituye a un determinado símbolo del alfabeto en claro, se usa una función matemática afín en aritmética modular. Para poder aplicar la función matemática lo primero que hay que hacer es asignar un orden que a cada símbolo de cada uno de los alfabeto le asocie un número de orden. Una vez establecido esto, la fórmula matemática tiene la siguiente forma:





Observación: Al momento de desencriptar el mensaje primero debemos evaluar que el valor del inverso de a exista caso contrario no se podrá realizar dicha operación.

En la implementación se han  visto algoritmos implementados con anterioridad , si no lo ha visto hasta el momento pase por las siguientes publicaciones:




Implementación:

import java.util.ArrayList;

/**
 *
 * @author Andres Esquivel
 */
public class Afin {
    private int a;
    private int b;
    private String cadena;
    private String alfabeto[] = new String[26];
    private String CadenaEncriptada;
    private String CadenaDesencriptada;
    public Afin(int a,int b,String cadena)
    {
        this.a=a;
        this.b=b;
        this.cadena=cadena;
        this.alfabeto[0]="a";
        this.alfabeto[1]="b";
        this.alfabeto[2]="c";
        this.alfabeto[3]="d";
        this.alfabeto[4]="e";
        this.alfabeto[5]="f";
        this.alfabeto[6]="g";
        this.alfabeto[7]="h";
        this.alfabeto[8]="i";
        this.alfabeto[9]="j";
        this.alfabeto[10]="k";
        this.alfabeto[11]="l";
        this.alfabeto[12]="m";
        this.alfabeto[13]="n";
        this.alfabeto[14]="o";
        this.alfabeto[15]="p";
        this.alfabeto[16]="q";
        this.alfabeto[17]="r";
        this.alfabeto[18]="s";
        this.alfabeto[19]="t";
        this.alfabeto[20]="u";
        this.alfabeto[21]="v";
        this.alfabeto[22]="w";
        this.alfabeto[23]="x";
        this.alfabeto[24]="y";
        this.alfabeto[25]="z";
    }
    public String LimpiarEspacios(String cadenas)
    {
        String aux="";
        //limpiando espacios en blanco
        for (int i = 0; i <  cadenas.length(); i++) 
        {
            if(cadenas.charAt(i)!=' ')//Mientras sea diferente de un espacio vamos concatenando caracter a caracter en una nueva cadena
            {
                aux=aux+cadenas.charAt(i);
            }
        }
        return aux;
    }
    public ArrayList< Integer > CadenaNumeros(String aux)
    {
        ArrayList< Integer > cadena_en_numeros= new ArrayList<  >();
        for (int j = 0; j <  aux.length(); j++) {
            
            for (int k = 0; k <  alfabeto.length; k++) 
            {
                if(alfabeto[k].charAt(0)==aux.charAt(j))//Comparando cada caracter de la cadena auxiliar con cada elemento del alfabeto y si corresponde a la letra estoy guardando su posicio
                {
                    cadena_en_numeros.add(k);
                }
            }
        }
        return cadena_en_numeros;
    }
    public String NumerosCadena(ArrayList< Integer > Lista)
    {
        String aux="";
        for (int i = 0; i <  Lista.size(); i++) {
            if(Lista.get(i)==0)
            {
                aux=aux+"a";
            }
            if(Lista.get(i)==1)
            {
                aux=aux+"b";
            }
            if(Lista.get(i)==2)
            {
                aux=aux+"c";
            }
            if(Lista.get(i)==3)
            {
                aux=aux+"d";
            }
            if(Lista.get(i)==4)
            {
                aux=aux+"e";
            }
            if(Lista.get(i)==5)
            {
                aux=aux+"f";
            }
            if(Lista.get(i)==6)
            {
                aux=aux+"g";
            }
            if(Lista.get(i)==7)
            {
                aux=aux+"h";
            }
            if(Lista.get(i)==8)
            {
                aux=aux+"i";
            }
            if(Lista.get(i)==9)
            {
                aux=aux+"j";
            }
            if(Lista.get(i)==10)
            {
                aux=aux+"k";
            }
            if(Lista.get(i)==11)
            {
                aux=aux+"l";
            }
            if(Lista.get(i)==12)
            {
                aux=aux+"m";
            }
            if(Lista.get(i)==13)
            {
                aux=aux+"n";
            }
            if(Lista.get(i)==14)
            {
                aux=aux+"o";
            }
            if(Lista.get(i)==15)
            {
                aux=aux+"p";
            }
            if(Lista.get(i)==16)
            {
                aux=aux+"q";
            }
            if(Lista.get(i)==17)
            {
                aux=aux+"r";
            }
            if(Lista.get(i)==18)
            {
                aux=aux+"s";
            }
            if(Lista.get(i)==19)
            {
                aux=aux+"t";
            }
            if(Lista.get(i)==20)
            {
                aux=aux+"u";
            }
            if(Lista.get(i)==21)
            {
                aux=aux+"v";
            }
            if(Lista.get(i)==22)
            {
                aux=aux+"w";
            }
            if(Lista.get(i)==23)
            {
                aux=aux+"x";
            }
            if(Lista.get(i)==24)
            {
                aux=aux+"y";
            }
            if(Lista.get(i)==25)
            {
                aux=aux+"z";
            }
        }
        return aux;
    }
    public void Encriptar()
    {
        ArrayList< Integer > cadena_en_numeros=new ArrayList<  >();
        ArrayList< Integer > numeros_encriptados=new ArrayList<  >();
        String aux;
        //LIMPIANDO ESPACIOS EN BLANCO
        aux=LimpiarEspacios(cadena);
        //Convirtiendo cadena auxiliar en numeros para luego proceder a su encripacion
        cadena_en_numeros=CadenaNumeros(aux);
        int C;
        //Encriptando = > C=aP+b(mod26)
        for (int m = 0; m< cadena_en_numeros.size(); m++) 
        {
            C=(a*cadena_en_numeros.get(m)+b)%26;
            numeros_encriptados.add(C);
        }
        //Convirtiendo numeros encriptados a una cadena que representara la cadena encriptada
        CadenaEncriptada=NumerosCadena(numeros_encriptados);
    }
    public void Desencriptar()
    {
        ArrayList< Integer > cadena_en_numeros=new ArrayList<  >();
        ArrayList< Integer > numeros_desencriptados=new ArrayList<  >();
        //Limpiar Espacios
        String aux=LimpiarEspacios(cadena);
        //Pasar la cadena a numeros
        cadena_en_numeros=CadenaNumeros(aux);
        //Desencriptando P=(inversa(a)*(c-b)))%26
        Inverso inverso= new Inverso();
        long inv;
        int aux_num;
        inv = (long) inverso.CalcularInverso(a,26);
        for (int i = 0; i <  cadena_en_numeros.size(); i++) {
            aux_num=(int) (inv*(cadena_en_numeros.get(i)-b))%26;
            if(aux_num< 0)
            {
                aux_num=aux_num+26;
            }
            numeros_desencriptados.add(aux_num);
        }
        //Convirtiendo de numeros a letras
        CadenaDesencriptada=NumerosCadena(numeros_desencriptados);
    }
    public String GetCadenaEncriptada()
    {
        return CadenaEncriptada;
    }
    public String GetCadenaDesencriptada()
    {
        return CadenaDesencriptada;
    }
}




Espero les halla sido de utilidad

CIFRADO DE CESAR

En criptografía, el cifrado César, también conocido como cifrado por desplazamiento, código de César o desplazamiento de César, es una de las técnicas de cifrado más simples y más usadas. Es un tipo de cifrado por sustitución en el que una letra en el texto original es reemplazada por otra letra que se encuentra un número fijo de posiciones más adelante en el alfabeto. Por ejemplo, con un desplazamiento de 3, la A sería sustituida por la D (situada 3 lugares a la derecha de la A ), la B sería reemplazada por la E, etc. Este método debe su nombre a Julio César, que lo usaba para comunicarse con sus generales.


El cifrado César muchas veces puede formar parte de sistemas más complejos de codificación, como el cifrado Vigenère, e incluso tiene aplicación en el sistema ROT13. Como todos los cifrados de sustitución alfabética simple, el cifrado César se descifra con facilidad y en la práctica no ofrece mucha seguridad en la comunicación.

EXPLICACIÓN DEL ALGORITMO:


El proceso  empieza  transformando las letras  del alfabeto en números, por ello considerando a P  como el equivalente numérico  de una  letra  en el texto plano,  y C como el equivalente  de la correspondiente letra  en el texto  cifrado, tenemos  la siguiente expresión denominada transformación del César:




IMPLEMENTACIÓN:
Nota el presente algoritmo recibe como parámetro el numero de desplazamientos a realizar, el algoritmo por defecto realiza 3.


public class Cesar{ 
 
    public String cifrado(String frase, int n){ 
 
        int i,j; 
 
        char fraseCifrada[] = new char[frase.length()]; 
 
        fraseCifrada = frase.toCharArray(); 
 
        for(i=0;i< frase.length();i++){ 
            for(j=0;j< n;j++){ 
                if((fraseCifrada[i] > =65 && fraseCifrada[i] < 90) || (fraseCifrada[i] > =97 && fraseCifrada[i] < 122)){ 
                    fraseCifrada[i]++;               
                } 
                else if(fraseCifrada[i]==90) 
                    fraseCifrada[i]='A'; 
                else if(fraseCifrada[i]==122) 
                    fraseCifrada[i]='a'; 
            } 
        } 
 
        frase = String.valueOf(fraseCifrada); 
 
        return frase; 
    } 
 
     
        public String descifrado(String frase, int n){ 
 
        int i,j; 
 
        char fraseDescifrada[] = new char[frase.length()]; 
 
        fraseDescifrada = frase.toCharArray(); 
 
        for(i=0;i< frase.length();i++){ 
            for(j=0;j< n;j++){ 
                if((fraseDescifrada[i] > 65 && fraseDescifrada[i] < = 90) || (fraseDescifrada[i] > 97 && fraseDescifrada[i] < =122)){ 
                    fraseDescifrada[i]--;               
                } 
                else if(fraseDescifrada[i]==65) 
                    fraseDescifrada[i]='Z'; 
                else if(fraseDescifrada[i]==97) 
                    fraseDescifrada[i]='z'; 
            } 
        } 
 
        frase = String.valueOf(fraseDescifrada); 
 
        return frase; 
    } 
}