martes, 24 de septiembre de 2013

Método de cifrado inventado (en Android)

En este caso voy a publicar una pequeña aplicación muy parecida a la de la publicación anterior, al menos en apariencia. En este caso, la principal diferencia con respecto a la anterior radica en el algoritmo de cifrado que se aplica. Se trata de un método creado por mi mismo mezclando sustitución y transposición en el mismo algoritmo.
Este algoritmo consiste en dos pasos:

  •  Primero se sustituye cada carácter del mensaje por el correspondiente a su posición en el alfabeto con un desplazamiento 9 si se trata de una letra y 5 si es un dígito. En caso de ser otro carácter no se modificará.
  • En segundo lugar, divide el mensaje resultante de aplicar el proceso anterior en partes de 3 caracteres y se invierte el orden de los caracteres en cada grupo. Después se vuelven a agrupar y así se obtiene el mensaje final cifrado.
La implementación del algoritmo de cifrado/descifrado se hace en una clase independiente con lo que es muy fácil cambiar el algoritmo utilizado sin tener que modificar la interfaz de usuario, o haciendo cambios mínimos.
A continuación podéis ver el código y descargar un fichero para instalarla en un dispositivo Android.


package com.example.firstapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ");


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     
       
        Button btnConvertir = (Button)findViewById(R.id.btnConvertir);
        Button btnLimpiar = (Button)findViewById(R.id.btnLimpiar);
     
        final EditText etPlano = (EditText)findViewById(R.id.etPlano);
        final EditText etCifrado = (EditText)findViewById(R.id.etCifrado);
     
        btnLimpiar.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
etPlano.setText("");
etCifrado.setText("");
}
});
     
        btnConvertir.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
String textoPlano = etPlano.getText().toString();
String textoCifrado = etCifrado.getText().toString();
int txtLen = etPlano.length();
int cifrLen = etCifrado.length();

ECipherDecipher ecd = new ECipherDecipher();

if ((txtLen != 0) || (cifrLen !=0))
{
if (txtLen > 0)
{
String contenidoCifrado = ecd.cifrar(textoPlano);
etCifrado.setText(contenidoCifrado);
}
else
{
String contenidoPlano = ecd.descifrar(textoCifrado);
etPlano.setText(contenidoPlano);
}
}
}
});
    }

}

El código correspondiente a la implementación del algorirtmo se muestra en el código siguiente.

package com.example.firstapp;

