Cifrado en JAVA

Iniciado por DeBobiPro, Junio 11, 2015, 10:27:12 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Junio 11, 2015, 10:27:12 PM Ultima modificación: Junio 12, 2015, 10:25:37 AM por DeBobiPro
Les comparto un código que realicé en JAVA que cifra palabras o frases según una llave numérica que nosotro definamos


¿Cómo funciona?
Definimos una clave privada la cual usaremos para cifrar y desifrar el código ( esta clave tiene que ser numérica de largo variable)

Lo que hace es lo siguiente:

Si utilizamos la clave 9876 y la palabra "cifrado ejemplo" se ordenará de la siguiente manera

C  I  F R A D O     E  J   E  M P L O
9 8  7 6 9 8 7       6 9  8   7 6  9 8

finalmente hará un cifrado Cesar de X cantidad de saltos según el número asociado en el siguiente alfabeto
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ . , ; :

Si llega al final del alfabeto seguirá con el inicio.

Espero les sirva , acá el Code
Código: java
package cifradoJava;

public class CifradoJAVA {
        static char ALFA[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', '.', ',', ';', ':'};
        static int count = 0, pos;
        static String aux,encrypt;
       
    static String Cifrar(String key, String phrase) {
        count = 0;
        aux = "";
        encrypt = "";
        for (int i = 0; i < phrase.length(); i++) {

            if (!" ".equals(phrase.substring(i, i + 1))) {
                aux = aux + key.substring(count, count + 1);
                count++;
            } else {
                aux = aux + " ";
            }

            if (count > key.length() - 1) {
                count = 0;
            }
        }

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

            for (int j = 0; j < ALFA.length; j++) {
                if (String.valueOf(ALFA[j]).equalsIgnoreCase(phrase.substring(i, i + 1))) {
                    pos = j + Integer.parseInt(aux.substring(i, i + 1));

                    if (pos >= ALFA.length) {
                        pos = pos - ALFA.length;
                    }
                    encrypt = encrypt + ALFA[pos];
                }
                if (phrase.substring(i, i + 1).equalsIgnoreCase(" ")) {
                    encrypt = encrypt + " ";
                    j = ALFA.length;
                }
            }

        }

        //System.out.println(phrase);
        //System.out.println(aux);
        //System.out.println(encrypt);
        return encrypt;
    }

    static String Decifrar(String key, String phrase) {
        count = 0;
        aux = "";
        encrypt = "";
        for (int i = 0; i < phrase.length(); i++) {

            if (!" ".equals(phrase.substring(i, i + 1))) {
                aux = aux + key.substring(count, count + 1);
                count++;
            } else {
                aux = aux + " ";
            }

            if (count > key.length() - 1) {
                count = 0;
            }
        }

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

            for (int j = 0; j < ALFA.length; j++) {
                if (String.valueOf(ALFA[j]).equalsIgnoreCase(phrase.substring(i, i + 1))) {
                    pos = j - Integer.parseInt(aux.substring(i, i + 1));

                    if (pos < 0) {
                        pos = (ALFA.length) - pos;
                    }
                    //System.out.println("pos: "+pos);
                    encrypt = encrypt + ALFA[pos];
                }
                if (phrase.substring(i, i + 1).equalsIgnoreCase(" ")) {
                    encrypt = encrypt + " ";
                    j = ALFA.length;
                }
            }

        }
        return encrypt;
    }

    public static void main(String[] args) {

        String phrase = "debobipro";
        String key = "9876"; //Cualquier número

        System.out.println(Cifrar(key, phrase));
        System.out.println(Decifrar(key, Cifrar(key, phrase)));

    }

}


Que lo aprovechen :)!
Nivel 77 No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Gracias por el source, DeBobi. Como pequeña recomendación, trata de documentar los métodos para que sea mas easy to read.


Salu2.

si si, ayer estaba medio pillado, lo tengo casi documentado ya :3

Gracias por la recomendación
Nivel 77 No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Cuenta considerar caracteres especiales como ser @ ;).

Regards,
Snifer
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta


Llaman traidor a la persona que evito que caiga el foro, gente bruta!



Hola DeBobiPro,

1) Solo puedo ponerte en el corazón: ocúpate más intensamente con fundamentos y especialmente con convenciones de código.
2) Aquí no quiero ser vil pero: si está haciendo un pequeño ejercicio de programación en la escuela que utiliza el cifrado César como contenido, no significa eso que el código resultante sea de alguna utilidad para el público en general. Solo sirve para el propio entrenamiento personal de quien hace el ejercicio - nada más. Para TODO lo que se publica como resultado de un ejercicio habrá mejores soluciones. Estoy muy seguro de eso. Por ejemplo para el tema: cifrado.
Y, si uno piensa: "Eso no está pensado para algún uso productivo, sino como una ayuda para las personas que realizan este ejercicio o un ejercicio similar" entonces digo: No, ni siquiera eso. Primero, el resultado del trabajo de tales ejercicios suele ser tan deficiente en calidad que solo sirve como un ejemplo negativo, y en segundo lugar, deberían hacer otros, que hacen tal ejercicio, los ejercicios ellos mismos y no copiarlos. Pues el propósito de tales ejercicios no es el resultado/código final, sino la experiencia de llegar allí.

