1

i have this issue on my java code and i'm kinda stuck with my solution, so i want to convert a raw bytes that i captured from a network sniffer tool (wireshark) to a string real value of the bytes

basically this was the solution i want to create but i don't have an idea because i can't type cast it

String array= "6549534f3030363030303036303038303038323230303030303030303030303030303430303030303030303030303030303034313830373432313730303030303130303103";
        char[] ch=array.toCharArray();
        String charTemp = "";
        byte[] byteArray= {};

        for (int i = 0; i < ch.length; i++) {
            if(i%2==0) {
                System.out.println(charTemp);
                System.out.println(byteArray.length);
                byteArray[byteArray.length]=(int) charTemp;
                charTemp="";
            }
            charTemp+=ch[i];
            System.out.print(ch[i] + " ");
        }

actually i want this link but on my java code because i want to learn how to byte manipulation, also maybe if someone have a reference/guide how to learn about byte manipulation, please recommend me :) Thanks

mc ser
  • 43
  • 1
  • 7

2 Answers2

2

There are at least 4 issues here, and on top of that, this isn't a particularly efficient algorithm (not that this is likely to matter).

conflating ASCII value with digit

The character 6 actually is value 54. No, really:

char c = '6';
int v = (int) c;
System.out.println(v); // this would print 54.

After all, a character could be 'A' to. What 'number' should that become? In computer systems, any character is looked up in a gigantic table that matches a symbol (such as a, or 5, or space, or enter, or ç, or é, or ☃, or even ) to a number.

And the CHARACTER (or symbol, if you prefer that terminology) '6', in that table, is associated with code 54.

Trying to cast a string to an int

charTemp is a string and will end up containing e.g. "4f". That's 2 numbers. Java correctly identifies that trying to cast this to an int doesn't make sense. (even if a string only contains 1 character, java does that - the compiler knows you can't convert strings to an int by casting, it doesn't bother checking if in this case it might possibly make some semblance of sense. It COULD make no sense, so you can't do it).

What you want is to convert the string "4f" into the value of it. "4f" is itself just a number in string form, just like "100" would be. Except, it's in base 16, instead of base 10. Still, a number though.

So, how do we turn numbers-in-strings into their values? With Integer.parseInt, of course. Which has a variant where you specify the base. So:

int v = Integer.parseInt("9", 16); // 16 = the base
System.out.println(v); // prints 9
v = Integer.parseInt("f", 16);
System.out.println(v); // prints 15. That's nice.
v = Integer.parseInt("4f", 16);
System.out.println(v); // Prints out 79. Which is what you wanted, I guess.

bytes and ints

You can't assign an int to a value in a byte array - you are casting to int. Once you fix everything above, you still have to replace that with (byte).

You erroneously think arrays can grow in java

Your byte array is empty. Arrays in java are fixed size, so when you make it, it is empty, and it cannot be grown, so, it's stuck there. x[x.length] will ALWAYS cause an ArrayIndexOutOfBoundsException (because an array's length is the first index that DOES NOT work). After all, an array of, say, length 3 has 3 indices: 0, 1, and 2. 3, itself, isn't valid. Thus, byteArray[0] = ... would crash.

One solution is to pre-size the byte array appropriately: byte[] byteArray = new byte[array.length() / 2];

And you would have to use byteArray[i / 2] = Integer.parseInt(charTemp, 16);

All this code is probably not needed

There are tools and libraries that read byte arrays formatted as hexadecimal strings (a.k.a. nibbled strings) in for you, you don't have to write this code. See this SO answer for more - because that's what you're trying to (presumably) do here.

An explanation of Hexadecimal counting

Start counting, like we're playing hide-and-seek. 1, 2, 3, 4,...

What happens after 8? We get to 9. Easy enough.

Why do we go to '10' - 2 separate symbols, when we need to count beyond 9?

Who knows - presumably because us humans have 10 fingers. Actually, in the times of the roman empire, but outside of its borders, 12 was much more common. Take out your thumb, and start counting finger segments. You have 3 on each of the 4 remaining fingers - it's an easy way to keep track of counting to 12.

Those nordic folks had symbols for 12 digits (0 up to 11). Just like you're used to having 10 digits (0, up to 9). When you 'run out of digits', you just add a 'place' - we start counting how many times we used all the digits. "24" simply means we ran out of digits twice (so that's 10, each time, so 20), and then 4 more.

Computers like to count in binary. 0, 1... and we ran out of digits. So, computers go 0, 1, 10, 11, 100, 101, and so on. But this gets unwieldy very quickly and hard to 'track' as a human.

So, we compromise and use hexadecimal instead. This is counting as if you had 16 fingers. You go 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f. And then we ran out of digits, so the number after that (so, 16, in decimal!) - is written as '10'. Just like when those old vikings got to writing '1' and '0' when they start counting the 12th thing, with hex you get to '1' and '0' when you get to the 16th thing.

