Simular el encryption de passwords () de MySql con .NET o MS SQL

Estoy actualizando una vieja aplicación web ASP / MySql a ASP.NET/MS SQL.

Nos gustaría mantener los inicios de session del antiguo website trabajando en la nueva aplicación.

Lamentablemente, las passwords se almacenaron en la database MySql utilizando la function de contraseña () de MySql.

¿Es posible simular la function de contraseña () de MySql en .NET o MS SQL?

Cualquier ayuda / enlaces son apreciados.

Según la documentation de MySQL, el algorithm es un hash doble SHA1. Al examinar el código fuente de MySQL, encontrará una function llamada make_scrambled_password () en libmysql / password.c. La function se define de la siguiente manera:

/* MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice applied to the password string, and then produced octet sequence is converted to hex string. The result of this function is used as return value from PASSWORD() and is stonetworking in the database. SYNOPSIS make_scrambled_password() buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string password IN NULL-terminated password string */ void make_scrambled_password(char *to, const char *password) { SHA1_CONTEXT sha1_context; uint8 hash_stage2[SHA1_HASH_SIZE]; mysql_sha1_reset(&sha1_context); /* stage 1: hash password */ mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password)); mysql_sha1_result(&sha1_context, (uint8 *) to); /* stage 2: hash stage1 output */ mysql_sha1_reset(&sha1_context); mysql_sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE); /* separate buffer is used to pass 'to' in octet2hex */ mysql_sha1_result(&sha1_context, hash_stage2); /* convert hash_stage2 to hex string */ *to++= PVERSION41_CHAR; octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE); } 

Dado este método, puede crear una contraparte .NET que básicamente haga lo mismo. Esto es lo que se me ocurrió. Cuando ejecuto SELECT PASSWORD ('testing'); contra mi copy local de MySQL, el valor devuelto es:

*94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29

De acuerdo con el código fuente (nuevamente en password.c), el asterisco inicial indica que este es el método posterior a MySQL 4.1 para encriptar la contraseña. Cuando emulo la funcionalidad en VB.Net, por ejemplo, esto es lo que se me ocurre:

 Public Function GenerateMySQLHash(ByVal strKey As String) As String Dim keyArray As Byte() = Encoding.UTF8.GetBytes(strKey) Dim enc = New SHA1Managed() Dim encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray)) Dim myBuilder As New StringBuilder(encodedKey.Length) For Each b As Byte In encodedKey myBuilder.Append(b.ToString("X2")) Next Return "*" & myBuilder.ToString() End Function 

Tenga en count que SHA1Managed () está en el espacio de nombres System.Security.Cryptography. Este método devuelve el mismo resultado que la llamada PASSWORD () en MySQL. Espero que esto te ayude

Editar: Aquí está el mismo código en C #

 public string GenerateMySQLHash(string key) { byte[] keyArray = Encoding.UTF8.GetBytes(key); SHA1Managed enc = new SHA1Managed(); byte[] encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray)); StringBuilder myBuilder = new StringBuilder(encodedKey.Length); foreach (byte b in encodedKey) myBuilder.Append(b.ToString("X2")); return "*" + myBuilder.ToString(); } 

Puede encriptar cadenas usando MD5 o SHA1 en .Net, pero el algorithm real utilizado por MySQL es probablemente diferente de estos dos methods. Sospecho que está basado en algún tipo de 'sal' basado en la instancia del server, pero no sé.

En teoría, dado que creo que MySQL es de código abierto, podrías investigar la fuente y determinar cómo se hace.

http://dev.mysql.com/doc/refman/5.1/en/encryption-functions.html#function_password

Edición 1: creo que el algorithm utilizado es un doble SHA1 con otros 'ajustes' (según esta publicación del blog).

"No van a revelar qué algorithm usan"

erm … alguien debería despertarse y decirle que MySQL es OPEN SOURCE … no necesitan "divulgar" algo porque todos pueden leer la estructura misma de la database – solo descargue las fonts, busque las funciones de encriptación (i) Supongo que están usando C ++) y comienzan a investigar … SHA1 parece bastante inseguro ahora – recientemente algunos científicos han demostrado que es posible elegir hasta el 20% de los datos sin limitaciones y producir el mismo hash, por lo que uno sería se aconseja utilizar AES o SHA2 (por lo tanto, no MySQL- PASSWORD -func)

Versión de C # modificada para corregir el problema de relleno.
[Prueba] public void GenerateMySQLHashX2 () {string password = "20iva05";

  byte[] keyArray = Encoding.UTF8.GetBytes(password); SHA1Managed enc = new SHA1Managed(); byte[] encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray)); StringBuilder myBuilder = new StringBuilder(encodedKey.Length); foreach (byte b in encodedKey) { log.Debug(b.ToString() + " -> " + b.ToString("X2")); myBuilder.Append(b.ToString("X2")); } Assert.AreEqual("*8C2029A96507478FD1720F6B713ADD57C66EED49", "*" + myBuilder.ToString()); } 

Para VB net, este rellena con 0 a la izquierda para que cuando el código hexadecimal sea [por ejemplo] 'E', esta function anexará correctamente '0E' a la cadena de resultados. De modo que, al final, incluido el '*' preanimado, la cadena resultante tendrá 41 caracteres, como se requiere en MySQL

 Public Function GenerateMySQLHash(ByVal strKey As String) As String Dim keyArray As Byte() = System.Text.UTF8Encoding.UTF8.GetBytes(strKey) Dim enc = New Security.Cryptography.SHA1Managed() Dim encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray)) Dim myBuilder As New System.Text.StringBuilder(encodedKey.ToString.Length) For Each b As Byte In encodedKey myBuilder.Append(Strings.Right("0" & b.ToString("X"), 2)) Next Return "*" & myBuilder.ToString() End Function 

las funciones de contraseña de mysql no son particularmente seguras (por ejemplo, no hay sal ni ningún otro método de protección contra la búsqueda de hashes) las únicas razones que puedo ver para querer duplicar el algorithm son 1: tiene una list / tabla de usuarios con contraseña mysql () s 2: quieres descifrar las passwords de mysql de los hashes en la tabla de usuarios.

De lo contrario, utilice algo diferente, por ejemplo, un hash que combine tanto el nombre del usuario (y / o algún otro invariante de fila) como su contraseña. De esta forma, si dos usuarios eligen la misma contraseña, no será obvio. y si la tabla queda expuesta, la security no disminuye a la misma velocidad (por ejemplo, google para 446a12100c856ce9 que es el hash de la contraseña () de una contraseña muy popular)

No podrá simular la function de contraseña de MySql (). al less no sin mucho trabajo y suerte. Siendo que MySql usa su propio algorithm para encriptar cadenas de una sola dirección, no van a revelar qué algorithm usan; lo que significa que tendría que hacer testings y errores, comparar las cadenas resultantes, etc.

Para solucionar su problema:

Replicaría el DB pero mantendría una connection con MySql. Use una bandera para identificar un inicio de session por primera vez. Pídales que usen su contraseña actual; verifique la contraseña con la function de contraseña de MySql (). Si la contraseña es válida; pídales que lo reinicien, ya sea ingresando la misma contraseña nuevamente o una nueva; en este punto, use su algorithm de encriptación favorito y almacene el resultado en su MS Sql DB.

Sé que suena como un dolor, pero es lo mejor que puedes hacer si no intentas hackear tu path para descifrar el algorithm de encriptación de MySql.

¡Buena suerte!