Foro de elhacker.net

Programación => PHP => Mensaje iniciado por: @XSStringManolo en 5 Octubre 2019, 20:27 pm



Título: [Aporte] Funciones para Cifrado Vernan. Cifrado Simétrico(con clave).
Publicado por: @XSStringManolo en 5 Octubre 2019, 20:27 pm
Estoy haciendo un proyecto en el que para aumentar la seguridad me decidí a diseñar e implementar mi propio cifrado de 0 sin guiarme por nada.
Por casualidad(o por sencillez) llegué a la misma conclusión que a la que llegó Vernan con su cifrado hace años. Asique en gran parte del proceso reinventé la rueda.
 Entonces se puede considerar este código como una implementación del cifrado de Vernan.
Las funciones no están muy debugeadas ni testeadas. De momento me funcionan bien en los códigos que utilicé. Comenté su funcionamiento y varios factores a tener en cuenta para utilizar el cifrado de forma segura en el propio código.

El cifrado lo tengo todo diseñado en papel. Parte implementada en javascript y ahora lo estoy rescribiendo en PHP.
Publicaré en el foro otras partes del cifrado como el CSPRNG que estoy acabando de mejorar para obtener numerosas fuentes de entropia a partir de la propia clave. La implementación del método de transposición, etc.

Cualquier error en el código, duda, sugerencia, comentario u opinion es bienvenida.

Descripción breve:
SMTaD($stringCipherText);
-Pasa el texto de un string a su posición decimal en el abecedario.
Retorna un array con las posiciones.
"abcdefg" -> [1,2,3,4,5,6,7]
"hola" -> [8,16,12,1]

SMDpD($arrayDecimalDeTextoPorCifrar, $arrayContraseñaDecimal);
-Suma los valores de cada posición de ambos arrays.
Retorna un nuevo array con la suma de ambos.
La contraseña debe ser el mismo o mayor tamaño.
[8,16,12,1] + [1,2,3,4,5,6,7] -> [9,18,15,5]

SMDaT($arrayDecimal)
-Transforma cada grupo de decimales al texto correspondiente a esa posición en el abecedario.
Retrona un nuevo array con los caracteres correspondientes.
[9,18,15,5] -> ['i','q','ñ','e']

