Los números pseudoaleatorios, son eso, pseudoaleatorios. Tampoco implica que sean predecibles. No obstante cuando uno crea una función con números pseudoaleatorios, y especialmente cuando es con vistas a la seguridad, debe verificarse que lo son, es decir deberá crearse exprofeso otras funciones que pongan de manifiesto la aleatoriedad que arroja la función creada... por lo que habría que hacer como digo varias funciones de análisis para descubrirlo.
Al final todo ese trabajo extra puede o no merecer el esfuerzo de realizarlo, cada uno decide en que emplea su tiempo...
Por eso yo te he sugerido partir de funciones que en principio no poseen aleatoriedad (usan una tabla de traducción) pero que partiendo de su trabajo, dos funciones con 'funcionalidad' igual, generan para una misma clave valores distintos... pasado por un bucle amplía la clave lo suficiente, como para luego reunir una clave que ahora sí será pseudoaleatoria sin necesidad de perder tiempo en verificarlas al hacer un xor entre ambas escisiones de la clave...
Más aún si crees que partiendo de sendas funciones arrojaran similitudes que pudieran explotarse (ya digo yo que no, pero no voy a perder tiempo en demostrarlo), todavía podías partir de la misma clave para cada función pero en una con la inversión de la clave:
A = Base64(clave)
B = UUEncode(stringReverse(clave)) // 'Reverse' la clave...
Bucle 1 a 3
A = Base64(A)
B = UUEncode(B)
Siguiente
Key = f(A Xor B) // esta expresión, denota una función que realiza el xor entre cada elemento del array como se explicaba más arriba.
ContenidoCifrado = f(ContenidoClaro xor Key) //Idem " " " "
Recuerda que la fuerza de un algoritmo, debe recaer en sus procedimientos, en el diseño y no en el secretismo del procedimiento, pues eso implicaría que conocido el procedmiento, la seguridad quedaría rota.
La operación "XOR" provee el secreto, la seguridad universal en programación... porque X xor Y, arroja 256 posibles distintas combinaciones entre 'X' e 'Y', exactamente las mismas combinaciones que hay de 'X' y de 'Y' sueltas. Luego, por cada carácter contenido, la combinaciones posibles se multiplican por 256. XOR, no ofrece facilidades ni pistas a ese respecto...
A pesar de los tan cacareados procesadores cuánticos, frente a un cifrado XOR, no tiene nada que hacer... serán incapaces de hacer nada más allá de lo que ya sabemos, que puede ser cualquiera de las 256 posibilidades, pero no sabrá por ningún medio cual de ellas es. Un ordenador cuántico podría eos si probar (por fuerza bruta en paralelo) chorrocientos millones de combinaciones pero sin resultados positivos... Si hemos interceptado un mensaje y el procesador cuántico ha trabajado sobre él, y sabemos (pongamos por espionaje) incluso que el contenido del mensaje tiene el nombre de uno que vende secretos de la empresa, el ordenador cuántico solo podrá ofrecer nombres, pongamos que todavía sabemos que el nombre es de tan solo 4 letras... ningún ordenador cuántico tendrá la capacidad de decibilidad sobre cual es la verdad, solo arrojaría resultados que alguien podría decir... si hay trabajadores en la empresa con ese nombre, luego lo añadiría a la lista de posibles: "Juan", Luis", "Pepe", "Coco", "Sara"... pero a fin de cuenta es algo que ya sabíamos sin usar el ordenador cuántico (el 'espía' dijo que: "...era el nombre de alguien de la empresa y que se compone de 4 letras..."), luego el uso de un ordenador cuántico, no nos revela nada que no supiéramos o pudiéramos obtener sin él...
...a la operación XOR, se la P3L4N los ordenadores cuánticos...
Lo mismo no es válido, ni aplicable para algoritmos basados por ejemplo en pesudo primos gigantes... pués ahí la fuerza radica casi exclusivamente en la fuerza de cálculo, algo que para un procesador cuántico, si estaría al alcance (siempre será cosas de más o menos potencia, de más o menos tiempo).
Piensa un número del 1 al 100... a ver si un ordenador cuántico puede decirte cual has pensado?. Eso es lo que hace XOR, básicamente. Desde el inicio se sabe que es un valor en el rango dado, peor nada ofrece capacidad para determinar de cual se trata, siempre podrá probarse por fuerza bruta las combinaciones una a una... claro siempre que tu dés por válido que el que tiene que adivinar el número que pensaste pueda darte 100 posibles respuestas...
Ahí es donde el diseños de los sistemas fallan, entre intento e intento debería existir siempre una espera forzada, una espera como un parpadeo que para un humano es tiempo inpreceptible, para un ordenador capacitado para procesar milooneso dentro de 10 años 100 veces más, haría que no hubiera diferencia entre operar con un ordenador de los 70 que pudiera procesar una combinación cada lapso, o 100 trillones de combinaciones en el mismo lapso, porque tras una combinación el sistema te hace esperar 300 ms. luego el tiempo empleado para probar por fuerza bruta x combinaciones sería para todos los equipos el mismo... sin importar la potencia de procesamiento del hardware.
es por ello que los algoritmos de verificación de cifrado, son (probablemente) los únicos, que deben ser diseñador sin eficiencia alguna, de hecho, como digo hasta debieran forzar (por hardware), una espera...
Mi recomendación es que uses XOR con claves pseudolaeatorias y te dejes de pamplinas que lo que harán solo es complicarte las cosas, perder tiempo en ello, para acabar no siendo más eficaces... Y al caso, dado que
la seguridad final depende del propio usuario con la clave que introduzca, centra tus esfuerzos en los puntos 1a, 1b y 1c, que te señalé más arriba, que admeás es algo enormemente sencillo de acometer. Debajo te pongo un pseudocódigo para cometer esos 3 pasos... así lo tendrás más fácil aún.
...pero bueno, entiendo que a la gente le gusta seguir la corriente de moda... por eso los 'procesadores cuánticos', la 'biotecnología en materia de seguridad' comparten las mismas necedades que la 'inteligencia artificial', mucho bombo y platillo donde sacar tajada de los ingenuos con promesas, solo promesas... que se acaban estrellando contra la irrespetuosa realidad.
Esto es solo una muestra para 3 requisitos, puede ser más complejo, peor como mínimo habría que exigirse esto... queda a tu entera libertad modificarlo a justarlo a tus necesidades.
Rechazar y solicitar nueva clave mientras se cumpla alguno de estos 3 requisitos:
1 - No permitir una contraseña menor de x caracteres (tú decides el límite menor).
2 - Si el mínimo son x caracteres, no permitir menos de x/3 de caracteres distintos.
3 - No permitir la presencia deun carácter en la contraseña de más de 1/5 de veces del tamaño de la clave.
// constantes:
SIZE_CLAVE_MIN =10 //10 caracteres mínimo de largo?, para Requisito 1
ENTROPIA_MIN = 3 // 1/3 del largo de clave, para Requisito 2
REDUNDANCIA_MAX = 25 // 25% del largo de clave. 1/5, para Requisito 3
enumeracion ResultadoCheckeo
CIFRADO_METODOS_IGUALES = -5 // Los 2 metodos elegidos deben ser distintos. Base64 y UUEncode (por ejemplo)
CIFRADO_CLAVE_CORTA = -4 // La clave no alcanza el mínimo de caracteres requeridos.
' -3 es la suma de -1 y -2
CIFRADO_REDUNDANCIA_EXCESIVA = -2 // Hay caracteres muy repetidos...
CIFRADO_ENTROPIA_ESCASA = -1 // Hay poca diversidad de caracteres
CIFRADO_AUSENTE = 0 // La clave y/o el contenido están vacíos.
CIFRADO_OK = 1 // Cifrado procesado satisfactoriamente.
fin enumeracion
resultadoCheckeo = Funcion VerificarClave(array de bytes Clave)
arrayde bytes Chars(0 a 255)
entero i, n
resultadoCheckeo rc = CIFRADO_AUSENTE // = 0
i = Clave.Tamaño
Si (i > 0)
Si (i >= SIZE_CLAVE_MIN) // Verificación del requisito: 1
// contar la presencia de cada carácter... en la clave
bucle para k desde 0 hasta i-1
n = Clave(k)
Chars(n) += 1
Next
Si CheckDistintos(Chars, i) = FALSO // Verificación del requisito: 2
rc = CIFRADO_ENTROPIA_ESCASA
Fin si
// nótese que estos 2 requisitos no son excluyentes entre sí, si no que se aunan, pueden darse los dos casos a la vez... por eso están seriados y no de forma alternativa.
Si CheckRedundancia(Chars, i) = FALSO // Verificación del requisito: 3
rc = (rc + CIFRADO_REDUNDANCIA_EXCESIVA)
Fin si
Si (rc = CIFRADO_AUSENTE) // pasó los requisitos ?
rc = CIFRADO_OK
Fin si
sino
rc = CIFRADO_CLAVE_CORTA
fin si
// sino: devolver valor 0
// rc = CIFRADO_AUSENTE
fin si
devolver rc
fin funccion
// Cuenta cuantos valores distintos hay y verifica si más o menos de 1/3 del total de 'size'.
// Size indica el tamaño original de la clave.
// Por ejemplo si la clave tiene 9 caracteres, debe estar compuesta por al menos 4 caracteres distintos.
buleano = Funccion CheckDistintos(array de bytes Chars(), entero Size)
entero k, distintos
Bucle para k desde 0 hasta 255
Si (Chars(k) > 0)
distintos += 1
Fin si
Siguiente
Devolver ((distintos > (Size \ ENTROPIA_MIN)))
fin funcion
// Verifica si hay algún carácter que aparezca más de un 25% del total de 'size'.
// Size indica el tamaño original de la clave.
// Por ejemplo si la clave tiene 16 caracteres ningún carácter puede aparecer más de 4 veces (pero si 4).
buleano = funccion CheckRedundancia(array de bytes Chars(), entero Size)
entero k, repes
// hay que redondear al entero superior... revisar el redondeo pués es dependiente del lenguaje usado.
// Asegurarse con claves de por ejemplo 10 caracteres, el 25% serían 2'5, si redonde a 2 en vez de a 3, sería (quizás) muy exigente... con claves más largas ese redondeo arriba o abajo no resulta tan tiquismiquis.
repes = (Size / (100 / REDUNDANCIA_MAX) + 1)
Bucle para k desde 0 hasta 255
Si (Chars(k) > repes) devolver FALSO
Siguiente
Devolver TRUE
fin Funcion
Si la funcion 'VerificarClave' devuelve el valor CIFRADO_OK (1), ha pasado los requisitos exigidos, proceder al cifrado, si no enviar un mensaje acorde al valor devuelto...
Funcion MensajeDeError(resultadoCheckeo Codigo)
string s
Seleccion de caso para Codigo
Caso 1; s = "Cifrado procesado satisfactoriamente."
caso 0; s = "La clave y/o el contenido están vacíos."
caso -1; s = "Hay poca diversidad de caracteres (por ejemplo: 'perrppeeperr')."
Caso -2; s = "Hay caracteres muy repetidos (por ejemplo: 'lacalabazafantasma')."
caso -3; s = "Hay poca diversidad de caracteres (por ejemplo: 'perrppeeperr').
Y También hay caracteres muy repetidos (por ejemplo: 'lacalabazafantasma')."
Caso -4; s = "La clave no alcanza el mínimo de caracteres requeridos (" + SIZE_CLAVE_MIN + ")."
caso -5; s = "Los 2 métodos elegidos deben ser distintos."
Resto de casos // No hay mensajes de error para otros códigos.
fin seleccion
mostrar al usuario el mensaje s
fin Funcion
...ya tienes casi la mitad del código hecho...
por cierto,
esta conversación no pinta nada en la sección de foro libre, trata un tema que versa el foro, de programación y más concretamente sobre seguridad, así que debería moverse a la sección de seguridad o mejor al de programación.
P.DA: Para el interés general...
Darse cuenta lo que hace una simples y conocidas funciones:
La clave de entrada son 12 caracteres A, se pone un bucle recibiendo como entrada la salida anterior:
BASE 64:AAAAAAAAAAAA
QUFBQUFBQUFBQUFB
UVVGQlFVRkJRVUZCUVVGQg==
VVZWR1FsRlZSa0pSVlVaQ1VWVkdRZz09
5E9:5U(Q1G-2;%I383!P4U9L5F%1,5975FMD4EIZ,#D`UUENCODE:AAAAAAAAAAAA
04%!04%!04%!04%!
,#0E(3 T)2$P-"4A,#0E(0``
+",P12@S(%0I,B10+2(T02PC,$4H,&!@
*R(L4#$R0%,H)3!)+$(Q,"LR*%0P,E!#+"0T2"PF(4 `Como se ve, después de la primera codificación, va perdiendo la redundancia (y ganando entropía), luego un XOR al final entre ambas salidas, no puede ofrecer pista alguna de que originalmente fueren 12 'A's...
Todavía
el algoritmo siempre puede complicarse tanto como se quiera, a base de usar más funciones distintas o usarlo de forma ligeramente diferente, por ejemplo:
... pude hacerse 3 codificados con una función y una última vez con otro... he aquí el resultado y el pseudocódigo de este ejemplo:
Base 64:
...
VVZWR1FsRlZSa0pSVlVaQ1VWVkdRZz09
y ahora esta salida con UUencode:
5E9:5U(Q1G-2;%I383!P4U9L5F%1,5975FMD4EIZ,#D`
UUEncode:
...
+",P12@S(%0I,B10+2(T02PC,$4H,&!@
y ahora esta salida con Base64:
KyIsUDEyQFMoJTBJLEIxMCsyKFQwMlBDLCQ0SCwmIUA=
A= Base64(clave)
A = Base64(A)
A = Base64(A)
A = UUEncode(A)
B = UUEncode(reverseString(clave))
B = UUEncode(B)
B = UUEncode(B)
B = Base64(B)
Key = f(A Xor B) // esta expresión, denota una función que realiza el xor entre cada elemento del array como se explicaba en un mensaje más arriba.
Incluso cada ampliación podría ser aplicada con un algoritno distinto...
Por ejemplo si la primera fuera un:
Ya tendríamos una clave del doble de largo, luego un hex como primera fase, si la clave es menor de x caracteres no sería mala idea...