How to SHA1 hash a string in Android?
Solution 1
You don't need andorid for this. You can just do it in simple java.
Have you tried a simple java example and see if this returns the right sha1.
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);
}
}
Also share what your expected sha1 should be. Maybe ObjectC is doing it wrong.
Solution 2
A simpler SHA-1 method: (updated from the commenter's suggestions, also using a massively more efficient byte->string algorithm)
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 );
}
Solution 3
If you can get away with using Guava it is by far the simplest way to do it, and you don't have to reinvent the wheel:
final HashCode hashCode = Hashing.sha1().hashString(yourValue, Charset.defaultCharset());
You can then take the hashed value and get it as a byte[]
, as an int
, or as a long
.
No wrapping in a try catch, no shenanigans. And if you decide you want to use something other than SHA-1, Guava also supports sha256, sha 512, and a few I had never even heard about like adler32 and murmur3.
Solution 4
final MessageDigest digest = MessageDigest.getInstance("SHA-1");
result = digest.digest(stringToHash.getBytes("UTF-8"));
// Another way to construct 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();
Solution 5
Totally based on @Whymarrh's answer, this is my implementation, tested and working fine, no dependencies:
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;
}
}
Martin
Updated on July 05, 2022Comments
-
Martin almost 2 years
In Objective C I've been using the following code to hash a string:
-(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] ]; }
Now I need the same for Android but can't find out how to do it. I've been looking for example at this: Make SHA1 encryption on Android? but that doesn't give me the same result as on iPhone. Can anyone point me in the right direction?
-
Martin about 13 yearsThanks for this answer! The convertToHex() I was using was doing it wrong. Your code is working fine.
-
Peter almost 13 yearsGreate .. Thank you very much
-
Melvin over 11 yearsif the sha1 string is supposed to start with a 0, then the 0 is left out. So this method returns a wrong sha-1 encoded string in some cases.
-
NicoMinsk over 11 yearsWARNING : not work if you want to hash '1122', it's start with 0
-
Adam over 11 yearsCorrect! Updated the answer to deal with this. Thanks for catching this guys.
-
eselk over 11 yearsAs the code is currently it just returns a hex version of original string, no hashing. Need to call digest.digest() somewhere.
-
CodesInChaos over 11 yearsWhy iso-8559-1 encoding instead of UTF-8? These is little reason to use such legacy encodings unless you need to be compatible with some existing application.
-
CodesInChaos over 11 yearsUsing default encoding(
somestring.GetBytes()
) will give you platform dependent hashes. Not nice. Use a fixed encoding, preferably UTF-8. -
Max Steinmeyer over 11 yearsAs someone mentioned below, text.length() isn't correct, as it won't return the number of bytes. You need to use the length of the array returned by getBytes. And, yeah, it really probably shouldn't be iso-8859.
-
Triang3l about 11 yearsThe point was not to show how to format the hash, the point was to show how to create it.
-
JM Lord about 9 yearsNote: use "%02x" if you want to avoid capitalization.
-
cprcrack over 8 yearsAwesome, I'm sharing my complete implementation: stackoverflow.com/a/33260623/423171
-
Ridcully over 8 yearsAs suggested for other answers, you should use
clearString.getBytes("UTF-8")
to be on the safe side. -
Muz about 8 yearsI really like this answer because it fits into Android so well, and doesn't need me to double check SO code for security holes :p
-
android developer over 7 yearsCan "md" ever be null on Android ?
-
Carlos Espinoza about 7 yearsI implemented this code into my Android App and works perfect. Thank for share.