Ideas para algoritmo matemático para cifrado?

Iniciado por @XSStringManolo, 23 Septiembre 2019, 03:07 AM

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

@XSStringManolo

Hola, estoy diseñando mi propio cifrado.

Lo que hago es:
Pido al usuario el texto a cifrar.
Pido al usuario la clave para el cifrado.

Obtengo el equivalente según mi diccionario de 7bits (127 caracteres) en decimal de los caracteres del texto plano y la clave.
Por ejemplo el usuario introduce:
Texto a cifrar:abcd
Clave:bbcc

Entonces lo que hago es obtener el equivalente decimal en base a un diccionario en un string:

abcd -> 1 2 3 4
bbcc -> 2 2 3 3

Entonces realizo operaciones con la clave y la sumo al texto:
b -> 2

2*2=4
4*(4+4)*5=160

Resto el tamaño de la clave al numero obtenido para poder representarlo en 7bits:
160-127 = 33

Sumo la clave + la contraseña -> a+33 = 34

a + b = 34

34 en mi diccionario es el caracter G.

Para descifrar hago:
G -> 34

2*2 =4
4*(4+4)*5=160
160-127=33

34-33=1

Caracter G descifrado con clave b -> a

El problema que tengo es que si el usuario introduce por ejemplo:
Texto:
abcdefghijklmnñopqrstuvwxyz
Clave:
aaaaaaaaaaaaaaaaaaaaaaaaa

El texto cifrado sería:
bcdefghijklmnñopqrstuvwzyzA

Por lo que sería extremadamente sencillo averiguar que el texto original era el abecedario en español sin saber la clave.

Tengo un diccionario de 127 caracteres donde los últimos 27 se repiten.

Cómo soluciono este problema de que el usuario introduzca una clave insegura y que el texto plano sigue correlacionado?

Se me ocurren muchas maneras a mi rollo de hacerlo. Busco ideas que tengais propias. No la "mejor manera" de hacerlo. Si no estaría usando números primos enormes y otros esquemas más apropiados para un sistema simétrico por clave donde el algoritmo de bastante igual.

El cifrado va a ser seguro independientemente del algoritmo que use ya que esto solo es una capa, usaré en otras capas bloques de 4096b y block chain entre otras cosas que me recomendó Kub0x y que tenía pensadas yo.

Solo quiero mejorar esta capa con algun algoritmo chulo y funcional. Este algoritmo que uso son 4 lineas tontas de código asique algo chulo no cuesta meterlo nada.

A mi se me ocurren ideas de medias aritméticas, geometrías básica y transposición de orden + bits con encoding en el propio cifrado. Esto último algo así como funciona la asimétrica. Indicar el orden cifrado con clave pública en el propio cifrado y descifrarla con la clave privada.

Qué se os ocurre? Ideas locas me gustan.  :D

engel lex

lo primero que veo, es que si es por hacerlo por gusto, ok, pero por seguridad, no vale la pena...

lo segundo, te recomiendo que te revises como funciona por ejemplo AES y saques ideas de allí, allí sin caer en mucha profundidad de largos e incompresibles algoritmos o "numeros primos" (que en realidad en este caso no se usarían, eso es principalmente para cifrado asimetrico) verás como puedes resolver el lio de crear una clave insegura
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

animanegra

una de las primeras cosas que igual debes hacer en un algoritmo de cifrado para evitar esquemas de criptoanálisis es utilizar el efecto avalancha. Introducir una entrada más en cada carácter a cifrar y combinarlo con la salida anterior. El primer carácter cifrado se puede dejar sin tener entrada adicional. de manera que si cifras usando una clave con los mismos caracteres el texto codificado saldrá diferente porque la nueva salida no dependerá sólo del mensaje y la clave, si no del carácter obtenido como texto cifrado del anterior.

abcde
aaaaa

a+a+0=b
b+a+b=e
c+a+e = ...

No se si se entiende.

