MD5 hashing in Android

AndroidCryptographyMd5

Android Problem Overview


I have a simple android client which needs to 'talk' to a simple C# HTTP listener. I want to provide a basic level of authentication by passing username/password in POST requests.

MD5 hashing is trivial in C# and provides enough security for my needs but I can't seem to find how to do this at the android end.

EDIT: Just to address the concerns raised about MD5 weakness - the C# server runs on the PCs of the users of my android client. In many cases, they'll be accessing the server using wi-fi on their own LANs but, at their own risk, they may choose to access it from the internet. Also the service on the server needs to use pass-through for the MD5 to a 3rd party application I have no control over.

Android Solutions


Solution 1 - Android

Here is an implementation you can use (updated to use more up to date Java conventions - for:each loop, StringBuilder instead of StringBuffer):

public static String md5(final String s) {
    final String MD5 = "MD5";
    try {
        // Create MD5 Hash
        MessageDigest digest = java.security.MessageDigest
                .getInstance(MD5);
        digest.update(s.getBytes());
        byte messageDigest[] = digest.digest();

        // Create Hex String
        StringBuilder hexString = new StringBuilder();
        for (byte aMessageDigest : messageDigest) {
            String h = Integer.toHexString(0xFF & aMessageDigest);
            while (h.length() < 2)
                h = "0" + h;
            hexString.append(h);
        }
        return hexString.toString();

    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return "";
}

Although it is not recommended for systems that involve even the basic level of security (MD5 is considered broken and can be easily exploited), it is sometimes enough for basic tasks.

Solution 2 - Android

The accepted answer didn't work for me in Android 2.2. I don't know why, but it was "eating" some of my zeros (0) . Apache commons also didn't work on Android 2.2, because it uses methods that are supported only starting from Android 2.3.x. Also, if you want to just MD5 a string, Apache commons is too complex for that. Why one should keep a whole library to use just a small function from it...

Finally I found the following code snippet here which worked perfectly for me. I hope it will be useful for someone...

public String MD5(String md5) {
   try {
        java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
        byte[] array = md.digest(md5.getBytes("UTF-8"));
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < array.length; ++i) {
          sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1,3));
       }
        return sb.toString();
    } catch (java.security.NoSuchAlgorithmException e) {
    } catch(UnsupportedEncodingException ex){
    }
    return null;
}

Solution 3 - Android

The androidsnippets.com code does not work reliably because 0's seem to be cut out of the resulting hash.

A better implementation is here.

> public static String MD5_Hash(String s) { > MessageDigest m = null; > > try { > m = MessageDigest.getInstance("MD5"); > } catch (NoSuchAlgorithmException e) { > e.printStackTrace(); > } > > m.update(s.getBytes(),0,s.length()); > String hash = new BigInteger(1, m.digest()).toString(16); > return hash; > }

Solution 4 - Android

If using Apache Commons Codec is an option, then this would be a shorter implementation:

String md5Hex = new String(Hex.encodeHex(DigestUtils.md5(data)));

Or SHA:

String shaHex= new String(Hex.encodeHex(DigestUtils.sha("textToHash")));

Source for above.

Please follow the link and upvote his solution to award the correct person.


Maven repo link: https://mvnrepository.com/artifact/commons-codec/commons-codec

Current Maven dependency (as of 6 July 2016):

<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.10</version>
</dependency>

Solution 5 - Android

A solution above using DigestUtils didn't work for me. In my version of Apache commons (the latest one for 2013) there is no such class.

I found another solution here in one blog. It works perfect and doesn't need Apache commons. It looks a little shorter than the code in accepted answer above.

public static String getMd5Hash(String input) {
	try {
		MessageDigest md = MessageDigest.getInstance("MD5");
		byte[] messageDigest = md.digest(input.getBytes());
		BigInteger number = new BigInteger(1, messageDigest);
		String md5 = number.toString(16);

		while (md5.length() < 32)
			md5 = "0" + md5;

		return md5;
	} catch (NoSuchAlgorithmException e) {
		Log.e("MD5", e.getLocalizedMessage());
		return null;
	}
}

You will need these imports:

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

