Converting from Hexadecimal to Bytes - java

I have some Java code that converts a Hexadecimal string into bytes. It seems to work okay for very short hexadecimal strings but flags an error if I use a long string, but I cant figure out why. I'm new to Java and programming in general. Feel free to point out any other areas which I could improve.
Here is my code:
public class Hextobinary {
static String hexToBinary(String hex) {
int i = Integer.parseInt(hex, 16);
String bin = Integer.toBinaryString(i);
return bin;
}
public static void main(String[] args) {
String h = "5F";
String x = hexToBinary(h);
System.out.println(x);
}
}
Many Thanks

There is a built-in for this using DatatypeConverter, so you may not have to do it yourself.
import javax.xml.bind.DatatypeConverter;
public class HexUtils {
public String toHex(final byte[] arr) {
return DatatypeConverter.printHexBinary(arr);
}
public byte[] fromHex(final String str) {
return DatatypeConverter.parseHexBinary(str);
}
}

You are parsing your string to an int. That will work for short hex strings, but not for longer ones. An int is 32 bits, or 8 hex characters. Any string longer than that will not fit into an int.
If you do write your own method, then split the hex string up into two character chunks, and process each pair of characters separately into a byte, and store the bytes in a byte array. That will allow you to deal with longer hex strings.

If you are using huge strings, the type int (Integer) of the variable i cannot store the value contained in the string hex. An Integer can only store values ranging from -80000000 (hexadecimal) to +7FFFFFFF. Any longer string will cause your function to produce false results.
One quick solution is to use the type Long (and the function parseLong) instead of Integer. The type Long can hold values ranging from -8000000000000000 (hexadecimal) to +7FFFFFFFFFFFFFFF. But if you need to convert longer strings, this is not going to work anymore.

Related

Encrypt using reapeting XOR

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.

Convert a byte[] array into a string of characters INCLUDING escape characters in java

I searched google about this information but the answers I found do not apply to my case.
I have an HEX string like the following:
hexString = '7d940ef9790c31334ac6f116814148b9abe73f32'
Python can convert this string to a binary value using the following function:
unhexlify('7d940ef9790c31334ac6f116814148b9abe73f32')
whose result is:
binString = '}\x94\x0e\xf9y\x0c13J\xc6\xf1\x16\x81AH\xb9\xab\xe7?2'
That is, a string containing the binary information of the original hex string.
I tried to use the .getBytes("encoding") method in java, but I am not able to reproduce this result, and unfortunately this result is critical for my application (I need exactly the same result).
I'm not an encodings pro, so it could easily be me overlooking something.
I need to convert to the same kind of string as "binString" a byte[] array resulting from e.g. a md5 digest, so any insight on how to convert a byte[] to such a string would be most appreciated.
It's not a solution, but it could be helpful:
import java.nio.charset.Charset;
import javax.xml.bind.DatatypeConverter;
public class Main {
public static void main(String args[])
{
String hexString = "7d940ef9790c31334ac6f116814148b9abe73f32";
byte[] out = toByteArray(hexString);
String result = new String(out,Charset.forName("UTF-8"));
System.out.println(result);
}
public static byte[] toByteArray(String s) {
return DatatypeConverter.parseHexBinary(s);
}
}
The output in my machine is:
}??y13J???AH????2
It can print all the ascii chracters, but there are problems with the escape characters like \x.

Java (BigInteger from byte array)

