[java] In Java, how do I convert a byte array to a string of hex digits while keeping leading zeros?

I'm working with some example java code for making md5 hashes. One part converts the results from bytes to a string of hex digits:

byte messageDigest[] = algorithm.digest();     
StringBuffer hexString = new StringBuffer();
for (int i=0;i<messageDigest.length;i++) {
    hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
    }

However, it doesn't quite work since toHexString apparently drops off leading zeros. So, what's the simplest way to go from byte array to hex string that maintains the leading zeros?

This question is related to java md5 hex

The answer is


You can get it writing less without external libraries:

String hex = (new HexBinaryAdapter()).marshal(md5.digest(YOUR_STRING.getBytes()))

And how can you convert back again from ascii to byte array ?

i followed following code to convert to ascii given by Jemenake.

public static String toHexString(byte[] bytes) {
    char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for ( int j = 0; j < bytes.length; j++ ) {
        v = bytes[j] & 0xFF;
        hexChars[j*2] = hexArray[v/16];
        hexChars[j*2 + 1] = hexArray[v%16];
    }
    return new String(hexChars);
}

static String toHex(byte[] digest) {
    String digits = "0123456789abcdef";
    StringBuilder sb = new StringBuilder(digest.length * 2);
    for (byte b : digest) {
        int bi = b & 0xff;
        sb.append(digits.charAt(bi >> 4));
        sb.append(digits.charAt(bi & 0xf));
    }
    return sb.toString();
}

String result = String.format("%0" + messageDigest.length + "s", hexString.toString())

That's the shortest solution given what you already have. If you could convert the byte array to a numeric value, String.format can convert it to a hex string at the same time.


It appears concat and append functions can be really slow. The following was MUCH faster for me (than my previous post). Changing to a char array in building the output was the key factor to speed it up. I have not compared to Hex.encodeHex suggested by Brandon DuRette.

public static String toHexString(byte[] bytes) {
    char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    char[] hexChars = new char[10000000];
    int c = 0;
    int v;
    for ( j = 0; j < bytes.length; j++ ) {
        v = bytes[j] & 0xFF;
        hexChars[c] = hexArray[v/16];
        c++;
        hexChars[c] = hexArray[v%16];
        c++;
    }
    return new String(hexChars, 0, c); }

IMHO all the solutions above that provide snippets to remove the leading zeroes are wrong.

byte messageDigest[] = algorithm.digest();
for (int i = 0; i < messageDigest.length; i++) {
    hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
}    

According to this snippet, 8 bits are taken from the byte array in an iteration, converted into an integer (since Integer.toHexString function takes int as argument) and then that integer is converted to the corresponding hash value. So, for example if you have 00000001 00000001 in binary, according to the code, the hexString variable would have 0x11 as the hex value whereas correct value should be 0x0101. Thus, while calculating MD5 we may get hashes of length <32 bytes(because of missing zeroes) which may not satisfy the cryptographically unique properties that MD5 hash does.

The solution to the problem is replacing the above code snippet by the following snippet:

byte messageDigest[] = algorithm.digest();
for (int i = 0; i < messageDigest.length; i++) {
    int temp=0xFF & messageDigest[i];
    String s=Integer.toHexString(temp);
    if(temp<=0x0F){
        s="0"+s;
    }
    hexString.append(s);
}

my variant

    StringBuilder builder = new StringBuilder();
    for (byte b : bytes)
    {
        builder.append(Character.forDigit(b/16, 16));
        builder.append(Character.forDigit(b % 16, 16));
    }
    System.out.println(builder.toString());

it works for me.


This will give two-char long string for a byte.

public String toString(byte b){
    final char[] Hex = new String("0123456789ABCDEF").toCharArray();
    return  "0x"+ Hex[(b & 0xF0) >> 4]+ Hex[(b & 0x0F)];
}

I found Integer.toHexString to be a little slow. If you are converting many bytes, you may want to consider building an array of Strings containing "00".."FF" and use the integer as the index. I.e.

hexString.append(hexArray[0xFF & messageDigest[i]]);

This is faster and ensures the correct length. Just requires the array of strings:

