Secured-Hash 2018 - Funciones para VFP6

Iniciado por eb4bgr, 29 Octubre 2019, 21:32 PM

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

eb4bgr

Son funciones de Hash seguras, incluyen cifrado y resumen.  Como ya he mencionado, paso de github.  Tampoco conozco ningún cifrado que incorpore los métodos de seguridad internos que yo he desarrollado en el mío.  Lo de la confianza me da igual, invento la seguridad que quiero para mis proyectos.  :-)

Serapis

#11
Antes de nada, perdón, pués yo puse un mensaje (que deben haber borrado) de "Esto es Spam", por la simple razón de que solo había 2 líneas de texto y un enlace (apuntando fuera del foro), además juraría que vi repetido el mensaje en otro lado... Sin más explicaciones, ni ningún simple ejemplo de nada, sonaba claramente a Spam.


Mirando así por encima, veo cosas muy mejorables.. por ejemplo la simple función de invertir una cadena de texto:

Function ReverseStr(_cIn)
* Invierte el orden de los caracteres de una cadena.

Local _rStr := ""
Local _nB00 := 0

For _nB00 = Len(_cIn) To 1 Step (-1)
_rStr := (_rStr + SubStr(_cIn, _nB00, 1))
Next _nB00

Return (_rStr)


Concatenar una cadena es algo que no debe hacerse más de 1 ó 2 veces para obtener un contenido, por que cada concatenación exige buscar memoria libre con la suma total de caracteres y copiar ahí las partes a unir... luego en un bucle de por ejemplo 100 caracteres invertir esa cadena supone crear 100 veces una cadena y copiar cada vez las partes que la componen, total para ir añadiendo cada vez un solo carácter respecto del contenido previo...

Crea una cadena del largo total (cuando se conoce) o más (si no se conoce y al final se devuelve el 'substring' de solo la parte ocupada)... "_rStr" será igual de larga finalmente que "_cIn", luego procede al comienzo hacerla del mismo tamaño.
... y vas tomando caracteres del final de la cadena y poniéndolos al comienzo, o al revés, los tomas del comienzo y los vas poniendo al final retrocediendo. Así a lo sumo creas solo 2 veces la cadena, independientemente del largo que tenga.

Una forma sencilla de probar ambas funciones (la que tienes y la que tendrías que rehacer), sería usar una cadena de por ejemplo 100Mb. y comparar tiempos, en la que te falta por hacer (la óptima), no llevaría más de unos segundos, en la que tienes posiblemente varios minutos (no sé si bastarían 20)...





Cansa ver la forma en que nombras las variables locales y parámetros:
La barra baja "_cStr", suele usarse en los lenguajes para:
- Separar visualmente palabras en identificadores largos, como en: "Precio_Articulo".
- También para unir 'gramáticamente' el nombre de un objeto al nombre de un evento, como en: "Precio_Changed", existiendo un objeto llamado "Precio" que pertenece a un tipo de datos que tiene un evento llamado "Changed".
- Microsoft, cuando finalmente dió facilidades para crear las propiedades autoimplementadas (yo mismo solicité esa característica... hace ya un chorro de años), usa precisamente la barra baja al comienzo del nombre con el mismo nombre de la propiedad para dar respaldo al campo que ha de mantener el valor de la propiedad, dando así oportunidad al usuario de no usar nombres en tal forma, para evitar errores por duplicidad de declaraciones, es una buena alternativa peor para usar exclusivamente en la parte del compilador, no para que un usuario deba enfrentarse a nombres así formados.

Sugiero que como mínimo remplaces esa barra baja por algún carácter legible... por ejemplo para las locales: "lcStr", para los parámetros: "pcStr", para las locales a nivel de módulo: "mcStr"... etc...
Fíjate que incluso leerlo obliga a decir "barra baja cStr", una vez no importa, pero por cada una es requetecansimo... intenta leer tu propio código para que otro lo copie a medida que te oye, y entenderás el absurdo. Y todas las excusas que te inventes, como indicarle de antemano que es 'una regla', sigue siendo absurda... cambia de interlocutor y verás que resulta absurdo explicarle a cada interlocutor una regla, innecesaria... porque para esos existen las letras del abecedario.. son legibles ocupan lo mismo y dispones de 26 mayúsculas y 26 minúdculas... si tienes una regla para señalar que "los nombres d evariables en parámetros las comienzo con 'p', es una regla que no hay necesidad de explicar a nadie, porque 'pcStr', podría llamarse de cualquier otra manera todo el mundo entenderá que hayas elegido ese nombre por alguna razón.