I'm using following code to create a BigInteger from hexadecimal string and print in to output.
package javaapplication2;
import java.math.BigInteger;
import javax.xml.bind.DatatypeConverter;
public class JavaApplication2 {
public static void main(String[] args) {
// Number in hexadecimal form
String HexString = "e04fd020ea3a6910a2d808002b30309d";
// Convertation from string to byte array
byte[] ByteArray = toByteArray(HexString);
// Creation of BigInteger from byte array
BigInteger BigNumber = new BigInteger(ByteArray);
// Print result
System.out.print(BigNumber + "\n");
}
public static String toHexString(byte[] array) {
return DatatypeConverter.printHexBinary(array);
}
public static byte[] toByteArray(String s) {
return DatatypeConverter.parseHexBinary(s);
}
}
After execution of this code I'm get a following result:
-42120883064304190395265794005525319523
But I'm expected to see this result:
298161483856634273068108813426242891933
What I'm doing wrong?
You're passing in a byte array where the first byte has a top bit that is set - making it negative. From the constructor documentation:
Translates a byte array containing the two's-complement binary representation of a BigInteger into a BigInteger. The input array is assumed to be in big-endian byte-order: the most significant byte is in the zeroth element.
A two's-complement binary representation with a leading set bit is negative.
To get the result you want, you can do any of:
Prefix the hex string with "00" so that you'll always get a top byte of 0
Pass the hex string straight into the BigInteger(String, int) constructor, where the sign is inferred from the presence or absence of "-" at the start of the string. (Obviously you'd pass in 16 as the base.)
Use the BigInteger(int, byte[]) constructor, passing 1 as the signum value
If your real context is that you've already got the byte array, and you were only parsing it from a hex string for test purposes, I'd use the third option. If you've genuinely got a hex string as input, I'd use the second option.
try
BigInteger bigInt = new BigInteger(HexString, 16);

Long value of a String that does not contain numbers

I have a String variable that I want to convert to a long variable.
The problem is that the String variable will never contain any numbers, so simply calling Long.parseLong(myString); will throw a NumberFormatException.
To clarify my intentions:
I have a method that returns a long from a String in-parameter. I want the method to generate an ID based on the String variable, to later be able to group the long values.
I might solve this using a RegEx expression, but my question is if there's any straight forward way to get a long value of a String?
You say you want a long value. The built in hashCode() returns an int, not a long. If you really do need a long then you need to use a hashing method that returns a long. There are a number of possibilities, though I usually suggest the FNV hash for non-cryptographic purposes. It is very easy to code and comes in a wide range of sizes, 64-bit included.
ETA: Code for the FNV hash is on the FNV website that I linked to. Things to be careful of are 1) unsigned v. signed 64-bit numbers and 2) character encodings.
long FNV64Hash(String inString) throws UnsupportedEncodingException {
// FNV-64 constants.
long FNVprime = 1099511628211L;
// Needs workround for unsigned 64-bit: 14695981039346656037.
long FNVbasis = (146959810393466560L * 100L) + 37L;
// Alternative: long FNVbasis = -3750763034362895579L;
// Convert string to bytes.
byte[] bytes = inString.getBytes("UTF-8"); // Specify a character encoding.
long hash = FNVbasis;
for (byte aByte : bytes) {
hash ^= aByte;
hash *= FNVprime;
}
return hash;
} // end FNV64Hash()
if you want a simple and easy way , you can use hashCode() in java , and here is an example
import java.io.*;
public class StringHashing{
public static void main(String args[]){
String Str = new String("HELLO WORLD !!");
System.out.println("Hashcode for Str :" + Str.hashCode() );
}
}
or you can implement your own hash function

Java: How to get a bi-directional numeric representation of a string?

I need to compute a numeric representation of a string which is bi-direction. For example, If I have a string "US" I would like an algorithm which when applied to "US" generates a number X (int or long). When another algorithm is applied to X, I want to get "US". Each string consists of two characters.
Thanks in advance.
The following does it easily by using DataInputStream and DataOutputStream to read/write to an underlying byte array.
public static void main(String[] args) {
String original = "US";
int i = stringToInt(original);
String copy = intToString(i);
System.out.println("original: "+original);
System.out.println("i: "+i);
System.out.println("copy: "+copy);
}
static int stringToInt(String s) {
byte[] bytes = s.getBytes();
if (bytes.length > 4) {
throw new IllegalArgumentException("String too large to be" +
" stored in an int");
}
byte[] fourBytes = new byte[4];
System.arraycopy(bytes, 0, fourBytes, 0, bytes.length);
try {
return new DataInputStream(new ByteArrayInputStream(fourBytes))
.readInt();
} catch (IOException e) {
throw new RuntimeException("impossible");
}
}
static String intToString(int i) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
new DataOutputStream(byteArrayOutputStream).writeInt(i);
} catch (IOException e) {
throw new RuntimeException("impossible");
}
return new String(byteArrayOutputStream.toByteArray());
}
This is in the general sense impossible; there are only 2^64 long values, and there are more than 2^64 64-character strings consisting only of the characters X, Y and Q.
Maybe you want to have a pair of hash tables A and B and a counter; if you're given a string you check whether it's in the first hash table, if so return the value you stored there, if not then you set
A[string]=counter; B[counter]=string; counter=1+counter;
What you're describing is bidirectional encryption. Something like this may help you. Another way to do this if you specifically want a numerical value, is to store the character codes (ASCII codes) of each letter. However the resulting number is going to be huge (especially for really long strings) and you probably won't be able to store it in an 32 or 64-bit integer. Even a long won't help you here.
UPDATE
According to your edit, which says that you only need two characters, you can use the ASCII codes by using getBytes() on the String. When you need to convert it back, the first two digits will correspond to the first character, whereas the last two will correspond to the second character.
This could do, assuming your Strings have length 2, i.e. consist of two Java char values:
public int toNumber(String s) {
return s.charAt(0) + s.charAt(1) << 16;
}
public String toString(int number) {
return (char)number + "" + (char)(number >> 16);
}
There are Unicode characters (those with numbers over 216) that do not fit into a single Java char, but are represented (by UTF-16) by two consecutive surrogates. This algorithm would work for a single-Character-string consisting of these two surrogates, but not for longer strings consisting of more than one such character.
Also, there are int values which do not map back to valid Unicode (or UTF-16) strings (e.g. which produce unpaired surrogates instead of valid characters). But each normal string gets converted to an int and back to the same string.

Categories