Por otro lado, también deberías utilizar bloques mas grandes, que tu algoritmo utilice cosas de las que no se pueda terminar obteniendo un diccionario.
Igual estaría bien leer un poco sobre redes de feistel, muy sencillas y potentes para hacer algoritmos de cifrado simétrico.
Si quieres hacer cosas de criptografía, personalmente te recomiendo el Lucena (http://www.grc.upv.es/biblioteca/cripto.pdf) si no tienes mucha fluidez en inglés, o el schneier (https://www.abebooks.com/servlet/BookDetailsPL?bi=30425390127&searchurl=kn%3Dapplied%2Bcryptography%2Bschneier%26sortby%3D17&cm_sp=snippet-_-srp1-_-title2) si no te importa leer texto en inglés (y comprarlo).

42
No contesto mensajes por privado, si tienes alguna pregunta, consulta o petición plantéala en el foro para que se aproveche toda la comunidad.

Serapis

#3
De entrada, como la gente suele arrojar contraseñas demasiado cortas y a veces tontas, recomiendo una primera etapa de requisitos:

Rechazar y solicitar nueva clave mientras se cumpla alguno de estos 3 requisitos:
1a No permitir una contraseña menor de x caracteres (tú decides el límite menor).
1b Si el mínimo son x caracteres, no permitir menos de x/3 de caracteres distintos.
1c No permitir la presencia de más de 3 veces para un carácter en la contraseña.



2a Usar un algoritmo de ampliación de la contraseña. al caso suele ser útil una fase de 'binario a texto', es decir considerar la contraseña entrada como si fuera binario y convertirlo a texto.. básicamente se está pidiendo usar funciones del tipo Base64, Base85, etc... que para una contraseña de x tamaño el resultado es una contraseña de un 133% más larga (caso del Base64 o UUEnconde, por ejemplo).
2b Desordenar la contraseña. Usa dos caracteres (los dos iniciales, dle medio, si osn del final asegúrate que no son predecibles, por ejemplo los algoritmos binario a texto, suelene usar padding al final, con lo que esos caracteres suelen repeirse con cierta frecuencia) del resultado previo. Y haz una resta entre ellos y modulas así el comienzo de la clave. Esto es, se trata de cortar (como si fueran cartas cortando el mazo), para no empezar con el primer carácter de la clave. Ejemplo (supongamos que como resultado de 2a tenemos): Aguila  (largo clave=6 caracteres) l-a (si sale negativo la resta, ignora el signo antes de calcular el modulo.
ix inicio = ((108-97) modulo 6) = (11 mdulo 6) =5
Así ahora es como si la contraseña fuera laAgui



3a Al llegar aquí digamos que tenemos la contraseña A. ahora partiendo del punto 1c, aplicar a ese valor en 1c, un algoritmo distinto para 2a, tras 2b tendríamos la contraseña B
3b Ahora metería una etapa XOR, entre A y B (dos claves distintas que en origen eran la misma).
Y listo, no tienes que hacer nada más, incluso aunque una contraseña originalmente fuere: "abcdefghijklmn", quedará rota...



4a Ahora cifra con Xor el texto en claro con la contraseña que sale de 3b. Si el contenido a cifrar es demasiado largo, yo ampliaría (paso 2a) la clave para obtener una contraseña aún más larga...
yo por ejemplo, en mis cifrados suelo crear una clave ampliada de al menos 1Mb. (en realidad es elegible y nunca tiene ese tamaño exacto, simplemente es un algoritmo recursivo que para cuando supera dicha cantidad, el cortado no lo hago físicamente simplemente 'recuerda' el índice como punto de comienzo para el paso 4).
4b Si el destino es fichero toca guardarlo a fichero, si el destino es un lugar para imprimir, hay que tener en cuenta que la salida es en binario (XOR, lo fuerza), luego procede una fase final Binario a texto.



Un sencillo ejemplo:
Omito los requisitos 1a,1b y 1c para ilustrar el ejemplo.
Texto a cifrar: "aaaaaaaaaaaa bbbbbbbbbb ccccccccc abcdefghijklmn"
Clave: "aaabbbccc"
A: (paso 2a aplicando base64 a la clave): YWFhYmJiY2Nj
B: (paso 2a aplicando UUEncode a la clave): 86%A8F)B8V-C
Repito el paso 2a 2 veces más a cada resutado:
ciclo2:
A2: YWFhYmJiY2Nj ---> WVdGaFltSmlZMk5q
B2: 86%A8F)B8V-C ---> .#8E03A&*4(X5BU#
ciclo3:
A3: WVdGaFltSmlZMk5q ---> V1ZkR2FGbHRTbWxaTWs1cQ==
B3: .#8E03A&*4(X5BU# ---> +B,X13 S028J-"A8-4)5(P``

