How do I decode a string from base 32 to a BigInteger - java

I tried the following code:
import java.math.BigInteger;
import org.apache.commons.codec.binary.Base32;
import org.junit.Test;
public class Sandbox
{
#Test
public void testSomething() {
String sInput = "GIYTINZUHAZTMNBX";
BigInteger bb = new BigInteger(new Base32().decode(sInput));
System.out.println("number = " + bb);
}
}
and heres the output:
number = 237025977136523702055991
using this website to convert between base 32 I get a different result than the actual output. Heres the result I expect to see based on what I got from the website:
expected output = 2147483647
Any idea why this is happening?
Edit:
Forgive me for making it confusing by purposefully attempting to convert 2^31-1.
Using the conversion website I linked to earlier, I changed the input:
String sInput = "GE4DE===";
Expected output:
number = 182
Actual output:
number = 3225650

What you're doing is correct... assuming that the Base32 string comes from Base32-encoding a byte array you get from calling BigInteger.toByteArray().
BigInteger(byte[] val) does not really take an array of arbitrary bytes. It takes the byte[] representation of a BigInteger. Also, it assumes the most-significant byte is in val[0]).

If it's base-32 the X, Y, and Z shouldn't be there. Are you sure it isn't base-36?

Related

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);

Trying to translate this line of Python to Java- getting different answers

Original Python code:
import hashlib
return int(hashlib.md5("string").hexdigest(), 16) % 100
My attempt to translate into Java:
import java.security.*;
import java.math.*;
String s = "string";
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(s.getBytes(), 0, s.length());
BigInteger i = BigInteger(1,m.digest());
return i % 100;
What am I doing wrong?
I see you haven't even tried to compile this code, since it's not working. BigInteger isn't a primitive type, therefore % operator doesn't work. You should use .mod method instead.
Your code, fixed:
String s = "string";
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(s.getBytes(), 0, s.length());
BigInteger i = new BigInteger(1, m.digest());
return i.mod(BigInteger.valueOf(100));
And since you're updating 0 - s.length(), you can just pass all the bytes to m.digest, make it one line shorter:
String s = "string";
MessageDigest m = MessageDigest.getInstance("MD5");
BigInteger i = new BigInteger(1, m.digest(s.getBytes()));
return i.mod(BigInteger.valueOf(100));
And if you really want an one-liner... Warning, highly unreadable:
return new BigInteger(1, MessageDigest.getInstance("MD5").digest( s.getBytes()) ).mod(BigInteger.valueOf(100));
Suggestion
It's always recommended to specify the encoding of the input string while converting to byte stream.
Without specifying an encoding scheme, programming language implementations are free to choose their default format. This can vary across programming languages and even across different versions of the same programming language.
Python
An advantage of python is, the ability to handle arbitrarily large integer values
import hashlib
data: str = "string"
print(int(hashlib.md5(data.encode('utf-8')).hexdigest(), 16) % 100)
Java
BigInteger is needed to deal with long values outside the Long.MIN_VALUE and Long.MAX_VALUE boundaries.
MessageDigest instances are not thread safe, so use with care(new instances or ThreadLocal) in multithreaded use cases.
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.math.BigInteger;
public class TestMD5 {
private static final String DIGEST_ALGO = "MD5";
public static void main(String[] args) throws Exception {
String data = "string";
byte[] digest = MessageDigest.getInstance(DIGEST_ALGO).digest(data.getBytes(StandardCharsets.UTF_8));
int value = new BigInteger(1, digest).mod(BigInteger.valueOf(100)).intValueExact();
System.out.println(value);
}
}
Both these solutions will print 81 for the given input string
Note
The implementation can print the same value for the given input string even without adding the encoding. It should not relied upon as this string is within the ascii range.
Even for unicode character set, it is recommended to specify encoding as the same code point can be encoded in different encoding schemes like utf-8, utf-16
while converting a byte stream to string, always specify the (de)encoding scheme

How to write a one-byte value in a binary file-java

