EnigmaCore: Mi proyecto de cifrado de texto para todos

Hola muy buenas, estoy aquí para presentaros mi proyecto: Enigma.

INSPIRACION:
La inspiración para este proyecto, como su nombre indica, viene de la maquina enigma utilizada en la segunda guerra mundial. Os dejo un video de Youtube donde se explica el mecanismo, para que os ubiquéis, ademas, me parece muy interesante: Video funcionamiento maquina enigma.

Aunque eso es, una inspiracion, a fin de cuentas, mi algoritmo no replica a la maquina Enigma, el funcionamiento es distinto.


EL PROYECTO:
El código esta escrito en Java.
Se trata de una clase que se encarga del cifrado y descifrado del texto proporcionado, según una contraseña única.

Al fin de cuentas es un cifrado cesar detras de otro, con un par de pasos extra para hacer mas dificil de romper el cifrado.

La idea es que la clase se use en diferentes proyectos, de hecho, necesita de otras clases para recibir el texto, la contraseña y otras instrucciones.
La idea es que se puedan crear diferentes programas orientados a diferentes aspectos (como puede ser, cifrado de texto, de documentos de texto, de mensajes, con interfaces gráficas o desde una terminal…), pero que todos compartan el núcleo, el proceso de cifrado / descifrado.

Es por eso que se llama EnigmaCore, porque es la base desde donde se pueden construir diferentes aplicaciones adaptadas a cada necesidad, todas compartiendo (y siendo compatibles entre ellas) el mismo algoritmo base.

Soy consciente de que existen algoritmos de cifrado mucho mas eficientes, complejos, seguros, y en definitiva, mejores. Pero yo, logicamente, no he crado este algoritmo con el objetivo de superar u ofrecer algo mejor que ningun algoritmo, sino como metodo de aprendizaje y frikeria pura.

Por eso mismo, me encantaria que alguien encontrara fallos y puntos debiles en mi algoritmo, y que me los expusiera, me encantaria que alguien rompa EnigmaCore_1.0, y que yo tenga que ingeniarmelas para crear EnigmaCore_2.0, y asi recursivamente, aprendiendo y disfrutando en el proceso.


FUNCIONAMIENTO EXTERNO (Como usar la clase EnigmaCore):
Como he dicho antes, la clase recibe el texto a procesar, y contraseña con la que procesar el texto.
La contraseña puede ser cualquier cadena de caracteres, con un minimo de 4, cuantos mas, en teoria mas seguro.
Estos parámetros se enviararn mediante los metodos getEncryptedText() y getDecryptedText().
Mediante dichos metodos, tambien recibiremos bien sea el texto encriptado, o desencrespado respectivamente.

Por lo tanto, y en teoría (depende del enfoque que se le quiera dar), la dinámica seria crear un objeto, utilizar uno de los dos métodos sobre el objeto, ya sea para encriptar o para desencriptar texto, al usar esos metodos, se pasaran por parametros la contraseña y el texto a manipular respectivamente, y ya, guardar, mostrar, o lo que se quiera hacer con el resultado.


CODIGO FUENTE:
En principio me propuse escribir todo el código en ingles, pero a la hora de comentarlo, bueno, simplemente me pase al castellano, por lo que disculpen la mezcla.
También me gustaría pediros perdón por mis muy probables faltas de ortografía en los comentarios, yo suelo programar en otro idioma, y no estoy acostumbrado a comentar código en castellano.
Dicho esto, os dejo el código de la clase EnigmaCore

/* EnigmaCore 1.0
 * Creado por: Sugoli15.
 * Subido a foro.linuxchad.org el dia 04/12/2024.
 * Editado el dia 10/12/2024: v0.0 --> v1.0 .
 */

/* Lista de caracteres sin revolver (130 elementos):
	{'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',
	'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',
	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
	'á', 'é', 'í', 'ó', 'ú', 'ü', 'Á', 'É', 'Í', 'Ó', 'Ú', 'Ü',
	'!', '"', '#', '$', '%', '&', '/', '(', ')', '=', '?', '¡', '¿', 
	'\'', '@', '€', '+', '-', '*', ',', '.', ';', ':', '_', '<', '>', '|', '\\', '^', '`', '[', ']', '{', '}', '~',
	' ', '\t', 
	'§', '°', 'ª', 'º', '·', '¤', '½', '¬', '¢', '£', '¥', '₧', '¶', '©', '®', '×', '÷'
	};*/

import java.util.Random;