Así finalmente quedan: 24 caracteres de clave (si no son simétricas las funciones 2a, es decir que son algoritmos que crean diferente tamaño, toma el tamaño de la menor y cortas el excedente de la más grande antes de seguir)...
Nota que A y B a quí son A3 y B3, ya qye el subíndice solo era indicativo del ciclo aplicado un bucle...
Es decir sería algo como:

A = clave
B = clave
bucle 1 a 3
  A = Base64(A)  
  B = UUEncode(B)
siguiente

A = V1ZkR2FGbHRTbWxaTWs1cQ==
B = +B,X13 S028J-"A8-4)5(P``

Aplicamos paso 2b sobre los caracteres iniciales:
Indice para A: j = (('V' - '1') modulo 24) = ((86 - 49 ) mod 24 ) = 13
Indice para B: k = (('+' - 'B') modulo 24) = ((43 - 66) mod 24 ) = 23

A = xaTWs1cQ==V1ZkR2FGbHRTbW
B = `+B,X13 S028J-"A8-4)5(P`
(corto, pero solo por claridad, no es preciso hacerlo físicamente porque luego se opera en un bucle al que puedes indicarle el punto de inicio de cada una):

En estos bucles haces un xor con ambas claves. Posiblemente arroje valores binarios, por lo que poner aquí el resultado al no ser valores imprimibles, no se vería bien... lo omito pues.

size = clave.largo  (24 en el ejemplo)
j = 13
k = 23
bucle para x desde 0 hasta size -1
   clave(x) = A(j) xor B(k)
   j = (j+1) mod size
   k = (k+1) mod size
siguiente


El resultado es la clave para aplicar finalmente al texto en claro mediante xor, la clave se aplica repetidamente si se alcanza su final hasta completar el cifrado de todo el texto (o de un fichero)....  

size2 = texto.largo
j = 0
bucle para k desde 0 hasta size2-1
   texto(k) = texto(k) xor clave(j)
   j = (j +1) mod size
siguiente


Ya tienes el texto cifrado... será binario, por lo que procede es guardarlo a fichero si se ha de imprimir, pués por contener caracteres no imprimibles, debería pasar por una fase final binarytotext


string = Funcion BinaryToText( array bytes X, tipofuncion y)
  Si y=0 //aume por ejemplo Base64
       devolver Base64(x)
  Si y= 1 // asume por ejemplo UUencode
       devolver UUEncode(x)
  Si y = ...
       .... otras funciones que tuvieres...
  fin si
fin funcion


p.d.: Pequeña corrección:
Había puesto: clave(x) = clave(j) xor clave(k)
Cuando debiera ser: clave(x) = A(j) xor B(k)

@XSStringManolo

Estoy mirando todo lo que comentais. La idea del Base64 para padding me parece curiosa. Igual la implemento de alguna forma.

_TTFH_3500

Hola, ANSI X9.23 es una forma bastante sensilla de padding, simplemente agrega ceros y la cantidad de ceros que agregaste hasta completar un multiplo del tamanio del bloque.

CitarIn ANSI X9.23, between 1 and 8 bytes are always added as padding. The block is padded with zeros and the last byte of the block is set to the number of bytes added.
Example: In the following example the block size is 8 bytes, and padding is required for 4 bytes (in hexadecimal format)

... | DD DD DD DD DD DD DD DD | DD DD DD DD 00 00 00 04 |


En cuanto al algoritmo de cifrado puedes inventar uno basado en AES con un tamanio de clave distinto.

MinusFour

Este metodo ya existe desde hace años, se les conocen como one-time pads. Te dejo el link de wikipedia en español: https://es.wikipedia.org/wiki/Libreta_de_un_solo_uso

@XSStringManolo

#7
Hice una función que sume cada caracter del texto plano con cada caracter de la clave aplicando un algoritmo que me inventé a cada caracter de la clave. Primero hice la transformación de los caracteres a decimal en base a un diccionario con otra función y después utilicé esta.

Quiero un padding que mejore la seguridad. Al usar los métodos que comentais no sería más fácil dar con la clave? Estaba pensando usar la media aritmética de todos los caracteres de la clave para generar una serie  de X tamaño. Por ejemplo si quiero 20 caracteres haría:

