Related
I'm trying to understand a byte[] to string, string representation of byte[] to byte[] conversion... I convert my byte[] to a string to send, I then expect my web service (written in python) to echo the data straight back to the client.
When I send the data from my Java application...
Arrays.toString(data.toByteArray())
Bytes to send..
[B#405217f8
Send (This is the result of Arrays.toString() which should be a string representation of my byte data, this data will be sent across the wire):
[-47, 1, 16, 84, 2, 101, 110, 83, 111, 109, 101, 32, 78, 70, 67, 32, 68, 97, 116, 97]
On the python side, the python server returns a string to the caller (which I can see is the same as the string I sent to the server
[-47, 1, 16, 84, 2, 101, 110, 83, 111, 109, 101, 32, 78, 70, 67, 32, 68, 97, 116, 97]
The server should return this data to the client, where it can be verified.
The response my client receives (as a string) looks like
[-47, 1, 16, 84, 2, 101, 110, 83, 111, 109, 101, 32, 78, 70, 67, 32, 68, 97, 116, 97]
I can't seem to figure out how to get the received string back into a
byte[]
Whatever I seem to try I end up getting a byte array which looks as follows...
[91, 45, 52, 55, 44, 32, 49, 44, 32, 49, 54, 44, 32, 56, 52, 44, 32, 50, 44, 32, 49, 48, 49, 44, 32, 49, 49, 48, 44, 32, 56, 51, 44, 32, 49, 49, 49, 44, 32, 49, 48, 57, 44, 32, 49, 48, 49, 44, 32, 51, 50, 44, 32, 55, 56, 44, 32, 55, 48, 44, 32, 54, 55, 44, 32, 51, 50, 44, 32, 54, 56, 44, 32, 57, 55, 44, 32, 49, 49, 54, 44, 32, 57, 55, 93]
or I can get a byte representation which is as follows:
B#2a80d889
Both of these are different from my sent data... I'm sure Im missing something truly simple....
Any help?!
You can't just take the returned string and construct a string from it... it's not a byte[] data type anymore, it's already a string; you need to parse it. For example :
String response = "[-47, 1, 16, 84, 2, 101, 110, 83, 111, 109, 101, 32, 78, 70, 67, 32, 68, 97, 116, 97]"; // response from the Python script
String[] byteValues = response.substring(1, response.length() - 1).split(",");
byte[] bytes = new byte[byteValues.length];
for (int i=0, len=bytes.length; i<len; i++) {
bytes[i] = Byte.parseByte(byteValues[i].trim());
}
String str = new String(bytes);
** EDIT **
You get an hint of your problem in your question, where you say "Whatever I seem to try I end up getting a byte array which looks as follows... [91, 45, ...", because 91 is the byte value for [, so [91, 45, ... is the byte array of the string "[-45, 1, 16, ..." string.
The method Arrays.toString() will return a String representation of the specified array; meaning that the returned value will not be a array anymore. For example :
byte[] b1 = new byte[] {97, 98, 99};
String s1 = Arrays.toString(b1);
String s2 = new String(b1);
System.out.println(s1); // -> "[97, 98, 99]"
System.out.println(s2); // -> "abc";
As you can see, s1 holds the string representation of the array b1, while s2 holds the string representation of the bytes contained in b1.
Now, in your problem, your server returns a string similar to s1, therefore to get the array representation back, you need the opposite constructor method. If s2.getBytes() is the opposite of new String(b1), you need to find the opposite of Arrays.toString(b1), thus the code I pasted in the first snippet of this answer.
String coolString = "cool string";
byte[] byteArray = coolString.getBytes();
String reconstitutedString = new String(byteArray);
System.out.println(reconstitutedString);
That outputs "cool string" to the console.
It's pretty darn easy.
What I did:
return to clients:
byte[] result = ****encrypted data****;
String str = Base64.encodeBase64String(result);
return str;
receive from clients:
byte[] bytes = Base64.decodeBase64(str);
your data will be transferred in this format:
OpfyN9paAouZ2Pw+gDgGsDWzjIphmaZbUyFx5oRIN1kkQ1tDbgoi84dRfklf1OZVdpAV7TonlTDHBOr93EXIEBoY1vuQnKXaG+CJyIfrCWbEENJ0gOVBr9W3OlFcGsZW5Cf9uirSmx/JLLxTrejZzbgq3lpToYc3vkyPy5Y/oFWYljy/3OcC/S458uZFOc/FfDqWGtT9pTUdxLDOwQ6EMe0oJBlMXm8J2tGnRja4F/aVHfQddha2nUMi6zlvAm8i9KnsWmQG//ok25EHDbrFBP2Ia/6Bx/SGS4skk/0couKwcPVXtTq8qpNh/aYK1mclg7TBKHfF+DHppwd30VULpA==
What Arrays.toString() does is create a string representation of each individual byte in your byteArray.
Please check the API documentation
Arrays API
To convert your response string back to the original byte array, you have to use split(",") or something and convert it into a collection and then convert each individual item in there to a byte to recreate your byte array.
Its simple to convert byte array to string and string back to byte array in java. we need to know when to use 'new' in the right way.
It can be done as follows:
byte array to string conversion:
byte[] bytes = initializeByteArray();
String str = new String(bytes);
String to byte array conversion:
String str = "Hello"
byte[] bytes = str.getBytes();
For more details, look at:
http://evverythingatonce.blogspot.in/2014/01/tech-talkbyte-array-and-string.html
The kind of output you are seeing from your byte array ([B#405217f8) is also an output for a zero length byte array (ie new byte[0]). It looks like this string is a reference to the array rather than a description of the contents of the array like we might expect from a regular collection's toString() method.
As with other respondents, I would point you to the String constructors that accept a byte[] parameter to construct a string from the contents of a byte array. You should be able to read raw bytes from a socket's InputStream if you want to obtain bytes from a TCP connection.
If you have already read those bytes as a String (using an InputStreamReader), then, the string can be converted to bytes using the getBytes() function. Be sure to pass in your desired character set to both the String constructor and getBytes() functions, and this will only work if the byte data can be converted to characters by the InputStreamReader.
If you want to deal with raw bytes you should really avoid using this stream reader layer.
Can you not just send the bytes as bytes, or convert each byte to a character and send as a string? Doing it like you are will take up a minimum of 85 characters in the string, when you only have 11 bytes to send. You could create a string representation of the bytes, so it'd be "[B#405217f8", which can easily be converted to a bytes or bytearray object in Python. Failing that, you could represent them as a series of hexadecimal digits ("5b42403430353231376638") taking up 22 characters, which could be easily decoded on the Python side using binascii.unhexlify().
[JDK8]
import java.util.Base64;
To string:
String str = Base64.getEncoder().encode(new byte[]{ -47, 1, 16, ... });
To byte array:
byte[] bytes = Base64.getDecoder().decode("JVBERi0xLjQKMyAwIG9iago8P...");
If you want to convert the string back into a byte array you will need to use String.getBytes() (or equivalent Python function) and this will allow you print out the original byte array.
Use the below code API to convert bytecode as string to Byte array.
byte[] byteArray = DatatypeConverter.parseBase64Binary("JVBERi0xLjQKMyAwIG9iago8P...");
[JAVA 8]
import java.util.Base64;
String dummy= "dummy string";
byte[] byteArray = dummy.getBytes();
byte[] salt = new byte[]{ -47, 1, 16, ... }
String encoded = Base64.getEncoder().encodeToString(salt);
You can do the following to convert byte array to string and then convert that string to byte array:
// 1. convert byte array to string and then string to byte array
// convert byte array to string
byte[] by_original = {0, 1, -2, 3, -4, -5, 6};
String str1 = Arrays.toString(by_original);
System.out.println(str1); // output: [0, 1, -2, 3, -4, -5, 6]
// convert string to byte array
String newString = str1.substring(1, str1.length()-1);
String[] stringArray = newString.split(", ");
byte[] by_new = new byte[stringArray.length];
for(int i=0; i<stringArray.length; i++) {
by_new[i] = (byte) Integer.parseInt(stringArray[i]);
}
System.out.println(Arrays.toString(by_new)); // output: [0, 1, -2, 3, -4, -5, 6]
But to convert the string to byte array and then convert that byte array to string, below approach can be used:
// 2. convert string to byte array and then byte array to string
// convert string to byte array
String str2 = "[0, 1, -2, 3, -4, -5, 6]";
byte[] byteStr2 = str2.getBytes(StandardCharsets.UTF_8);
// Now byteStr2 is [91, 48, 44, 32, 49, 44, 32, 45, 50, 44, 32, 51, 44, 32, 45, 52, 44, 32, 45, 53, 44, 32, 54, 93]
// convert byte array to string
System.out.println(new String(byteStr2, StandardCharsets.UTF_8)); // output: [0, 1, -2, 3, -4, -5, 6]
I have also answered the same in the following question:
https://stackoverflow.com/a/70486387/17364272
I have this code:
private static c e;
private static byte[] f = { 55, -86, -102, 55, -23, 26, -83, 103, 125, -57, -110, -34, 70, 102, 48, -103 };
private String a;
private SecureRandom b;
private int c;
private byte[] d;
public c(String paramString, SecureRandom paramSecureRandom)
{
this.a = paramString;
this.b = paramSecureRandom;
}
public static c a()
{
if (e == null)
{
e = new c("AES/CBC/PKCS7Padding", new SecureRandom());
e.a(f, 16);
}
return e;
}
With f being the array of bytes and 16 to do with reading 16 bytes of the IV generated with SecureRandom(). (atleast I assume that's what it is doing?) However when I use this:
byte[] byteArray = { 55, -86, -102, 55, -23, 26, -83, 103, 125, -57, -110, -34, 70, 102, 48, -103 };
String value = new String(byteArray, "ISO-8859-1");
System.out.println(value);
I get this output: 7ª7ég}ÇÞFf0
I'm attempting to work out how this app i've got generates the encryptionkey used for encrypting/decrypting... that result above surely can't be anything right? Am I completely on the wrong track here?
I've included the full class code here incase it helps: http://pastie.org/private/5fhp9yqknzoansd1vc0xfg
Would really love to know what the code above is actually doing so I can port it to PHP, not too good # Java.
Thanks in advance.
Your output 7ª7ég}ÇÞFf0 makes sense to me.
You are using the character set: ISO-8859-1, and thus the bytes will be decoded to the characters they are mapped to in that character set.
Your byte array is created using base 10, and java bytes are signed. This means your byte array has the following hexadecimal values (in order):
37, AA, 9A, 37, E9, 1A, AD, 67, 7D, C7, 92, DE, 46, 66, 30, 99
According to the ISO-8859-1 character set, these values map to the following:
7, ª, (nil), 7, é, (nil), SHY, g, }, Ç, (nil), Þ, F, f, 0, (nil)
Which is pretty close to what your string is actually. The (nil) characters are not rendered in your string because the character set does not have glyphs for the corresponding values. And for the character SHY, I will assume again there is no glyph (while the standard indicates there actually should be).
Your output seems correct to me! :)
Remember, your encryption key is just a sequence of bytes. You shouldn't expect the data to be human-readable.
I saw problem in this piece of code:
byte[] buf = new byte[6];
buf = "abcdef".getBytes();
System.out.println(buf.length);
Array was made for 6 bytes. If I get bytes from string with length 6 I will get much more bytes. So how will all these bytes get into this array? But this is working. Moreover, buf.length shows length of that array as it is array of chars not those bytes.
Afterwards, I realized that in
byte[] buf = new byte[6];
6 does not mean much, i.e. I can put there 0 or 1 or 2 or so on and code will work (with buf.length showing length of given string not array - what I see as second problem or discrepancy).
This question is different than Why does Java's String.getBytes() uses “ISO-8859-1” because it have one aspect more, at least: variables assignment oversight (getBytes() returns new array), i.e. it don't fully address my question.
That is not how variable assignments work
Thinking that assigning a 6 byte array to a variable will limit the length of any other arrays assigned to the same variable show a fundamental lack of comprehension on what variable are and how they work.
Really think about why you think assigning a variable to a fixed length array would limit the length of being assigned to another length array?
Strings are Unicode in Java
Strings in Java are Unicode and internally represented as UTF-16 which means they are 2 or 4 bytes per character in memory.
When they are converted to a byte array the number of bytes that represents the string is determined by what encoding is used when converting to the byte[].
Always specify an appropriate character encoding when converting Strings to arrays to get what you expect.
But even then UTF-8 would not guarantee single bytes per character, and ASCII would be not be able to represent non ASCII Unicode characters.
Character encoding is tricky
The ubiquitous internet encoding standard is UTF-8 it will correct in 99.9999999% of all cases, in those cases it isn't converting UTF-8 to the correct encoding is trivial because UTF-8 is so well supported in every toolchain.
Learn to make everything final and you will a lot easier time and less confusion.
import com.google.common.base.Charsets;
import javax.annotation.Nonnull;
import java.util.Arrays;
public class Scratch
{
public static void main(final String[] args)
{
printWithEncodings("Hello World!");
printWithEncodings("こんにちは世界!");
}
private static void printWithEncodings(#Nonnull final String s)
{
System.out.println("s = " + s);
final byte[] defaultEncoding = s.getBytes(); // never do this, you do not know what you will get!
// for ASCII characters the first three will all be the same single byte representations
final byte[] iso88591Encoding = s.getBytes(Charsets.ISO_8859_1);
final byte[] asciiEncoding = s.getBytes(Charsets.US_ASCII);
final byte[] utf8Encoding = s.getBytes(Charsets.UTF_8);
final byte[] utf16Encoding = s.getBytes(Charsets.UTF_16);
System.out.println("Arrays.toString(defaultEncoding) = " + Arrays.toString(defaultEncoding));
System.out.println("Arrays.toString(iso88591) = " + Arrays.toString(iso88591Encoding));
System.out.println("Arrays.toString(asciiEncoding) = " + Arrays.toString(asciiEncoding));
System.out.println("Arrays.toString(utf8Encoding) = " + Arrays.toString(utf8Encoding));
System.out.println("Arrays.toString(utf16Encoding) = " + Arrays.toString(utf16Encoding));
}
}
results in
s = Hello World!
Arrays.toString(defaultEncoding) = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
Arrays.toString(iso88591) = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
Arrays.toString(asciiEncoding) = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
Arrays.toString(utf8Encoding) = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
Arrays.toString(utf16Encoding) = [-2, -1, 0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 33]
s = こんにちは世界!
Arrays.toString(defaultEncoding) = [-29, -127, -109, -29, -126, -109, -29, -127, -85, -29, -127, -95, -29, -127, -81, -28, -72, -106, -25, -107, -116, 33]
Arrays.toString(iso88591) = [63, 63, 63, 63, 63, 63, 63, 33]
Arrays.toString(asciiEncoding) = [63, 63, 63, 63, 63, 63, 63, 33]
Arrays.toString(utf8Encoding) = [-29, -127, -109, -29, -126, -109, -29, -127, -85, -29, -127, -95, -29, -127, -81, -28, -72, -106, -25, -107, -116, 33]
Arrays.toString(utf16Encoding) = [-2, -1, 48, 83, 48, -109, 48, 107, 48, 97, 48, 111, 78, 22, 117, 76, 0, 33]
Always specify the Charset encoding!
.bytes(Charset) is always the correct way to convert a String to bytes. Use whatever encoding you need.
Internally supported encodings for JDK7
new byte[6]; has no effect whatsoever as the array reference buf is getting updated with reference of the array returned by "abcdef".getBytes();.
That's because String.getBytes() returns an entirely different array object which is then assigned to buf. You could have just as easily done this:
byte[] buf = "abcdef".getBytes();
System.out.println(buf.length);
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 7 years ago.
Improve this question
I have a byte array, and I want to compute the MD5 hash in java and C# separately. However, their generate very different result.
below is my C# code:
byte[] input = { 90, 12, 200, 139, 85, 104, 9, 202, 0, 0, 0, 0, 28, 251, 54, 201, 233, 153, 79, 1 };
MD5 md5 = MD5.Create();
byte[] result = md5.ComputeHash(input);
It generate md5 hash: 85,126,37,15,86,254,54,94,243,185,219,84,21,17,192,153,.
and below is the java code:
byte[] input = {90,12,-56,-117,85,104,9,-54,0,0,0,0,28,-5,54,-47,-23,-103,79,1};
byte[] md5 = MessageDigest.getInstance("MD5").digest(input);
and it results in:
-56,-74,-89,-76,9,35,-83,-89,-73,-39,17,83,24,18,-91,-62,
As you can see, the results are quite different. I know c# use unsigned byte, java uses signed byte. There is no way make me believe the results are identical.
Thanks in advance.
Your C# and Java inputs aren't the same.
Let's try to convert the C# input to signed bytes:
byte[] input = { 90, 12, 200, 139, 85, 104, 9, 202, 0, 0, 0, 0, 28, 251, 54, 201, 233, 153, 79, 1 };
sbyte[] signedInput = input.Select(i => unchecked((sbyte)i)).ToArray();
Console.WriteLine(string.Join(", ", signedInput));
This outputs:
90, 12, -56, -117, 85, 104, 9, -54, 0, 0, 0, 0, 28, -5, 54, -55, -23, -103, 79, 1
There's a different byte here, in bold. The Java version contains -47 at this offset.
And just to be sure, we can do a simple check using the Java version's input:
var javaInput = new[] { 90, 12, -56, -117, 85, 104, 9, -54, 0, 0, 0, 0, 28, -5, 54, -47, -23, -103, 79, 1 };
var javaInputUnsigned = javaInput.Select(i => unchecked((byte)i)).ToArray();
var hash = MD5.Create().ComputeHash(javaInputUnsigned).Select(i => unchecked((sbyte)i)).ToArray();
Console.WriteLine(string.Join(", ", hash));
This yields the same result as in the Java version:
-56, -74, -89, -76, 9, 35, -83, -89, -73, -39, 17, 83, 24, 18, -91, -62
I am trying to encrypt the password using a salt and storing it into the MySQL database.
I referred to this stackOverflow question
My code is similar to this:
private byte[] encrypt(String passwordToSave, byte[] salt)
throws UnsupportedEncodingException
{
int seedBytes = 20;
int hashBytes = 20;
int iterations = 1000;
if(null == salt)
{
SecureRandom rng = new SecureRandom();
salt = rng.generateSeed(seedBytes);
}
PKCS5S2ParametersGenerator kdf = new PKCS5S2ParametersGenerator();
kdf.init(passwordToSave.getBytes("UTF-8"), salt, iterations);
byte[] hash =
((KeyParameter) kdf.generateDerivedMacParameters(8*hashBytes)).getKey();
return hash;
}
I just altered the function little to make use of it for both the purposes.
Encrypt the password while creating the user account and store it with the salt.
Encrypt the user password with the stored salt from database when he is trying to logging in and check it with the stored value of password.
The issue with this is,
I am not getting back what I stored.
I used a lot of different things,
I used Base64 for encoding and stored into DB and decoded using the same while getting it back.
I tried to use VARBINARY and BLOB to save the byte[] data but no luck.
Then I used VARCHAR and just stored the byte[] by creating a new String from it using "UTF-8" encoding type.
I am new to cryptography so if I am wrong, please point it out.
Thanks in advance. :)
EDIT:
The output when I ran the encrypt twice:
Salt : [34, 17, -80, -59, 93, -90, 37, -25, -11, -43, 44, 1, 10, 7, -66, -108, 97, 36, 95, -116]
First Attempt: [-76, -3, 114, -69, 78, 21, -59, 23, 127, -15, 114, -106, -52, 23, 34, 91, 123, 6, 76, -115]
Second Attempt: [-76, -3, 114, -69, 78, 21, -59, 23, 127, -15, 114, -106, -52, 23, 34, 91, 123, 6, 76, -115]
Salt : [34, 17, -80, -59, 93, -90, 37, -25, -11, -43, 44, 1, 10, 7, -66, -108, 97, 36, 95, -116]