Saludos
Este es el mayor reproche al pueblo hispanohablante:

Que a pesar de su inteligencia y a pesar de su valentía siempre adoran el poder.

A lo mejor el autor ya ha aprendido la lección en los últimos cuatro años ;)

Pero ya que abres el debate...

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Primero, el resultado del trabajo de tales ejercicios suele ser tan deficiente en calidad que solo sirve como un ejemplo negativo
¿Y por qué es este un ejemplo negativo? ¿Qué harías de otra forma, y por qué?

Junio 03, 2019, 10:29:35 AM #6 Ultima modificación: Junio 03, 2019, 10:31:18 AM por Adalher
Hola ravenheart,

un detalle: los nombres de los métodos en Java se escriben por convención en lowerCamelCase.
Generalmente, los métodos para cifrar y descifrar están demasiado sobrecargados y difíciles de entender porque DeBobiPro ha puesto todos los pasos del cifrado/descifrado en un método. Además, el cambia las variables de clase dentro de los métodos. Estas variables pueden ser variables locales dentro de los métodos porque DeBobiPro no desea transportar información a través de múltiples llamadas de métodos con esas variables. Entonces esto evita un posible Multithreading (llamada de sus métodos desde múltiples Threads hacia afuera).
Los pasos individuales, así como se ven en DeBobiPro, son:
1. Asignar la frase a una secuencia de valores clave/números clave (su primer bucle).
2. Encontrar el índice de un carácter en el alfabeto (el bucle interno dentro del segundo bucle).
3. "Offsettear" este índice con el valor clave/dígito clave calculado en el paso uno.
4. Componer el resultado (en la variable 'encrypt').
5. Además, atender siempre el espacio.
Yo separaría más estos aspectos individuales, de tal forma que este claro qué cosa sucede exactamente y donde.
Por diversión, se ha construido una realización funcional del cifrado (usen jOOL No tienes permitido ver los links. Registrarse o Entrar a mi cuenta - según algunas opiniones, esto debería ser parte del JRE, pero da igual...) y se ha dividido más los pasos.
Código: java

import static java.util.stream.IntStream.range;
import static org.jooq.lambda.Seq.seq; // <- https://github.com/jOOQ/jOOL
import java.util.ArrayList;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class VerschlüsselungJAVA2 {
  private final static int ALFA[] = {
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', '.', ',', ';', ':'
  };
  private static Supplier<? extends IllegalArgumentException> characterNotInAlphabet(int cp) {
    return () -> new IllegalArgumentException("Character not in alphabet: " + Character.toString(cp));
  }
  private static int alphaAt(int index) {
    return ALFA[index % ALFA.length];
  }
  public static String encrypt(String key, String phrase) {
    // zip the phrase characters with the exclusive prefix
    // sum mapping the space to 0 and every other character to 1,
    // lookup the alphabet character and offset by the key digit
    // at the index provided by the prefix sum
    return seq(phrase.chars())
          .map(Character::toUpperCase)
          .zip(keyIndicesOf(phrase))
          .map(t -> t.v1 == ' ' ? ' ' : alphaAt(offset(t.v1, key, t.v2)))
          .map(Character::toString)
          .toString();
  }
  private static int findAlphabetIndexOf(int cp) {
    // 'C' -> 2
    return range(0, ALFA.length)
          .filter(i -> ALFA[i] == cp)
          .findFirst()
          .orElseThrow(characterNotInAlphabet(cp));
  }
  private static int offset(int phraseChar, String key, int keyIndex) {
    // Find the index of the phrase character and offset by the digit at the key index
    return findAlphabetIndexOf(phraseChar)
         + key.charAt(keyIndex % key.length()) - '0';
  }
  private static Stream<Integer> keyIndicesOf(String phrase) {
    // Exclusive prefix sum of the stream producing
    // 0 for spaces and 1 for every other character
    // "abc de f" -> [0, 1, 2, 2, 3, 4, 4, 5]
    return phrase.chars()
          .map(c -> isIgnored(c) ? 0 : 1)
          .collect(ArrayList<Integer>::new,
                   (l, v) -> l.add(v + (l.isEmpty() ? 0 : l.get(l.size() - 1))),
                   (l1, l2) -> {}).stream()
          .map(i -> i - 1);
  }
  private static boolean isIgnored(int c) {
    return c == ' ';
  }
  public static void main(String[] args) {
    String phrase = "cifrado ejemplo";
    String key = "9876"; // Cualquier número
    System.out.println(encrypt(key, phrase));
  }
}


