Cannot get my base64 string to decode on my javascript client - java

I am sending data from my java tomcat server to my browser using a WebSocket. I get the error: "Uncaught InvalidCharacterError: 'atob' failed: The string to be decoded is not correctly encoded."
Here is my code:
(java server code):
public void open(Session session)
{
String base64ImageString = generateImageString();
try
{
session.getBasicRemote().sendText(base64ImageString);
}
catch(IOException e)
{
e.printStackTrace();
}
}
private String generateImageString()
{
int imageData[] = new int[2];
imageData[0] = 255;
imageData[1] = 128;
String base64Image = "";
for(int i = 0; i < imageData.length; i++)
{
try
{
base64Image += Base64.encode(Integer.toString(imageData[i]).getBytes("UTF8"));
catch (UnsupportedEncodingException e)
}
catch( UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
return base64Image;
}
(JavaScript code):
function onMessage(evt)
{
base64ImageDataString = evt.data;
imageDataString = window.atob(base64ImageDataString);
}
My base64 string looks like this on the java and javascript side: [B#74193bd0[B#24a6103c
I am using org.glassfish.jersey.internal.util.Base64 if it matters. I am really stumped :(

My base64 string looks like this on the java and javascript side: [B#74193bd0[B#24a6103c
That's not base64. That's the concatenation of the result of calling toString() on two byte arrays. You're using a method which returns a byte[], not a string, which means your string concatenation is inappropriate. You could use Base64.encodeAsString - or use a different base64 library entirely (e.g. the iharder one). But really you shouldn't be doing any string concatenation.
Your generateImageString code is completely broken. It's not at all clear why you'd convert an integer to a string, get the UTF-8 representation of that, and then convert the byte array to base64... and then do that in a loop. That's just not the way to get anything meaningful.
I suspect you should actually be starting with a byte[] rather than an int[] - it's not clear what those values are meant to be - but then you want a single call to Base64.encode, passing the byte[] in. If you're calling Integer.toString or concatenating bits of Base64 data, you're doing it wrong.

[B#24a6103c represents a byte array as a string since Base64.encode returns a byte array.
You need to convert the byte array to a string before concatenating it to the String base64Image
I think you want to do this:
base64Image += new String(Base64.encode(Integer.toString(imageData[i]).getBytes("UTF8")));

Related

Convert string from file to ASCII and binary

Say I open a text file like this:
public static void main(String[] args) throws IOException {
String file_name = "file.txt";
try {
Read file = new ReadFile(file_name);
String[] Lines = file.openFile();
for (int i = 0; i < es.length; i++) {
System.out.println(Lines[i]);
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
Now, I want to change the result to binary (for further conversion into AMI coding), and I suppose that firstly I should turn it to ASCII (though I'm also not 100% certain if that's absolutely necessary), but I'm not sure if I should better change it to chars, or perhaps is there an easier way?
Please, mind that I'm just a beginner.
Do you happen to know for sure that the files will be ASCII encoded? Assuming it is, you can just use the getBytes() function of string:
byte[] lineDefault = line.getBytes();
There is a second option for .getBytes() as well if you don't want to use the default encoding. I often am using:
byte[] lineUtf8 = line.getBytes("UTF-8");
which gives byte sequences which are equivalent to ASCII for characters whose hex values are less than 0x80.

MD5 encoded parameter in URL

I am using following code to encrypt my email id in Java and sending it as a parameter in url (Using URLEncoder.encode(encrypteInput("email"))):
public static String encrypteInput(String input) {
String output = null;
input = input + ((int) Math.random()) % 1000;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
output = new String(md5.digest(input.getBytes()));
} catch (Exception e) {
output = "";
}
return output;
}
but, when I am getting the same parameter from servlet, it is not giving me the same output as encrypteInput("email").
Whenever you have a byte array that you want to store in a string, you should be Hex- or Base64-encoding the byte array (hex-encoding is probably better in this particular case).
Apache commons-codec has a Hex class you can use for this:
byte[] bytes = ...
char[] encoded = Hex.encodeHex(bytes);
String encodedString = new String(encoded);

JAVA Md5 returning non-deterministic results

I have written following function to compute Md5 checksum in Java.
class Utils {
public static String md5Hash(String input) {
String result = "";
try {
System.out.println("Input=" + input);
final MessageDigest md = MessageDigest.getInstance("MD5");
md.reset();
md.update(input.getBytes());
result = md.digest().toString();
} catch (Exception ee) {
System.err.println("Error computing MD5 Hash");
}
return result;
}
};
Calling Utils.md5Hash("abcde") multiple times gives different results. My understanding says md5 returns a deterministic and unique checksum for a string. Is that wrong? Else please let me know the bug in my implementation. Thanks
The toString() method of a byte array doesn't return a meaningful string. It returns the type of the array object, followed by the hashCode of the array.
Transform the byte array to a String using Hex or Base64 encoding if you want it printed. Apache commons-codec has methods to do that.
Also, make sure to specify en encoding which supports any kind of character to transform your string to a byte array. The method you're using uses the platform default encoding, which could fail if, for example, it's latin-1 and you're transforming non-latin-1 characters. UTF-8 is a good choice.
I have done using the following way :
public static String encryptedLoginPassword( String password )
{
String encryptedData="";
try{
MessageDigest algorithm = MessageDigest.getInstance("MD5");
byte[] defaultBytes = password.getBytes();
algorithm.reset();
algorithm.update(defaultBytes);
byte messageDigest[] = algorithm.digest();
StringBuffer hexString = new StringBuffer();
for (int i=0;i<messageDigest.length;i++) {
hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
}
encryptedData=hexString.toString();
}catch(NoSuchAlgorithmException nsae){
}
return encryptedData;
}
int the code given by Dinup Kandel, I had to change this:
for (int i=0;i<messageDigest.length;i++) {
hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
}
in to
if ((0xff & messageDigest[i]) < 0x10) {
hexString.append("0"
+ Integer.toHexString((0xFF & messageDigest[i])));
} else {
hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
}
to get my unit tests working.
note: i used this to verify the correct answer:
echo -n MyTestString | md5sum

Converting part of a ByteBuffer to a String

I have a ByteBuffer containing bytes that were derived by String.getBytes(charsetName), where "containing" means that the string comprises the entire sequence of bytes between the ByteBuffer's position() and limit().
What's the best way for me to get the string back? (assuming I know the encoding charset) Is there anything better than the following (which seems a little clunky)
byte[] ba = new byte[bbuf.remaining()];
bbuf.get(ba);
try {
String s = new String(ba, charsetName);
}
catch (UnsupportedEncodingException e) {
/* take appropriate action */
}
String s = Charset.forName(charsetName).decode(bbuf).toString();

Compressing strings for client/server transport in Java

I work with a propriety client/server message format that restricts what I can send over the wire. I can't send a serialized object, I have to store the data in the message as a String. The data I am sending are large comma-separated values, and I want to compress the data before I pack it into the message as a String.
I attempted to use Deflater/Inflater to achieve this, but somewhere along the line I am getting stuck.
I am using the two methods below to deflate/inflate. However, passing the result of the compressString() method to decompressStringMethod() returns a null result.
public String compressString(String data) {
Deflater deflater = new Deflater();
byte[] target = new byte[100];
try {
deflater.setInput(data.getBytes(UTF8_CHARSET));
deflater.finish();
int deflateLength = deflater.deflate(target);
return new String(target);
} catch (UnsupportedEncodingException e) {
//TODO
}
return data;
}
public String decompressString(String data) {
String result = null;
try {
byte[] input = data.getBytes();
Inflater inflater = new Inflater();
int inputLength = input.length;
inflater.setInput(input, 0, inputLength);
byte[] output = new byte[100];
int resultLength = inflater.inflate(output);
inflater.end();
result = new String(output, 0, resultLength, UTF8_CHARSET);
} catch (DataFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
From what I can tell, your current approach is:
Convert String to byte array using getBytes("UTF-8").
Compress byte array
Convert compressed byte array to String using new String(bytes, ..., "UTF-8").
Transmit compressed string
Receive compressed string
Convert compressed string to byte array using getBytes("UTF-8").
Decompress byte array
Convert decompressed byte array to String using new String(bytes, ..., "UTF-8").
The problem with this approach is in step 3. When you compress the byte array, you create a sequence of bytes which may no longer be valid UTF-8. The result will be an exception in step 3.
The solution is to use a "bytes to characters" encoding scheme like Base64 to turn the compressed bytes into a transmissible string. In other words, replace step 3 with a call to a Base64 encode function, and step 6 with a call to a Base64 decode function.
Notes:
For small strings, compressing and
encoding is likely to actually
increase the size of the transmitted string.
If the compacted String is going to be incorporated into a URL, you may want to pick a different encoding to Base64 that avoids characters that need to be URL escaped.
Depending on the nature of the data you are transmitting, you may find that a domain specific compression works better than a generic one. Consider compressing the data before creating the comma-separated string. Consider alternatives to comma-separated strings.
The problem is that you convert compressed bytes to a string, which breaks the data. Your compressString and decompressString should work on byte[]
EDIT: Here is revised version. It works
EDIT2: And about base64. you're sending bytes, not strings. You don't need base64.
public static void main(String[] args) {
String input = "Test input";
byte[] data = new byte[100];
int len = compressString(input, data, data.length);
String output = decompressString(data, len);
if (!input.equals(output)) {
System.out.println("Test failed");
}
System.out.println(input + " " + output);
}
public static int compressString(String data, byte[] output, int len) {
Deflater deflater = new Deflater();
deflater.setInput(data.getBytes(Charset.forName("utf-8")));
deflater.finish();
return deflater.deflate(output, 0, len);
}
public static String decompressString(byte[] input, int len) {
String result = null;
try {
Inflater inflater = new Inflater();
inflater.setInput(input, 0, len);
byte[] output = new byte[100]; //todo may oveflow, find better solution
int resultLength = inflater.inflate(output);
inflater.end();
result = new String(output, 0, resultLength, Charset.forName("utf-8"));
} catch (DataFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
TO ME: write compress algorithm myself is difficult but writing binary to string is not. So if I were you, I will serialize the object normally and zip it with compression (as provided by ZipFile) then convert to string using something like Base64 Encode/Decode.
I actually have BASE64 ENCODE/DECODE functions. If you wanted I can post it here.
If you have a piece of code which seems to be silently failing, perhaps you shouldn't catch and swallow Exceptions:
catch (UnsupportedEncodingException e) {
//TODO
}
But the real reason why decompress returns null is because your exception handling doesn't specify what to do with result when you catch an exception - result is left as null. Are you checking the output to see if any Exceptions are occuring?
If I run your decompress() on a badly formatted String, Inflater throws me this DataFormatException:
java.util.zip.DataFormatException: incorrect header check
at java.util.zip.Inflater.inflateBytes(Native Method)
at java.util.zip.Inflater.inflate(Inflater.java:223)
at java.util.zip.Inflater.inflate(Inflater.java:240)
Inflator/Deflator is not a solution for compress string.
I think GZIPInputString and GZIPOutputString is the proper tool to compress the string
I was facing similar issue which was resolved by base64 decoding the input.
i.e instead of
data.getBytes(UTF8_CHARSET)
i tried
Base64.decodeBase64(data)
and it worked.

Categories