Binary strings to Hex strings java - java

I have this code here, which get a plain text, and turns it to a 512-bit binary string.
Then, I would like to turn each 32-bit piece of the string to 8-bit of Hex string, but that part gives me a java.lang.NumberFormatException
// ----- Turning the message to bits
byte[] binaryS = s.getBytes("UTF-8");
String mesInBinary = "";
for (byte b : binaryS) {
mesInBinary += '0' + Integer.toBinaryString(b);
}
// ----- Message padding & Pre-Processing
// Binary representation of the length of the message in bits
String mesBitLength = Integer.toBinaryString(mesInBinary.length());
// We need the size of the message in 64-bits, so we'll
// append zeros to the binary length of the message so
// we get 64-bit
String appendedZeros = "";
for (int i = 64 - mesBitLength.length() ; i > 0 ; i--)
appendedZeros += '0';
// Calculating the k zeros to append to the message after
// the appended '1'
int numberOfZeros = (448 - (mesInBinary.length() + 1)) % 512;
// Append '1' to the message
mesInBinary += '1';
// We need a positive k
while (numberOfZeros < 0)
numberOfZeros += 512;
for (int i = 1 ; i <= numberOfZeros ; i++)
mesInBinary += '0';
// append the message length in 64-bit format
mesInBinary += appendedZeros + mesBitLength;
System.out.println(mesInBinary);
// ----- Parsing the padded message
// Breaking the message to 512-bit pieces
// And each piece, to 16 32-bit word blocks
String[] chunks = new String[mesInBinary.length() / 512];
String[] words = new String[64 * chunks.length];
for (int i = 0 ; i < chunks.length ; i++) {
chunks[i] = mesInBinary.substring((512 * i), (512 * (i + 1)));
// Break each chunk to 16 32-bit blocks
for (int j = 0 ; j < 16 ; j++) {
words[j] = Long.toHexString(Long.parseLong(chunks[i].substring((32 * j), (32 * (j + 1)))));
}
}
The last code line is the problematic one and of which I get the execption. Any suggestions?

The last statement* should specify a radix of 2, I think:
words[j] = Long.toHexString(
Long.parseLong(chunks[i].substring((32 * j), (32 * (j + 1))), 2));
*Not the last line of code, MДΓΓ :-)

From the Long docs:
public static long parseLong(String s) throws NumberFormatException:
Parses the string argument as a signed decimal long. The characters in the string must all be decimal digits...
public static long parseLong(String s, int radix) throws NumberFormatException:
Parses the string argument as a signed long in the radix specified by the second argument. The characters in the string must all be digits of the specified radix...
You're calling the first version of Long.parseLong(), which expects a decimal number, not a binary one. Use the second version with a radix of 2 to indicate binary.
EDIT: The reason being that a 32-digit decimal number won't fit into a Long, but a binary one will.

for (int i = 0 ; i < chunks.length ; i++)
{
chunks[i] = mesInBinary.substring((512 * i), (512 * (i + 1)));
// Break each chunk to 16 32-bit blocks
for (int j = 0 ; j < 16 ; j++)
{
words[j] = Long.toHexString(Long.parseLong(chunks[i].substring((32 * j), (32 * (j + 1))),2));
}
}

Related

Best way to convert parts of a string to int to convert from binary to float JAVA