Solution 6 - Android

This is a slight variation of Andranik and Den Delimarsky answers above, but its a bit more concise and doesn't require any bitwise logic. Instead it uses the built-in String.format method to convert the bytes to two character hexadecimal strings (doesn't strip 0's). Normally I would just comment on their answers, but I don't have the reputation to do so.

public static String md5(String input) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");

        StringBuilder hexString = new StringBuilder();
        for (byte digestByte : md.digest(input.getBytes()))
            hexString.append(String.format("%02X", digestByte));

        return hexString.toString();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
}

If you'd like to return a lower case string instead, then just change %02X to %02x.

Edit: Using BigInteger like with wzbozon's answer, you can make the answer even more concise:

public static String md5(String input) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        BigInteger md5Data = new BigInteger(1, md.digest(input.getBytes()));
        return String.Format("%032X", md5Data);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
}

Solution 7 - Android

I have made a simple Library in Kotlin.

Add at Root build.gradle

allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io' }
		}
	}

at App build.gradle

implementation 'com.github.1AboveAll:Hasher:-SNAPSHOT'

Usage

In Kotlin

val ob = Hasher()

Then Use hash() method

ob.hash("String_You_Want_To_Encode",Hasher.MD5)

ob.hash("String_You_Want_To_Encode",Hasher.SHA_1)

It will return MD5 and SHA-1 Respectively.

More about the Library

https://github.com/ihimanshurawat/Hasher

Solution 8 - Android

Here is Kotlin version from @Andranik answer. We need to change getBytes to toByteArray (don't need to add charset UTF-8 because the default charset of toByteArray is UTF-8) and cast array[i] to integer

fun String.md5(): String? {
    try {
        val md = MessageDigest.getInstance("MD5")
        val array = md.digest(this.toByteArray())
        val sb = StringBuffer()
        for (i in array.indices) {
            sb.append(Integer.toHexString(array[i].toInt() and 0xFF or 0x100).substring(1, 3))
        }
        return sb.toString()
    } catch (e: java.security.NoSuchAlgorithmException) {
    } catch (ex: UnsupportedEncodingException) {
    }
    return null
}

Hope it help

Solution 9 - Android

Please use SHA-512, MD5 is insecure

public static String getSHA512SecurePassword(String passwordToHash) {
    String generatedPassword = null;
    try {
        MessageDigest md = MessageDigest.getInstance("SHA-512");
        md.update("everybreathyoutake".getBytes());
        byte[] bytes = md.digest(passwordToHash.getBytes());
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
        }
        generatedPassword = sb.toString();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return generatedPassword;
}

Solution 10 - Android

Useful Kotlin Extension Function Example

fun String.toMD5(): String {
    val bytes = MessageDigest.getInstance("MD5").digest(this.toByteArray())
    return bytes.toHex()
}

fun ByteArray.toHex(): String {
    return joinToString("") { "%02x".format(it) }
}

Solution 11 - Android

In our MVC application we generate for long param

using System.Security.Cryptography;
using System.Text;
    ...
    public static string getMD5(long id)
    {
        // convert
        string result = (id ^ long.MaxValue).ToString("X") + "-ANY-TEXT";
        using (MD5 md5Hash = MD5.Create())
        {
            // Convert the input string to a byte array and compute the hash. 
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(result));

            // Create a new Stringbuilder to collect the bytes and create a string.
            StringBuilder sBuilder = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
                sBuilder.Append(data[i].ToString("x2"));

            // Return the hexadecimal string. 
            result = sBuilder.ToString().ToUpper();
        }

        return result;
    }

and same in Android application (thenk helps Andranik)

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
...
public String getIdHash(long id){
    String hash = null;
    long intId = id ^ Long.MAX_VALUE;
    String md5 = String.format("%X-ANY-TEXT", intId);
    try {
        MessageDigest md = java.security.MessageDigest.getInstance("MD5");
        byte[] arr = md.digest(md5.getBytes());
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < arr.length; ++i)
            sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1,3));

        hash = sb.toString();
    } catch (NoSuchAlgorithmException e) {
        Log.e("MD5", e.getMessage());
    }

    return hash.toUpperCase();
}