Cita de: Diccionario Que UsoabcdefghijklmnñopqrstuvwxyzABCDEFGHIJKLMNÑOPQRSTUVWXYZ1234567890.!@#$/^&*()-'":;,?+×÷=<>{}[]€%~_\|abcdefghijklmnñopqrstuvwxyzESPACIO

Cita de: Ejemplo De Padding que se me ocurriovar semilla = mediaAritmeticaDigitosClave;
GenerarSeriePseudoaleatoria (semilla, "20");

En el caso de que la clave fuese 12345 la media es 3.
La serie generada podría ser: (Tengo que consultar algoritmos de generación pseudoaleatoria)
8 13 6 4 3 2 7 3 81 2 9 32 7 126 8 3 6 2 1 32

Le sumo la clave en bucle y cifro con el resultado:

8+1 9
13+2 15
6+3 9
4+4 8
3+5 8
2+1 3
7+2 9
3+3 6
81+4 85
2+5 7
9+1 10
32+2 34
7+3 10
126+4 130-127 ->3
8+5 13
3+1 4
6+2 8
2+3 5
1+4 5
32+5 37

Texto a cifrar hola -> 8 16 12 1

Clave -> 9 15 9 8 8 3 9 6 85 7 10 34 10 3 13 4 8 5 5 37

Resultado del cifrado -> sJwQPÑntyGfGÑe×PvvKn
Lo veis seguro? O creeis que es posible dar con la clave? O dependerá 100% del algoritmo pseudoaleatorio?



Código (javascript) [Seleccionar]
var textoEnDecimal="8 16 12 1";
var claveEnDecimal="1 2 3 4";
var resultado;

resultado = SumaDeStrings(textoEnDecimal, claveEnDecimal, " ");

/*Lo que pasa al cifrar este texto con esta clave:

1*1*(1+1)*5 -> 10
10+8 -> 18
Pos1 -> q

2*2*(2+2)*5 -> 80
80+16 -> 96
Pos2 -> \
Uso un diccionario de 127 caracteres (7bits) donde 96 es la barra invertida \

3*3*(3+3)*5 -> 270
270+12 -> 282
282-127 -> 155
155-127 -> 28
Pos3 -> A

4*4*(4+4)*5 -> 640
640+1 -> 641
641-127 -> 514
514 -127 -> 387
387 -127 -> 260
260-127 -> 133
133-127 -> 6
Pos4 -> f

Resultado de cifrar el texto "hola" con la clave "abcd" -> "q\Af"
*/

/*Aqui la función:*/

function SumaDeStrings (sumando1, sumando2, caracterSeparador)
{
var sum1Tam = sumando1.length;
var sum2Tam = sumando2.length;
var auxSum1 ="";
var auxSum2 ="";
var auxSum1INT =0;
var auxSum2INT =0;
var resultadoSTRING ="";
var resultadoSumaDeStrings ="";
var resultadoINT =0;
var x = 0;
--x;

  /*if(sum1Tam != sum2Tam)
  {
  alert("Error de programación en el código. El tamaño de la clave no coincide con el tamaño del texto a cifrar.\nRevisa código de parseo");
  resultadoSumaDeStrings+="Error. Es necesario que los bloques computados sean del mismo tamaño.";
  alert("Tamaño Texto + Padding = " + sum1Tam);
  alert("Tamaño Clave + Padding = " + sum2Tam);
  }*/if(1==2){}

  else
  {
     for (var y = 0; y<sum1Tam; ++y)
     {
        if(sumando1[y] != caracterSeparador)
        {
        auxSum1+= sumando1[y];
             // alert("Encontrado CaracterSum1: " + sumando1[y]);
        }

        else
        {
           //  alert("auxSum1 tiene dentro: " + auxSum1);
         
              ++x;
              while(sumando2[x] != caracterSeparador)
              {
              auxSum2+= sumando2[x];
              //       alert("Encontrado CaracterSum2: " + sumando2[x]);
             ++x;
              }

             
             
       //      alert("auxSum2 tiene dentro: " + auxSum2);
       //       alert("Contendio de auxSum1INT antes de parseo: " + auxSum1INT);

              auxSum1INT=parseInt(auxSum1);
      //  alert("Contendio de auxSum1INT despues de parseo: " + auxSum1INT);
      //  alert("Numero completo encontrado: " + auxSum1INT);
             
              auxSum2INT=parseInt(auxSum2);
      //  alert("Numero2 completo encontrado: " + auxSum2INT);
        /*      mediaAritClave = mediaAritClave + auxSum2INT;
              ++contadorAritClave; */

              auxSum3INT = auxSum2INT*auxSum2INT;
              auxSum3INT = auxSum3INT*auxSum2INT + auxSum2INT*5;
     

              resultadoINT=auxSum1INT+auxSum3INT;
              while (resultadoINT>127){
              resultadoINT=resultadoINT-127; }
              resultadoSTRING = resultadoINT.toString();
              resultadoSumaDeStrings+=resultadoSTRING;
              resultadoSumaDeStrings+=caracterSeparador;
       //  alert("Resultado String" + resultadoSumaDeStrings);

       
              auxSum1="";
              auxSum2="";
              auxSum1INT =0;
              auxSum2INT =0;
             
           }

     }
  }
return resultadoSumaDeStrings;
}