I am writing a program where I have strings of 9 bits of "0" and "1" to convert to exponent (taking each index and doing 2 ^ n from right to left).
example: ["1","0","1"] = 2^2 + 0^1 + 2^0
I know this is wrong because of the errors I am getting but am confused what to do which will calculate it in an efficient manner.
expoBefore = (strNum.charAt(9)) * 1 + (strNum.charAt(8)) * 2 + (strNum.charAt(7)) * 4 + (strNum.charAt(6)) * 8 + (strNum.charAt(5)) * 16 + (strNum.charAt(4)) * 32 + (strNum.charAt(3)) * 64 + (strNum.charAt(8)) * 128;
for example for one of the strings I am passing through [11111111] I want it to add 1 * 2^0 + 1 * 2 ^1 + 1 * 2^2.....etc
Clarification edit:
What is a more efficient way of converting a string of 0's and 1's to an integer?
You're trying to multiply a character's ascii value with an integer.
You must take the integer value of this character and then multiply it with another integer. Hope this helps.
String str = "111";
int x = Character.getNumericValue(str.charAt(0));
int y = Character.getNumericValue(str.charAt(1));
int z = Character.getNumericValue(str.charAt(2));
System.out.println(x + y + z);
Output:
3
You need to use a loop.
Iterate over the binary string. For each character, add 2^x to an accumulator if the bit is set (where x is the position of the bit), otherwise, add 0.
String binary = "11111111";
int number = 0;
for(int i = binary.length() - 1; i >= 0; i--) {
char c = binary.charAt(i);
number += Integer.parseInt(c + "") * Math.pow(2, binary.length() - i - 1);
}
System.out.println(number); // prints 255
How to convert binary to decimal
Just use a for loop and increment down to miniplate each number
It is very inefficient to use Math.pow(2, i) in a loop.
Faster to keep the previous value and multiply by 2 each time through (code untested):
int ip = 1;
int sum = 0;
for ( int i = binary.length -1; i >= 0) {
if ( binary.charAt(i) == '1' ) {
sum += ip;
}
ip *= 2;
}
You may want to use long ints if the number gets large.
Also, be sure to check that binary contains only zeroes and ones.

Caesar Cipher with Ascii Characters

I'm trying to encrypt a String using ascii characters with a key position integer. I've got two methods, one for encrypting, one for decrypting.
The problem is that when the character value is above 126, I try to mod 126 it and then add 32 back into it but I get numbers far out of these limits.
public static String encrypt(String s, int k) {
char[] arr = s.toCharArray();
int ascii;
for(int i = 0; i < arr.length; i++) {
ascii = (int) arr[i];
ascii = ascii + k;
// System.out.println(ascii);
if (ascii > 126) {
ascii = 32 + (126 % ascii);
// System.out.print("Changed: " + ascii);
}
arr[i] = (char) ascii;
}
return String.valueOf(arr);
}
The two commented out lines were for testing, and the changed values are crazy high, like instead of going from 127 % 126 = 1 + 32 for a total of 33 (intended value), I get 15870.
First, as mypetlion mentioned, the modulo operation a % b equals the remainder when a is divided by b. E.g. 11 % 4 = 3, 8 % 15 = 8. To be precise, it is the value k that satisfies b * n + k = a, b * (n + 1) > a, k < b where n is an integer. There are more appropriate descriptions using discrete maths and I'm ignoring negative arguments but they are not important. So in your case you should be doing ascii % 128.
As of why the modulo should be 128 and not 126, 7 bit ascii code goes from 0-127, 128 values in total. Also I'm a bit confused as to what the +32 is for, since you already did +k.
Also you can omit your if block completely because c % 128 = c for any c in range [0, 128).
So I would write the following code:
public static String encrypt(String s, int k) {
char[] arr = s.toCharArray();
for(int i = 0; i < arr.length; i++){
arr[i] = (char) ((arr[i] + k) % 128);
}
return String.valueOf(arr);
}
public static String decrypt(String s, int k) {
char[] arr = s.toCharArray();
for(int i = 0; i < arr.length; i++){
arr[i] = (char) ((arr[i] + 128 - k % 128) % 128);
// + 128 - k % 128 because I don't want do deal with negative numbers.
}
return String.valueOf(arr);
}
I am confident my code will work (for all positive values of k), but I cannot explain why your code produced some crazy high ascii values. When I ran your code on my IDE it didn't do that nor could I see why it would from your code.
Finally, this cipher method will encrypt and decrypt alright, but note that ascii does contain lots of control characters that are not print-friendly. So if you want to limit your cipher vocabulary to only letters and punctuations, you would need to do some character mapping to limit the characters you want to encrypt and encrypt to. This will be much more complicated, not to mention that you would have to consider problems like CR+LF in Windows v. LF in Unix. The following is a simple example that only encrypts and decrypts letters.
public static int asciiToCustom(char ascii) {
// Maps 65-90 & 97-122 to 0-51.
int customCode;
if(ascii >= 65 && ascii <= 90){
customCode = ascii - 65;
}
else if(ascii >= 97 && ascii <= 122){
customCode = ascii - 71;
}
else{
throw new RuntimeException("not a letter!");
}
return customCode;
}
public static char customToAscii(int custom) {
// Maps 0-51 to 65-90 & 97-122.
int ascii;
if(custom >= 0 && custom <= 25){
ascii = custom + 65;
}
else if(custom >= 26 && custom <= 51){
ascii = custom + 71;
}
else{
throw new RuntimeException("not a valid custom code!");
}
return (char) ascii;
}
public static String encrypt(String s, int k) {
char[] arr = s.toCharArray();
for(int i = 0; i < arr.length; i++){
if(Character.isLetter(arr[i])){
arr[i] = customToAscii((asciiToCustom(arr[i]) + k) % 52);
}
}
return String.valueOf(arr);
}
public static String decrypt(String s, int k) {
char[] arr = s.toCharArray();
for(int i = 0; i < arr.length; i++){
if(Character.isLetter(arr[i])){
arr[i] = customToAscii((asciiToCustom(arr[i]) + 52 - k % 52) % 52);
// + 52 - k % 52 because I don't want do deal with negative numbers.
}
}
return String.valueOf(arr);
}
Your modulo statement is written backwards for a start. Try:
ascii = 32 + (ascii % 126);

