How to convert minus hex value to String and byte array - java

I want to convert decimal -10 value to hex in a String and byte array format.
I have tried
String minHex = Integer.toHexString(Integer.valueOf(-10));
System.out.println(minHex);
Which results in fffffff6, and I think it is not correct. And for converting byte array I am using below function which I found from
Convert a string representation of a hex dump to a byte array using Java?
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
So also not sure it will work for minus hex value or not.

To convert an hex to a String the way you expect it i.e. -10 is converted to -a, use:
String hex = Integer.toString(-10, 16);
To convert to a byte array, simply convert the int to a byte array, it is represented the same way:
byte[] bytes = ByteBuffer.allocate(4).putInt(-10).array();

Related

How to convert byte array to Base 64 string in unsigned way in java?

I am struggling to get the same Base64 string in both C# and Java
I want Java to treat bytes as unsigned ones when converting to Base64.
Here's my C# code
private static void Main(string[] args)
{
long baseTimeStamp = 1501492600;
byte[] bytes = BitConverter.GetBytes(baseTimeStamp * 114);
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = (byte)(bytes[i] >> 2);
}
string base64 = Convert.ToBase64String(bytes);
Console.WriteLine(base64);
}
In Java, I want to get the same Base64 for the same long value
Here's the code
public static void main(String[] args) {
long myLong = 1501492600;
byte[] bytes = longToBytes(myLong);
for(int i = 0; i < bytes.length / 2; i++)
{
int temp = bytes[i];
bytes[i] = bytes[bytes.length - i - 1];
bytes[bytes.length - i - 1] = (byte) temp;
bytes[i] = (byte)((bytes[i] >> 2));
}
System.out.println(DatatypeConverter.printBase64Binary(bytes));
}
private static byte[] longToBytes(long x) {
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
buffer.putLong(x);
return buffer.array();
}
I tried both the commented way, and the DatatypeConverter way, but I get different String values. Is there a standard JDK way, or should I write my own base64 method to treat bytes as unsigned ones?
Base64 converts bits. It doesn't know or care about whether you think of the bytes as signed or unsigned. If you're getting different values, the problem is somewhere else.
However, since you're doing bit shifting, you need to use the zero-fill version >>> instead of the sign extend >>. That may be the source of your problem.
DatatypeConverter is still the easiest way to go.

string to byte then byte[] 0xformat

I am having problems of conversion through string->byte->byte[]
What I have done so far:
double db = 1.00;
double ab = db*100;
int k = (int) ab;
String aa = String.format("%06d", k);
String first = aa.substring(0,2);``
String second = aa.substring(2,4);
String third = aa.substring(4,6);
String ff = "0x"+first;
String nn = "0x"+second;
String yy = "0x"+third;
I want to write those bytes to an byte[]. What I mean is:
byte[] bytes = new byte[]{(byte) 0x02, (byte) 0x68, (byte) 0x14,
(byte) 0x93, (byte) 0x01, ff,nn,yy};
in this order and casted with 0x's. Any help is greatly appriciated.
Regards,
Ali
You can use Byte.decode()
Decodes a String into a Byte. Accepts decimal, hexadecimal, and octal numbers given by the following grammar:
DecodableString:
Signopt DecimalNumeral
Signopt 0x HexDigits
Signopt 0X HexDigits
Signopt # HexDigits
Signopt 0 OctalDigits
Below code will print 10, 11 which is value of 0XA, 0XB
byte[] temp = new byte[2];
temp[0] = Byte.decode("0xA");
temp[1] = Byte.decode("0xB");
System.out.println(temp[0]);
System.out.println(temp[1]);
As I see, the main question here is how to convert a 2 char String representing a hexa number to a byte type. The Byte class has a static method parseByte(String s, int radix) that can parse a String to number using the radix you want (in this case, 16). Here is an example of how you can do the parsing and save the result in a byte array:
public static void main(String [] args){
System.out.println(Arrays.toString(getBytes("0001020F")));
}
public static byte[] getBytes(String str) {
byte [] result = new byte[str.length() / 2]; //assuming str has even number of chars...
for(int i = 0; i < result.length; i++){
int startIndex = i * 2;
result[i] = Byte.parseByte(str.substring(startIndex, startIndex + 2), 16);
}
return result;
}