String[] hexArray = {
"00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F",
"10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F",
"20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F",
"30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F",
"40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F",
"50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F",
"60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F",
"70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F",
"80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F",
"90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F",
"A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF",
"B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF",
"C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF",
"D0","D1","D2","D3","D4","D5","D6","D7","D8","D9","DA","DB","DC","DD","DE","DF",
"E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF",
"F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF"};

This will give two-char long string for a byte.

public String toString(byte b){
    final char[] Hex = new String("0123456789ABCDEF").toCharArray();
    return  "0x"+ Hex[(b & 0xF0) >> 4]+ Hex[(b & 0x0F)];
}

The method javax.xml.bind.DatatypeConverter.printHexBinary(), part of the Java Architecture for XML Binding (JAXB), was a convenient way to convert a byte[] to a hex string. The DatatypeConverter class also included many other useful data-manipulation methods.

In Java 8 and earlier, JAXB was part of the Java standard library. It was deprecated with Java 9 and removed with Java 11, as part of an effort to move all Java EE packages into their own libraries. It's a long story. Now, javax.xml.bind doesn't exist, and if you want to use JAXB, which contains DatatypeConverter, you'll need to install the JAXB API and JAXB Runtime from Maven.

Example usage:

byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
String hex = javax.xml.bind.DatatypeConverter.printHexBinary(bytes);

Will result in:

000086003D

This what I am using for MD5 hashes:

public static String getMD5(String filename)
        throws NoSuchAlgorithmException, IOException {
    MessageDigest messageDigest = 
        java.security.MessageDigest.getInstance("MD5");

    InputStream in = new FileInputStream(filename);

    byte [] buffer = new byte[8192];
    int len = in.read(buffer, 0, buffer.length);

    while (len > 0) {
        messageDigest.update(buffer, 0, len);
        len = in.read(buffer, 0, buffer.length);
    }
    in.close();

    return new BigInteger(1, messageDigest.digest()).toString(16);
}

EDIT: I've tested and I've noticed that with this also trailing zeros are cut. But this can only happen in the beginning, so you can compare with the expected length and pad accordingly.


This is also equivalent but more concise using Apache util HexBin where the code reduces to

HexBin.encode(messageDigest).toLowerCase();

I liked Steve's submissions, but he could have done without a couple of variables and saved several lines in the process.

public static String toHexString(byte[] bytes) {
    char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for ( int j = 0; j < bytes.length; j++ ) {
        v = bytes[j] & 0xFF;
        hexChars[j*2] = hexArray[v/16];
        hexChars[j*2 + 1] = hexArray[v%16];
    }
    return new String(hexChars);
}

What I like about this is that it's easy to see exactly what it's doing (instead of relying on some magic BigInteger black box conversion) and you're also free from having to worry about corner cases like leading-zeroes and stuff. This routine takes every 4-bit nibble and turns it into a hex char. And it's using a table lookup, so it's probably fast. It could probably be faster if you replace v/16 and v%16 with bitwise shifts and AND's, but I'm too lazy to test it right now.


byte messageDigest[] = algorithm.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
    String hexByte = Integer.toHexString(0xFF & messageDigest[i]);
    int numDigits = 2 - hexByte.length();
    while (numDigits-- > 0) {
        hexString.append('0');
    }
    hexString.append(hexByte);
}

static String toHex(byte[] digest) {
    String digits = "0123456789abcdef";
    StringBuilder sb = new StringBuilder(digest.length * 2);
    for (byte b : digest) {
        int bi = b & 0xff;
        sb.append(digits.charAt(bi >> 4));
        sb.append(digits.charAt(bi & 0xf));
    }
    return sb.toString();
}

You can use the one below. I tested this with leading zero bytes and with initial negative bytes as well

public static String toHex(byte[] bytes) {
    BigInteger bi = new BigInteger(1, bytes);
    return String.format("%0" + (bytes.length << 1) + "X", bi);
}

If you want lowercase hex digits, use "x" in the format String.


byte messageDigest[] = algorithm.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
    String hexByte = Integer.toHexString(0xFF & messageDigest[i]);
    int numDigits = 2 - hexByte.length();
    while (numDigits-- > 0) {
        hexString.append('0');
    }
    hexString.append(hexByte);
}

Guava makes it pretty simple too:

BaseEncoding.base16().encode( bytes );

It's a nice alternative when Apache Commons is not available. It also has some nice controls of the output like:

byte[] bytes = new byte[] { 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
BaseEncoding.base16().lowerCase().withSeparator( ":", 2 ).encode( bytes );
// "0a:0b:0c:0d:0e:0f"

Another option

public static String toHexString(byte[]bytes) {
    StringBuilder sb = new StringBuilder(bytes.length*2);
    for(byte b: bytes)
      sb.append(Integer.toHexString(b+0x800).substring(1));
    return sb.toString();
}

In order to keep leading zeroes, here is a small variation on what has Paul suggested (eg md5 hash):

public static String MD5hash(String text) throws NoSuchAlgorithmException {
    byte[] hash = MessageDigest.getInstance("MD5").digest(text.getBytes());
    return String.format("%032x",new BigInteger(1, hash));
}

Oops, this looks poorer than what's Ayman proposed, sorry for that


You can get it writing less without external libraries:

String hex = (new HexBinaryAdapter()).marshal(md5.digest(YOUR_STRING.getBytes()))

static String toHex(byte[] digest) {
    StringBuilder sb = new StringBuilder();
    for (byte b : digest) {
        sb.append(String.format("%1$02X", b));
    }

    return sb.toString();
}

String result = String.format("%0" + messageDigest.length + "s", hexString.toString())

That's the shortest solution given what you already have. If you could convert the byte array to a numeric value, String.format can convert it to a hex string at the same time.


Guava makes it pretty simple too:

BaseEncoding.base16().encode( bytes );

It's a nice alternative when Apache Commons is not available. It also has some nice controls of the output like:

byte[] bytes = new byte[] { 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
BaseEncoding.base16().lowerCase().withSeparator( ":", 2 ).encode( bytes );
// "0a:0b:0c:0d:0e:0f"

String result = String.format("%0" + messageDigest.length + "s", hexString.toString())

That's the shortest solution given what you already have. If you could convert the byte array to a numeric value, String.format can convert it to a hex string at the same time.


This solution requires no bit-shifting or -masking, lookup tables, or external libraries, and is about as short as I can get:

byte[] digest = new byte[16];       

Formatter fmt = new Formatter();    
for (byte b : digest) { 
  fmt.format("%02X", b);    
}

fmt.toString()

Is that a faulty solution? (android java)

    // Create MD5 Hash
    MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
    digest.update(s.getBytes());
    byte[] md5sum = digest.digest();
    BigInteger bigInt = new BigInteger(1, md5sum);
    String stringMD5 = bigInt.toString(16);
    // Fill to 32 chars
    stringMD5 = String.format("%32s", stringMD5).replace(' ', '0');
    return stringMD5;

So basically it replaces spaces with 0.


This solution is a little older school, and should be memory efficient.

public static String toHexString(byte bytes[]) {
    if (bytes == null) {
        return null;
    }

    StringBuffer sb = new StringBuffer();
    for (int iter = 0; iter < bytes.length; iter++) {
        byte high = (byte) ( (bytes[iter] & 0xf0) >> 4);
        byte low =  (byte)   (bytes[iter] & 0x0f);
        sb.append(nibble2char(high));
        sb.append(nibble2char(low));
    }

    return sb.toString();
}

private static char nibble2char(byte b) {
    byte nibble = (byte) (b & 0x0f);
    if (nibble < 10) {
        return (char) ('0' + nibble);
    }
    return (char) ('a' + nibble - 10);
}

I liked Steve's submissions, but he could have done without a couple of variables and saved several lines in the process.

public static String toHexString(byte[] bytes) {
    char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for ( int j = 0; j < bytes.length; j++ ) {
        v = bytes[j] & 0xFF;
        hexChars[j*2] = hexArray[v/16];
        hexChars[j*2 + 1] = hexArray[v%16];
    }
    return new String(hexChars);
}

What I like about this is that it's easy to see exactly what it's doing (instead of relying on some magic BigInteger black box conversion) and you're also free from having to worry about corner cases like leading-zeroes and stuff. This routine takes every 4-bit nibble and turns it into a hex char. And it's using a table lookup, so it's probably fast. It could probably be faster if you replace v/16 and v%16 with bitwise shifts and AND's, but I'm too lazy to test it right now.


Or you can do this:

byte[] digest = algorithm.digest();
StringBuilder byteContet = new StringBuilder();
for(byte b: digest){
 byteContent = String.format("%02x",b);
 byteContent.append(byteContent);
}

Its Short, simple and basically just a format change.


Check out Hex.encodeHexString from Apache Commons Codec.

import org.apache.commons.codec.binary.Hex;

String hex = Hex.encodeHexString(bytes);

I've been looking for the same thing ... some good ideas here, but I ran a few micro benchmarks. I found the following to be the fastest (modified from Ayman's above and about 2x as fast, and about 50% faster than Steve's just above this one):

public static String hash(String text, String algorithm)
        throws NoSuchAlgorithmException {
    byte[] hash = MessageDigest.getInstance(algorithm).digest(text.getBytes());
    return new BigInteger(1, hash).toString(16);
}

Edit: Oops - missed that this is essentially the same as kgiannakakis's and so may strip off a leading 0. Still, modifying this to the following, it's still the fastest:

public static String hash(String text, String algorithm)
        throws NoSuchAlgorithmException {
    byte[] hash = MessageDigest.getInstance(algorithm).digest(text.getBytes());
    BigInteger bi = new BigInteger(1, hash);
    String result = bi.toString(16);
    if (result.length() % 2 != 0) {
        return "0" + result;
    }
    return result;
}

This what I am using for MD5 hashes:

public static String getMD5(String filename)
        throws NoSuchAlgorithmException, IOException {
    MessageDigest messageDigest = 
        java.security.MessageDigest.getInstance("MD5");

    InputStream in = new FileInputStream(filename);

    byte [] buffer = new byte[8192];
    int len = in.read(buffer, 0, buffer.length);

    while (len > 0) {
        messageDigest.update(buffer, 0, len);
        len = in.read(buffer, 0, buffer.length);
    }
    in.close();

    return new BigInteger(1, messageDigest.digest()).toString(16);
}

EDIT: I've tested and I've noticed that with this also trailing zeros are cut. But this can only happen in the beginning, so you can compare with the expected length and pad accordingly.


In order to keep leading zeroes, here is a small variation on what has Paul suggested (eg md5 hash):

public static String MD5hash(String text) throws NoSuchAlgorithmException {
    byte[] hash = MessageDigest.getInstance("MD5").digest(text.getBytes());
    return String.format("%032x",new BigInteger(1, hash));
}

Oops, this looks poorer than what's Ayman proposed, sorry for that


I would use something like this for fixed length, like hashes:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));