And that is what you are trying to parse in here. Note how your input contains "4f" for example. That 'f' isn't a letter. It's the '9' (the last digit) of the hexadecimal system.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • Hi, thanks for your deep explanation regarding to my code, can you explain me about this part `except, it's in base 16, instead of base 10`, because im not familiar with bytes though hehe – mc ser Apr 20 '23 at 11:45
  • Thank you @rzwitserloot for explaining like i'm 5, is there any explanation how byte works tho? – mc ser Apr 27 '23 at 13:59
  • That talk about 10 fingers and how computers count as if they have 16 fingers __is__ the explanation of the difference between base 16 and base 10. A byte is just 8 bits (or 2 hexadecimal digits). Just like if I ask you to write down a number using no more than 2 digits, you're limited to 0-99, with hex, you're limited to 0-ff. ff is 15*16 + 15 = 255 (because 99 is 9*10 + 9 = 99, same principle). – rzwitserloot Apr 27 '23 at 14:39
  • 4 bits is one hexadecimal digit because 4 digits in base 2 (base 2 = a 0 or 1, that's all the digits you have, there is no 2, we go 0, 1, 10, 11, 100, 101, and so on) is 2^4 = 16 different options (write em all down; given 4 0/1 digits, how many combinations can you make? 16. Just like given 2 0-9 digits you can make 100 combos: 0-99). 16 options? Hey, that's how many digits hexadecimal has - so, 8 bits becomes 2 hex digits. Because 10 isn't a factor of 2, decimal digits don't "work well" here, hence why computer science likes hexadecimal digits. – rzwitserloot Apr 27 '23 at 14:41
  • Actually what makes me confused is this line of code `byteArray[i / 2] = (byte) ((Character.digit(ch[i], 16) << 4) + Character.digit(ch[i + 1], 16));` why i need to shift it, instead of just put both hex together like `byteArray[i / 2] = (byte) (Character.digit(ch[i], 16) + Character.digit(ch[i + 1], 16));` any reason behind this? – mc ser Apr 27 '23 at 17:02
  • 1
    If I give you the digit '5' and the digit '2', and I ask you to put them together, you get 52. What you propose is to do '5 + 2' which would give 7. You need to multiply that '5' by 10 because it is in the '10s' place. That first digit is in the '10s' place, but in hex, so, * 16 instead of * 10. <<4 is the same as *16. – rzwitserloot Apr 27 '23 at 17:22
  • Alright now i'm able to understand, thanks – mc ser Apr 30 '23 at 13:49
1

As you mentioned there is an type casting issue since you can't cast charTemp which is a String to an int. Other than that there are some issue I can see.

  1. The length of the byteArray is always 0. Therefore, byteArray[byteArray.length] does not make any sense.
  2. Since your input bytes (the array) is in HEX, you need a way to handle the HEX values properly.

I would suggest an approach like this,

String array = "6549534f3030363030303036303038303038323230303030303030303030303030303430303030303030303030303030303034313830373432313730303030303130303103";
char[] ch = array.toCharArray();
System.out.println(Arrays.toString(ch));

int length = ch.length;
byte[] byteArray = new byte[length / 2];

for (int i = 0; i < ch.length; i += 2) {
    byteArray[i / 2] = (byte) ((Character.digit(ch[i], 16) << 4)
            + Character.digit(ch[i + 1], 16));
}
String string = new String(byteArray);
System.out.println(string);

The changes I made,

  • Removed charTemp since it will not be needed.
  • Initialized byteArray to half of the length of the ch.
  • Changed the for loop to iterate over every other element instead of checkin i%2 in the body of the for loop.
  • Used Character.digit() method to handle the HEX values.
  • Created the String string with the generated byteArray so that this can be used as your output.

This should work fine.

chameerar
  • 322
  • 1
  • 2
  • 8
  • 1
    Hi chameerar, i get the most part of your solution but i have the thing that i don't understand in this part `(Character.digit(ch[i], 16) << 4` can you explain what are you trying to do especially with << i'm unfamiliar with this operator, thanks – mc ser Apr 20 '23 at 14:01
  • @mcser The `Character.digit(ch[i], 16)` part outputs the value of the `ch[i]` (that is the first digit of the HEX number in your `array`) in radix 16. The `<< ` is the bitwise left shift operator. This add four trailing zeros to the value. This gives room to the second digit of the HEX number (that is `ch[i+1]`) to be added so it forms the desired byte value. – chameerar Apr 21 '23 at 17:41
  • Hi sorry for the long reply, i still don't get it about bitwise left shift operator, but when i debug it using this code `System.out.println((Character.digit(ch[i],16) << 3) + " " +(Character.digit(ch[i],16) << 4)+ " " + ch[i]); ` the result are weird, is there any guide to help me understand this bitwise operator so i can comprehend? – mc ser Apr 27 '23 at 13:56
  • Sure. This will be useful. https://www.geeksforgeeks.org/shift-operator-in-java/amp/?ref=gcse – chameerar Apr 27 '23 at 21:02