Cómo SHA1 hash una cadena en Android?

En Objective C he estado usando el siguiente código para hash una cadena:

-(NSString *) sha1:(NSString*)stringToHash { const char *cStr = [stringToHash UTF8String]; unsigned char result[20]; CC_SHA1( cStr, strlen(cStr), result ); return [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15], result[16], result[17], result[18], result[19] ]; } 

Ahora necesito lo mismo para Android, pero no puedo encontrar la manera de hacerlo. He estado buscando por ejemplo en esto: ¿ Haces el cifrado SHA1 en Android? pero eso no me da el mismo resultado que en iPhone. ¿Alguien puede señalarme en la dirección correcta?

No necesitas andorid para esto. Puedes hacerlo en Java simple.

¿Has probado un ejemplo simple de Java y ver si esto devuelve el sha1 correcto?

 import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class AeSimpleSHA1 { private static String convertToHex(byte[] data) { StringBuilder buf = new StringBuilder(); for (byte b : data) { int halfbyte = (b >>> 4) & 0x0F; int two_halfs = 0; do { buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10))); halfbyte = b & 0x0F; } while (two_halfs++ < 1); } return buf.toString(); } public static String SHA1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException { MessageDigest md = MessageDigest.getInstance("SHA-1"); byte[] textBytes = text.getBytes("iso-8859-1"); md.update(textBytes, 0, textBytes.length); byte[] sha1hash = md.digest(); return convertToHex(sha1hash); } } 

También comparta cuál debería ser su sha1 esperado. Quizás ObjectC lo está haciendo mal.

Un método SHA-1 más simple: ( actualizado a partir de las sugerencias del comentarista, también utilizando un algoritmo de byte-> string masivamente más eficiente )

 String sha1Hash( String toHash ) { String hash = null; try { MessageDigest digest = MessageDigest.getInstance( "SHA-1" ); byte[] bytes = toHash.getBytes("UTF-8"); digest.update(bytes, 0, bytes.length); bytes = digest.digest(); // This is ~55x faster than looping and String.formating() hash = bytesToHex( bytes ); } catch( NoSuchAlgorithmException e ) { e.printStackTrace(); } catch( UnsupportedEncodingException e ) { e.printStackTrace(); } return hash; } // http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); public static String bytesToHex( byte[] bytes ) { char[] hexChars = new char[ bytes.length * 2 ]; for( int j = 0; j < bytes.length; j++ ) { int v = bytes[ j ] & 0xFF; hexChars[ j * 2 ] = hexArray[ v >>> 4 ]; hexChars[ j * 2 + 1 ] = hexArray[ v & 0x0F ]; } return new String( hexChars ); } 

Si puedes salirte con la suya con la guayaba, es la forma más sencilla de hacerlo , y no tienes que reinventar la rueda:

 final HashCode hashCode = Hashing.sha1().hashString(yourValue, Charset.defaultCharset()); 

Luego puede tomar el valor hash y obtenerlo como un byte[] , como int , o como long .

Sin envolverse en una captura de prueba, sin travesuras. Y si decides que quieres usar algo que no sea SHA-1, la guayaba también es compatible con sha256, sha 512, y algunos de los que nunca había escuchado como adler32 y murmur3.

 final MessageDigest digest = MessageDigest.getInstance("SHA-1"); result = digest.digest(stringToHash.getBytes("UTF-8"); // Another way to make HEX, my previous post was only the method like your solution StringBuilder sb = new StringBuilder(); for (byte b : result) // This is your byte[] result.. { sb.append(String.format("%02X", b)); } String messageDigest = sb.toString(); 

Totalmente basado en la respuesta de @ Whymarrh, esta es mi implementación, probada y funcionando bien, sin dependencias:

 public static String getSha1Hex(String clearString) { try { MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); messageDigest.update(clearString.getBytes("UTF-8")); byte[] bytes = messageDigest.digest(); StringBuilder buffer = new StringBuilder(); for (byte b : bytes) { buffer.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1)); } return buffer.toString(); } catch (Exception ignored) { ignored.printStackTrace(); return null; } } 

Android viene con el códec de Apache’s Commons, o lo agrega como dependencia. Entonces hazlo:

 String myHexHash = DigestUtils.shaHex(myFancyInput); 

Ese es el método obsoleto anterior que obtienes con Android 4 de manera predeterminada. Las nuevas versiones de DigestUtils ofrecen todos los sabores de los métodos shaHex () como sha256Hex () y también sobrecargan los métodos con diferentes tipos de argumentos.

http://commons.apache.org/proper/commons-codec//javadocs/api-release/org/apache/commons/codec/digest/DigestUtils.html

El método que está buscando no es específico de Android, sino de Java en general. Está buscando import java.security.MessageDigest ( import java.security.MessageDigest ).

Aquí se puede ver una implementación de un sha512(String s) , y el cambio para un hash SHA-1 cambiaría la línea 71 a:

 MessageDigest md = MessageDigest.getInstance("SHA-1"); 
 String.format("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15], result[16], result[17], result[18], result[19]);