The 0 in the mask does the padding...


I'm surprised that no one came up with the following solution:

StringWriter sw = new StringWriter();
com.sun.corba.se.impl.orbutil.HexOutputStream hex = new com.sun.corba.se.impl.orbutil.HexOutputStream(sw);
hex.write(byteArray);
System.out.println(sw.toString());

You can use the one below. I tested this with leading zero bytes and with initial negative bytes as well

public static String toHex(byte[] bytes) {
    BigInteger bi = new BigInteger(1, bytes);
    return String.format("%0" + (bytes.length << 1) + "X", bi);
}

If you want lowercase hex digits, use "x" in the format String.


And how can you convert back again from ascii to byte array ?

i followed following code to convert to ascii given by Jemenake.

public static String toHexString(byte[] bytes) {
    char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for ( int j = 0; j < bytes.length; j++ ) {
        v = bytes[j] & 0xFF;
        hexChars[j*2] = hexArray[v/16];
        hexChars[j*2 + 1] = hexArray[v%16];
    }
    return new String(hexChars);
}

byte messageDigest[] = algorithm.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
    String hexByte = Integer.toHexString(0xFF & messageDigest[i]);
    int numDigits = 2 - hexByte.length();
    while (numDigits-- > 0) {
        hexString.append('0');
    }
    hexString.append(hexByte);
}

Another option

public static String toHexString(byte[]bytes) {
    StringBuilder sb = new StringBuilder(bytes.length*2);
    for(byte b: bytes)
      sb.append(Integer.toHexString(b+0x800).substring(1));
    return sb.toString();
}

static String toHex(byte[] digest) {
    StringBuilder sb = new StringBuilder();
    for (byte b : digest) {
        sb.append(String.format("%1$02X", b));
    }

    return sb.toString();
}

my variant

    StringBuilder builder = new StringBuilder();
    for (byte b : bytes)
    {
        builder.append(Character.forDigit(b/16, 16));
        builder.append(Character.forDigit(b % 16, 16));
    }
    System.out.println(builder.toString());