public class EnigmaCore {

	
	private final static char [][] ruedas = {
		{'y', '€', 'ú', 'Ü', '7', 'S', '÷', 'O', '(', '1', '/', 'H', ':', 'u', 'q', 'Ñ', 'ü', 'á', 'e', 'L', 'P', '\'', '=', 'ñ', 'b', 'p', '-', '\t', '2', '¤', 'j', '{', '¥', 'U', '8', '?', '<', '®', 't', '°', '#', 'é', '%', '¶', 'X', 'V', 'Ó', 'T', '9', '©', 'R', '¬', 'M', 'z', 'Á', '§', '`', 'C', 'n', '3', 'W', '>', '.', '|', 'g', '₧', '6', '}', '·', '£', ']', '4', 'w', 'x', 'Í', 'c', 'J', 'l', '×', '5', ',', 'f', ';', '~', 'E', 'N', 'r', '@', 'v', '½', 'í', 'F', 'D', 'Q', 'Y', '_', 'Z', ' ', '0', '^', '¡', 'ó', 'ª', 'm', 'º', '!', '\\', 'k', 's', '¢', 'A', '&', '+', 'o', ')', 'K', 'I', '*', '[', '¿', 'B', 'a', 'i', 'd', '"', 'h', 'Ú', '$', 'É', 'G'}, // Rueda0
		{'Ú', 'Á', 'ó', 'z', 'n', '-', '_', ' ', ']', 'k', 'u', '©', 'f', '×', 'K', '¥', 'M', '#', 'w', '¶', 'v', 'Ü', '°', 'O', ';', '§', 'Y', '3', 'W', 'b', '&', '5', 'V', 'p', '>', '{', '<', 'g', 'i', 'X', '^', '/', 'U', 'É', 'I', '€', '(', '}', '\'', 'D', 'ü', '2', '1', '4', '\\', 'N', 'ú', '₧', '=', 'A', 'r', '÷', '¤', 'l', 'L', '!', 'ª', 'T', '6', '¬', 'G', 'ñ', 'm', 'S', '\t', 'h', 'H', '"', 'Q', 'Ó', '.', 'E', 'd', 'á', '%', '@', '¿', 'j', '8', 'q', 's', 't', '7', 'B', '9', '~', 'J', '[', 'Í', '+', '?', 'x', 'Z', '¡', 'P', 'F', '£', ':', 'C', '$', ',', 'Ñ', '·', 'a', '0', '`', '½', 'e', '¢', 'é', 'R', ')', '|', '®', 'c', 'í', 'o', 'y', 'º', '*'}, // Rueda1
		{'G', '×', '3', '¡', 'b', 'i', 'p', '¢', 'Y', 'í', 'v', '½', '#', 'I', 'Á', '@', ':', '\t', '!', 'x', 'Ú', '¬', 'f', 's', '©', '?', ',', '^', 'u', 'V', '/', ')', 'c', '|', 'T', 'W', '%', 'J', 'Ó', 'm', '\'', '{', 'P', '4', 'º', 'F', '.', 'C', 'ñ', 'ú', 'y', 'á', '>', 'a', '=', '6', 'n', '0', 'O', '₧', 'o', 'ó', 'j', 'U', '\\', '·', 't', 'h', 'é', ']', '£', 'l', 'B', 'M', 'L', 'D', '}', '_', '¤', '(', 'K', 'e', '¿', '[', '+', 'r', 'H', '1', '7', '€', 'Í', 'g', 'Q', '§', 'Ñ', '*', 'Ü', '5', 'ü', 'N', 'd', '9', 'w', '÷', '°', 'Z', 'A', '~', 'É', 'q', 'ª', '2', '8', 'z', 'E', '&', '¶', '®', 'R', '`', '-', 'X', '$', '¥', ' ', '"', 'S', '<', 'k', ';'}, // Rueda2
		{'h', 'Í', '2', '€', '*', '®', 'z', '°', 'T', 'J', 'y', 'b', '¿', 'x', 'Z', '5', 'w', '%', 'o', '!', 'j', 'ó', 'a', '§', '}', 'U', 'Y', 'R', 'ª', '~', ' ', 'ú', '·', '¬', '0', '¤', '1', 'Ó', '"', 'Ñ', 'i', '/', 'í', '6', '\t', ',', 'Ü', 'é', 'B', '4', 'L', 'M', '=', 'ñ', ';', 'K', 'S', '¢', '9', 'l', 'c', '©', 's', 'N', 'ü', 't', 'P', 'C', 'u', '-', 'V', 'q', '3', '\'', ']', '½', 'n', 'á', 'r', '÷', '8', '$', '#', 'H', 'd', ')', '(', '<', '₧', '@', 'p', '{', 'v', '&', '£', 'E', 'I', 'g', '¥', '7', 'k', 'Ú', '^', 'G', 'e', 'F', '.', 'f', 'X', 'm', '\\', 'º', 'Á', 'W', 'O', '?', '_', '¶', '¡', 'Q', 'D', '>', '`', '×', '[', '|', ':', 'É', 'A', '+'}, // Rueda3
		{'¤', ')', '=', 'x', '`', '_', '{', 'P', '4', 'U', ';', '>', '$', '¶', 'É', 'C', 'Í', '0', 'M', 'F', '®', '·', '8', '©', '2', '÷', 'O', 'N', '£', '6', '₧', '%', '&', '3', '5', 'Ü', '7', '°', 'z', 'c', 'j', 'K', 'k', 'ó', '¥', ']', '¬', '@', 'S', '^', '?', 'f', '€', '"', 'y', 'D', 'o', ',', '¿', 'X', 'E', 'u', 'l', '\\', '}', 'I', 'H', 'ª', 'b', 'º', 'Á', 'w', 'é', '[', '¡', 'J', 'Ñ', 'Ó', '§', '1', 'a', 'W', 'R', 'V', 'A', '*', 'e', 'ñ', 'Z', 's', 'T', 'q', '~', 'r', '<', 'v', 'Y', '\'', '#', ' ', '.', ':', 'L', 't', 'h', '+', 'ú', '½', '|', 'ü', '(', '-', '×', 'G', 'p', 'd', '!', '/', 'Ú', 'm', 'g', '\t', 'i', 'í', 'Q', '¢', 'n', 'B', 'á', '9'}, // Rueda4
		{'`', '€', '7', 't', 'z', '¬', '9', '6', '£', 'ó', '¿', '-', 'Ú', 'P', ']', 'N', 'ú', '#', '÷', '{', 'b', '§', '>', '2', '×', 'C', 'm', ',', '₧', 'o', 'h', 'k', 'B', 'u', 'S', 'Ñ', 'í', 'T', '$', '~', ':', '®', 'Í', 'J', '\'', 'á', 'D', 'Ü', 'X', '\\', '¡', '^', 'v', 'I', 'ª', 'R', 'é', 'H', 'Á', 'ñ', ')', 'r', 'ü', '8', '@', '}', 'A', '¤', 'W', '©', 'K', 'y', 'f', 'F', '1', '!', 'O', '=', 'a', 'x', 'q', '&', 'j', '3', 'V', 'n', 'l', 'Ó', 'U', '"', '0', '[', 'g', '|', 'Z', '·', '4', '%', 'G', '¥', '<', 'd', '¶', 'p', '?', 'L', '/', '¢', '+', 'E', '(', ';', '*', 'c', ' ', '\t', 'Q', '½', '_', 'Y', 'w', 'i', '.', 'e', 's', '5', '°', 'É', 'º', 'M'}, // Rueda5
		{'Y', '"', 'é', '^', '\\', 'G', '6', '¶', 'p', '4', '/', '½', 'W', 'U', 'Ó', 'f', '&', '{', 'E', 'P', '9', 's', '-', 'á', 'o', 'v', 'k', 'R', 'A', 'h', '¢', '.', 'ª', 'H', 'm', 'í', 'Z', '[', 'º', 'z', 'K', '©', 'I', 'Ü', '>', 'C', '1', 'i', 'Í', 'Q', '×', 'V', 'S', 'M', '@', '<', 'e', '#', 'x', '(', '§', 'É', 'F', 'a', 'y', '$', '\t', '}', '¥', '¤', '°', 'c', 'D', '`', 'Ú', 'g', '=', 'ó', '·', '®', '£', '7', 'u', '+', 'ñ', '¡', 'B', ' ', '0', 'X', '₧', 'j', 'Ñ', 'L', 'O', 'w', 'l', '_', ';', '%', 'J', '~', '5', 'ú', '?', '÷', 'q', '\'', '¿', 'b', 'N', '2', ')', '|', '€', 'Á', 'ü', ',', 't', 'T', '3', '8', ':', '!', '*', ']', 'r', 'd', 'n', '¬'}, // Rueda6
		{'^', '!', '°', '½', '"', 'e', '¥', '+', 'Ü', 'Ú', 'ó', '£', 'N', '&', 'ü', 'º', '5', 'T', ',', '*', '$', 'w', 'B', 'X', '3', '2', '4', 'A', '¿', 'r', 'ª', 'Ñ', 'í', 'k', 'Ó', 'I', '(', '§', 'a', 'g', '€', 'J', 'P', '©', ')', 'M', 't', '\\', '0', '_', 'ú', 'y', '\'', '>', 'S', 'D', '₧', '~', 'Á', 'Z', '#', 'F', '/', '¢', 'n', '®', '¤', '×', 'E', 'ñ', 'q', 'Y', 'f', 'C', 'u', '=', '¬', '?', 'é', 'O', 's', 'b', 'j', '|', 'p', '%', '\t', '}', 'L', ' ', 'i', 'U', '¶', 'z', ']', 'm', '`', 'l', '{', 'V', '@', 'H', 'R', ':', 'c', '÷', '¡', '6', 'Í', 'h', '9', 'v', 'K', '·', '.', 'á', '[', 'É', '1', 'W', '<', '7', '8', 'o', 'x', 'Q', 'G', '-', 'd', ';'}, // Rueda7
		{'y', 'f', '@', 'p', 'u', 's', 'Ü', 'x', 'n', '©', ']', ')', '5', 'S', '§', '\\', 'P', 'ª', '%', 'Y', '[', 'E', 'o', 'z', 'Ú', '(', 'i', '1', '~', 'U', 'ú', '*', 'F', 'e', ':', '9', 'ó', '_', '₧', 'í', 'D', '£', 't', 'H', '7', 'N', 'ü', 'Ó', 'M', '+', 'É', '^', '>', '÷', 'q', '}', 'Ñ', 'W', 'A', 'L', '·', 'g', 'm', '3', '×', ' ', '!', '€', '°', '=', 'é', 'º', '¤', '¢', '®', 'I', 'c', '8', 'h', '6', 'b', '#', '0', 'j', 'r', 'B', 'V', 'O', '¬', 'l', ';', '\t', '4', 'Í', '\'', 'k', '-', 'ñ', 'X', '`', '{', 'Z', '|', 'C', '¡', 'K', 'T', 'a', 'w', ',', '/', '¥', 'Q', 'd', 'v', '"', 'J', '&', 'á', '¶', '$', '½', '<', 'G', 'R', '¿', '?', 'Á', '2', '.'}, // Rueda8
		{'J', 't', 'Ü', '(', 'ª', '₧', '¢', ']', 'l', 'C', 'F', '4', '@', '[', 'ü', '·', 'X', '½', 'O', ')', 'É', '?', 'Á', 'º', '}', 'p', 'k', 'Y', 'e', '-', '§', '9', 'u', 'ó', 'ñ', ' ', ',', 'Z', 'Ó', '€', 'h', 'o', 'M', '#', '.', '÷', 'P', 'a', 'b', '3', '$', 'r', 'z', '+', '_', '2', '¥', '!', 'G', 'f', '1', 'c', '{', '¡', 'L', 'x', 'i', 'v', 'S', '<', 'N', '`', 'K', 'B', 'Í', 'W', '>', '¶', 'I', '\\', 'j', '\t', '=', '×', '|', '®', '*', 'n', ':', '"', 'y', '¿', 'g', 'í', '°', 'Q', '6', 'U', 'á', ';', 'A', 'Ñ', '7', '%', 'H', '/', '^', 'D', '&', '¤', '0', 'd', 'T', 'ú', 'q', 'é', '¬', 'm', 'R', 'E', 'Ú', 'w', '\'', 'V', 's', '8', '©', '5', '~', '£'}  // Rueda9
	};
	