public class ECipherDecipher {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ");
private final String abc2 = new String("0123456789");

//Definición del desplazamiento en la parte de cifrado por sustitución (César)
private int DESPLAZAMIENTO_CARACTERES = 9;
private int DESPLAZAMIENTO_DIGITOS = 5;

public ECipherDecipher()
{

}

public String cifrar(String cadena)
{
char caracterCifrado;
int posCaracterPlano;
int posCaracterCifrado;
int endPosSubCadena;
StringBuilder sbTextoIntermedio = new StringBuilder();
StringBuilder sbTextoCifrado = new StringBuilder();
StringBuilder subCadena3;

//Convertimos a mayúsculas
String texto = cadena.toUpperCase();

//Para cada caracter del texto
for (int i=0; i<texto.length(); i++)
{
char caracter = texto.charAt(i);
//Si es alfabético
if (Character.isLetter(caracter))
{
//Desplazamiento de cada carácter 9 posiciones
posCaracterPlano = abc.indexOf(caracter);
posCaracterCifrado = (posCaracterPlano + DESPLAZAMIENTO_CARACTERES) % abc.length();
caracterCifrado = abc.charAt(posCaracterCifrado);
sbTextoIntermedio.append(caracterCifrado);
}
else if (Character.isDigit(caracter))
{
//Si es numérico
//Desplazamiento de cada dígito 5 posiciones
posCaracterPlano = abc2.indexOf(caracter);
posCaracterCifrado = (posCaracterPlano + DESPLAZAMIENTO_DIGITOS) % abc2.length();
caracterCifrado = abc2.charAt(posCaracterCifrado);
sbTextoIntermedio.append(caracterCifrado);

}
else
{
//En otro caso no modificar el carácter
sbTextoIntermedio.append(caracter);
}
}

//Con el texto convertido anteriormente cogemos subcadenas de longitud 3
//y los invertimos.
while (sbTextoIntermedio.length()>0)
{
endPosSubCadena = 3;

if (sbTextoIntermedio.length()< 3)
{
endPosSubCadena = sbTextoIntermedio.length();
}
subCadena3 = new StringBuilder(sbTextoIntermedio.substring(0, endPosSubCadena));
sbTextoIntermedio = sbTextoIntermedio.delete(0, endPosSubCadena);
subCadena3 = subCadena3.reverse();
sbTextoCifrado.append(subCadena3);
}

return sbTextoCifrado.toString();
}

public String descifrar(String texto)
{
char caracterDescifrado;
int posCaracterCifrado;
int posCaracterDescifrado;
int endPosSubCadena;
StringBuilder sbTextoIntermedio = new StringBuilder();
StringBuilder sbTextoCifrado = new StringBuilder();
StringBuilder sbTextoPlano = new StringBuilder();
StringBuilder subCadena3;

sbTextoCifrado = new StringBuilder(texto.toUpperCase());

//Con el texto cogemos subcadenas de longitud 3 y los invertimos.
while (sbTextoCifrado.length()>0)
{
//Posición de fin de la subcadena
endPosSubCadena = 3;

if (sbTextoCifrado.length()< 3)
{
endPosSubCadena = sbTextoCifrado.length();
}
subCadena3 = new StringBuilder(sbTextoCifrado.substring(0, endPosSubCadena));
sbTextoCifrado = sbTextoCifrado.delete(0, endPosSubCadena);
subCadena3 = subCadena3.reverse();
sbTextoIntermedio.append(subCadena3);
}

//Para cada caracter del texto
texto = sbTextoIntermedio.toString();

for (int i=0; i<texto.length(); i++)
{

char caracter = texto.charAt(i);
//Si es alfabético
if (Character.isLetter(caracter))
{
//Desplazamiento de cada carácter -9 posiciones
posCaracterCifrado = abc.indexOf(caracter);
posCaracterDescifrado = (posCaracterCifrado - DESPLAZAMIENTO_CARACTERES +
(abc.length())) % abc.length();
caracterDescifrado = abc.charAt(posCaracterDescifrado);
sbTextoPlano.append(caracterDescifrado);
}
else if (Character.isDigit(caracter))
{
//Si es numérico
//Desplazamiento de cada dígito -5 posiciones
posCaracterCifrado = abc2.indexOf(caracter);
posCaracterDescifrado = (posCaracterCifrado - DESPLAZAMIENTO_DIGITOS +
(abc2.length())) % abc2.length();
caracterDescifrado = abc2.charAt(posCaracterDescifrado);
sbTextoPlano.append(caracterDescifrado);
}
else
{
//En otro caso no modificar el carácter
sbTextoPlano.append(caracter);
}
}

return sbTextoPlano.toString();
}
}

La apariencia de la aplicación es casi igual a la de la aplicación descrita en la entrada anterior del blog.


El fichero de instalación se puede descargar aquí.

Cifrado César (aplicación en Android)

En esta entrada voy a mostrar una pequeña aplicación que permite cifrar mensajes utilizando el método César. Del mismo modo, permite descifrar los mensajes cifrados utilizando el proceso inverso. En este caso la interfaz de usuario es muy sencilla, la parte un poco más compleja es el código que realiza las operaciones de cifrado/descifrado.
A continuación os muestro el código y alguna imagen de la aplicación en funcionamiento. En primer lugar se muestra el código correspondiente a la actividad principal.

package com.example.firstapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;

public class MainActivity extends Activity {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ");
private int desplazamiento = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     
        Spinner spin1 = (Spinner)findViewById(R.id.spin1);
     
        ArrayAdapter<CharSequence> adaptador = ArrayAdapter.createFromResource(this, R.array.desplazamientos,
        android.R.layout.simple_spinner_item);
        adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spin1.setAdapter(adaptador);
     
     
        Button btnConvertir = (Button)findViewById(R.id.btnConvertir);
        Button btnLimpiar = (Button)findViewById(R.id.btnLimpiar);
     
        final EditText etPlano = (EditText)findViewById(R.id.etPlano);
        final EditText etCifrado = (EditText)findViewById(R.id.etCifrado);
     
        btnLimpiar.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
etPlano.setText("");
etCifrado.setText("");
}
});
     
        etCifrado.setOnKeyListener(new EditText.OnKeyListener() {
@Override
public boolean onKey(View arg0, int arg1, KeyEvent arg2) {
if (etPlano.getText().toString().compareTo("") != 0)
{
etPlano.setText("");
}
return false;
}
        });
     
        spin1.setOnItemSelectedListener(new OnItemSelectedListener() {

@Override
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
desplazamiento = pos;
}

@Override
public void onNothingSelected(AdapterView<?> arg0) {
desplazamiento = 0;
}
       
        });
     
        btnConvertir.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
