Byte to Integer and then to String conversion in Java - java

I got a code for MD5 hash generation in Java. It generates the hash in byte array "bytes" and then converts to integer and then to string as follows:
byte[] bytes=md.digest(textToHash.getBytes());
StringBuilder sb=new StringBuilder();
for(int i=0;i<bytes.length;i++)
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
I understood that bytes[i] & 0xff converts byte to integer of 32 bit length copying the byte to the least significant byte of the integer:
What does value & 0xff do in Java?
However I couldn't understand what + 0x100, 16 does in the parentheses at line 4 of the above code. Your help is appreciated.

Breaking down Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1):
Adding 0x100 (which is 256 decimal) sets the 9th bit to 1, which guarantees the binary number representation of the result has exactly 9-bits. You could equivalently do & 0x100.
After setting bit 8, the result from the toString() will be 9 chars long (of zeroes and ones).
substring(1) effectively ignores bit 8 and outputs the lower 8 bits
So what?
This code puts leading zeroes on values, so all values are exactly 8 binary characters. There's no way to make Integer.toString() alone do this.

Related

JAVA Byte Manipulation

I want to read a binary file and do some manipulation on each byte. I want to test that I am manipulating the bytes correctly. I want to set a byte variable1 to "00000000" and then another byte variable2 set at "00001111" and OR them newvariable = variable1|variable2, shift the newvariable << 4 bits and then print out the int value.
byte a = 00000000;
//Convert first oneByte to 4 bits and then xor with a;
byte b = 00001111;
byte c = (byte)(a|b);
c = c << 4;
System.out.println("byte= " + c + "\n");
I am not sure why I keep getting "incompatiable types:possible lossy conversion from byte to int"
You need to put a '0b' in front of those numbers to express binary constants. The number 00001111 is interpreted as a literal in octal, which is 585 in decimal. The max byte is 127 (since it's signed). Try 0b00001111 instead.
As literals, those will still be int, so depending on where you do the assignment, you may also need to explicitly cast down to byte.

parseInt on a string of 8 bits returns a negative value when the first bit is 1

I've got a huge string of bits (with some \n in it too) that I pass as a parameter to a method, which should isolate the bits 8 by 8, and convert them all to bytes using parseInt().
Thing is, every time the substring of 8 bits starts with a 1, the resulting byte is a negative number. For example, the first substring is '10001101', and the resulting byte is -115. I can't seem to figure out why, can someone help? It works fine with other substrings.
Here's my code, if needed :
static String bitsToBytes(String geneString) {
String geneString_temp = "", sub;
for(int i = 0; i < geneString.length(); i = i+8) {
sub = geneString.substring(i, i+8);
if (sub.indexOf("\n") != -1) {
if (sub.indexOf("\n") != geneString.length())
sub = sub.substring(0, sub.indexOf("\n")) + sub.substring(sub.indexOf("\n")+1, sub.length()) + geneString.charAt(i+9);
}
byte octet = (byte) Integer.parseInt(sub, 2);
System.out.println(octet);
geneString_temp = geneString_temp + octet;
}
geneString = geneString_temp + "\n";
return geneString;
}
In Java, byte is a signed type, meaning that when the most significant bit it set to 1, the number is interpreted as negative.
This is precisely what happens when you print your byte here:
System.out.println(octet);
Since PrintStream does not have an overload of println that takes a single byte, the overload that takes an int gets called. Since octet's most significant bit is set to 1, the number gets sign-extended by replicating its sign bit into bits 9..32, resulting in printout of a negative number.
byte is a signed two's complement integer. So this is a normal behavior: the two's complement representation of a negative number has a 1 in the most-significant bit. You could think of it like a sign bit.
If you don't like this, you can use the following idiom:
System.out.println( octet & 0xFF );
This will pass the byte as an int while preventing sign extension. You'll get an output as if it were unsigned.
Java doesn't have unsigned types, so the only other thing you could do is store the numbers in a wider representation, e.g. short.
In Java, all integers are signed, and the most significant bit is the sign bit.
Because parseInt parse signed int that means it converts the binary if it begins with 0 its positive and if 1 its negative try to use parseUnsignedInt instead

What does & 0xff do And MD5 Structure?

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class JavaMD5 {
public static void main(String[] args) {
String passwordToHash = "MyPassword123";
String generatedPassword = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(passwordToHash.getBytes());
byte[] bytes = md.digest();
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) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(generatedPassword);
}
}
This line is the problem :
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
what does each part do in this structure????
Thanks and I'm sorry for asking Beacuse I'm new in java.
Presumably most of the code is clear and the only mystery for you here is this expression:
(bytes[i] & 0xff) + 0x100
The first part:
bytes[i] & 0xff
widens the byte at position i to an int value with zeros in bit positions 8-31. In Java, the byte data type is a signed integer value, so the widening sign-extends the value. Without the & 0xff, values greater than 0x7f would end up as negative int values. The rest is then fairly obvious: it adds 0x100, which simply turns on the bit at index 8 (since it is guaranteed to be 0 in (bytes[i] & 0xff). It is then converted to a hex String value by the call to Integer.toString(..., 16).
The reason for first adding 0x100 and then stripping off the 1 (done by the substring(1) call, which takes the substring starting at position 1 through the end) is to guarantee two hex digits in the end result. Otherwise, byte values below 0x10 would end up as one-character strings when converted to hex.
It's debatable whether all that has better performance (it certainly isn't clearer) than:
sb.append(String.format("%02x", bytes[i]));
It's a really messy way of translating to a hexadecimal string.
& 0xFF performs a binary AND, causing the returning value to be between 0 and 255 (which a byte always is anyway)
+ 0x100 adds 256 to the result to ensure the result is always 3 digits
Integer.toString(src, 16) converts the integer to a string with helix 16 (hexadecimal)
Finally .substring(1) strips the first character (the 1 from step 2)
So, this is a very elaborate and obfuscated way to convert a byte to an always 2-character hexadecimal string.