	private String password;
	private String text;
	private String passwordInt = "";
	
	/**
	 * Emula el comportamiento del metodo constructor.
	 * @param pass (String), Contraseña unica.
	 * @param txt (String), Texto a manipular.
	 */
	private void builder(String pass, String txt) {
		password = pass;
		text = txt;
		
		/**
		 * Convertir contraseña (String) a numeros,
		 * los cuales podran ser interpretados en los calculos de encriptacion y desencriptacion.
		 * Seguira manejandose como String por razones de comodidad.
		 * 
		 * La conversion de char a int, sera en base al codigo ascii de cada caracter.
		 */
		passwordInt = "";
		for (int i = 0; i < password.length(); i++) {
			passwordInt += ((int)password.charAt(i));
		}
	}
	
	/**
	 * Metodo publico para encriptacion de texto.
	 * Encripta el texto proporcionado.
	 * Utiliza la contraseña proporcionada.
	 * @param pass (String), Contraseña unica.
	 * @param txt (String), Texto a manipular.
	 * @return (String), Texto encriptado.
	 */
	public String getEncryptedText(String pass, String txt) {
		
		builder(pass, txt);
		
		String encryptedText = "";
		String textForEncrypt = getRandomChars() + text; // Contiene los caracteres aleatorios + el texto a encriptar.
		
		String temporalEncryptedText = "";
		
		/**
		 * Se ejecutara el numero de elementos de la contraseña utilizados para la identificacion de diferentes ruedas.
		 * En cada ejecucion i hara referencia a la rueda que se usara para encriptar el texto.
		 */
		for (int i = 0; i < GetListCuantity(); i++) {
			/**
			 * Se ejecutara el numero de caracteres que existan en el texto a encriptar.
			 * En cada ejecucion se encriptara un caracter y se iran sumando en temporalEncryptedText.
			 */
			for (int j = 0; j < textForEncrypt.length(); j++) {
				
				char decryptedChar = textForEncrypt.charAt(j); // Guardara el caracer que se encriptara en esta ronda.
				
				int decryptedCharIndex = getIndexOf(decryptedChar, getList(i)); // Guardara la posicion del caracter sin encriptar. 
				
				/**
				 * Guarda la posicion del caracter encriptado.
				 * Se produce la "encriptacion".
				 * Se calcula con el salto de posicion de la rueda, y j (la posicion del caracter en el String textForEncrypt).
				 */
				int encryptedCharIndex = decryptedCharIndex + getJumpsCuantity() + j;

				/**
				 * Se asegura que despues de la operacion, encryptedCharIndex este dentro de los limites de la rueda.
				 * Entender este proceso como un circulo: Cuando llega al final de la lista, vuelve al principio.
				 */
				while ((encryptedCharIndex < 0) || (encryptedCharIndex >= ruedas[getList(i)].length)) {
					encryptedCharIndex -= ruedas[getList(i)].length;
				}
				
				temporalEncryptedText += ruedas[getList(i)][encryptedCharIndex] + ""; // Se guardan los caracteres encriptados de esta ronda.
			}

			textForEncrypt = temporalEncryptedText; // El proceso se reinicia, siendo el texto que se va a encriptar ahora, el anteriormente encriptado.
			temporalEncryptedText = "";
		}
		
		encryptedText = textForEncrypt;
		
		return encryptedText;
	}
	
