Codificación de cadena SHA-512: el resultado de C#y JAVA es diferente
encoding (3)
Estoy tratando de comparar dos cadenas diferentes codificadas por sha512. Pero, el resultado es diferente. Puede ser un problema de codificación, quiero decir. Espero que puedas ayudarme.
Este es mi código de Java:
MessageDigest digest = java.security.MessageDigest.getInstance("SHA-512");
digest.update(MyString.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
String h = Integer.toHexString(0xFF & messageDigest[i]);
while (h.length() < 2)
h = "0" + h;
hexString.append(h);
}
return hexString.toString();
y, este es mi código C #:
UnicodeEncoding UE = new UnicodeEncoding();
byte[] hashValue;
byte[] message = UE.GetBytes(MyString);
SHA512Managed hashString = new SHA512Managed();
string hex = "";
hashValue = hashString.ComputeHash(message);
foreach (byte x in hashValue)
{
hex += String.Format("{0:x2}", x);
}
return hex;
Dónde está el problema ? Thx muchachos
ACTUALIZAR
Si no especifico el tipo de codificación, supongo que Unicode creo. El resultado es esto (sin especificar nada):
Java SHA: a99951079450e0bf3cf790872336b3269da580b62143af9cfa27aef42c44ea09faa83e1fbddfd1135e364ae62eb373c53ee4e89c69b54a7d4d268cc2274493a8
C# SHA: 70e6eb559cbb062b0c865c345b5f6dbd7ae9c2d39169571b6908d7df04642544c0c4e6e896e6c750f9f135ad05280ed92b9ba349de12526a28e7642721a446aa
En cambio, si especifico UTF-16 en Java:
Java UTF-16: SHA f7a587d55916763551e9fcaafd24d0995066371c41499fcb04614325cd9d829d1246c89af44b98034b88436c8acbd82cd13ebb366d4ab81b4942b720f02b0d9b
¡Siempre es diferente!
El UnicodeEncoding
en C # que utiliza corresponde a la codificación little-endian UTF-16, mientras que "UTF-16" en Java corresponde a la codificación UTF-16 big-endian . Otra diferencia es que C # no genera el marcador de orden de bytes (llamado "preámbulo" en la API) si no lo solicita, mientras que "UTF-16" en Java lo genera siempre. Para que los dos programas sean compatibles, puedes hacer que Java también use el little-endian UTF-16:
digest.update(MyString.getBytes("UTF-16LE"));
O puede cambiar a otra codificación conocida, como UTF-8.
La razón probablemente sea que no especificó la codificación que se usará al convertir la cadena a bytes, Java usa la codificación predeterminada de la plataforma, mientras que UnicodeEncoding
parece usar utf-16.
Editar:
La documentación para UnicodeEncoding dice
Este constructor crea una instancia que usa el orden de bytes little endian , proporciona una marca de orden de bytes Unicode y no lanza una excepción cuando se detecta una codificación no válida.
Sin embargo, el "utf-16" de Javas parece predeterminado para el orden de bytes de Big Endian . Con las codificaciones de caracteres es mejor ser realmente específico, hay un constructor UnicodeEncoding que toma dos órdenes de bytes que especifican booleanos , mientras que en java también hay "utf-16le" y "utf-16be". Puedes probar lo siguiente en c #
new UnicodeEncoding(true, false) // big endian, no byte order mark
y en java
myyString.getBytes("utf-16be")
O mejor aún, use "utf-8" / Encoding.UTF8 en ambos casos, ya que no se ve afectado por diferentes byteorders .
Aquí,
digest.update(MyString.getBytes());
debe especificar explícitamente la codificación de caracteres deseada en String#getBytes()
método String#getBytes()
. De lo contrario, se establecerá de forma predeterminada en el juego de caracteres predeterminado de la plataforma, tal como lo ha obtenido Charset#defaultCharset()
.
Solucionarlo en consecuencia:
digest.update(MyString.getBytes("UTF-16LE"));
Al menos debería ser el mismo conjunto de caracteres que UnicodeEncoding
usa internamente.
Sin relación con el problema concreto, Java también tiene un bucle for
mejorado y un String#format()
.