I am trying to calculate a simple checksum and then I'm doing a checksum test.
public void readfile()
{
byte counter = 0;
byte[] data = new byte[68];
while(x.hasNextInt())
{
data[counter++] = (byte)x.nextInt();
if(counter == 67)
break;
}
int sum = 0;
for (int i = 0; i < 67; i++)
sum += (data[i] & 0xFF);
System.out.println((int)(sum & 0xFF)); //checksum
//perform checksum test.
data[counter] = (byte)(sum & 0xFF);
sum = 0;
for (int i = 0; i < 68; i++)
sum += (data[i] & 0xFF);
System.out.println((int)(sum & 0xFF)); //checksum test
}
I am reading the first 67 integer values of a file and saving them inside a byte array. All the integers are < 256. The variable 'x' is the file that I am reading. However, when I perform the checksum test, the value outputted isn't 0. I am not able to diagnose where I am computing incorrectly.
I'm not sure what you're trying to do.
You get the first 67 characters, calculate a checksum, and then assume that those 67, plus the checksum, is 0. It is not. You're ADDING the checksum, not subtracting it.
So if the checksum is not 0 or 128, you end up with a value that is twice the checksum. Right?
Related
I am using this hashing algorithm..
public long DEKHash(String str)
{
long hash = str.length();
for(int i = 0; i < str.length(); i++)
{
hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
}
return hash;
}
I have modified it slightly so that it produces a larger number. But this number is larger than a long and then overflows and becomes negative. I am beginning Java and wanted to know if it is possible to get the real value?
I was looking into BigInteger but I am not having any luck with it.
Perhaps this will solve your problem. Use Long.unsignedCompare().
long a1 = 1;
long a2 = -1;
if (a2 < a1) {
// a2 is less which is what you would expect
System.out.println(a2);
}
if (Long.compareUnsigned(a1,a2) < 0) {
// here, a1 is less
System.out.println(a1);
}
prints
-1
1
Also, above you have
hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
Did you know that >> extends the sign bit to the right. If you want to just right shift and not extend (i.e. fill with 0 bits, then do >>>)
I have written a function that computes the checksum for a given tcp packet. However, when I capture a tcp packet sent over ipv4 from wireshark and let my function compute its checksum, then its not the same checksum as in the wireshark captured packet. I checked and the bytes I give to the computeChecksum function are exactly the same as the tcp packet bytes i captured with wireshark.
I computed the checksum according to the RFC 793. Does anybody see if there's anything wrong in my code?
public long computeChecksum( byte[] buf, int src, int dst ){
int length = buf.length; // nr of bytes of the tcppacket in total.
int pseudoHeaderLength = 12; // nr of bytes of pseudoheader.
int i = 0;
long sum = 0;
long data;
buf[16] = (byte)0x0; // set checksum to 0 bytes
buf[17] = (byte)0x0;
// create the pseudoheader as specified in the rfc.
ByteBuffer pseudoHeaderByteBuffer = ByteBuffer.allocate( 12 );
pseudoHeaderByteBuffer.putInt( src );
pseudoHeaderByteBuffer.putInt( dst );
pseudoHeaderByteBuffer.put( (byte)0x0 ); // store the 0x0 byte
pseudoHeaderByteBuffer.put( (byte)PROTO_NUM_TCP ); // stores the protocol number
pseudoHeaderByteBuffer.putShort( (short) length ); // store the length of the packet.
byte[] pbuf = pseudoHeaderByteBuffer.array();
// loop through all 16-bit words of the psuedo header
int bytesLeft = pseudoHeaderLength;
while( bytesLeft > 0 ){
// store the bytes at pbuf[i] and pbuf[i+1] in data.
data = ( ((pbuf[i] << 8) & 0xFF00) | ((pbuf[i + 1]) & 0x00FF));
sum += data;
// Check if the sum has bit 17 or higher set by doing a binary AND with the 46 most significant bits and 0xFFFFFFFFFF0000.
if( (sum & 0xFFFFFFFF0000) > 0 ){
sum = sum & 0xFFFF; // discard all but the 16 least significant bits.
sum += 1; // add 1 (because we have to do a one's complement sum where you add the carry bit to the sum).
}
i += 2; // point to the next two bytes.
bytesLeft -= 2;
}
// loop through all 16-bit words of the TCP packet (ie. until there's only 1 or 0 bytes left).
bytesLeft = length;
i=0;
while( bytesLeft > 1 ){ // note that with the pseudo-header we could never have an odd byte remaining.
// We do do exactly the same as with the pseudo-header but then for the TCP packet bytes.
data = ( ((buf[i] << 8) & 0xFF00) | ((buf[i + 1]) & 0x00FF));
sum += data;
if( (sum & 0xFFFF0000) > 0 ){
sum = sum & 0xFFFF;
sum += 1;
}
i += 2;
bytesLeft -= 2;
}
// If the data has an odd number of bytes, then after adding all 16 bit words we remain with 8 bits.
// In that case the missing 8 bits is considered to be all 0's.
if( bytesLeft > 0 ){ // ie. there are 8 bits of data remaining.
sum += (buf[i] << 8 & 0xFF00); // construct a 16 bit word holding buf[i] and 0x00 and add it to the sum.
if( (sum & 0xFFFF0000) > 0) {
sum = sum & 0xFFFF;
sum += 1;
}
}
sum = ~sum; // Flip all bits (ie. take the one's complement as stated by the rfc)
sum = sum & 0xFFFF; // keep only the 16 least significant bits.
return sum;
}
If you don't see anything wrong with the code then let me know that too. In that case I know to look somewhere else for the problem.
I've tested your code and it works correctly. I've done the following:
Configure wireshark to "Validate the TCP checksum if possible" in order to avoid to do the test with a packet with an incorrect checksum.
Add the long type suffix L to the constant 0xFFFFFFFF0000 in order to avoid the compile time error integer number too large (Java 8).
Use an hexadecimal representation of a TCP segment coming from wireshark
String tcpSegment = "0050dc6e5add5b4fa9bf9ad8a01243e0c67c0000020405b4010303000101080a00079999000d4e0e";
Use a method to convert an hexadecimal string to a byte array
public static byte[] toByteArray(String strPacket) {
int len = strPacket.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(strPacket.charAt(i), 16) << 4)
+ Character.digit(strPacket.charAt(i + 1), 16));
}
return data;
}
Use a ByteBuffer to write the source and destination adress into an int
int src = ByteBuffer.wrap(toByteArray("c0a80001")).getInt();
int dst = ByteBuffer.wrap(toByteArray("c0a8000a")).getInt();
With this, I obtain a checksum of C67C, the same as in wireshark.
P.S.: There is an error in your code when you do
pseudoHeaderByteBuffer.putShort( (short) length );
you store the length in two's-complement inside the pseudo header which will be a problem if the length is greater than 2^15. You better used char which is 16 bit unsigned.
I am working with Local Binary Patterns (LBP) which produce numbers in the range 0-255.
That means that they can fit in a byte (256 different values may be included into a byte). So that explains why many (if not all) implementation in java I have found uses byte[] to store these values.
The problem is that since I am interested in the rank of these values when converted to byte (from int for example) they do not keep the previous rank they had (as int for example) since byte are signed (as all but chars in java I think) and so the greater 128 values (127 and after) of the range 0-255 becomes negative numbers. Furthermore I think they are inverted in order (the negative ones).
Some examples to be more specific:
(int) 0 = (byte) 0
(int) 20 = (byte) 20
(int) 40 = (byte) 40
(int) 60 = (byte) 60
(int) 80 = (byte) 80
(int) 100 = (byte) 100
(int) 120 = (byte) 120
(int) 140 = (byte) -116
(int) 160 = (byte) -96
(int) 180 = (byte) -76
(int) 200 = (byte) -56
(int) 220 = (byte) -36
(int) 240 = (byte) -16
My question is whether there is a specific way to maintain the order of int values when converted to byte (meaning 240 > 60 should hold true in byte also -16 < 60!) while keeping memory needs minimum (meaning use only 8bits if that many are required). I know I could consider comparing the byte in a more complex way (for example every negative > positive and if both bytes are negative inverse the order) but I think it's not that satisfactory.
Is there any other way to convert to byte besides (byte) i?
You could subtract 128 from the value:
byte x = (byte) (value - 128);
That would be order-preserving, and reversible later by simply adding 128 again. Be careful to make sure you do add 128 later on though... It's as simple as:
int value = x + 128;
So for example, if you wanted to convert between an int[] and byte[] in a reversible way:
public byte[] toByteArray(int[] values) {
byte[] ret = new byte[values.length];
for (int i = 0; i < values.length; i++) {
ret[i] = (byte) (values[i] - 128);
}
return ret;
}
public int[] toIntArray(int[] values) {
int[] ret = new byte[values.length];
for (int i = 0; i < values.length; i++) {
ret[i] = values[i] + 128;
}
return ret;
}
If you wanted to keep the original values though, the byte comparison wouldn't need to be particularly complex:
int unsigned1 = byte1 & 0xff;
int unsigned2 = byte2 & 0xff;
// Now just compare unsigned1 and unsigned2...
When:
byte[] b = {-128, 0, 0, 0};
long total = 0;
The first expression returns -2,147,483,648:
for (int i = 0; i < b.length; i++) {
int shift = (b.length - 1 - i) * 8;
total += (b[i] & 255) << shift;
}
The second returns 2,147,483,648:
for (int i = 0; i < b.length; i++) {
int shift = (b.length - 1 - i) * 8;
long tmp = (b[i] & 255);
total += tmp << shift;
}
My question is; why is the first statement positive and the second negative when they appear to be the same statement?
In this line
total += (b[i] & 255) << shift;
the parenthesized expression is of type int and the left shift sets its leftmost bit to one, making it a negative number. The conversion to long happens only after all the calculation is done.
long tmp = (b[i] & 255);
Here the expression is long and the leftmost bit will stay zero after the shift.
If you want to keep the first expression, just add a cast to long for the parenthesized expression or use a long constant 255L.
shifting an int into the sign bit results in a negative number
shifting a long by the same amount results in a positive number
If you run the following code you may understand what is going on :
System.out.println(Integer.toBinaryString(-2147483648));
System.out.println(Long.toBinaryString(2147483648L));
It prints
10000000000000000000000000000000
10000000000000000000000000000000
The same bits are interpreted differently for long and int.
I need to convert a signed decimal number into a 32 bit little-endian binary value. Does anyone by any chance know of a built-in Java class or function that can do this? Or have built one to do this?
The data is a longtitude/latitude value like -78.3829. Thanks for any help.
If it helps at all, here's a class that I made that converts longs to binary Strings and binary Strings to longs:
public class toBinary {
public static void main(String[] args) {
System.out.println(decimalToBinary(16317));
System.out.println(binaryToDecimal("11111111111111111111111111111111111100101001"));
}
public static long binaryToDecimal(String bin) {
long result = 0;
int len = bin.length();
for(int i = 0; i < len; i++) {
result += Integer.parseInt(bin.charAt(i) + "") * Math.pow(2, len - i - 1);
}
return result;
}
public static String decimalToBinary(long num) {
String result = "";
while(true) {
result += num % 2;
if(num < 2)
break;
num = num / 2;
}
for(int i = result.length(); i < 32; i++)
result += "0";
result = reverse(result);
result = toLittleEndian(result);
return result;
}
public static String toLittleEndian(String str) {
String result = "";
result += str.substring(24);
result += str.substring(16, 24);
result += str.substring(8, 16);
result += str.substring(0, 8);
return result;
}
public static String reverse(String str) {
String result = "";
for(int i = str.length() - 1; i >= 0; i--)
result += str.charAt(i);
return result;
}
}
It doesn't take decimal values, but it could probably give you a bit of guidance.
The conversion is trivial once you know what the endianess means on binary level. The question is more what do you really want to do with it?
public static int flipEndianess(int i) {
return (i >>> 24) | // shift byte 3 to byte 0
((i >> 8) & 0xFF00) | // shift byte 2 to byte 1
(i << 24) | // shift byte 0 to byte 3
((i & 0xFF00) << 8); // shift byte 1 to byte 2
}
This little method will swap around the bytes in an int to switch between little/big endian order (the conversion is symetric). Now you have a little endian int. But what would you do with that in Java?
More likely you need to write the data to a stream or something, then its only a question in which order you write the bytes out:
// write int to stream so bytes are little endian in the stream
// OutputStream out = ...
out.write(i);
out.write(i >> 8);
out.write(i >> 16);
out.write(i >> 24);
(For big endian you would just order the lines from bottom to top...)