How to generate an MD5 checksum for a file in Android?

AndroidMd5Checksum

Android Problem Overview


In my app I have a requirement to generate an MD5 checksum for a file. Could you please tell me if there is any way in which this can be achieved?

Thank you.

Android Solutions


Solution 1 - Android

This code is from the CMupdater, from the CyanogenMod 10.2 android ROM. It tests the downloaded ROMs into the updater App.

code: https://github.com/CyanogenMod/android_packages_apps_CMUpdater/blob/cm-10.2/src/com/cyanogenmod/updater/utils/MD5.java

It works like a charm:

/*
 * Copyright (C) 2012 The CyanogenMod Project
 *
 * * Licensed under the GNU GPLv2 license
 *
 * The text of the license can be found in the LICENSE file
 * or at https://www.gnu.org/licenses/gpl-2.0.txt
 */

package com.cyanogenmod.updater.utils;

import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5 {
    private static final String TAG = "MD5";

    public static boolean checkMD5(String md5, File updateFile) {
        if (TextUtils.isEmpty(md5) || updateFile == null) {
            Log.e(TAG, "MD5 string empty or updateFile null");
            return false;
        }

        String calculatedDigest = calculateMD5(updateFile);
        if (calculatedDigest == null) {
            Log.e(TAG, "calculatedDigest null");
            return false;
        }

        Log.v(TAG, "Calculated digest: " + calculatedDigest);
        Log.v(TAG, "Provided digest: " + md5);

        return calculatedDigest.equalsIgnoreCase(md5);
    }

    public static String calculateMD5(File updateFile) {
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, "Exception while getting digest", e);
            return null;
        }

        InputStream is;
        try {
            is = new FileInputStream(updateFile);
        } catch (FileNotFoundException e) {
            Log.e(TAG, "Exception while getting FileInputStream", e);
            return null;
        }

        byte[] buffer = new byte[8192];
        int read;
        try {
            while ((read = is.read(buffer)) > 0) {
                digest.update(buffer, 0, read);
            }
            byte[] md5sum = digest.digest();
            BigInteger bigInt = new BigInteger(1, md5sum);
            String output = bigInt.toString(16);
            // Fill to 32 chars
            output = String.format("%32s", output).replace(' ', '0');
            return output;
        } catch (IOException e) {
            throw new RuntimeException("Unable to process file for MD5", e);
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                Log.e(TAG, "Exception on closing MD5 input stream", e);
            }
        }
    }
}

Solution 2 - Android

Convert the file content into string & use the below method:

public static String getMD5EncryptedString(String encTarget){
		MessageDigest mdEnc = null;
		try {
			mdEnc = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			System.out.println("Exception while encrypting to md5");
			e.printStackTrace();
		} // Encryption algorithm
		mdEnc.update(encTarget.getBytes(), 0, encTarget.length());
		String md5 = new BigInteger(1, mdEnc.digest()).toString(16);
        while ( md5.length() < 32 ) {
 			md5 = "0"+md5;
	    }
		return md5;
	}

Note that this simple approach is suitable for smallish strings, but will not be efficient for large files. For the latter, see dentex's answer.

Solution 3 - Android

I had the same task and this code works excellent:

public static String fileToMD5(String filePath) {
    InputStream inputStream = null;
    try {
        inputStream = new FileInputStream(filePath);
        byte[] buffer = new byte[1024];
        MessageDigest digest = MessageDigest.getInstance("MD5");
        int numRead = 0;
        while (numRead != -1) {
            numRead = inputStream.read(buffer);
            if (numRead > 0)
                digest.update(buffer, 0, numRead);
        }
        byte [] md5Bytes = digest.digest();
        return convertHashToString(md5Bytes);
    } catch (Exception e) {
        return null;
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (Exception e) { }
        }
    }
}

private static String convertHashToString(byte[] md5Bytes) {
    String returnVal = "";
    for (int i = 0; i < md5Bytes.length; i++) {
        returnVal += Integer.toString(( md5Bytes[i] & 0xff ) + 0x100, 16).substring(1);
    }
    return returnVal.toUpperCase();
}

Solution 4 - Android

public static String getMd5OfFile(String filePath)
{
    String returnVal = "";
    try 
    {
        InputStream   input   = new FileInputStream(filePath); 
        byte[]        buffer  = new byte[1024];
        MessageDigest md5Hash = MessageDigest.getInstance("MD5");
        int           numRead = 0;
        while (numRead != -1)
        {
            numRead = input.read(buffer);
            if (numRead > 0)
            {
                md5Hash.update(buffer, 0, numRead);
            }
        }
        input.close();

        byte [] md5Bytes = md5Hash.digest();
        for (int i=0; i < md5Bytes.length; i++)
        {
            returnVal += Integer.toString( ( md5Bytes[i] & 0xff ) + 0x100, 16).substring( 1 );
        }
    } 
    catch(Throwable t) {t.printStackTrace();}
    return returnVal.toUpperCase();
}

Solution 5 - Android

If you're using Okio (which most apps use today, directly or indirectly by using OkHttp or Retrofit), you can also do something like this:

return File(path).source().buffer().use { source ->
   HashingSink.md5(blackholeSink()).use { sink ->
     source.readAll(sink)
     sink.hash.hex()
   }
}

This doesn't have to buffer the entire file in memory (the HashingSink will update the md5sum with every write call and then call down to blackholeSink(), which does nothing with the bytes). You can also use HashingSource instead to do something similar.

Solution 6 - Android

Here's clean little kotlin extension function. Works well on large files too.

fun File.md5(): String {
    val md = MessageDigest.getInstance("MD5")
    return this.inputStream().use { fis ->
        val buffer = ByteArray(8192)
        generateSequence {
            when (val bytesRead = fis.read(buffer)) {
                -1 -> null
                else -> bytesRead
            }
        }.forEach { bytesRead -> md.update(buffer, 0, bytesRead) }
        md.digest().joinToString("") { "%02x".format(it) }
    }
}

And the unit test to go with it:

@Test
fun `computes md5 checksum correctly`() {
    val file = File.createTempFile("test-", ".tmp")
    // did md5 on unix machine to comfirm -- put a literal LF at end to compare
    val content = "This is the content of a file." + 0x0a.toChar()
    file.writer().use { w -> w.write(content) }
    assertEquals("a149f5161e873921d84636b2a1b3aad2", file.md5())
}

Solution 7 - Android

If you need to calculate MD5 of the big file , you may like to use this:

Import:

import java.security.MessageDigest;

Method:

 private byte[] calculateMD5ofFile(String location) throws IOException, NoSuchAlgorithmException {
        FileInputStream fs= new FileInputStream(location);
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] buffer=new byte[bufferSize];
        int bytes=0;
        do{
            bytes=fs.read(buffer,0,bufferSize);
            if(bytes>0)
                md.update(buffer,0,bytes);

        }while(bytes>0);
        byte[] Md5Sum = md.digest();
        return Md5Sum;
    }

Refrence: https://docs.oracle.com/javase/7/docs/api/java/security/MessageDigest.html


To convert byte array to Hex. use this

public static String ByteArraytoHexString(byte[] bytes) {
    StringBuilder hexString = new StringBuilder();
    for (int i = 0; i < bytes.length; i++) {
        String hex = Integer.toHexString(bytes[i] & 0xFF);
        if (hex.length() == 1) {
            hexString.append('0');
        }
        hexString.append(hex);
    }
    return hexString.toString();
}

Refrence https://stackoverflow.com/questions/332079/in-java-how-do-i-convert-a-byte-array-to-a-string-of-hex-digits-while-keeping-l

Solution 8 - Android

buddy try following code

MessageDigest md = MessageDigest.getInstance("MD5");
InputStream is = new FileInputStream("file.txt");
try {
      is = new DigestInputStream(is, md);
      // read stream to EOF as normal...
    }
finally {
      is.close();
   }
byte[] digest = md.digest();

Solution 9 - Android

I've found the following to work really well:

Process process = Runtime.getRuntime().exec("md5 "+fileLocation);
BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream()));
String result = inputStream.readLine().split(" ")[0];

This calls the built-in md5 command. The variable fileLocation is to be set to the location of the file. Of course I do recommend constructing some checks around here to check that the file exists.

Solution 10 - Android

This method worked for me, on a 131MB zip file. MD5 calculated matches that calculated on same file by AccuHash (http://www.accuhash.com)

public static String calculateMD5(File updateFile) {
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            Log.e("calculateMD5", "Exception while getting Digest", e);
            return null;
        }

        InputStream is;
        try {
            is = new FileInputStream(updateFile);
        } catch (FileNotFoundException e) {
            Log.e("calculateMD5", "Exception while getting FileInputStream", e);
            return null;
        }

        byte[] buffer = new byte[8192];
        int read;
        try {
            while ((read = is.read(buffer)) > 0) {
                digest.update(buffer, 0, read);
            }
            byte[] md5sum = digest.digest();
            BigInteger bigInt = new BigInteger(1, md5sum);
            String output = bigInt.toString(16);
            // Fill to 32 chars
            output = String.format("%32s", output).replace(' ', '0');
            return output;
        } catch (IOException e) {
            throw new RuntimeException("Unable to process file for MD5", e);
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                Log.e("calculateMD5", "Exception on closing MD5 input stream", e);
            }
        }
    }	

Solution 11 - Android

Kotlin version:



fun File.getMD5Hash(path: String): ByteArray {
    val md = MessageDigest.getInstance("MD5")
    val stream: InputStream
    stream = FileInputStream(this)

    val buffer = ByteArray(8192)
    var read: Int
    while (stream.read(buffer).also { read = it } > 0) {
        md.update(buffer, 0, read)
    }
    stream.close()
    return md.digest()
}

Solution 12 - Android

 public static String md5(String data) throws NoSuchAlgorithmException {
    // Get the algorithm:
    MessageDigest md5 = MessageDigest.getInstance("MD5");
    // Calculate Message Digest as bytes:
    byte[] digest = md5.digest(data.getBytes(StandardCharsets.UTF_8));
    // Convert to 32-char long String:
    return String.format("%032x", new BigInteger(1, digest));
}

Solution 13 - Android