String textoPlano = etPlano.getText().toString();
String textoCifrado = etCifrado.getText().toString();
int txtLen = etPlano.length();
int cifrLen = etCifrado.length();
CifradorDescifradorSustitucion cifDecif = new CifradorDescifradorSustitucion(desplazamiento);

if ((txtLen != 0) || (cifrLen !=0))
{
if (txtLen > 0)
{
String contenidoCifrado = cifDecif.cifrar(textoPlano);
etCifrado.setText(contenidoCifrado);
}
else
{
String contenidoPlano = cifDecif.descifrar(textoCifrado);
etPlano.setText(contenidoPlano);
}
}
}
});
    }

}

En segundo lugar se muestra el código de la clase dónde se implementa el cifrado y descifrado mediante el método César.

package com.example.firstapp;

public class CifradorDescifradorSustitucion {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ0123456789");

private int desplazamiento;
private String textoPlano;
private String textoCifrado;

public CifradorDescifradorSustitucion() {
desplazamiento = 0;
}

public CifradorDescifradorSustitucion(int desplazamiento) {
this.desplazamiento = desplazamiento;
}

public String descifrar(String textoCifrado) {
char caracterCifrado = ' ';
char caracterPlano = ' ';

textoCifrado = textoCifrado.toUpperCase();
StringBuilder textoPlano = new StringBuilder(textoCifrado.length());

for (int i = 0; i < textoCifrado.length(); i++) {
caracterCifrado = textoCifrado.charAt(i);
if (abc.contains(String.valueOf(caracterCifrado))) {
int posCaracterCifrado = abc.indexOf(caracterCifrado);
int posCaracterPlano = ((posCaracterCifrado - desplazamiento) + (abc
.length() + 1)) % (abc.length());
caracterPlano = abc.charAt(posCaracterPlano);
} else {
caracterPlano = caracterCifrado;
}
textoPlano.append(caracterPlano);
}

return textoPlano.toString();
}

public String cifrar(String textoPlano) {
char caracterCifrado = ' ';
char caracterPlano = ' ';

textoPlano = textoPlano.toUpperCase();
StringBuilder textoCifrado = new StringBuilder(textoPlano.length());

for (int i = 0; i < textoPlano.length(); i++) {
caracterPlano = textoPlano.charAt(i);
if (abc.contains(String.valueOf(caracterPlano))) {
int posCaracterPlano = abc.indexOf(caracterPlano);
int posCaracterCifrado = (posCaracterPlano + desplazamiento)
% (abc.length());
caracterCifrado = abc.charAt(posCaracterCifrado);
} else {
caracterCifrado = caracterPlano;
}
textoCifrado.append(caracterCifrado);
}
return textoCifrado.toString();
}

public int getDesplazamiento() {
return desplazamiento;
}

public void setDesplazamiento(int desplazamiento) {
this.desplazamiento = desplazamiento;
}

public String getTextoPlano() {
return textoPlano;
}

public void setTextoPlano(String textoPlano) {
this.textoPlano = textoPlano;
}

public String getTextoCifrado() {
return textoCifrado;
}

public void setTextoCifrado(String textoCifrado) {
this.textoCifrado = textoCifrado;
}

}

Por último se puede ver el código xml correspondiente al layout (muy sencillo como ya comenté anteriormente).

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Spinner
        android:id="@+id/spin1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/textView3"
        android:layout_below="@+id/textView1" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:text="@string/titulo_spin1" />

    <EditText
        android:id="@+id/etPlano"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/textView2"
        android:ems="10"
        android:hint="Texto plano aquí..."
        android:lines="4" >

        <requestFocus />
    </EditText>

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/etCifrado"
        android:layout_below="@+id/etPlano"
        android:layout_marginTop="45dp"
        android:text="@string/texto_cifrado" />

    <EditText
        android:id="@+id/etCifrado"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/etPlano"
        android:layout_below="@+id/textView3"
        android:ems="10"
        android:hint="Texto cifrado aquí..."
        android:lines="4" />

    <Button
        android:id="@+id/btnConvertir"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/etCifrado"
        android:layout_below="@+id/etCifrado"
        android:layout_marginTop="17dp"
        android:layout_toRightOf="@+id/textView3"
        android:text="@string/convertir" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/spin1"
        android:layout_below="@+id/spin1"
        android:text="@string/texto_plano" />

    <Button
        android:id="@+id/btnLimpiar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/btnConvertir"
        android:layout_alignBottom="@+id/btnConvertir"
        android:layout_alignLeft="@+id/etCifrado"
        android:text="Limpiar" />

</RelativeLayout>

El archivo de instalación podéis descargarlo aquí.