Serapis

#8
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...  :silbar: :silbar: :silbar: :silbar:

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:
A = HEX(clave)
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...

@XSStringManolo

Ya diseñe un algoritmo para hacer el padding tras cifrar para después volver a darle otra capa de cifrado y generar un cifrado de un tamaño determinado que yo quiera. Ya lo tengo implementado. Lo estoy debugeando.

Me fascina el número aureo asique me decante por utilizar una propiedad matemática en torno al numero de oro para generar la serie del padding.

La propiedad es:
Eliges 2 numeros aleatorios. Por ejemplo 2 y 4.
Le aplicas la serie fibonacci de tal forma que:
2 4 6 10 16 26 42 68 110 178 ...
Donde dividir un número entre el anterior te genera una aproximación del número aureo.

10/6 = 1.6666666667
16/10 = 1.6
42/26 = 1.6153846154
68/42 = 1.619047619
110/68 = 1.6176470588
178/110 = 1.6181818182

En mi algoritmo tomo la primera fracción la cual el mayor número pasa de 127.
En el ejemplo anterior el primero en pasarse es 178. Asique tomo 178/110.


Hago esta serie en base a la media aritmética de los caracteres de la contraseña en decimal.

Por ejemplo de a b c d e.
La media de 1 2 3 4 5 es 3.

Entonces tomo todas las series:
3y1
3y2
3y3
3y4
3y5

Y obtengo:
1.6178861789
1.6179775281
1.6176470588
1.6173913043
1.619047619

La clave serian 5 caracteres.
8.0899596891

8.0899596891/5=

1.6179919378 sería la media.

Ahora este número le elimino la parte más frecuente. (4 primeros digitos por la izquierda).
Y obtengo:
9919378

Si quiero por ejemplo un cifrado de 20 caracteres fijos multiplico por 2, añado con transposición y trunco al pasarme de 20 digitos:
9919378
19,838,756
199981398377586
399962796755172
319999996821739968735757157826
Resultado:
31999999682173996873

Le sumo el resultado del cifrado a todas las cifras, que por simplicidad en el ejemplo fue 12345

3 1 9 9 9 9 9 9 6 8 2 1 7 3 9 9 6 8 7 3
1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5

4 3 12 13 14 10 11 12 10 13 3 3 10 7 14 10 8 11 11 8

dclmnjkljmccjgnjhkkh

Lo bueno es que el tamaño del cifrado puede superar el tamaño fijado, como sería en el caso de que en vez de "abcde" fuese:
abcdefghijklmnopqrstvwxyz

3 1 9 9 9 9 9 9 6 8 2    1 7 3 9 9 6 8 7 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25


4 3 12 13 14 15 16 17 15 18 13 13 20 17 24 25 23 26 26 23

Sobra:
21 22 23 24 25
Lo sumo otra vez en bucle:
4 3 12 13 14 + 21 22 23 24 25

15 16 17 15 18 + 21 22 23 24 25

13 13 20 17 24 + 21 22 23 24 25

25 23 26 26 23 + 21 22 23 24 25

Resultado
25 25 35 27 29 36 38 ...
z z J B D K M ...