...de todos modos, es siempre preferible poner nombres significativos a las variables (significativas, los parámetros lo son, las variables de tipo contador por ejemplo no y para ellas les baste j, k, t, n, v, etc...).
...en el mismo sentido los nombres de la mayoría de funciones son amorfas... si el códiigo es para tí, no tiene más importancia, tu sabes 'tus reglas', pero si ofeces tu código a otros, complicas innecesariamente las cosas... de qué sirve poner debajo luego un comentario de lo que hace la función, cuando el propio nombre de la función debería sugerir bastante claro lo que debe hacer...
ejemplo:
Tu nombre: Function "SB"
Lo adecuado: Function "StringToBase36"
O como mínimo: Function "StrToB36"




Otro ejemplo de ineficiencia es ese par de funciones de conversión de ASCII a base 36 y viceversa

Function SB(_cIn)
* Conversor de cadenas de caracteres a cadenas en Base-36.


Local _SB := ""
Local _cTemp00 := ""
Local _cTemp01 := ""
Local _nTemp00 := 0
Local _nB00 := 0

For _nB00 = 1 To Len(_cIn) Step 1
_cTemp00 := (_cTemp00 + AS(Str(Asc(SubStr(_cIn, _nB00, 1)) + 256), 3, (-1), 48))
Next _nB00

Do While (Len(_cTemp00) > 0)
_cTemp01 := Left(_cTemp00, 9)
_nTemp00 := (Val(_cTemp01) + 10^9)
_SB := (_SB + NToC(_nTemp00, 36))
_cTemp00 := Right(_cTemp00, (Len(_cTemp00) - 9))
EndDo

Return (Lower(_SB))



Function BS(_cIn)
* Conversor de cadenas en Base-36 a cadena de caracteres original.


Local _BS := ""
Local _cTemp00 := _cIn
Local _cTemp01 := ""
Local _cTemp02 := ""
Local _cTemp03 := ""
Local _cTemp04 := ""
Local _nTemp00 := 0
Local _nTemp01 := 0

Do While (Len(_cTemp00) > 0)
_cTemp01 := Left(_cTemp00, 6)
_nTemp00 := (CToN(_cTemp01, 36) - 10^9)
_cTemp03 := AllTrim(Str(_nTemp00, 9, 0))
_nTemp01 := IIf((Len(_cTemp03) > 6), 9, IIf((Len(_cTemp03) > 3), 6, 3))
_cTemp04 := AS(_cTemp03, _nTemp01, (-1), 48)
_cTemp02 := (_cTemp02 + _cTemp04)
_cTemp00 := Right(_cTemp00, (Len(_cTemp00) - 6))
EndDo

Do While (Len(_cTemp02) > 0)
_cTemp01 := Left(_cTemp02, 3)
_nTemp00 := xVal(_cTemp01)
_BS := (_BS + Chr(_nTemp00))
_cTemp02 := Right(_cTemp02, (Len(_cTemp02) - 3))
EndDo

Return (_BS)


De entrada el código es tortuoso,  mareante  y pecas de nuevo con concatenaciones...
Cuando una conversion forma parte de un proyecto, forozoso es, crear sendos arrays para convertir a y desde usando un simple bucle con apenas 1-4 líneas dentro del bucle, tanto para la codificación como para la decodificación...

Incluso en el caso de tener que hacer variadas conversiones tal que no resulte adecuado tener tablar para cada base usada, entonces procede in situ hacer la conversión de forma matemática (división y módulo para codificar y multiplicación y suma para decodificar).
Siempre que se pueda es preferible crear arrays para una traducción rápida, ya que luego el compilador, viendo que tiene un bucle y un array, tratará la direcciones con registro de índice, lo que acelerará las conversiones, pués evita calcular la dirección absoluta para cada índice del array con multiplicaciones...