	/**
	 * Metodo publico para desencriptacion de texto.
	 * Desencripta el texto proporcionado.
	 * Utiliza la contraseña proporcionada.
	 * @param pass (String), Contraseña unica.
	 * @param txt (String), Texto a manipular.
	 * @return (String), Texto desencriptado.
	 */
	public String getDecryptedText(String pass, String txt) {
		
		builder(pass, txt);
		
		String decryptedText = "";
		String textForDecryp = text;
		
		String temporalDecryptedText = "";
		
		/**
		 * Se ejecutara el numero de elementos de la contraseña utilizados para la identificacion de diferentes ruedas.
		 * En cada ejecucion i hara referencia a la rueda que se usara para desenciptar el texto.
		 * Empieza desde el final de dichos elementos hasta el primero de los mismos, ya que la encriptacion es en sentido contrario.
		 */
		for (int i = GetListCuantity() - 1; i >= 0; i--) {
			/**
			 * Se ejecutara el numero de caracteres que existan en el texto a encriptar.
			 * En cada ejecucion se encriptara un caracter y se iran sumando en temporalDecryptedText.
			 */
			for (int j = 0; j < textForDecryp.length(); j++) {
				
				char encryptedChar = textForDecryp.charAt(j); // Guardara el caracer que se desencriptara en esta ronda.
				
				int encryptedCharIndex = getIndexOf(encryptedChar, getList(i)); // Guardara la posicion del caracter encriptado. 
				
				/**
				 * Guarda la posicion del caracter desencriptado.
				 * Se produce la "desencriptacion".
				 * Se calcula con el salto de posicion de la rueda, y j (la posicion del caracter en el String textForDecryp).
				 */
				int decryptedCharIndex = encryptedCharIndex - getJumpsCuantity() - j;

				/**
				 * Se asegura que despues de la operacion, decryptedCharIndex este dentro de los limites de la rueda.
				 * Entender este proceso como un circulo: cuando llega al final de la lista, vuelve al principio.
				 */
				while ((decryptedCharIndex < 0) || (decryptedCharIndex >= ruedas[getList(i)].length)) {
					decryptedCharIndex += ruedas[getList(i)].length;
				}
				
				temporalDecryptedText += ruedas[getList(i)][decryptedCharIndex] + ""; // Se guardan los caracteres desencriptados de esta ronda.
			}
			textForDecryp = temporalDecryptedText; // El proceso se reinicia, siendo el texto que se va a desencriptar ahora, el anteriormente desencriptado.
			temporalDecryptedText = "";
		}
		
		// Elimina los caracteres aleatorios y guarda el resultado final en decryptedText.
		for (int i = getRandomCharsCuantity(); i < textForDecryp.length(); i++) {
			decryptedText += textForDecryp.charAt(i);
		}

		return decryptedText;
	}
	
	
	// ---------- Metodos para facilitar Encriptacion / Desencriptacion ----------
	