Independientemente de la implementación real: el cifrado César NUNCA es razonable. Hay mejores métodos para cifrar.
Déjame intentar aclarar lo que realmente se quiere expresar con esto: El cifrado es relativamente complejo. Cuando se trata de cifrado, hay que tener en cuenta muchos aspectos. Ya el generador aleatorio de números aleatorios juega un papel importante. Los conceptos básicos ya son tan complejos que ellos obtienen su propia conferencia. Encriptaciones de César tan simples son una broma. Ellas pueden ser descifradas por ataques triviales. A esto entonces, de niño, ya basta con leer un libro correspondiente (Así que tenía un libro ? ? ? con acertijos en aquel entonces. Pues en un tiempo eso también era precisamente un tema...).
Y solo un ejemplo que muestra la complejidad:
Después de que se supo que alguien está trabajando para la NSA en un gran sistema operativo de código abierto y de que la confianza se había ido de repente, se necesitaron dos semanas (creo) solamente para ver si existía un debilitamiento del cifrado y cómo había llegado a existir este. Solo se tenía que comprobar los Commits de la persona.
U otro tema:
Imagínate que escribes un algoritmo que muestre de qué forma está ese algoritmo actualmente detrás del cifrado SSL. Uno podría pensar: Hurra, algoritmo logrado. Se ve bien. Pero no - incluso ahí hay muchos expertos que optimizan constantemente y descartan cosas antiguas! Por lo tanto, pertenece a la administración tanto en el cliente como en el lado del servidor, qué algoritmos se querrá permitir para el acceso SSL.
Por consiguiente, el cifrado no es tan trivial. Y si se desea tener un cifrado que conserve el formato, entonces también existen posibilidades correspondientes (No tienes permitido ver los links. Registrarse o Entrar a mi cuenta).
En general, se debe tener en cuenta que, con trabajos de desarrollo tan pequeños en la escuela y en el estudio, el aprendizaje está en primer plano. Allí se simplifica mucho. Entonces, de ahí se querrá escribir un árbol de búsqueda ordenado y equilibrado, pero eso no jugará ningún papel más más adelante porque se obtendrá soluciones mucho mejores (con mejor rendimiento), en donde además se utilizan hashcodes (Por lo tanto, el tipo de datos almacenado ya no necesita implementar un Comparable) y mucho más.
Si se quiere se puede hacer esto hasta tal punto que al final se tiene una base de datos In Memory o una base de datos en donde todo está almacenado con un Caching adecuado.
Así que, por favor, que no se tome esto personalmente, pero la evaluación del código para tareas estándar es correspondientemente así.

Saludos
Este es el mayor reproche al pueblo hispanohablante:

Que a pesar de su inteligencia y a pesar de su valentía siempre adoran el poder.

Hola DeBobiPro,

revisando de nuevo tu código se me ocurren estas cosas:
Esto está un poco roto en MUCHOS casos. Todos se reducen a un solo problema. Cuando la frase contiene algún carácter, ese cambio de N veces es un valor demasiado grande y causa un IndexOutOfBounds (phrase = ".", key = "4").

Ahora, la calidad del código:
. Los nombres de las clases deben ser camelCased.
. ALFA tendría que ser final.
. Código repetitivo que se puede reducir.

Aquí hay una versión mejorada que hace lo que hace el tuyo, pero es más limpia y extensible:
Código: java

public class Cifrar {
    private final String alfabeto;

    public Cifrar(String alfabeto) {
        this.alfabeto = alfabeto;
    }

    public String cifrar(String key, String phrase) {
        return rot(key, phrase, true);
    }

    public String decifrar(String key, String phrase) {
        return rot(key, phrase, false);
    }

    private String rot(String key, String phrase, boolean avanzar) {
        char[] fuera = new char[phrase.length()];
        for(int i = 0; i < phrase.length(); i++) {
            char c = phrase.charAt(i);
            int indexAlfa = alfabeto.indexOf(c);
            // Solo reemplaza caracteres en el alfabeto
            if (indexAlfa >= 0) {
                // Determina la cantidad de cambios del i'th char en la frase
                int keyIndex = i % key.length();
                int llave = Integer.parseInt(key.substring(keyIndex, keyIndex + 1));
                if(!avanzar)
                    llave = -llave;
                // Obtener el índice de reemplazo en el alfabeto
                int reemplazarIndex = (indexAlfa + llave) % alfabeto.length();
                if (reemplazarIndex < 0)
                    reemplazarIndex = alfabeto.length() + reemplazarIndex;
                // Reemplazar
                c = alfabeto.charAt(reemplazarIndex);
            }
            fuera[i] = c;
        }
        return new String(fuera);
    }
}