How do I convert a large string into hex and then into byte?

I work with cellphones and deal with MEID numbers on a daily basis. So instead of searching online for a MEID (a hex number of length 14) to pseudo ESN (a hex number of length 8) calculator, I figured I can make my own program. The way to obtain a pESN from MEID is fairly simple in theory. For example, given MEID 0xA0000000002329, to make a pESN, SHA-1 needs to be applied to the MEID. SHA-1 on A0000000002329 gives e3be267a2cd5c861f3c7ea4224df829a3551f1ab. Take the last 6 hex numbers of this result, and append it to 0x80 - the result is 0x8051F1AB.
Now here is the code I have so far:
public void sha1() throws NoSuchAlgorithmException {
String hexMEID = "A0000000002329";
MessageDigest mDigest = MessageDigest.getInstance("SHA1");
byte[] result = mDigest.digest(hexMEID.getBytes());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < result.length; i++) {
sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println(sb.toString());
}
The problem is that using this method, SHA-1 on A0000000002329 gives a89b611b421f57705bd013297ce3fc835f706ab0 instead of e3be267a2cd5c861f3c7ea4224df829a3551f1ab. What am I doing wrong here??
Someone gave me a hint that "the trick is to apply SHA-1 to the number representing the MEID, not the string representing the MEID. You'll need to process it byte-by-byte, so you must give it two hex numbers at a time (since two hex numbers make a byte) and make sure they are interpreted as numbers and not ASCII characters". If this is true then how do I change my string into hex and then into byte so that SHA1 can give me the correct result???
Without libraries, you can follow the example here:
In Java, how do you convert a hex string to a byte[]?
byte[] b = new BigInteger(s,16).toByteArray();
One library (I'm sure there are many) that also provides this is POJava:
<dependency>
<groupId>org.pojava</groupId>
<artifactId>pojava</artifactId>
<version>2.8.1</version>
</dependency>
byte[] hexMEIDBytes=EncodingTool.hexDecode(hexMEID);
[EDIT] ==============
Here's a more complete example per your followup question:
byte[] hexMEIDBytes = EncodingTool.hexDecode(hexMEID);
byte[] hash = HashingTool.hash(hexMEIDBytes, HashingAlgorithm.SHA);
String pESN="0x80" + EncodingTool.hexEncode(hash).substring(34).toUpperCase();
// a hexMEID value of "A0000000002329" results in a pESN value of "0x8051F1AB"
For String to Hex:
public String StrToHex(String arg) {
return String.format("%040x", new BigInteger(arg.getBytes(//Your Charset//)));
}
For Hex to byte:
This below code wont work for "0".
public byte[] hexStrToByteArray(String s) {
int leng = s.length();
byte[] data = new byte[leng / 2];
for (int i = 0; i < leng; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
You can use the following two methods
public static synchronized String bytesToHex(byte [] buf){
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10){
strbuf.append("0");
}
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
public synchronized static byte[] hexToBytes(String hexString) {
byte[] b = new BigInteger(hexString,16).toByteArray();
return b;
}

Java BigInteger vs Mono .net BigInteger

I use in .Net project mono implementation of BigInteger (link) In Java I use java.math.BigInteger.
The same code produces different results in Java.
.Net code
String inputBytes = "8E5BD77F0DCC30864634C134E28BFB42A149675A320786B616F4530708350D270353C30A40450325801B7AFED12BCCA274B8187072A89CC0CC3F95A24A8251243C1835898246F4D64CA3AC61DB841518F0E8FBC8996A40EB626153AE7F0BB87FD713FAC522719431428DE178E780A3FA45788A72C431926AED990E6DA268D2CC";
String modulus = "00e6b4b4511e0bd1b3d9c82ee189ba6d0c70b1466d94126f99a741af99a92701a789451742a357ddb61a4dea409965ec58dcaa5e30826de871b04700ed0fd46b1693446049734e8f95faba2bf9301347e63ba1771650e71982adef0cca6890b6f7baa7f5421a6533652f4b70c3c4270c480cf54cc06635f22901a42716d1dadf4f";
String exp = "010001";
BigInteger mModulus = new BigInteger(hexStringToByteArray(modulus));
BigInteger mExponent = new BigInteger(hexStringToByteArray(exp));
BigInteger input = new BigInteger(hexStringToByteArray(inputBytes));
BigInteger output = input.ModPow(mExponent, mModulus);
Console.WriteLine("==RESULT==" + byteArray2Hex(output.GetBytes()));
public static byte[] hexStringToByteArray(string hexString)
{
if (hexString.Length % 2 != 0)
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The binary key cannot have an odd number of digits: {0}", hexString));
byte[] HexAsBytes = new byte[hexString.Length / 2];
for (int index = 0; index < HexAsBytes.Length; index++)
{
string byteValue = hexString.Substring(index * 2, 2);
HexAsBytes[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return HexAsBytes;
}
==RESULT==01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003020300C06082A864886F70D02050500041009EB0D996BFC1EFA5675997712A1AB6E
Java code.
The same inputBytes array, the same exponent and modulus, but different result.
String inputBytes = "8E5BD77F0DCC30864634C134E28BFB42A149675A320786B616F4530708350D270353C30A40450325801B7AFED12BCCA274B8187072A89CC0CC3F95A24A8251243C1835898246F4D64CA3AC61DB841518F0E8FBC8996A40EB626153AE7F0BB87FD713FAC522719431428DE178E780A3FA45788A72C431926AED990E6DA268D2CC";
String modulus = "00e6b4b4511e0bd1b3d9c82ee189ba6d0c70b1466d94126f99a741af99a92701a789451742a357ddb61a4dea409965ec58dcaa5e30826de871b04700ed0fd46b1693446049734e8f95faba2bf9301347e63ba1771650e71982adef0cca6890b6f7baa7f5421a6533652f4b70c3c4270c480cf54cc06635f22901a42716d1dadf4f";
String exp = "010001";
BigInteger mModulus = new BigInteger(hexStringToByteArray(modulus));
BigInteger mExponent = new BigInteger(hexStringToByteArray(exp));
BigInteger input = new BigInteger(hexStringToByteArray(inputBytes));
BigInteger output = input.modPow(mExponent, mModulus);
System.out.println("==RESULT==" + Utils.byteArray2Hex(output.getBytes()));
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
==RESULT==6ce02bd9536ad76bcfd7633b6a2305ed98b43b0bb5fc2acbf984566f1ab35db02e651e9ed8793bf64b018455872b8ae3a06af082e8d680df407ea1e5df1336a19c6f3e116c6ff1940066396afa1de5633fad814fb42790b3af0e62e6dd53977f78794b2d105cdca9272f9c0feea119fe2c9691b6f6e21db3065fb25d840acea2
I do not understand why the results are different.
P.S.
e.g. if I use InputBytes
String inputBytes = "242e35241b85fcfd75a53441ef9fc0941064c16f8e4555dabef5ce8ebc91400c6961b6b607e5dd762dbcabce51b11c8594e7d7183786c8e3c5300c7583c1871fc6f350b817682150b5cd0430ca9a2c3f8315b425c8fea0e7cc18187237ed47d29b082e7e7154888d5fb09f092a6dd5e2d3dac9df8de45837b708b5ae17f03e7f";
the the results in Java and .Net are the same
==RESULT==01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003020300c06082a864886f70d02050500041046fd8e86a4833e7141cbe4718e8e92f7
Where is the magic?
From the docs for java.math.BigInteger(byte[]):
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.
From the docs for System.Numerics.BigInteger(byte[]):
The individual bytes in the value array should be in little-endian order, from lowest-order byte to highest-order byte.
So you might want to just try reversing the input bytes for one of the values you've got - it's not clear which set you should reverse, as we don't know what values you're trying to represent. I would suggest adding diagnostics of just printing out the normal decimal representation immediately after construction in each case - if those aren't the same, the rest of the code is irrelevant.
I solved my problem by adding 0 bit at the begining of inputBytes.

Java byte arrays and copying ints into them

What's the best way to put an int at a certain point in a byte[] array?
Say you have a byte array:
byte[] bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
int someInt = 12355; //0x43, 0x30
How can I do like bytes[4] = someInt; so that now bytes[4] will equal 0x43 and bytes[5] will be equal to 0x30?
I'm used to just using memcpy with C++ and don't know the alternatives in Java.
Thanks
If you want also high 0-bytes of the int put into the byte[]:
void place(int num, byte[] store, int where){
for(int i = 0; i < 4; ++i){
store[where+i] = (byte)(num & 0xFF);
num >>= 8;
}
}
If you only want the bytes to the highest nonzero byte:
void place(int num, byte[] store, int where){
while(num != 0){
store[where++] = (byte)(num & 0xFF);
num >>>= 8;
}
}
If you want the bytes big-endian (highest byte at lowest index), the version storing all four bytes is very easy, the other one slightly more difficult:
void placeBigEndian(int num , byte[] store, int where){
for(int i = 3; i >= 0; --i){
store[where+i] = (byte)(num & 0xFF);
num >>= 8;
}
}
void placeBigEndian(int num, byte[] store, int where){
in mask = 0xFF000000, shift = 24;
while((mask & num) == 0){
mask >>>= 8;
shift -= 8;
}
while(shift > 0){
store[where++] = (byte)((num & mask) >>> shift);
mask >>>= 8;
shift -= 8;
}
}
Note, you assume a big endian ordering! x86 is little endian... What's more, your int is 32bits long, hence 0x00004330 in big endian.
If this is what you want, use a ByteBuffer (which uses big endian ordering by default):
ByteBuffer buf = ByteBuffer.allocate(8);
// then use buf.putInt(yourint, index)
// buf.get(index) will read byte at index index, starting from 0
I don't see the problem, it looks like you solved it your own way:
public static void putShort(bytes[] array, int position, short value)
{
byte leftByte = (byte) (value >>> 8);
byte rightByte = (byte) (value & 0xFF);
array[position] = leftByte;
array[position + 1] = rightByte;
}
Note that an int is 4 bytes and a short is 2 bytes.
First of all, in Java you don't need to initialize byte arrays to zeroes. All arrays are initialized on construction time to 0/false/null.
Second, ints are signed 32-bit big-endian integers, so 12355 is actually 0x00003043. If you want to use 16-bit integers, use the short type.
Then, to get the individual bytes in your integer, you could do:
bytes[ i ] = (byte) (someInt >> 24);
bytes[ i+1 ] = (byte) (someInt >> 16);
bytes[ i+2 ] = (byte) (someInt >> 8);
bytes[ i+3 ] = (byte) (someInt);
The conversion to byte truncates the remaining bits, so no & 0xFF mask is needed. I'm assuming i is the index of the array. To change the endianness, swap the offsets at the indices.
One approach would be to use a DataOutputStream and it's writeInt() method, wrapped around a ByteArrayOutputStream. e.g. (with no error-handling)
public byte[] writeIntAtPositionX(int position, int iVal) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
// now, advancing to a specific spot is awkward.
// presumably you are actually writing other stuff out before the integer
// but if you really want to advance to a specific position
for (int i = 0; i < position; i++)
dos.writeByte(0);
dos.writeInt(iVal);
dos.flush();
dos.close();
return baos.toByteArray();
}
The big advantage of this method is that the guys who wrote Java figured out the byte ordering and the masking with 0xFF and all that stuff. Plus, if you ever envision writing doubles, shorts, longs or Strings etc. to your buffer you won't need to add all those methods, the work is already done.

Categories

Resources