I have the problem, that the method does not work as expected. In most cases it works. However there is a case it does not work.
I have a byte array containing some values. In hex e.g.: 0x04 0x42 (littleEndian). If I use the method convertTwoBytesToInt, I get a really small number. It should be > 16000 and not smaller than 2000.
I have two methods:
private static int convertTwoBytesToInt(byte[] a){
String f1 = convertByteToHex(a[0]);
String f2 = convertByteToHex(a[1]);
return Integer.parseInt(f2+f1,RADIX16);
}
private static byte[] convertIntToTwoByte(int value){
byte[] bytes = ByteBuffer.allocate(4).putInt(value).array();
System.out.println("Check: "+Arrays.toString(bytes));
byte[] result = new byte[2];
//big to little endian:
result[0] = bytes[3];
result[1] = bytes[2];
return result;
}
I call them as follows:
byte[] h = convertIntToTwoByte(16000);
System.out.println("AtS: "+Arrays.toString(h));
System.out.println("tBtInt: "+convertTwoBytesToInt(h));
If I use the value 16000, there is no problem, but if I use 16900, the integer value of "convertTwoBytesToInt" is 1060.
Any Idea?
Based on the example you provided, my guess is that convertByteToHex(byte) is converting to a single-digit hex string when the byte value is less than 0x10. 16900 is 0x4204 and 1060 is 0x424.
You need to ensure that the conversion is zero-padded to two digits.
A much simpler approach is to use bit manipulation to construct the int value from the bytes:
private static int convertTwoBytesToInt(byte[] a) {
return ((a[1] & 0xff) << 8) | (a[0] & 0xff);
}
Related
i have to encrypy a string using repeating XOR with the KEY:"ICE".
I think that i made a correct algorith to do it but the solution of the problem has 5 byte less then my calculated Hex string, why? Until this 5 bytes more the string are equals.
Did i miss something how to do repeating XOR?
public class ES5 {
public static void main(String[] args) throws UnsupportedEncodingException {
String str1 = "Burning 'em, if you ain't quick and nimble";
String str2 = "I go crazy when I hear a cymbal";
String correct1 = "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a2622632427276527";
byte[] cr = Encript(str1.getBytes(StandardCharsets.UTF_8),"ICE");
String cr22 = HexFormat.of().formatHex(cr);
System.out.println(cr22);
System.out.println(correct1);
}
private static byte doXOR(byte b, byte b1) {
return (byte) (b^b1);
}
private static byte[] Encript(byte[] bt1, String ice) {
int x = 0;
byte[] rt = new byte[bt1.length];
for (int i=0;i< bt1.length;i++){
rt[i] = doXOR(bt1[i],(byte) (ice.charAt(x) & 0x00FF));
x++;
if(x==3)x=0;
}
return rt;
}
}
Hmmm. The String contains characters, and XOR works on bytes.
That's why the first thing is to run String.getBytes() to receive a byte array.
Here, depending on the characters and their encoding the amount of bytes can be more than the amount of characters. You may want to print and compare the numbers already.
Then you perform XOR on the bytes, which may bring you into a completely different area for characters - so you cannot rely on new String(byte[]) at all. Instead you have to create a HEX string representation of the byte[].
Finally compare this HEX string with the value in correct. To me that string already looks like a HEX representation, so do not apply HEX again.
I was wondering it there is any way to specify how many bytes to use when creating the byte array using toByteArray method. For example:
BigInteger bigInteger = new BigInteger("-12");
I want bigInteger.toByteArray() to return an array with values FF and F4 (assuming that the value is represented using 4 bytes - short variable, but it returns only F4.
You could just make your own helper class.
public class BigIntegerHelper {
public static byte[] toByteArray(BigInteger big, int minLength) {
byte[] base=big.toByteArray();
byte[] returnArray=new byte[Math.max(base.length, minLength)];
if ((base[0]&128)!=0) {
Arrays.fill(returnArray, (byte) 0xFF);
}
System.arraycopy(base,0,returnArray,returnArray.length-base.length,base.length);
return returnArray;
}
}
It's unclear exactly what you're going for but BigInteger has a shortValue() method that might help.
For example,
BigInteger big = new BigInteger("-12");
short s = big.shortValue();
byte [] bytes = ByteBuffer.allocate(2).putShort(s).array();
Something similar can be done if you want 4 bytes (int) or 8 bytes(long).
I have a byte array read over a network connection that I need to transform into a String without any encoding, that is, simply by treating each byte as the low end of a character and leaving the high end zero. I also need to do the converse where I know that the high end of the character will always be zero.
Searching the web yields several similar questions that have all got responses indicating that the original data source must be changed. This is not an option so please don't suggest it.
This is trivial in C but Java appears to require me to write a conversion routine of my own that is likely to be very inefficient. Is there an easy way that I have missed?
No, you aren't missing anything. There is no easy way to do that because String and char are for text. You apparently don't want to handle your data as text—which would make complete sense if it isn't text. You could do it the hard way that you propose.
An alternative is to assume a character encoding that allows arbitrary sequences of arbitrary byte values (0-255). ISO-8859-1 or IBM437 both qualify. (Windows-1252 only has 251 codepoints. UTF-8 doesn't allow arbitrary sequences.) If you use ISO-8859-1, the resulting string will be the same as your hard way.
As for efficiency, the most efficient way to handle an array of bytes is to keep it as an array of bytes.
This will convert a byte array to a String while only filling the upper 8 bits.
public static String stringFromBytes(byte byteData[]) {
char charData[] = new char[byteData.length];
for(int i = 0; i < charData.length; i++) {
charData[i] = (char) (((int) byteData[i]) & 0xFF);
}
return new String(charData);
}
The efficiency should be quite good. Like Ben Thurley said, if performance is really such an issue don't convert to a String in the first place but work with the byte array instead.
Here is a sample code which will convert String to byte array and back to String without encoding.
public class Test
{
public static void main(String[] args)
{
Test t = new Test();
t.Test();
}
public void Test()
{
String input = "Hèllo world";
byte[] inputBytes = GetBytes(input);
String output = GetString(inputBytes);
System.out.println(output);
}
public byte[] GetBytes(String str)
{
char[] chars = str.toCharArray();
byte[] bytes = new byte[chars.length * 2];
for (int i = 0; i < chars.length; i++)
{
bytes[i * 2] = (byte) (chars[i] >> 8);
bytes[i * 2 + 1] = (byte) chars[i];
}
return bytes;
}
public String GetString(byte[] bytes)
{
char[] chars = new char[bytes.length / 2];
char[] chars2 = new char[bytes.length / 2];
for (int i = 0; i < chars2.length; i++)
chars2[i] = (char) ((bytes[i * 2] << 8) + (bytes[i * 2 + 1] & 0xFF));
return new String(chars2);
}
}
Using deprecated constructor String(byte[] ascii, int hibyte)
String string = new String(byteArray, 0);
String is already encoded as Unicode/UTF-16. UTF-16 means that it can take up to 2 string "characters"(char) to make one displayable character. What you really want is to use is:
byte[] bytes = System.Text.Encoding.Unicode.GetBytes(myString);
to convert a String to an array of bytes. This does exactly what you did above except it is 10 times faster in performance. If you would like to cut the transmission data nearly in half, I would recommend converting it to UTF8 (ASCII is a subset of UTF8) - the format the internet uses 90% of the time, by calling:
byte[] bytes = Encoding.UTF8.GetBytes(myString);
To convert back to a string use:
String myString = Encoding.Unicode.GetString(bytes);
or
String myString = Encoding.UTF8.GetString(bytes);
I am working with hex and byte numbers and now face with a problem at converting a thing as bellow:
int i= 26;
byte b = 0x00;
I want to have :
b = 0x26; ( 0x26 must be in format "byte")
or for example for
i= 90;
i must have
Byte b = 0x90;
Can you give me a method which does my work?
Thank u...
You could use the Byte.parseByte(String, int) method to simply parse your "26" into a hex value used to create a byte primitive:
int number = 26;
String intString = Integer.toString(number);
byte b = Byte.parseByte(intString, 16);
The radix value of 16 is used because you want the byte to have a value which is equal to 0x26 and the 0x prefix means hexadecimal which is base 16.
If you want a Byte object you can use valueOf instead:
Byte b = Byte.valueOf(intString, 16);
I have two numbers: one is an int, other is byte. I want to create a single long value out of them in a way that person knowing the byte value can decipher original int from it. Whats the best way to do it?
Assuming i understood your question correct,
The Simplest Solution, You Could XOR the 'int' using the 'byte'
Repeat the process to decrypt...
byte key = 8;
int secret = 123;
System.out.println("Secret : " + secret);
int encrypted = (secret ^ (key | (key << 8)));
System.out.println("Encrypted : " + encrypted );
int decrypt = (encrypted ^ (key | (key << 8)));
System.out.println("Decrypted : " + decrypt );
The result is an 'int' but, you could always just cast it into a long...
long mylong = (((long)mybyte) << 40) | myint;
To retrieve the original value:
int myorigint = (int)(mylong & ~(((long)mybyte) << 40));
But this requires 8-byte longs. Which are not required by the C standard. If a long is 4 bytes, you're out of luck. This means long and int would have the same length. If sizeof(int)==sizeof(long)==4, then asking to store an int and a byte in a long is asking to store 5 arbitrary bytes of information in 4 bytes. Which is completely impossible.
Of course, there's also the trivial "solution":
long mylong = (long)myint;
and the reverse is:
int myint = (int)mylong;
Now, someone knowing (or not knowing!) the byte can retrieve the original data.
If you want a solution such that only someone knowing the correct byte can retrieve the original int, you can use this:
long mylong = (long)(myint-mybyte);
and reverse:
int myint = (int)(mylong+mybyte);
But know that encrypting four bytes with one byte will not be truly secure. You should use a 4-byte one-time pad to encrypt four bytes. If you have a four-byte key, use XOR for a truly unbreakable cipher. No, really.
One idea is to apply a reversible function the number of times indicated by the byte.
To get the original number back just apply the inverse function the same number of times.
e.g.
public static int encrypt(int value, byte key) {
int result=value;
for (int i=0; i<=(key&255); i++) {
result=Integer.rotateRight(result,7)^(i+0xCAFEBABE);
}
return result;
}
Finding the reverse function left as an exercise for the reader.....