it works for me.


This what I am using for MD5 hashes:

public static String getMD5(String filename)
        throws NoSuchAlgorithmException, IOException {
    MessageDigest messageDigest = 
        java.security.MessageDigest.getInstance("MD5");

    InputStream in = new FileInputStream(filename);

    byte [] buffer = new byte[8192];
    int len = in.read(buffer, 0, buffer.length);

    while (len > 0) {
        messageDigest.update(buffer, 0, len);
        len = in.read(buffer, 0, buffer.length);
    }
    in.close();

    return new BigInteger(1, messageDigest.digest()).toString(16);
}

EDIT: I've tested and I've noticed that with this also trailing zeros are cut. But this can only happen in the beginning, so you can compare with the expected length and pad accordingly.


It appears concat and append functions can be really slow. The following was MUCH faster for me (than my previous post). Changing to a char array in building the output was the key factor to speed it up. I have not compared to Hex.encodeHex suggested by Brandon DuRette.

public static String toHexString(byte[] bytes) {
    char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    char[] hexChars = new char[10000000];
    int c = 0;
    int v;
    for ( j = 0; j < bytes.length; j++ ) {
        v = bytes[j] & 0xFF;
        hexChars[c] = hexArray[v/16];
        c++;
        hexChars[c] = hexArray[v%16];
        c++;
    }
    return new String(hexChars, 0, c); }

byte messageDigest[] = algorithm.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
    String hexByte = Integer.toHexString(0xFF & messageDigest[i]);
    int numDigits = 2 - hexByte.length();
    while (numDigits-- > 0) {
        hexString.append('0');
    }
    hexString.append(hexByte);
}

The method javax.xml.bind.DatatypeConverter.printHexBinary(), part of the Java Architecture for XML Binding (JAXB), was a convenient way to convert a byte[] to a hex string. The DatatypeConverter class also included many other useful data-manipulation methods.

In Java 8 and earlier, JAXB was part of the Java standard library. It was deprecated with Java 9 and removed with Java 11, as part of an effort to move all Java EE packages into their own libraries. It's a long story. Now, javax.xml.bind doesn't exist, and if you want to use JAXB, which contains DatatypeConverter, you'll need to install the JAXB API and JAXB Runtime from Maven.

Example usage:

byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
String hex = javax.xml.bind.DatatypeConverter.printHexBinary(bytes);

Will result in:

000086003D

This solution is a little older school, and should be memory efficient.

public static String toHexString(byte bytes[]) {
    if (bytes == null) {
        return null;
    }

    StringBuffer sb = new StringBuffer();
    for (int iter = 0; iter < bytes.length; iter++) {
        byte high = (byte) ( (bytes[iter] & 0xf0) >> 4);
        byte low =  (byte)   (bytes[iter] & 0x0f);
        sb.append(nibble2char(high));
        sb.append(nibble2char(low));
    }

    return sb.toString();
}

private static char nibble2char(byte b) {
    byte nibble = (byte) (b & 0x0f);
    if (nibble < 10) {
        return (char) ('0' + nibble);
    }
    return (char) ('a' + nibble - 10);
}

Check out Hex.encodeHexString from Apache Commons Codec.

import org.apache.commons.codec.binary.Hex;

String hex = Hex.encodeHexString(bytes);

This solution is a little older school, and should be memory efficient.

public static String toHexString(byte bytes[]) {
    if (bytes == null) {
        return null;
    }

    StringBuffer sb = new StringBuffer();
    for (int iter = 0; iter < bytes.length; iter++) {
        byte high = (byte) ( (bytes[iter] & 0xf0) >> 4);
        byte low =  (byte)   (bytes[iter] & 0x0f);
        sb.append(nibble2char(high));
        sb.append(nibble2char(low));
    }

    return sb.toString();
}

private static char nibble2char(byte b) {
    byte nibble = (byte) (b & 0x0f);
    if (nibble < 10) {
        return (char) ('0' + nibble);
    }
    return (char) ('a' + nibble - 10);
}

I'm surprised that no one came up with the following solution:

StringWriter sw = new StringWriter();
com.sun.corba.se.impl.orbutil.HexOutputStream hex = new com.sun.corba.se.impl.orbutil.HexOutputStream(sw);
hex.write(byteArray);
System.out.println(sw.toString());

String result = String.format("%0" + messageDigest.length + "s", hexString.toString())

That's the shortest solution given what you already have. If you could convert the byte array to a numeric value, String.format can convert it to a hex string at the same time.


This what I am using for MD5 hashes:

public static String getMD5(String filename)
        throws NoSuchAlgorithmException, IOException {
    MessageDigest messageDigest = 
        java.security.MessageDigest.getInstance("MD5");

    InputStream in = new FileInputStream(filename);

    byte [] buffer = new byte[8192];
    int len = in.read(buffer, 0, buffer.length);

    while (len > 0) {
        messageDigest.update(buffer, 0, len);
        len = in.read(buffer, 0, buffer.length);
    }
    in.close();

    return new BigInteger(1, messageDigest.digest()).toString(16);
}

EDIT: I've tested and I've noticed that with this also trailing zeros are cut. But this can only happen in the beginning, so you can compare with the expected length and pad accordingly.


Or you can do this:

byte[] digest = algorithm.digest();
StringBuilder byteContet = new StringBuilder();
for(byte b: digest){
 byteContent = String.format("%02x",b);
 byteContent.append(byteContent);
}

Its Short, simple and basically just a format change.


I would use something like this for fixed length, like hashes:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));

The 0 in the mask does the padding...


Check out Hex.encodeHexString from Apache Commons Codec.

import org.apache.commons.codec.binary.Hex;

String hex = Hex.encodeHexString(bytes);

This solution requires no bit-shifting or -masking, lookup tables, or external libraries, and is about as short as I can get:

byte[] digest = new byte[16];       

Formatter fmt = new Formatter();    
for (byte b : digest) { 
  fmt.format("%02X", b);    
}

fmt.toString()

Is that a faulty solution? (android java)

    // Create MD5 Hash
    MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
    digest.update(s.getBytes());
    byte[] md5sum = digest.digest();
    BigInteger bigInt = new BigInteger(1, md5sum);
    String stringMD5 = bigInt.toString(16);
    // Fill to 32 chars
    stringMD5 = String.format("%32s", stringMD5).replace(' ', '0');
    return stringMD5;

So basically it replaces spaces with 0.


I found Integer.toHexString to be a little slow. If you are converting many bytes, you may want to consider building an array of Strings containing "00".."FF" and use the integer as the index. I.e.

hexString.append(hexArray[0xFF & messageDigest[i]]);

This is faster and ensures the correct length. Just requires the array of strings:

String[] hexArray = {
"00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F",
"10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F",
"20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F",
"30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F",
"40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F",
"50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F",
"60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F",
"70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F",
"80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F",
"90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F",
"A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF",
"B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF",
"C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF",
"D0","D1","D2","D3","D4","D5","D6","D7","D8","D9","DA","DB","DC","DD","DE","DF",
"E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF",
"F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF"};

This is also equivalent but more concise using Apache util HexBin where the code reduces to

HexBin.encode(messageDigest).toLowerCase();

Check out Hex.encodeHexString from Apache Commons Codec.

import org.apache.commons.codec.binary.Hex;

String hex = Hex.encodeHexString(bytes);

IMHO all the solutions above that provide snippets to remove the leading zeroes are wrong.

byte messageDigest[] = algorithm.digest();
for (int i = 0; i < messageDigest.length; i++) {
    hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
}    

According to this snippet, 8 bits are taken from the byte array in an iteration, converted into an integer (since Integer.toHexString function takes int as argument) and then that integer is converted to the corresponding hash value. So, for example if you have 00000001 00000001 in binary, according to the code, the hexString variable would have 0x11 as the hex value whereas correct value should be 0x0101. Thus, while calculating MD5 we may get hashes of length <32 bytes(because of missing zeroes) which may not satisfy the cryptographically unique properties that MD5 hash does.

The solution to the problem is replacing the above code snippet by the following snippet:

byte messageDigest[] = algorithm.digest();
for (int i = 0; i < messageDigest.length; i++) {
    int temp=0xFF & messageDigest[i];
    String s=Integer.toHexString(temp);
    if(temp<=0x0F){
        s="0"+s;
    }
    hexString.append(s);
}