How to SHA1 hash a string in Android?

AndroidHashSha1

Android Problem Overview


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: https://stackoverflow.com/questions/5757024/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?

Android Solutions


Solution 1 - Android

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 - Android

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 - Android

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 - Android

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 - Android

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;
    }
}

Solution 6 - Android

Android comes with Apache's Commons Codec - or you add it as dependency. Then do:

String myHexHash = DigestUtils.shaHex(myFancyInput);

That is the old deprecated method you get with Android 4 by default. The new versions of DigestUtils bring all flavors of shaHex() methods like sha256Hex() and also overload the methods with different argument types.

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

Solution 7 - Android

with Kotlin this can be shortened and put into one line:

MessageDigest.getInstance("SHA-1").digest(theString.toByteArray()).joinToString("") { "%02x".format(it) }

Solution 8 - Android

The method you are looking for is not specific to Android, but to Java in general. You're looking for the MessageDigest (import java.security.MessageDigest).

An implementation of a sha512(String s) method can be seen here, and the change for a SHA-1 hash would be changing line 71 to:

MessageDigest md = MessageDigest.getInstance("SHA-1");

Solution 9 - Android

Here is the Kotlin version to get SHA encryption string.

import java.security.MessageDigest

object HashUtils {
    fun sha512(input: String) = hashString("SHA-512", input)

    fun sha256(input: String) = hashString("SHA-256", input)

    fun sha1(input: String) = hashString("SHA-1", input)

    /**
     * Supported algorithms on Android:
     *
     * Algorithm	Supported API Levels
     * MD5          1+
     * SHA-1	    1+
     * SHA-224	    1-8,22+
     * SHA-256	    1+
     * SHA-384	    1+
     * SHA-512	    1+
     */
    private fun hashString(type: String, input: String): String {
        val HEX_CHARS = "0123456789ABCDEF"
        val bytes = MessageDigest
                .getInstance(type)
                .digest(input.toByteArray())
        val result = StringBuilder(bytes.size * 2)

        bytes.forEach {
            val i = it.toInt()
            result.append(HEX_CHARS[i shr 4 and 0x0f])
            result.append(HEX_CHARS[i and 0x0f])
        }

        return result.toString()
    }
}

Its originally posted here: https://www.samclarke.com/kotlin-hash-strings/

Solution 10 - Android

To simplify it using extentions funcions on kotlin:

/**
 * Encrypt String to SHA1 format
 */
fun String.toSha1(): String {
    return MessageDigest
        .getInstance("SHA-1")
        .digest(this.toByteArray())
        .joinToString(separator = "", transform = { "%02x".format(it) })
}

Solution 11 - Android

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]);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMartinView Question on Stackoverflow
Solution 1 - AndroidAmir RaminfarView Answer on Stackoverflow
Solution 2 - AndroidAdamView Answer on Stackoverflow
Solution 3 - AndroidyarianView Answer on Stackoverflow
Solution 4 - AndroidSuphi ÇEVİKERView Answer on Stackoverflow
Solution 5 - AndroidcprcrackView Answer on Stackoverflow
Solution 6 - AndroidRisadinhaView Answer on Stackoverflow
Solution 7 - AndroidBeniBelaView Answer on Stackoverflow
Solution 8 - AndroidWhymarrhView Answer on Stackoverflow
Solution 9 - AndroidHitesh DhamshaniyaView Answer on Stackoverflow
Solution 10 - AndroidMakiXView Answer on Stackoverflow
Solution 11 - AndroidSuphi ÇEVİKERView Answer on Stackoverflow