2009-04-26 21 views
34

Estoy tratando de calcular una Hash SHA-1 a partir de una cadena, pero cuando calculo la cadena utilizando la función sha1 de php, obtengo algo diferente a cuando lo intento en C#. Necesito C# para calcular la misma cadena que PHP (ya que la cadena de php es calculada por un tercero que no puedo modificar). ¿Cómo puedo obtener C# para generar el mismo hash que PHP? ¡¡¡Gracias!!!C# SHA-1 contra PHP SHA-1 ... ¿Diferentes resultados?

String = [email protected]

código C# (Genera d32954053ee93985f5c3ca2583145668bb7ade86)

 string encode = secretkey + email; 
     UnicodeEncoding UE = new UnicodeEncoding(); 
     byte[] HashValue, MessageBytes = UE.GetBytes(encode); 
     SHA1Managed SHhash = new SHA1Managed(); 
     string strHex = ""; 

     HashValue = SHhash.ComputeHash(MessageBytes); 
     foreach(byte b in HashValue) { 
      strHex += String.Format("{0:x2}", b); 
     } 

Código PHP (Genera a9410edeaf75222d7b576c1b23ca0a9af0dffa98)

sha1(); 
+8

tal vez el texto se maneja como Unicode en un sistema y como ASCII en el otro? – Aziz

+2

Increíble lo que hace la codificación simple;). Eso lo solucionó, acabo de cambiar UnicodeEncoding por ASCIIEncoding y funcionó perfectamente ... ¡Muchas gracias! –

Respuesta

35

Uso ASCIIEncoding en lugar de UnicodeEncoding. PHP usa juego de caracteres ASCII para cálculos hash.

+0

¡Gracias, ese fue el problema! –

+1

Como alguien eliminó su respuesta a continuación, UTF8Encoding también funcionará en su caso de prueba, pero no funcionará cuando tenga caracteres UTF8 como 艾. La codificación adecuada para usar cuando se trabaja con PHP es ASCIIEncoding. –

+1

Dado que me llevó algo de tiempo averiguarlo: ¡la entrada a la función hash también debe convertirse en ASCII! Y gracias por las respuestas! SO es simplemente genial! –

1

FWIW, tuve un problema similar en Java. Resultó que tenía que usar la codificación "UTF-8" para producir los mismos hash SHA1 en Java, ya que la función sha1 se produce en PHP 5.3.1 (ejecutándose en XAMPP Vista).

private static String SHA1(final String text) throws NoSuchAlgorithmException, UnsupportedEncodingException { 
     final MessageDigest md = MessageDigest.getInstance("SHA-1"); 
     md.update(text.getBytes("UTF-8")); 
     return new String(org.apache.commons.codec.binary.Hex.encodeHex(md.digest())); 
    } 
2

Tenía el mismo problema. Este código funcionó para mí:

string encode = secretkey + email; 
SHA1 sha1 = SHA1CryptoServiceProvider.Create(); 
byte[] encodeBytes = Encoding.ASCII.GetBytes(encode); 
byte[] encodeHashedBytes = sha1.ComputeHash(passwordBytes); 
string pencodeHashed = BitConverter. 
ToString(encode HashedBytes).Replace("-", "").ToLowerInvariant(); 
5

Tuve este problema también. El siguiente código funcionará.

string dataString = "string to hash"; 
SHA1 hash = SHA1CryptoServiceProvider.Create(); 
byte[] plainTextBytes = Encoding.ASCII.GetBytes(dataString); 
byte[] hashBytes = hash.ComputeHash(plainTextBytes); 
string localChecksum = BitConverter.ToString(hashBytes) 
.Replace("-", "").ToLowerInvariant(); 
+0

Casi tuve esto aceptar que me faltaba ToLowerInvariant. ¡¡¡Gracias!!! – AaronLS

-1

Probar Lo siguiente! Creo que será un gran trabajo:

public static string SHA1Encodeb64(string toEncrypt) 
    { 
     //Produce an array of bytes which is the SHA1 hash 
     byte[] sha1Signature = new byte[40]; 

     byte[] sha = System.Text.Encoding.Default.GetBytes(toEncrypt); 
     SHA1 sha1 = SHA1Managed.Create(); 
     sha1Signature = sha1.ComputeHash(sha); 


     /** 
     * The BASE64 encoding standard's 6-bit alphabet, from RFC 1521, 
     * plus the padding character at the end. 
     */ 
     char[] Base64Chars = { 
      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 
      'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 
      'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 
      'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 
      'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 
      'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 
      'w', 'x', 'y', 'z', '0', '1', '2', '3', 
      '4', '5', '6', '7', '8', '9', '+', '/', 
      '=' 
      }; 
     //Algorithm to encode the SHA1 hash using Base64 
     StringBuilder sb = new StringBuilder(); 
     int len = sha1Signature.Length; 
     int i = 0; 
     int ival; 
     while (len >= 3) 
     { 
      ival = ((int)sha1Signature[i++] + 256) & 0xff; 
      ival <<= 8; 
      ival += ((int)sha1Signature[i++] + 256) & 0xff; 
      ival <<= 8; 
      ival += ((int)sha1Signature[i++] + 256) & 0xff; 
      len -= 3; 
      sb.Append(Base64Chars[(ival >> 18) & 63]); 
      sb.Append(Base64Chars[(ival >> 12) & 63]); 
      sb.Append(Base64Chars[(ival >> 6) & 63]); 
      sb.Append(Base64Chars[ival & 63]); 
     } 
     switch (len) 
     { 
      case 0: // No pads needed. 
       break; 
      case 1: // Two more output bytes and two pads. 
       ival = ((int)sha1Signature[i++] + 256) & 0xff; 
       ival <<= 16; 
       sb.Append(Base64Chars[(ival >> 18) & 63]); 
       sb.Append(Base64Chars[(ival >> 12) & 63]); 
       sb.Append(Base64Chars[64]); 
       sb.Append(Base64Chars[64]); 
       break; 
      case 2: // Three more output bytes and one pad. 
       ival = ((int)sha1Signature[i++] + 256) & 0xff; 
       ival <<= 8; 
       ival += ((int)sha1Signature[i] + 256) & 0xff; 
       ival <<= 8; 
       sb.Append(Base64Chars[(ival >> 18) & 63]); 
       sb.Append(Base64Chars[(ival >> 12) & 63]); 
       sb.Append(Base64Chars[(ival >> 6) & 63]); 
       sb.Append(Base64Chars[64]); 
       break; 
     } 
     //Encode the signature using Base64 
     string base64Sha1Signature = sb.ToString(); 
     return base64Sha1Signature; 
    } 
+1

usando 'System.Text.Encoding.Default' es una ** muy ** mala idea cuando se trata de cadenas y criptografía. Diferentes plataformas usan diferentes valores predeterminados (UTF8, ASCII, Unicode) y usar 'Default' solo lo hace aún más complicado (ya que puede cambiar entre sistemas, configuración y versiones). – poupou

+0

Hay un codificador Base64 en .NET. También veo 'byte [] sha1Signature = new byte [40];', y luego 'sha1Signature = sha1.ComputeHash (sha);'. No es necesario 'nuevo byte [40]'. – quantum

9

Este método en .NET es equivalente a SHA1 en php:

string sha1Hash(string password) 
{ 
    return string.Join("", SHA1CryptoServiceProvider.Create().ComputeHash(Encoding.UTF8.GetBytes(password)).Select(x => x.ToString("x2"))); 
} 
+0

Just courious: ¿Por qué 'string.Join'? – Spontifixus

+1

El método Select (...) genera una matriz de cadenas, cada una representa un solo byte de los bytes devueltos por el método ComputeHash(), estas cadenas deben juntarse, una detrás de otra. El método de unión tiene este prototipo: String.Join (string separator, params string [] value), consulte (http://msdn.microsoft.com/en-us/library/57a79xd0.aspx). – OmarElsherif

+0

Ahh ...no se desplazó hacia la derecha, y por lo tanto no vio la selección. Olvida esa pregunta. ;) – Spontifixus