	/**
	 * Devuelve un String con caracteres aleatroios (contemplados en ruedas[0]) que seran usados en la construccion del texto encriptado.
	 * El tamaño del String depende del metodo getRandomCharsCuantity().
	 * @return (String), Caracteres aleatorios.
	 */
	private String getRandomChars() {
		
		Random random = new Random();
		String randomChars = "";
		
		for (int i = 0; i < getRandomCharsCuantity(); i++) {
			randomChars += ruedas[0][random.nextInt(0, ruedas[0].length)] + "";
		}
		
		return randomChars;
	}

	/**
	 * Devuelve la posicion del caracter especificado en la lista ("rueda") especificada.
	 * Si no encuentra el caracter, devolvera la posicion 0.
	 * @param c (char), El caracter que buscamos.
	 * @param r (int), La lista en la que se buscara el caracter. (0-10)
	 * @return (int), Posicion (index) del caracter especificado en la lista especificada.
	 */
	private int getIndexOf(char c, int r) {
		for (int i = 0; i < ruedas[r].length; i++) {
			if (ruedas[r][i] == c) {
				return i;
			}
		}
		return 0;
	}
	
	
	// ---------- Metodos para segmentar contraseña	----------
	
	/**
	 * Devuelve El primer elemento de passwordInt, ese numero determinara cuantos caracteres aleatorios se generan al inicio de un texto encriptado.
	 * @return (int), Cantidad de caracteres aleatorios.
	 */
	private int getRandomCharsCuantity() {
		return Integer.parseInt(passwordInt.charAt(0) + "");
	}
	
	/**
	 * Devuelve El segundo y tercer elemento de passwordInt, como un unico numero de dos digitos. 
	 * Ese numero determinara cuantos saltos dara un caracter en la lista al ser encriptado / desencriptado.
	 * @return (int), Cantidad de saltos.
	 */
	private int getJumpsCuantity() {
		return Integer.parseInt(passwordInt.charAt(1) + "" + passwordInt.charAt(2));
	}
	
	/**
	 * Devuelve la cantidad de elementos que quedan por usar en passwordInt, del 4. elemneto en adelante. 
	 * Se podria entender como una lista imaginaria.
	 * @return Cantidad de elementos lista ficticia.
	 */
	private int GetListCuantity() {
		return passwordInt.length() - 3;
	}
	
	/**
	 * Devuelve el elemento que expecifiquemos de la lista imaginaria que se puede definir gracias al metodo GetListCuantity().
	 * Enpezara del 4. elemneto en adelante. 
	 * @param index (int), Correspornde al elemento de la linera imaginaria, empezndo por 0.
	 * @return (int), Elemento especificado.
	 */
	private int getList(int index) {
		return Integer.parseInt(passwordInt.charAt(index + 3) + "");
	}
		
}

Tambier os dejo una clase secundaria muy basica que he credo como ejemplo de un uso basico de EnigmaCore, la he llamado EnigmaCoreTester

import java.util.Scanner;

public class EnigmaCoreTester {