Here is my complete working code. I need to find duplicate files using checksum.

/**
 * this method is used for create check Sum further process...
 *
 * @param models    path of image.
 * @param asyncTask asyncTask of activity
 * @return return array of all files check sum.
 * <p>
 * before put BufferedInputStream
 * with BufferedInputStream (buffer 8192) with Logs
 * with BufferedInputStream (buffer 16384) with Logs
 * with BufferedInputStream (buffer 4194304) with Logs
 * with BufferedInputStream (buffer 32768) with Logs
 * with BufferedInputStream (buffer 32768) without Logs(MD5)
 * with BufferedInputStream (buffer 32768) without Logs (SHA-256)
 */
public static ArrayList<FileModel> generateCheckSum(ScanningListener scanningListener, ArrayList<FileModel> lstAllFile, AsyncTask asyncTask) {
    FileInputStream fis;
    MessageDigest md;
    byte[] buffer;
    int numOfBytesRead;
    byte[] hash;

    long startTime = System.currentTimeMillis();
    for (FileModel s : lstAllFile) {

        if (scanningListener != null)
            scanningListener.onGoingProgress(lstAllFile.size(),lstAllFile.indexOf(s));
        try {
            if (asyncTask.isCancelled()) {
                break;
            }

            fis = new FileInputStream(s.getFilePath());
            md = MessageDigest.getInstance("MD5");
            buffer = new byte[16384];//(1024*2048)


            while ((numOfBytesRead = fis.read(buffer)) > 0) {
                md.update(buffer, 0, numOfBytesRead);
            }

            hash = md.digest();
            s.setChecksum(convertHashToString(hash));
            CustomLog.error("path", String.valueOf(s.getFilePath()));
        } catch (IOException ex) {
            CustomLog.error("IOException", String.valueOf(ex));
        } catch (NoSuchAlgorithmException ex) {
            CustomLog.error("NoSuchAlgorithmException ", String.valueOf(ex));
        }
    }
    long endTime = System.currentTimeMillis();

    long totalTime = endTime - startTime;
    CustomLog.error("Total Time : ", TimeUtils.getDateIn24HrsFormatInUTC(totalTime));
    return lstAllFile;
}

convertHashToString(hash)

/**
 * this method is help for convert hash value into string file and return hash code.
 *
 * @param hash byte array.
 * @return return string of hash code
 */
private static String convertHashToString(byte[] hash) {
    StringBuilder returnVal = new StringBuilder();
    for (byte md5Byte : hash) {
        returnVal.append(Integer.toString((md5Byte & 0xff) + 0x100, 16).substring(1));
    }
    return returnVal.toString();
}

This method will give you a hashmap of all the given files.

I've tried many different types of buffer size as well as MD5 and SHA-1 that you can see in the comments section

Solution 14 - Android

I use these two extensions in Kotlin:

fun File.calcHash(algorithm: String = "MD5", bufferSize: Int = 1024): ByteArray {
    this.inputStream().use { input ->
        val buffer = ByteArray(bufferSize)
        val digest = MessageDigest.getInstance(algorithm)

        read@ while (true) {
            when (val bytesRead = input.read(buffer)) {
                -1 -> break@read
                else -> digest.update(buffer, 0, bytesRead)
            }
        }

        return digest.digest()
    }
}

fun ByteArray.toHexString(): String {
    return this.fold(StringBuilder()) { result, b -> result.append(String.format("%02X", b)) }.toString()
}

Solution 15 - Android

    fun md5(file: File): String {
        val digest = MessageDigest.getInstance(MD5_ALGORITHM)
        file.inputStream().buffered(BUFFER_SIZE).use { it.iterator().forEach(digest::update) }
        return digest.digest().joinToString("") { "%02x".format(it) }
    }

Solution 16 - Android

With OKio, it is a one-liner:

val md5_as_hex_string = Okio.buffer(Okio.source(file).readByteString().md5().hex()

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
QuestionIngrid CooperView Question on Stackoverflow
Solution 1 - AndroiddentexView Answer on Stackoverflow
Solution 2 - AndroidhemuView Answer on Stackoverflow
Solution 3 - AndroidyuralifeView Answer on Stackoverflow
Solution 4 - AndroidXXXView Answer on Stackoverflow
Solution 5 - AndroidahmedreView Answer on Stackoverflow
Solution 6 - Androidbroc.seibView Answer on Stackoverflow
Solution 7 - AndroidM atView Answer on Stackoverflow
Solution 8 - AndroidRonak MehtaView Answer on Stackoverflow
Solution 9 - AndroidDaniël van den BergView Answer on Stackoverflow
Solution 10 - Androidgman413View Answer on Stackoverflow
Solution 11 - AndroidMorteza RastgooView Answer on Stackoverflow
Solution 12 - AndroidToufiqul Haque MamunView Answer on Stackoverflow
Solution 13 - AndroidMehul BoghraView Answer on Stackoverflow
Solution 14 - Androidt3chb0tView Answer on Stackoverflow
Solution 15 - AndroidJuan RadaView Answer on Stackoverflow
Solution 16 - AndroidInterkotView Answer on Stackoverflow