Convert an int to byte in java

String boxVal = "FB";
Integer val = Integer.parseInt(boxVal, 16);
System.out.println(val); //prints out 251
byte sboxValue = (byte) val;
System.out.println("sboxValue = " + Integer.toHexString(sboxValue)); //fffffffb
The last line should print out "fb". I am not sure why it prints out "fffffffb."
What am I doing wrong? How should I fix my code to print "fb"?
You have an overflow when you convert 251 to a byte. Byte has a minimum value of -128 and a maximum value of 127 (inclusive)
See here: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
Why does it print "fffffffb": because you first convert the byte value (which is -5) to an integer with value -5 and then print that integer.
The easiest way to get the output you want is:
System.out.printf("sboxValue = %02x\n", sboxValue);
Or, you could also use:
System.out.println("sboxValue = " + Integer.toHexString(sboxValue & 0xff));
What happens here in detail:
the byte value fb is converted to an integer. Since the value is negative, as you can see because the leftmost bit is 1, it is sign extended to 32 bits: fffffffb.
By masking out the lower 8 bits (with the bitwise and operation &) we get the integer value 000000fb.

how to get the binary values of the bytes stored in byte array

i am working on a project that gets the data from the file into a byte array and adds "0" to that byte array until the length of the byte array is 224 bits. I was able to add zero's but i am unable to confirm that how many zero's are sufficient. So i want to print the file data in the byte array in binary format. Can anyone help me?
For each byte:
cast to int (happens in the next step via automatic widening of byte to int)
bitwise-AND with mask 255 to zero all but the last 8 bits
bitwise-OR with 256 to set the 9th bit to one, making all values exactly 9 bits long
invoke Integer.toBinaryString() to produce a 9-bit String
invoke String#substring(1) to "delete" the leading "1", leaving exactly 8 binary characters (with leading zeroes, if any, intact)
Which as code is:
byte[] bytes = "\377\0\317\tabc".getBytes();
for (byte b : bytes) {
System.out.println(Integer.toBinaryString(b & 255 | 256).substring(1));
}
Output of above code (always 8-bits wide):
11111111
00000000
11001111
00001001
01100001
01100010
01100011
Try Integer.toString(bytevalue, 2)
Okay, where'd toBinaryString come from? Might as well use that.
You can work with BigInteger like below example, most especially if you have 256 bit or longer.
Put your array into a string then start from there, see sample below:
String string = "10000010";
BigInteger biStr = new BigInteger(string, 2);
System.out.println("binary: " + biStr.toString(2));
System.out.println("hex: " + biStr.toString(16));
System.out.println("dec: " + biStr.toString(10));
Another example which accepts bytes:
String string = "The girl on the red dress.";
byte[] byteString = string.getBytes(Charset.forName("UTF-8"));
System.out.println("[Input String]: " + string);
System.out.println("[Encoded String UTF-8]: " + byteString);
BigInteger biStr = new BigInteger(byteString);
System.out.println("binary: " + biStr.toString(2)); // binary
System.out.println("hex: " + biStr.toString(16)); // hex or base 16
System.out.println("dec: " + biStr.toString(10)); // this is base 10
Result:
[Input String]: The girl on the red dress.
[Encoded String UTF-8]: [B#70dea4e
binary: 101010001101000011001010010000001100111011010010111001001101100001000000110111101101110001000000111010001101000011001010010000001110010011001010110010000100000011001000111001001100101011100110111001100101110
hex: 546865206769726c206f6e20746865207265642064726573732e
You can also work to convert Binary to Byte format
try {
System.out.println("binary to byte: " + biStr.toString(2).getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {e.printStackTrace();}
Note:
For string formatting for your Binary format you can use below sample
String.format("%256s", biStr.toString(2).replace(' ', '0')); // this is for the 256 bit formatting
First initialize the byte array with 0s:
byte[] b = new byte[224];
Arrays.fill(b, 0);
Now just fill the array with your data. Any left over bytes will be 0.

Categories