Y para usarlo:
Código: java

// Da caracteres soportados como cadena, pueden aparecer en cualquier orden.
Cifrar c = new Cifrar(
        "abcdefghijklmnopqrstuvwxyz" +
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
        "1234567890"
);
// key es una secuencia numérica
String key = "123456789";
// Frase y estados codificados/decodificados
String phrase = "aaaaaaaaaa abc def ghi jkl mno pqr stu vwxyz 123 456 7890 -_=+*&^%$#@! () [] {}";
String codificado = c.cifrar(key, phrase);
String decodificado = c.decifrar(key, codificado);
// Imprimir valores
System.out.println(phrase);
System.out.println(codificado);
System.out.println(decodificado);


Salida:
Código: php

aaaaaaaaaa abc def ghi jkl mno pqr stu vwxyz 123 456 7890 -_=+*&^%$#@! () [] {}
bcdefghijb dfh kmo ikm prt npr uwy Buw zBDFH 246 9ac f9ac -_=+*&^%$#@! () [] {}
aaaaaaaaaa abc def ghi jkl mno pqr stu vwxyz 123 456 7890 -_=+*&^%$#@! () [] {}


Cita de: DeBobiPro
ea

Cita de: Adalher
Retazo

Ten en cuenta que mi código es más limpio y cumple con los estándares POO.
DeBobiPro, escucha mis consejos para todo lo demás y deja de declarar matrices como si Java fuera C, por favor.
* 1 != 2: Esto es simplemente un meme. El paso 8 es donde las cosas van mal.

Lo mantuve conforme a la implementación de OP a este respecto intencionalmente.
Si bien la llave podría especificarse como int, eventualmente se convertiría en un string en este caso para obtener los dígitos. No es solo un gran número, sino una serie de números para cambiar. Probablemente sería mejor verificar las entradas en el constructor y lanzar una InvalidKeyException comprobada para casos ofensivos en lugar de tomar un int primitivo.
Código: java

public String cifrar(String key, String phrase) throws InvalidKeySpecException {
    verificar(key);
    return rot(key, phrase, true);
}

public String decifrar(String key, String phrase) throws InvalidKeySpecException {
    verificar(key);
    return rot(key, phrase, false);
}

private void verificar(String key)throws InvalidKeySpecException  {
    if (!key.matches("\\d+"))
        throw new InvalidKeySpecException("La clave solo debe contener una secuencia de dígitos");
}


Alternativamente, puedes pasar una matriz int para omitir el análisis de dígitos.
Entonces incluso podrías usar llaves como: int[] key = { -241, 24, 48, -3, 0, 93, 5 };
Código: java

public String cifrar(int[] key, String phrase) {
    return rot(key, phrase, true);
}

public String decifrar(int[] key, String phrase) {
    return rot(key, phrase, false);
}

private String rot(int[] key, String phrase, boolean avanzar) {
    char[] fuera = new char[phrase.length()];
    for(int i = 0; i < phrase.length(); i++) {
        char c = phrase.charAt(i);
        int indexAlfa = alfabeto.indexOf(c);
        // Solo reemplaza caracteres en el alfabeto
        if (indexAlfa >= 0) {
            // Determina la cantidad de cambios del i'th char en la frase
            int keyIndex = i % key.length;
            int llave = key[keyIndex];
            if(!avanzar)
                llave = -llave;
            // Obtener el índice de reemplazo en el alfabeto
            int reemplazarIndex = (indexAlfa + llave) % alfabeto.length();
            if (reemplazarIndex < 0)
                reemplazarIndex = alfabeto.length() + reemplazarIndex;
            // Reemplazar
            c = alfabeto.charAt(reemplazarIndex);
        }
        fuera[i] = c;
    }
    return new String(fuera);
}


Y sí, sea cual sea la salida que realmente se desee, mi código sería la opción óptima aquí, especialmente el fragmento final que ofrece más versatilidad y diversidad a pesar de que rompe por completo cualquier parecido con tu 'cifrado' (lo que de hecho es algo bueno en lo que respecta a esto porque el tuyo está roto y limitado a valores positivos de un solo dígito y falla en ciertos escenarios).
De todos modos, DeBobiPro, es una mejora con respecto a las publicaciones de BigBear al ver cómo esto al menos se compila. No es que debas tomar esto como un elogio. O tal vez deberías, ya no estoy seguro.


Saludos
Este es el mayor reproche al pueblo hispanohablante:

Que a pesar de su inteligencia y a pesar de su valentía siempre adoran el poder.