1

I know this question is asked a lot of times but please hear me out.

Previously I have tried following methods to convert hex string to byte array.

say my keyA = "D14E2C5A5B5F", I use byte[] of this key to authenticate a mifare card

First Approach:

byte[] ka = new BigInteger(keyA, 16).toByteArray();

(With this approach using ka as key authenticates few cards and fails in few cards)

Second Approach:

byte[] ka = hexStringToByteArray(keyA);
public byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

(With this approach using ka as key authenticates few cards, but success rate is more than first approach and fails in few cards).

Am I missing anything? Is there any better way to convert hex string to byte array in java?

Thanks in advance.

2

4 Answers 4

2

The difference is in the leading 0 values created by BigInteger.

public void test() {
    test("D14E2C5A5B5F");
    test("00D14E2C5A5B5F");
    test("614E2C5A5B5F");
    test("00614E2C5A5B5F");
}

private void test(String s) {
    byte[] ka = new BigInteger(s, 16).toByteArray();
    byte[] kb = hexStringToByteArray(s);
    if (!Arrays.equals(ka, kb)) {
        System.out.println(s + ":" + Arrays.toString(ka) + " != " + Arrays.toString(kb));
    }
}

public byte[] hexStringToByteArray(String s) {
    byte[] data = new byte[s.length()/2];
    for (int i = 0; i < data.length; i ++) {
        data[i] = (byte) ((Character.digit(s.charAt(i*2), 16) << 4)
                + Character.digit(s.charAt(i*2 + 1), 16));
    }
    return data;
}

prints

D14E2C5A5B5F:[0, -47, 78, 44, 90, 91, 95] != [-47, 78, 44, 90, 91, 95]

00614E2C5A5B5F:[97, 78, 44, 90, 91, 95] != [0, 97, 78, 44, 90, 91, 95]

See the extra leading 0s.

Also, your hexStringToByteArray is assuming an even number of hex digits - this may be an issue.

Something like this should be correct. It ensure the byte[] is always the right length whatever the length of the string. You may wish to add an exception for when the string is too long.

public byte[] asKey(String hex, int bytes) {
    // Make sure the byte [] is always the correct length.
    byte[] key = new byte[bytes];
    // Using i as the distance from the END of the string.
    for (int i = 0; i < hex.length() && (i / 2) < bytes; i++) {
        // Pull out the hex value of the character.
        int nybble = Character.digit(hex.charAt(hex.length() - 1 - i), 16);
        if ((i & 1) != 0) {
            // When i is odd we shift left 4.
            nybble = nybble << 4;
        }
        // Use OR to avoid sign issues.
        key[bytes - 1 - (i / 2)] |= (byte) nybble;
    }
    return key;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Note the BigInteger behavior is documented "Returns ... two's-complement representation ... contain[ing] ... at least one sign bit". Another option (also assuming even length in hexits) is javax.xml.bind.DatatypeConverter
0

Try this.

public static byte[] hexStringToByteArray(String s) {
    byte[] b = new byte[s.length() / 2];
    for (int i = 0; i < b.length; i++) {
      int index = i * 2;
      int v = Integer.parseInt(s.substring(index, index + 2), 16);
      b[i] = (byte) v;
    }
    return b;
  }

Comments

0

This is what works for me:

public static byte[] hexToByteData(String hex)
{
    byte[] convertedByteArray = new byte[hex.length()/2];
    int count  = 0;

    for( int i = 0; i < hex.length() -1; i += 2 )
    {
        String output;
        output = hex.substring(i, (i + 2));
        int decimal = (int)(Integer.parseInt(output, 16));
        convertedByteArray[count] =  (byte)(decimal & 0xFF);
        count ++;
    }
    return convertedByteArray;
}

Comments

0

Here is my code that showed the best performance...

    public static byte[] hex2bytes(String str) {
        if( str == null || str.length() == 0 )
            return null;

        byte[] hex = new byte[str.length() / 2];
        int tmp1, tmp2;

        for(int i=0; i < hex.length; i++) {
            tmp1 = str.charAt(i*2);
            tmp2 = str.charAt(i*2+1);
            hex[i] = (byte)( (tmp1 < 0x41 ? (tmp1 & 0x0F) << 4 : ((tmp1 & 0x0F) + 9) << 4)
                    | (tmp2 < 0x41 ? tmp2 & 0x0F : (tmp2 & 0x0F) + 9) );
        }

        return hex;
    }

2 Comments

"best performance" comparing to what?
@Emil I tested the time it takes to convert a specific string 100 million times with various sources posted here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.