I have tried a lot with many ways to write a program that : write a one byte value in a file as it is.. for example write 01010101 in a file.. then i want to read the file and print what i wrote.So it should display 01010101. None of my codes worked so. Any help?
Because i am writing a compression program it essential to be 1 byte and not 8
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.File;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main2 {
public static void main(String[] args) throws Exception {
DataOutputStream dos = new DataOutputStream(new FileOutputStream("Text.t"));
dos.writeBytes(String.valueOf(01010101));
File file = new File("Text.t");
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream(file)));
System.out.println(br.readLine());
dos.close();
br.close();
}
}
It works well with binary code that starst with 1 but with 0 not.. for example for 01010101 it shows 266305
The problem with "It works well with binary code that starst with 1 but with 0 not.. for example for 01010101 it shows 266305" is that 01010101 is an octal literal and is read in by the compiler as base-8 (aka Octal).
Use 1010101 when writing the literal - leading zeros mean nothing to numbers; but they do mean something to how the Java code is parsed!
Decimal numbers that are displayed as "00xyz" are often zero-padded, which is applied to the string representation; the number itself is xyz.
From the comment I believe the desired operation is to use a binary literal. You'll have to emit this using a "bit converter" to display as expected - the bit converter will take the value of eg. 0b11 (integer 3) and turn it into a string "11". You may also want to apply a padding with an assumed output width - again, 0b01 == 0b1 and the leading 0 means nothing to an integer.
The following will emit the decimal string representation of the huffman bit sequence, without any leading zeros. However this when paired with above should get you off on the right track.
dos.writeBytes(String.valueOf(0b01001010));
I would use a Byte representation for radix 2 e.g. Byte.parseByte("00010001", 2).
But the problem is Java's primitives are signed numbers so it won't work for negative values (when first digit is 1), thus Byte.parseByte("10010011", 2) will throw a NumberFormatException.
The trick here is to initially replace leading digit (if it is 1, with 0), parse it and then set the bit again to 1. Then store this byte to your file.
private static byte binaryStringToByte(String s) {
//also check for null, length = 8, contain 0/1 only etc.
if (s.startsWith("0")) {
return Byte.parseByte(s, 2);
} else {
StringBuilder sBuilder = new StringBuilder(s);
sBuilder.setCharAt(0, '0');
byte temp = Byte.parseByte(sBuilder.toString(), 2);
return (byte) (temp | (1 << 7));
}
}
Then, to get the binary String representation of a byte use this code:
byte b = binaryStringToByte("10001000");
String s1 = String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0');

java convert to int

I am trying to convert to int like this, but I am getting an exception.
String strHexNumber = "0x1";
int decimalNumber = Integer.parseInt(strHexNumber, 16);
Exception in thread "main" java.lang.NumberFormatException: For input string: "0x1"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:458)
It would be a great help if someone can fix it.
Thanks.
That's because the 0x prefix is not allowed. It's only a Java language thing.
String strHexNumber = "F777";
int decimalNumber = Integer.parseInt(strHexNumber, 16);
System.out.println(decimalNumber);
If you want to parse strings with leading 0x then use the .decode methods available on Integer, Long etc.
int value = Integer.decode("0x12AF");
System.out.println(value);
Sure - you need to get rid of the "0x" part if you want to use parseInt:
int parsed = Integer.parseInt("100", 16);
System.out.println(parsed); // 256
If you know your value will start with "0x" you can just use:
String prefixStripped = hexNumber.substring(2);
Otherwise, just test for it:
number = number.startsWith("0x") ? number.substring(2) : number;
Note that you should think about how negative numbers will be represented too.
EDIT: Adam's solution using decode will certainly work, but if you already know the radix then IMO it's clearer to state it explicitly than to have it inferred - particularly if it would surprise people for "035" to be treated as octal, for example. Each method is appropriate at different times, of course, so it's worth knowing about both. Pick whichever one handles your particular situation most cleanly and clearly.
Integer.parseInt can only parse strings that are formatted to look just like an int. So you can parse "0" or "12343" or "-56" but not "0x1".
You need to strip off the 0x from the front of the string before you ask the Integer class to parse it. The parseInt method expects the string passed in to be only numbers/letters of the specified radix.
try using this code here:-
import java.io.*;
import java.lang.*;
public class HexaToInteger{
public static void main(String[] args) throws IOException{
BufferedReader read =
new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter the hexadecimal value:!");
String s = read.readLine();
int i = Integer.valueOf(s, 16).intValue();
System.out.println("Integer:=" + i);
}
}
Yeah, Integer is still expecting some kind of String of numbers. that x is really going to mess things up.
Depending on the size of the hex, you may need to use a BigInteger (you can probably skip the "L" check and trim in yours ;-) ):
// Convert HEX to decimal
if (category.startsWith("0X") && category.endsWith("L")) {
category = new BigInteger(category.substring(2, category.length() - 1), 16).toString();
} else if (category.startsWith("0X")) {
category = new BigInteger(category.substring(2, category.length()), 16).toString();
}

Categories