Encuentro iguales problemas de inficiencia en muchas otras funciones...




También juraría que las funciones "SHCrypt" y "SHDeCrypt" son idénticas... Procede hacerlo más coherente, una sola función basta, puede llamarse "Crypt" y que acepte un parámetro adicional con valor buelano: Si FALSE=SHDeCrypt y si TRUE=SHCrypt, aunque como no hay diferencias en lo que hace da igual.
Otra forma si prefieres mantener los nombres, es dejar una sola funcion, y la otra compleamente vacía se remite simplemente a invocar a la que tiene el código... (porque hacen exactamente lo mismo, solo cambia el nombre de la función).

Además en esa función de cifrado veo muchos 'modulo', pero no veo ningún 'xor'. Ya te digo por descontado que funciones de cifrado basadas exclusivamente en operaciones aritméticas, son proclives a generar patrones reproducibles de los que aprovecharse. Incluso teniendo operaciones 'xor' si no se controlan adecuadamente también están sujetas a lo mismo, como le pasa por ejemplo al algoritmo RC4.

...
En fin, solo he mirado el fichero "S-Hash.Prg" y si no me gusta lo que veo, no creo que el resto vaya a ser distinto...



p.d.: He tenido que retirar las etiqeutas GEsHI, porque al parecer duplica el contenido cuando el lenguaje es "visualfoxpro", y se ve mal...

kub0x

CitarSon funciones de Hash seguras, incluyen cifrado y resumen.
Keyed hash functions estilo HMAC supongo. Si es así entonces la palabra cifrar si tiene sentido. Podría haberlo deducido leyendo tu código, pero basic dejó de ser lo mío hace más de un lustro. Pero como puedes ver el gran NEBIRE está al día en el lenguaje y te está dando buenos consejos, como siempre :D

CitarTampoco conozco ningún cifrado que incorpore los métodos de seguridad internos que yo he desarrollado en el mío.
Bueno quizá por aquí te podamos ayudar si aportas algo de información al respecto. Es fácil construir y díficil destruir, pero merece la pena si te gusta el campo. Esto lo digo porque en mis comienzos no encontraba referencias a ninguno de los métodos con los que yo trabajaba. Una vez me especialicé en matemáticas empece leer y leer libros-publicaciones en el campo y ya entonces vi que existían métodos parecidos, incluso idénticos lo que te llena de rabia y alegría a la vez pues sabes que vas por el buen camino. Por lo tanto si eres versado en matemáticas te irá bien, al menos personalmente me ha ido bien aprendiendo teoría de números, álgebra lineal, álgebra cominatorial, álgebra geométrica, teoría de la representación y teoría de grupos. Para hacer algoritmos asimétricos clásicos (no post-quanticos) con saber teoría de números y grupos te vale.

CitarLo de la confianza me da igual, invento la seguridad que quiero para mis proyectos.
No entendí bien lo de "confianza".Supongo que quieres decir que en tus proyectos mandas tú. Supongo que para tí la crypto es un hobby nada más, pero el día de mañana si quieres publicar tus esquemas criptográficos, te aviso  de que la comunidad criptografa no revisará ningún esquema  sin la parte del criptonálisis-complejidad-seguridad. Como el gran Bruce Schneier dijo
CitarAnyone, from the most clueless amateur to the best cryptographer, can create an algorithm that he himself can't break.
En mi vida lo he visto, pues he conseguido romper casi todo lo que he creado, y lo que no, analizado y publicado está. Incluso he publicado lo roto, todo aprendizaje si está bien documentado (matemáticamente) es candidato a ser publicado. Así que si lo rompes podrías publicarlo de todas formas.

Saludos.
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate


eb4bgr

No es Basic, es un lenguaje parecido a dBase.  Si no dispone de funciones tan específicas para trabajar con caracteres habrá que crearlas.  Si lo meto todo en una matriz y luego lo recodifico pierdo el tiempo haciendo 2 bucles.  Los nombres de variables los asigno así porque todo ese código forma parte de otro proyecto más complejo en el que me hace falta esa denominación.