Se usan diccionarios para definir el "abecedario".


  
Código
  1. function SMTaD($cipherText)
  2.   {
  3.  
  4.   $cipherTextTam = strlen($cipherText);
  5.   $cipherText = strtolower($cipherText);
  6.   $diccionario = array('a','b','c','d','e','f','g','h','i','j','k','l',
  7. 'm','n','ñ','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C',
  8. 'D','E','F','G','H','I','J','K','L','M','N','Ñ','O','P','Q','R','S',
  9. 'T','U','V','W','X','Y','Z','1','2','3','4','5','6','7','8','9','0','.',
  10. ':','/',' ');
  11.   $diccionarioTam = count($diccionario);
  12.   $cipherTextDec = [];
  13.  
  14.  
  15.   $y = 0;
  16.      for($i = 0; $i < $cipherTextTam; ++$i)
  17.      {
  18.         for($x = 0; $x < $diccionarioTam; ++$x)
  19.         {
  20.            if($cipherText[$i] == $diccionario[$x])
  21.            {
  22.            $cipherTextDec[$y] = 1+$x;
  23.            ++$y;
  24.            }
  25.  
  26.            else
  27.            {
  28.            /*Caracter no está en el diccionario*/
  29.            }
  30.         }
  31.      }
  32.   return $cipherTextDec;
  33.   }
  34. /*StringManolo Texto a Decimal.
  35. Esta función toma como argumento un
  36. string $cipherText.
  37.  
  38. *Se recorre todo el string y se compara cada
  39. caracter con los caracteres que contiene el diccionario.
  40.  
  41. *En el caso de que el caracter a comprobar del
  42. $cipherText coincida con alguno de los caracteres
  43. del diccionario, se añade a un array la posición de
  44. ese caracter+1 (alfabéticamente) en el diccionario.
  45.  
  46. *Finalmente se retorna este array que hace referencia
  47. al orden alfabético de cada caracter.
  48.  
  49. *EJEMPLO:
  50. -Si $cipherText contiene la frase "Me van a cifrar".
  51.  
  52. 1) -Se busca el caracter M en el diccionario.
  53.  
  54. -La letra 'M' ocupa la posición 40 en el diccionario.
  55.  
  56. -En el array diccionario 'M' en realidad corresponde al
  57. índice 39. Debido a que el array utiliza el 0 como
  58. primer índice y no el 1. Debido a esto se suma +1 para
  59. obtener 40.
  60.  
  61. -Si no se encuentra 'M' en el diccionario o si
  62. ya se añadio el numero 40 se pasa a la siguiente letra.
  63.  
  64. 2) Se repite el proceso anterior para la letra 'e'.
  65.  
  66. 3) El resultado final de pasar el string "Me van a cifrar"
  67. seria el mismo que al hacer:
  68. $TextoEnDecimal = array('40','5','68','23','1','14','68','1','68','3','9','6','19','1','19');
  69. Hace referencia a: array('M','e',' ','v','a','n',' ','a',' ','c','i','f','r','a','r');
  70.  
  71. *Utilizo strToLower para convertir todas las letras mayúsculas
  72. a minúsculas. Comenta o borra esa línea si te interesa mantener la
  73. información original.
  74.  
  75. *Asegurate que todos los caracteres del
  76. texto a cifrar estén contemplados en el diccionario.
  77. Puedes crear una funcion para obtener todos los caracteres
  78. distintos del texto a cifrar y crear el diccionario en base a ellos.
  79. Así evitas comprobaciones innecesarias con caracteres que
  80. sabes de antemano que no vas a encotrar.
  81. Por ejemplo si aplicas base64 antes de la función, puedes
  82. eliminar ' ',':','.' del diccionario y añadir '+','=' ya que sabes de
  83. antemano que un texto cifrado en base64 no puede contener
  84. espacios, dos puntos o puntos.
  85.  
  86. **Obtener una referencia numérica de las letras tiene entre
  87. otras utilidades poder operar matemáticamente con los caracteres.
  88. */
  89.  
  90.  
  91.  
  92.   function SMDpD($decimal1, $decimal2)
  93.   {
  94.  
  95.   $diccionario = array('1','2','3','4','5','6','7','8','9',
  96. '10','11','12','13','14','15','16','17','18','19','20','21',
  97. '22','23','24','25','26','27','28','29','30','31','32','33',
  98. '34','35','36','37','38','39','40','41','42','43','44','45',
  99. '46','47','48','49','50','51','52','53','54','55','56','57',
  100. '58','59','60','61','62','63','64','65','66','67','68','69');
  101.   $diccionarioTam = count($diccionario);
  102.   $decimal1Tam = count($decimal1);
  103.   $decimal2Tam = count($decimal2);
  104.   $cipherTextSum = [];
  105.  
  106.      $y = 0;
  107.      for($i = 0; $i < $decimal1Tam; ++$i)
  108.      {
  109.         for($x = 0; $x < $diccionarioTam; ++$x)
  110.         {
  111.            if($decimal1[$i] == $diccionario[$x])
  112.            {
  113.            $cipherTextSum[$y] = $decimal1[$i] + $decimal2[$y];
  114.            ++$y;
  115.            }
  116.         }
  117.      }
  118.   return $cipherTextSum;
  119.   }
  120. /*StringManolo Decimal plus Decimal.
  121. StringManolo Decimal + Decimal.
  122. Esta función toma como argumentos 2 arrays
  123. que contienen numeros y los suma.
  124.  
  125. Durante el diseño de este cifrado llegué a la
  126. conclusión de que esta suma modular de 2 caracteres
  127. ya se utilizaba por el Cifrado Vernan. El Cifrado Vernan
  128. sentó las bases para otros cifrados de uso frecuente
  129. a lo largo de la historia. Uno de los principios más
  130. seguros es el conocido como Libreta De Un Solo Uso.
  131. https://es.m.wikipedia.org/wiki/Libreta_de_un_solo_uso
  132.  
  133. IMPORTANTE:
  134. Este cifrado está probado como irrompible bajo ciertas
  135. condiciones. Esta implementación deja a cargo del
  136. usuario de estas condiciones. Y algunas
  137. consideraciones. Paso a comentar estos puntos a
  138. continuación:
  139. 1)Se espera que se utilize como uno de los parámetros
  140. de la función una cadena *Aleatoria del mismo o mayor
  141. tamaño que el texto a cifrar.
  142.  
  143. En computación (sin entrar propiedades cuánticas)
  144. es imposible generar un número totalmente aleatorio.
  145.  
  146. Para suplir este inconveniente se
  147. recurre a utilizar algoritmos para generar numeros
  148. pseudoaleatorios resistentes a criptoanálisis.
  149. Estos algoritmos son conocidos como CSPRNG.
  150. Algunos de los provados como más seguros son
  151. aquellos que generan secuencias pseudoaleatorias
  152. utilizaneo como entropia el "ruido de fondo" o "ruido"
  153. ambiente captado por el micrófono.
  154. En realidad puedes escribir letras aleatoria como clave
  155. para el cifrado siempre y cuando:
  156. -No sigas ningún patrón que se pueda replicar para
  157. genear la clave que vas a utilizar.
  158. -El cifrado lo debes generar en un equipo offline únicamente
  159. dedicado para ello. En caso de que el equipo se conecte
  160. a otros equipos, un atacante podría llegar a infiltrarse
  161. en el sistema y obtener la clave utilizada.
  162. El cifrado de la Libreta De Un Solo Uso se basa en que una
  163. vez utilizada la clave esta se destruya.
  164.  
  165.  
  166. 2) El tamaño de la clave debe ser igual o mayor que el tamaño
  167. del texto a cifrar.
  168.  
  169. Consideraciones:
  170. -No deja de ser un cifrado de substitución. Si la
  171. clave es insegura "aaaaaaaaa" o se tienen indicios del
  172. idioma en el que se escribió el texto a cifrar, se pueden realizar
  173. diversos analisis de frecuencia. Para eliminar esta posibilidad
  174. recomiendo utilizar algún cifrado de transposición para desordenar
  175. el texto a cifrar. Mas adelante recomiendo cual utilizar.
  176.  
  177. -No debe reutilizarse la clave ni dejar a un usuario cifrar con la misma
  178. clave. Si estas utilizando la misma clave, por ejemplo
  179. "abcdefghijk..." para cifrar un texto. Si dejas a un usuario
  180. cifrar con ella, podría cifrar el texto "aaaaaaaaaaaaa..." y así
  181. generar la clave +1 para cada caracter.
  182.  
  183. Siguiendo estos principios se espera que el primer parámetro de la
  184. función sea un array con los decimales del texto a cifrar.
  185. Y que el segundo parámetro sea la contraseña tambien en decimal.
  186. Se pueden pasar strings a la función SMTaD(); para obtener el array
  187. en decimal correspondiente.
  188. Ejemplo:
  189.  
  190. $Saludo = "Hola";
  191. $Contraseña = "ceaf";
  192.  
  193. $Saludo = SMTaD($Saludo);
  194. $Contraseña = SMTaD($Contraseña);
  195.  
  196. $SaludoCifrado = SMDpD($Saludo, $Contraseña);
  197.  
  198. $SaludoCifrado = SMDaT($SaludoCifrado);
  199.  
  200. Sucede lo siguiente:
  201. SMTaD($Saludo); devuelve el array 8,16,12,1
  202. SMTaD($Contraseña); devuelve el array 3,5,1,6
  203. SMDpD($Saludo, $Contraseña); devuelve el array 11,21,13,7
  204.  
  205. La siguiente función SMDaT($array); utiliza un diccionario para
  206. convertir los decimales a texto.
  207.  
  208. SMDaT($SaludoCifrado); devuelve el array k,t,m,g
  209.  
  210. Puedes usar:
  211. Un diccionario de 27 caracteres (a-z) y usar el operador módulo
  212. o restar el tamaño del diccionario. En este caso a+z seria 28.
  213. 28-27 es 1.
  214. 1 es igual a 'a'.
  215.  
  216. Un diccionario de 54 caracteres (a-Z).
  217. Un diccionario de 64 caracteres (a-9).
  218.  
  219. O un diccionario que contemple las máximas posibilidades.
  220. En caso de solo operar con minúsuculas tanto en la clave
  221. como en la contraseña (a-z) tendrías un valor máximo posible
  222. de z+z (27+27). Es decir, puedes representar todos
  223. los resultados en un diccionario de 54 caracteres.
  224. Por ejemplo (a-Z). Así z+a = 28. que sería 'A'.
  225. Esta última opción puede ser menos o más segura criptográficamente.
  226. Pero sigue siendo irrompible si se siguen todas las pautas.
  227. Ya que 'A' puede ser a+z, b+y, c+x, d+w, e+v, f+u ...
  228. En conclusión 'A' puede ser cualquier letra del abecedario
  229. en conjunto con otra letra opuesta (en relación con su orden alfabético).
  230. Es difícil analizar que método es mejor.
  231. Teoricamente ninguno da información relevante en el supuesto de
  232. utilizar una clave aleatoria y cifrando por transposición el texto.
  233.  
  234. Debido a que la seguridad del cifrado se basa en el desconocimiento de la clave
  235. por parte del atacante, recomiendo utilizar la propia clave para aplicar transposición
  236. al texto que se va a cifrar, o al propio resultado del cifrado.
  237. Siguiendo el ejemplo anterior:
  238. texto -> h o l a
  239. contraseña -> c e a f
  240. resultado -> k t m g
  241.  
  242. Puedes utilizar el propio orden alfabético de la clave para reordenar el resultado:
  243. c e a f -> 1c=2, 2e=3, 3a=1, 4f=4
  244. k t m g -> 1k pos2, 2t pos3, 3m pos1, 4g pos4
  245. resultado -> m k t g
  246.  
  247. *Esta funcion puede ser utilizada sin modificaciones para cifrar utilizando varios
  248. cifrados comunes.
  249. Por ejemplo para cifrar con cifrado Cesar introduce como clave la letra
  250. que corresponda alfabéticamente al numero de vueltas.
  251. $Saludo = "Hola";
  252. $Contraseña = "bbbb";
  253. $Saludo = SMTaD($Saludo);
  254. $Contraseña = SMTaD($Contraseña);
  255. $SaludoCifrado = SMDpD($Saludo, $Contraseña);
  256. $SaludoCifrado = SMDaT($SaludoCifrado);
  257. El resultado de cifrar hola con bbbb es j q n c.
  258.  
  259. Para cifrar con vigenere:
  260. $Saludo = "Hola";
  261. $Contraseña = "abcd";
  262. $Saludo = SMTaD($Saludo);
  263. $Contraseña = SMTaD($Contraseña);
  264. $SaludoCifrado = SMDpD($Saludo, $Contraseña);
  265. $SaludoCifrado = SMDaT($SaludoCifrado);
  266. El resultado de cifrar hola con abcd es iqñe
  267. en el diccionario incluí la ñ. Si la eliminas el
  268. resultado seria el mismo que en el diccionario
  269. inglés de uso común resultado -> iqoe.
  270. Se obtiene el mismo resultado que cifrando hola
  271. con vigenere y la clave bcde.
  272. Con un par de modificaciones se puede conseguir el
  273. mismo resultado.
  274.  
  275. Si quieres imprimir el contenido del array puedes usar:
  276. foreach($SaludoCifrado as $value)
  277. {
  278. echo "$value" ;
  279. }
  280.  
  281. Y para imprimirlo en un documento de texto:
  282. file_put_contents("carpeta/resultado.txt", $SaludoCifrado, FILE_APPEND);
  283.  
  284. */
  285.  
  286.  
  287.   function SMDaT($cipherText)
  288.   {
  289.   $cipherTextTam = count($cipherText);
  290.  
  291.   $diccionario = array('a','b','c','d','e','f','g','h','i','j','k','l',
  292. 'm','n','ñ','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C',
  293. 'D','E','F','G','H','I','J','K','L','M','N','Ñ','O','P','Q','R','S',
  294. 'T','U','V','W','X','Y','Z','1','2','3','4','5','6','7','8','9','0','.',
  295. ':','/','-','!','@','^','&','*','+','=','<','>','{','}','[',']','€','%','?','_','|',
  296. 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','ñ','o','p','q','r','s',
  297. 't','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L',
  298. 'M','N','Ñ','O','P','Q','R','S','T','U','V','W','X','Y','Z'); $diccionarioTam = count($diccionario);
  299.  
  300.   $diccionario2 = array('1','2','3','4','5','6','7','8','9',
  301. '10','11','12','13','14','15','16','17','18','19','20','21',
  302. '22','23','24','25','26','27','28','29','30','31','32','33',
  303. '34','35','36','37','38','39','40','41','42','43','44','45',
  304. '46','47','48','49','50','51','52','53','54','55','56','57',
  305. '58','59','60','61','62','63','64','65','66','67','68','69',
  306. '70','71','72','73','74','75','76','77','78','79','80','81',
  307. '82','83','84','85','86','87','88','89','90','91','92','93',
  308. '94','95','96','97','98','99','100','101','102','103',
  309. '104','105','106','107','108','109','110','111','112',
  310. '113','114','115','116','117','118','119','120','121',
  311. '122','123','124','125','126','127','128','129','130',
  312. '131','132','133','134','135','136','137','138','139');
  313.   $diccionario2Tam = count($diccionario2);
  314.  
  315.   $cipherTextText = [];
  316.  
  317. $z=0;
  318.      for($i = 0; $i < $cipherTextTam; ++$i)
  319.      {
  320.         for($x =0; $x<$diccionarioTam; ++$x)
  321.         {
  322.            if($cipherText[$i] == $diccionario2[$x])
  323.            {
  324.            $cipherTextText[$z] = $diccionario[$x];
  325.            ++$z;
  326.            }
  327.         }
  328.      }
  329.   return $cipherTextText;
  330.   }
  331.  
  332.  
  333.  
  334.  


Título: Re: [Aporte] Funciones para Cifrado Vernan. Cifrado Simétrico(con clave).
Publicado por: e en 5 Octubre 2019, 20:37 pm
Hacía unos dias estaba pensando sobre eso  :o, aunque en C.