	public static void main(String[] args) {
		
		Scanner entrada = new Scanner(System.in);
		
		char accion;
		do {
			System.out.print("  > ¿Que proceso desea realizar? Encriptar (E) / Desencriptar (D): ");
			accion = entrada.nextLine().toLowerCase().charAt(0);
		} while (accion != 'e' && accion != 'd');
		
		String pass;
		String mensageError = "";
		do {
			System.out.print("  > " + mensageError + "Introduzca su contraseña: ");
			pass = entrada.nextLine();
			mensageError = "La contraseña proporcionada es demasiado corta, ";
		} while (pass.length() < 4);
		
		System.out.print("  > Introduzca el texto que desea procesar: ");
		String texto = entrada.nextLine();
		
		entrada.close();
		
		EnigmaCore enigma = new EnigmaCore();
		
		if (accion == 'e') {
			
			System.out.println("   => Texto encriptado:");
			System.out.println("----------------------------------------");
			System.out.println(enigma.getEncryptedText(pass, texto));
			System.out.println("----------------------------------------");
			
		} else {

			System.out.println("   => Texto desencriptado:");
			System.out.println("----------------------------------------");
			System.out.println(enigma.getDecryptedText(pass, texto));
			System.out.println("----------------------------------------");
			
		}
	}

}


POSDATA
Me gustaria aclarar que soy estudiante de programacion, no tengo ni mucha experiencia ni muchos conocimientos, y, que es la primera vez que publico un proyecto personal, por lo que es muy probable que comente mal, mucho, poco… Paero bueno, es por eso mismo que hago este tipo de cosas, para aprender.

Ademas, como ya he dicho antes, lo que mas me gustaria es que alguien rompa mi algoritmo, por lo voy a dejar un reto, un texto cifrado:

¿6¥áj#ɶ£"÷;×Lw(Up=G¥.Ñ XLsº0L¥LÜUmo·e9!€LHq€®/é×*©Bm.$uXá.LWF¤"¡l@@7WKGKs!qqv!áf_|UPVv~9^ AÑ¿BHN:"á·÷U6:Mp]~7@º4]{L6aij6ÜÑdLº+odt¶É&D~ai׬oWuaR]|1º9)¥	'?Ü<ɽ!épbq\(d=¿>19:VdpªíH¿w+£

Esperare ansioso a que alguien me responda con el texto original y la contraseña que he usado…

Sin mucho mas que decir,
Estare encantado de responder cualquier pregunta o duda, y mas aun de recivir algun consejo.
Muchas gracias por leer,
Un saludo : )


EDITADO EL DIA 10/12/2024 v0.0 → v1.0
He editado un aspecto del codigo que NO influye en el algoritmo de cifrado / descifrado, por lo que los textos encriptados con la version 0.0 seguiran siendo compatibles con la version 1.0 .

Lo que he modificado es como se interactua con la clase EnigmaCore, en esta version, en vez de especificar el texto a manipular y la contraseña en la creacion del objeto (condenandolo a tener que crear un objeto para cada vez que queremos usar uno de los dos metodos publicos), dichos parametros seran especificados en los metodos getEncryptedText() y getDecryptedText().

Por lo que al crear un objeto, se podran usar los metodos todas las veces que se quiera, sin que estos influyan entre ellos.

Los apartados editados de este tema son:

  • FUNCIONAMIENTO EXTERNO (Como usar la clase EnigmaCore).
  • CODIGO FUENTE: EnigmaCore , y EnigmaCoreTester

A parte de estos cambios, ha sido solucionado un bug critico relacionado con el metodo builder(), gracias al reporte del usuario @LosHerederosDeRosas.

9 Me gusta

Esta interesante, aunque yo soy más de usar c. Aunque puedo entender algo de java, soy auto didacta.
Lo adapte para poder usar los argumentos de linea de comandos, y me funciona mal…

package main;

public class Main{
	public static void main(String[] args){
		//Inserte su codigo de la funcion main
		EnigmaCore enigma =
			new EnigmaCore(
				args[0]
			,	args[1]
			);
		String pass = enigma.getEncryptedText();
		System.out.println(pass);
		String rtas = enigma.getDecryptedText();
		System.out.println(rtas);
	}
}

Y a la hora de usarlo:

java -cp bin main.Main claveausar textoadesencriptar
(m^ñÚúDºp¥|.+EUh¢VO¿pé¢QSVi
`H6NCÉ$÷ª

El primero es el encriptado, y el segundo es el desencriptado, eso se supone…

1 me gusta

Buenas @LosHerederosDeRosas,
Por lo que veo, parece que tienes un pequeño error de lógica en tu clase Main.

Al crear un objeto EnigmaCore, le estás pasando un texto a manipular y una contraseña, por lo que la acción de cifrar / descifrar siempre sera sobre el mismo texto.

Si creas el objeto pasándole como parámetro el texto al que quieres aplicarle el cifrado, y le pides el el resultado cifrado respectivamente recibirás el texto cifrado, pero el texto del objeto seguirá siendo el texto no cifrado, por lo que si después le pides que lo descifre, aplicará el algoritmo de descifrado en el texto que no esta cifrado, y el resultado no sera el esperado…

Aplicando esto a la práctica, he retocado tu clase Main:

package main;

public class Main{
	public static void main(String[] args){

		// Primer objeto, destinado a encriptar el texto que le pasemos por parametro.
		EnigmaCore enigma =
			new EnigmaCore(
				args[0]
			,	args[1]
			);

		// Recoger y mostrar el texto encriptado
		String textoEncriptado = enigma.getEncryptedText();
		System.out.println(textoEncriptado);

		// Segundo objeto, destinado a desencriptar el texto que anteriormente hemos encriptado.
		EnigmaCore enigma2 = new EnigmaCore(args[0], textoEncriptado);

		// Recoger y mostrar el texto desencriptado
		String textoDesencriptado = enigma2.getDecryptedText();
		System.out.println(textoDesencriptado);
	}
}

Ahora si, el resultado de la ejecucion seria algo asi:

~$ java -cp bin main.Main claveausar textoadesencriptar
Wú/l?3á¿W¥|.+EUh¢VO¿pé¢QSVi
textoadesencriptar

Donde la primera linea es el texto encriptado y la segunda el texto desencriptado.

De todas formas esto me ha hecho reflexionar, creo que es muy ineficiente el que por cada objeto solo se pueda llevar a cabo una acción… Mañana editaré la publicación y cambiaré el código para que solo sea necesario declarar el objeto una vez, y los parámetros se pasen a través de los métodos getEncryptedText(), y getDecryptedText().

Muchas gracias por el interes,
Un saludo : ) .

No me esperaba tener que crear otro objeto para des encriptar.
No leí mucho la clase del enigma, no sé mucho de java.
Me gusta la criptografía, pero me estaba planteando hacer mi propia maquina, pero en un lenguaje que domino más, C.
Especialmente, ahora que estoy intentando desarrollar un analizador léxico cómo interprete para un juego (interesante para que se puedan desarrollar mods…).
Saludos!

1 me gusta

@LosHerederosDeRosas, Ya he editado el código fuente y algunas explicaciones de este tema.
He renombrado EnigmaCore0.0 a EnigmaCore1.0.
Ahora el uso de EnigmaCore debería ser mas sencillo y practico: la contraseña y el texto se pasan a través de los métodos getEncryptedText(), y getDecryptedText(), por lo que con un solo objeto bastara.

Respecto a tu proyecto, tiene buena pinta, a ver si cuando lo termines lo subes por este foro :wink: .

Y lo de C, pues si, tiene mas potencial para estas cosas, peo aun no lo he aprendido, y actualmente estoy estudiando java, por lo que este proyecto me ha venido muy bien para consolidar mis escasos conocimientos sobre el lenguaje. Aunque cuando aprenda C, quien sabe, igual adapto Enigma.

Si tu estas interesado en crear algo parecido en C, te podría facilitar un pseudo código del proceso de cifrado / descifrado.

Un saludo, y te animo a intentar romper mi algoritmo jeje : ) .

Primero, reporte de bug, cuando se intenta des-encriptar el texto previamente encriptado, falla. Sigue necesitando de dos objetos…

package main;
import enigma.EnigmaCore;

public class Main{
	public static void main(String[] args){
		//Inserte su codigo de la funcion main
		EnigmaCore enigma = new EnigmaCore();


		System.out.println(
			"Clave: " + args[0] + "\n" +
			"Texto: " + args[1]
			);


		String bloq = enigma.getEncryptedText(
				args[0]
			,	args[1]
			);
		System.out.println("Text encrypted\n" +
			bloq);

		System.out.println();

		EnigmaCore enigma2 = new EnigmaCore();
		

		String desb = enigma2.getDecryptedText(
				args[0]
			,	bloq
			);
		System.out.println("Text descrypted\n" +
			desb);
	}
}

Bug arreglado:

	private void builder(String pass, String txt) {
		password = pass;
		text = txt;
		
		/**
		 * Convertir contraseña (String) a numeros,
		 * los cuales podran ser interpretados en los calculos de encriptacion y desencriptacion.
		 * Seguira manejandose como String por razones de comodidad.
		 * 
		 * La conversion de char a int, sera en base al codigo ascii de cada caracter.
		 */
		passwordInt = "";
		for (int i = 0; i < password.length(); i++) {
			passwordInt += ((int)password.charAt(i)) /* + "" */; // Tenga o no tenga, da igual...
		}
	}

Ese + “” de passwordInt += ((int)password.charAt(i)) + ""; no es necesario, según lo que vi.
Después, si se le agrega:

passwordInt = "";

Cada ves que se llame a un método de encriptación o desencriptación, la clave para encriptar o desencriptar vuelve a cargarse. Si no, concatenas la nueva clave a la vieja clave…

Y, le agregue un:
package enigma;
Dejando la máquina en un paquete…

Luego, estuve desarrollando (aunque en c) un gestor de paquetes java, para crear un proyecto java, agregarle paquetes, compilarlo y generar un .jar desde el código.

También genera un Makefile que automatiza los comandos para usar el jdk.
Así, uno puede dejar de depender de un entorno, al ver que comandos java se ejecutan para formar la aplicación que está desarrollando…

Link del repositorio del programa:

1 me gusta

Sobre el analizador léxico, tengo implementado un código muy sencillo de prueba, dónde hice, por ejemplo, una función que me dice si es una letra en un rango (sin guardar caracteres en un array).


int ifIsLetterOrNumber(char letter)
{
	char status = 0;
	for(char i = 'a'; i<='z'; ++i)
		if(letter == i) status = 1;
	for(char i = 'A'; i<='Z'; ++i)
		if(letter == i) status = 1;
	for(char i = '0'; i<='9'; ++i)
		if(letter == i) status = 1;
	if(status == 1) return 0;
	return 1;
}

Leer un archivo y guardar su tamaño:

char *readFile(const char *name,long *sizefile)
{
	FILE *fvscript = fopen(name,"rb");
	fseek(fvscript,0,SEEK_END);
	*sizefile = ftell(fvscript);
	fseek(fvscript,0,SEEK_SET);
	char *const file = (char*)malloc(*sizefile);
	fread(file,1,*sizefile,fvscript);
	fclose(fvscript);
	return file;
}

Y, un lector de funciones pre-definidas…

		// First parameter (string)
		char *value=(char*)malloc(20);
		// [(] -> ["] -> [1] || Three moves
		*pcode += 3;
		// Capture value of first parameter
		int j = 0;
		while(**pcode != QUOTES){
			*value = **pcode;
			value++;
			++*pcode;
			j++;
		}
		// End array on NULL
		*value = ZERO;
		// Address memory
		value -= j;
		puts(value);
		free(value);
		// Delete name function
		*pstring -= (*i-1);
		*i = 0;
		nextLine(pcode);

Está última se ve muy fea, está muy en pañales, es solo un lenguaje de “script de carga” para diseñar niveles, historia, esa es la idea…

1 me gusta

Mi primer idea:

yay -S crunch
crunch 1 5 qwertyuiopasdfghjklñzxcvbnm1234567890 -o pass.d

De una a 5 combinaciones en el rango de caracteres tal, dejandolo en en archivo pass.d.

El archivo pesa 435,2 MB de posibles contraseñas.

Luego, escribir un programa de c que lea las contraseñas, y las intente:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *readFile(long *);

int main(int argc,char **argv)
{
	long size = 0;
	char java[] = "java -jar program.jar ";
	char *coman = (char*)malloc(sizeof(java)+7);
	char *file = readFile(&size);
	char string[20];
	long i = 0;
	long j = 0;
	while(i < size){
		if(*file == 0x0A){
			j = 0;
			strcpy(coman,java);
			strcat(coman,string);
			system(coman);
			++i;
			file++;
		}
		string[j] = *file;
		string[j+1] = 0x00;
		++i;
		++j;
		file++;
	}
	file -= i;
	free(file);
	return 0;
}



char *readFile(long *sizefile)
{
	FILE *archive = fopen("pass.d","rb");
	fseek(archive,0,SEEK_END);
	*sizefile = ftell(archive);
	fseek(archive,0,SEEK_SET);
	char *const file = (char*)malloc(*sizefile);
	fread(file,1,*sizefile,archive);
	fclose(archive);
	return file;
}
package main;
import enigma.EnigmaCore;

public class Main{
	public static void main(String[] args){
		//Inserte su codigo de la funcion main
		EnigmaCore enigma = new EnigmaCore();

		String dec = "¿6¥áj#ɶ£\"÷;×Lw(Up=G¥.Ñ XLsº0L¥LÜUmo·e9!€LHq€®/é×*©Bm.$uXá.LWF¤\"¡l@@7WKGKs!qqv!áf_|UPVv~9^ AÑ¿BHN:\"á·÷U6:Mp]~7@º4]{L6aij6ÜÑdLº+odt¶É&D~ai׬oWuaR]|1º9)¥	'?Ü<ɽ!épbq\\(d=¿>19:VdpªíH¿w+£";

		String msg = enigma.getDecryptedText(
				args[0]
			,	dec
			);

		System.out.println(msg + "\n");


	}
}

Y, un script de java en el que se pide en el primer argumento de la terminal una posible contraseña.

Fue compilado a un archivo .jar, y luego se ejecuta:

java -jar program.jar {args[0]}

El programa de c ejecuta correctamente la contraseña en el script de java.

Consumo el %100 de la cpu de cada uno de mis4 hilos del pc y 500MB de ram.

Y, solo para intentar las primeras contraseñas, si se quiere resolver, se necesita más potencia para no quemar la pc y no demorarse una eternidad.

Bueno, ahí está documentado el primer intento de resolverlo. Un ataque de fuerza bruta que se cargaría la pc antes de resolver la encriptación…
(Quizá, si se tiene una de esas pc de criptominería…)

1 me gusta

Toda la razon @LosHerederosDeRosas,
No se como se me ha podido pasar por alto, yo juraria haber provado el codigo antes de subirlo :thinking: .
En fin, muchisimas gracias, no me habia dado cuenta.
Ya esta el tema actualizado con el codigo arreglado, es exacramente lo que tu me has puesto.

Sobre tu proyecto del gestor de paquetes, me parece super interesante, tienes toda la razón sobre la dependencia de los IDEs, por ejemplo, yo dependo totalmente de Eclipse.

Tu intento de tomper Enigma esta de lujo, muy trabajado, un mounstro de fuerza bruta, no me imaginaria que utilizara tantos recursos (tambien es verdad que mi codigo seguramente no este muy optimizado…).

Pero me surge una duda, con la de miles de resultados de desencriptacion fallidos, como serias capaz de distinguir entre un texto desencriptado y uno sin sentido alguno, quiero decir, no te vas a poner a comprobar una lista de miles de lineas…

Aunque después, el consumo del cpu bajo entre % 60 y % 70.
Y, Consume casi 500MB de RAM, porque la máquina virtual de java consume cómo 70 MB de RAM al parecer. Y, la base de datos generada, que no alcanzaría para romper el encriptado, pesa 445MB, y esta, a su vez, es cargada a memoria…

Por lo qué, viendo el alto consumo y todo lo que conseva, no me valió la pena…

Quizá durante el año que viene, ya que en mi segundo año del profesorado de física veré derivadas e integrales, pueda ver de desencriptar.

Después de todo, encriptar está más fácil que desencriptar. Especialmente si se necesita una contraseña (que mientras más segura sea más díficil es)…

1 me gusta