Este algoritmo es solo para fixear el resultado final a un tamaño determinado. Se da por hecho que abcde es el resultado cifrado generado por mi algoritmo simetrico previo.
Utilizo este método de padding devido a que si el usuario quiere una seguridad rápida, le fixeo el tamaño de cifrado por ejemplo a 20 caracteres.

Pero si elige máxima seguridad y por ejemplo le devuelvo el texto cifrado en 5000 caracteres, no van a coincidir los 20 primeros caracteres del cifrado fragil con la misma clave y plaintext cifrados en 5000 caracteres.

Finalmente a este cifrado de tamaño fijo lo vuelvo a cifrar con la clave original usando asimétrico. Así con una clave de ***** o similar a la original no se obtiene información relevante.

Todo sigue dependiendo de la seguridad de la clave. Ya que se puede probar a fuerza bruta a descifrar y comparar con un diccionario hasta acertar con el plaintext.

Supongo que lo mejor es hacer una intro en el programa para dar unas guidelines para inducir de como generar la contraseña de forma que el atacante viéndo las guidelines no pueda averiguar que se le va a ocurrir o va a usar el usuario.

Algo en plan:
CitarPara generar una contraseña segura haz lo siguiente:
-Pon la hora a la que comiste ayer en letras.
-Abre un libro por la página 13 y escribe la primera palabra que veas.
-Pon el dia multiplicado por el mes en el que caduca algo de tu nevera.
-Pon el minuto que marca tu despertador.
-Pon la radio y escribe la primera frase que escuches. Primera palabra en minúsculas, segunda en mayusculas.. Intercalando las letras entre el resto de la contraseña.
-Añade símbolos.
-Utiliza una contraseña distinta por cifrado.

La clave debería ser algo así:
Hora-> dosymedia
Libro-> antecesor
Caducidad -> 32
Radio -> never CARE for WHAT they DO
Minuto -> 4
Simbolos -> ,.;


Contraseña:
dosymediaantecesor324

Contraseña Intercalada y con simbolos.
,ndeov,se.yr;mCe,Ad.RiE;afao,nrtW;eH.cAeTs,tohr.e3y,2D4O

Lo que buscaba con el post eran ideas ingeniosas propias de cada uno para hacer un cifrado nuevo. Si quisiese usar XOR o factorización para que iba a diseñar un cifrado propio si ya lo hacen todos?
Para eso pillo una librería y hago:
var texto=prompt("Pon texto a cifrar");
var clave=prompt("Pon clave segura");
var resultado = RSA(texto, clave, 8192);
clave=prompt("Pon otra clave distinta");
resultado = Chacha20(resultado, clave)
clave=prompt("Pon la ultima clave");
resultado = Serpent(resultado, clave);

Y ya. Si quisiese eso para que iba a preguntar nada? XD


Dices muchas cosas basadas en casos hipotéticos muy concretos que no se pueden aplicar como norma general.

Qué más da que pongas una espera en tu cifrado si no es un cifrado por oscuración para detener la potencia cuántica? Al ser el cifrado público se hará una implementación sin la limitación por hardware o se simulará de alguna forma.

Lo puse en foro libre porque es una pregunta sobre algoritmos matemáticos.

Te cito lo que pregunté:
CitarBusco ideas que tengais propias. No la "mejor manera" de hacerlo. Si no estaría usando números primos enormes y otros esquemas más apropiados para un sistema simétrico por clave donde el algoritmo de bastante igual.

El cifrado va a ser seguro independientemente del algoritmo que use ya que esto solo es una capa, usaré en otras capas bloques de 4096b y block chain entre otras cosas que me recomendó Kub0x y que tenía pensadas yo.

Solo quiero mejorar esta capa con algun algoritmo chulo y funcional. Este algoritmo que uso son 4 lineas tontas de código asique algo chulo no cuesta meterlo nada.

A mi se me ocurren ideas de medias aritméticas, geometrías básica y transposición de orden + bits con encoding en el propio cifrado. Esto último algo así como funciona la asimétrica. Indicar el orden cifrado con clave pública en el propio cifrado y descifrarla con la clave privada.

Qué se os ocurre? Ideas locas me gustan.  :D

Gracias por tomarte el tiempo de responder.