Solution 12 - Android

i have used below method to give me md5 by passing string for which you want to get md5

public static String getMd5Key(String password) {

//        String password = "12131123984335";

        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(password.getBytes());

            byte byteData[] = md.digest();

            //convert the byte to hex format method 1
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < byteData.length; i++) {
                sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
            }

            System.out.println("Digest(in hex format):: " + sb.toString());

            //convert the byte to hex format method 2
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < byteData.length; i++) {
                String hex = Integer.toHexString(0xff & byteData[i]);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
            System.out.println("Digest(in hex format):: " + hexString.toString());

            return hexString.toString();

        } catch (Exception e) {
            // TODO: handle exception
        }

        return "";
}

Solution 13 - Android

MD5 is a bit old, SHA-1 is a better algorithm, there is a example here.

(Also as they note in that post, Java handles this on it's own, no Android specific code.)

Solution 14 - Android

Far too wasteful toHex() conversion prevails in other suggestions, really.

private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();

public static String md5string(String s) {
    return toHex(md5plain(s));
}

public static byte[] md5plain(String s) {
    final String MD5 = "MD5";
    try {
        // Create MD5 Hash
        MessageDigest digest = java.security.MessageDigest.getInstance(MD5);
        digest.update(s.getBytes());
        return digest.digest();
    } catch (NoSuchAlgorithmException e) {
        // never happens
        e.printStackTrace();
        return null;
    }
}

public static String toHex(byte[] buf) {
    char[] hexChars = new char[buf.length * 2];
    int v;
    for (int i = 0; i < buf.length; i++) {
        v = buf[i] & 0xFF;
        hexChars[i * 2] = HEX_ARRAY[v >>> 4];
        hexChars[i * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

Solution 15 - Android

this is working perfectly for me, I used this to get MD5 on LIST Array(then convert it to JSON object), but if you only need to apply it on your data. type format, replace JsonObject with yours.

Especially if you have a mismatch with python MD5 implementation use this!

private static String md5(List<AccelerationSensor> sensor) {

    Gson gson= new Gson();
    byte[] JsonObject = new byte[0];
    try {
        JsonObject = gson.toJson(sensor).getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    MessageDigest m = null;

    try {
        m = MessageDigest.getInstance("MD5");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }

    byte[] thedigest = m.digest(JsonObject);
    String hash = String.format("%032x", new BigInteger(1, thedigest));
    return hash;


}

Solution 16 - Android

The provided solutions for the Scala language (a little shorter):

def getMd5(content: Array[Byte]) =
	try {
		val md = MessageDigest.getInstance("MD5")
		val bytes = md.digest(content)
		bytes.map(b => Integer.toHexString((b + 0x100) % 0x100)).mkString
	} catch {
		case ex: Throwable => null
	}

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
QuestionSquonkView Question on Stackoverflow
Solution 1 - AndroidDen DelimarskyView Answer on Stackoverflow
Solution 2 - AndroidAndranikView Answer on Stackoverflow
Solution 3 - AndroidChristianView Answer on Stackoverflow
Solution 4 - AndroidtbraunView Answer on Stackoverflow
Solution 5 - AndroidDenis KutlubaevView Answer on Stackoverflow
Solution 6 - AndroidrsimpView Answer on Stackoverflow
Solution 7 - AndroidHimanshu RawatView Answer on Stackoverflow
Solution 8 - AndroidLinhView Answer on Stackoverflow
Solution 9 - AndroidCarlos Jesus Arancibia TaborgaView Answer on Stackoverflow
Solution 10 - AndroidArda KazancıView Answer on Stackoverflow
Solution 11 - AndroidOleg GrabetsView Answer on Stackoverflow
Solution 12 - AndroidGhanshyam PatidarView Answer on Stackoverflow
Solution 13 - AndroidAdamView Answer on Stackoverflow
Solution 14 - AndroidGena BatsyanView Answer on Stackoverflow
Solution 15 - AndroidMehran Sahandi FarView Answer on Stackoverflow
Solution 16 - Androiddavid.perezView Answer on Stackoverflow