Convert each character of a string in bits

String message= "10";
byte[] bytes = message.getBytes();
for (int n = 0; n < bytes.length; n++) {
byte b = bytes[n];
for (int i = 0; i < 8; i++) {//do something for each bit in my byte
boolean bit = ((b >> (7 - i) & 1) == 1);
}
}
My problem here is that it takes 1 and 0 as their ASCII values, 49 and 48, instead of 1 and 0 as binary(00000001 and 00000000). How can I make my program treat each character from my string as a binary sequence of 8 bits?
Basicly, I want to treat each bit of my number as a byte. I do that like this byte b = bytes[n]; but the program treats it as the ASCII value.
I could assign the number to an int, but then, I can't assign the bits to a byte.
It's a bit messy, but the first thing that comes to mind is to first, split your message up into char values, using the toCharArray() method. Next, use the Character.getNumericValue() method to return the int, and finally Integer.toBinaryString.
Example
String message = "123456";
for(char c : message.toCharArray())
{
int numVal = Character.getNumericValue(c);
String binaryString = Integer.toBinaryString(numVal);
for(char bit : binaryString)
{
// Do something with your bits.
}
}
String msg = "1234";
for(int i=0 ; i<msg.length() ; i++ ){
String bits = Integer.toBinaryString(Integer.parseInt(msg.substring(i, i+1)));
for(int j=0;j<8-bits.length();j++)
bits = "0"+bits;
}
Now bits is a string of length 8.
1
00000001
10
00000010
11
00000011
100
00000100
You can use getBytes() on the String
Use Java's parseInt(String s, int radix):
String message= "10";
int myInt = Integer.parseInt(message, 2); //because we are parsing it as base 2
At that point you have the correct sequence of bits, and you can do your bit-shifting.
boolean[] bits = new boolean[message.length()];
System.out.println("Parsed bits: ");
for (int i = message.length()-1; i >=0 ; i--) {
bits[i] = (myInt & (1 << i)) != 0;
System.out.print(bits[i] ? "1":"0");
}
System.out.println();
You could make it bytes if you really want to, but booleans are a better representation of bits...

Java converting negative binary back to integer

I'm trying to convert an base 10 number to a base 2 and back to base 10. It works only for positive argument_decimal
argument_binary = Integer.toBinaryString(argument_decimal);
back_converted_argument_decimal = Integer.valueOf(argument_binary, 2);
For argument_decimal beeing negative, I get "java.lang.NumberFormatException: For input string: "11111111111111111111111111111111""
EDIT: here is what I do:
latitude_binary = Integer.toBinaryString((int)(latitude_decimal * 1000000));
back_converted_latitude_decimal = Long.parseLong(latitude_binary, 2) / 1000000.0;
which gives me bad results like -1.1 being forth and back converted to 4293.867296
Try to go via a long:
String binary = Integer.toBinaryString(-1);
long l = Long.parseLong(binary, 2);
int i = (int) l;
Tested, and working.
Why this works is because -1 is represented as a sequence of 32 bits 1 in system memory. When using the toBinaryString method, it creates a string using that exact representation. But, 32 bits of one is in fact equal to 2^32 - 1. That is too large for an int (4 bytes), because an int goes from [-2^31, 2^31-1]. This is because the most left bit is representing the sign. So to fix that overflow, first interpret that sequence of 1 and 0 characters as a Long. A long will do because the maximum value for a long is 2^63-1. Then convert the long to an int. This is done by simply taking the lower 32 bits.
The bug in your code is that you didn't cast the Long.parseLong to an int. So this should work:
lat_bin = Integer.toBinaryString((int)(lat_dec * 1000000));
lat_dec_conv = ((int) Long.parseLong(lat_bin, 2)) / 1000000.0;
public static void convertStringToDecimal(String binary) {
int decimal = 0;
int power = 0;
if (binary.charAt(0) == '1' && binary.length() == 32) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < binary.length(); i++) {
builder.append((binary.charAt(i) == '1' ? '0' : '1'));
}
while (binary.length() > 0) {
int temp = Integer
.parseInt(builder.charAt((binary.length()) - 1)+"");
decimal += temp * Math.pow(2, power++);
binary = binary.substring(0, binary.length() - 1);
}
System.out.println((decimal + 1) * (-1));
} else {
while (binary.length() > 0) {
int temp = Integer
.parseInt(binary.charAt((binary.length()) - 1) + "");
decimal += temp * Math.pow(2, power++);
binary = binary.substring(0, binary.length() - 1);
}
System.out.println(decimal);
}
}

Integer to two digits hex in Java

I need to change a integer value into 2-digit hex value in Java.Is there any way for this.
Thanks
My biggest number will be 63 and smallest will be 0.
I want a leading zero for small values.
String.format("%02X", value);
If you use X instead of x as suggested by aristar, then you don't need to use .toUpperCase().
Integer.toHexString(42);
Javadoc: http://docs.oracle.com/javase/6/docs/api/java/lang/Integer.html#toHexString(int)
Note that this may give you more than 2 digits, however! (An Integer is 4 bytes, so you could potentially get back 8 characters.)
Here's a bit of a hack to get your padding, as long as you are absolutely sure that you're only dealing with single-byte values (255 or less):
Integer.toHexString(0x100 | 42).substring(1)
Many more (and better) solutions at Left padding integers (non-decimal format) with zeros in Java.
String.format("%02X", (0xFF & value));
Use Integer.toHexString(). Dont forget to pad with a leading zero if you only end up with one digit. If your integer is greater than 255 you'll get more than 2 digits.
StringBuilder sb = new StringBuilder();
sb.append(Integer.toHexString(myInt));
if (sb.length() < 2) {
sb.insert(0, '0'); // pad with leading zero if needed
}
String hex = sb.toString();
If you just need to print them try this:
for(int a = 0; a < 255; a++){
if( a % 16 == 0){
System.out.println();
}
System.out.printf("%02x ", a);
}
i use this to get a string representing the equivalent hex value of an integer separated by space for every byte
EX : hex val of 260 in 4 bytes = 00 00 01 04
public static String getHexValString(Integer val, int bytePercision){
StringBuilder sb = new StringBuilder();
sb.append(Integer.toHexString(val));
while(sb.length() < bytePercision*2){
sb.insert(0,'0');// pad with leading zero
}
int l = sb.length(); // total string length before spaces
int r = l/2; //num of rquired iterations
for (int i=1; i < r; i++){
int x = l-(2*i); //space postion
sb.insert(x, ' ');
}
return sb.toString().toUpperCase();
}
public static void main(String []args){
System.out.println("hex val of 260 in 4 bytes = " + getHexValString(260,4));
}
According to GabrielOshiro, If you want format integer to length 8, try this
String.format("0x%08X", 20) //print 0x00000014

Categories