Apache codec base64 encode/decode - not getting expected result - java

I did a POC using apache codec base64 library, where I encrypted a string using SHA. (This can be ignored).
Step 1 - I printed byte array for that string.
Step 2 - Encoded the byte array and printed its value.
Step 3 - Decoded the encoded value and printed it.
public static void main(String[] args)
{
MessageDigest messageDigest = null;
String ALGORITHM = "SHA";
try
{
messageDigest = MessageDigest.getInstance(ALGORITHM);
byte[] arr = "admin1!".getBytes();
byte[] arr2 = messageDigest.digest(arr);
System.out.println(arr2);
String encoded = Base64.encodeBase64String(arr2);
System.out.println(encoded);
byte[] decoded = Base64.decodeBase64(encoded);
System.out.println(decoded);
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
}
Expected result : Step 1 and Step 3 should produce same output. But I am not getting that.
Output :
[B#5ca801b0
90HMfRqqpfwRJge0anZat98BTdI=
[B#68d448a1

Your program is all good and fine. Just one mistake.
System.out.println(byteArray); prints hashCode of byte array object. (Note: Arrays are object in Java not primitive type)
You should use System.out.println(Arrays.toString(byteArray)); instead and you will get same value for both steps 1 and 3.
As per javadocs Arrays.toString(byte[] a) returns a string representation of the contents of the specified array.
Your code after changes will be :
public static void main(String[] args)
{
MessageDigest messageDigest = null;
String ALGORITHM = "SHA";
try
{
messageDigest = MessageDigest.getInstance(ALGORITHM);
byte[] arr = "admin1!".getBytes();
byte[] arr2 = messageDigest.digest(arr);
System.out.println(Arrays.toString(arr2));
String encoded = Base64.encodeBase64String(arr2);
System.out.println(encoded);
byte[] decoded = Base64.decodeBase64(encoded);
System.out.println(Arrays.toString(decoded));
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
}
and output will be :
[-9, 65, -52, 125, 26, -86, -91, -4, 17, 38, 7, -76, 106, 118, 90, -73, -33, 1, 77, -46]
90HMfRqqpfwRJge0anZat98BTdI=
[-9, 65, -52, 125, 26, -86, -91, -4, 17, 38, 7, -76, 106, 118, 90, -73, -33, 1, 77, -46]
Note value of byte array is same.

Related

No sense length() result

Since today I'm fronting a really weird error related to byte[] to String conversion.
Here is the code:
private static final byte[] test_key = {-112, -57, -45, 125, 91, 126, -118, 13, 83, -60, -119, 57, 38, 118, -115, -52, -92, 39, -24, 75, 59, -21, 88, 84, 66, -125};
public static void main(String[] args) {
byte[] encryptedArray = xor("ciao".getBytes(), test_key);
System.out.println("Encrypted arrray: " + Arrays.toString(encryptedArray));
final String encrypted = new String(encryptedArray);
System.out.println("Length: " + new String(encryptedArray).length());
System.out.println(Arrays.toString(encrypted.getBytes()));
System.out.println("Encrypted value: " + encrypted);
System.out.println("Decrypted value: " + new String(xor(encrypted.getBytes(), test_key)));
}
private static byte[] xor(byte[] data, byte[] key) {
byte[] result = new byte[data.length];
for (int i = 0; i < data.length; i++) {
result[i] = (byte) (data[i] ^ key[i % key.length]);
}
return result;
}
My output is:
Encrypted arrray: [-13, -82, -78, 18]
Length: 2
[-17, -65, -67, 18]
Encrypted value: �
Decrypted value: xno
Why does length() return 2? What am I missing?
There is no 1-to-1 mapping between byte and char, rather it depends on the charset you use. Strings are logically chars sequences. So if you want to convert between chars and bytes, you need a character encoding, which specifies the mapping from chars to bytes, and vice versa. Your bytes in encryptedArray are first converted to Unicode string, which attempts to create UTF-8 char sequence from these bytes.
If you want to use String and revert back the exact bytes, you need to do a Base64 of the encryptedArray and then do a new String() of it:
String encoded = new String(Base64.getEncoder().encode(encryptedArray));
To retreive, just decode:
Base64.getDecoder().decode(encoded);
I just thought of a good way of showing what happens by simply replacing the new String(byte[]) method by another one, which is why I will answer the question. This one performs the same basic action as the constructor, with one change: it throws an exception if any invalid characters are found.
private static final byte[] test_key = {-112, -57, -45, 125, 91, 126, -118, 13, 83, -60, -119, 57, 38, 118, -115, -52, -92, 39, -24, 75, 59, -21, 88, 84, 66, -125};
public static void main(String[] args) throws Exception {
byte[] encryptedArray = xor("ciao".getBytes(), test_key);
System.out.println("Encrypted arrray: " + Arrays.toString(encryptedArray));
final String encrypted = new String(encryptedArray);
// original
System.out.println("Length: " + new String(encryptedArray).length());
// replacement
System.out.println("Length: " + decode(encryptedArray).length());
System.out.println(Arrays.toString(encrypted.getBytes()));
System.out.println("Encrypted value: " + encrypted);
System.out.println("Decrypted value: " + new String(xor(encrypted.getBytes(), test_key)));
}
private static String decode(byte[] encryptedArray) throws CharacterCodingException {
var decoder = Charset.defaultCharset().newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPORT);
var decoded = decoder.decode(ByteBuffer.wrap(encryptedArray));
return decoded.toString();
}
private static byte[] xor(byte[] data, byte[] key) {
byte[] result = new byte[data.length];
for (int i = 0; i < data.length; i++) {
result[i] = (byte) (data[i] ^ key[i % key.length]);
}
return result;
}
The method is called decode because that's what you are actually doing: you are decoding the bytes to a text. A character encoding is the encoding of characters as bytes, which means that the opposite must be decoding after all.
As you will see, the above will first print out 2 if your platform uses the default UTF-8 encoding (Linux, Android, MacOS). You can get the same result by replacing Charset.defaultCharset() with StandardCharsets.UTF_8 on Windows which uses the Windows-1252 charset instead (a single byte encoding which is an expansion of Latin-1, which itself is an expansion of ASCII). However, it will generate the following exception if you use the decode method:
java.nio.charset.MalformedInputException: Input length = 3
at java.base/java.nio.charset.CoderResult.throwException(CoderResult.java:274)
at java.base/java.nio.charset.CharsetDecoder.decode(CharsetDecoder.java:815)
at StackExchange/com.stackexchange.so.ShowBadEncoding.decode(ShowBadEncoding.java:36)
at StackExchange/com.stackexchange.so.ShowBadEncoding.main(ShowBadEncoding.java:24)
Now maybe you'd expect 4 here, the size of the byte array. But note that UTF-8 characters may be encoded over multiple bytes. The error occurs not on the entire string, but on the last character it is trying to read. Obviously it is expecting a longer encoding based on the previous byte values.
If you replace REPORT with the default decoding action REPLACE (heh) you will see that the result is identical to the constructor, and length() will now return the value 2 again.
Of course, Topaco is correct when he says you need to use base 64 encoding. This encodes bytes to characters instead so that all of the meaning of the bytes is maintained, and the reverse is of course the decoding of text back to bytes.
The elements of a String are not bytes, they are chars. A char is not a byte.
There are many ways of converting a char to a sequence of bytes (i.e., many character-set encodings).
Not every sequence of chars can be converted to a sequence of bytes; there is not always a mapping for every char. It depends on your chosen character-set encoding.
Not every sequence of bytes can be converted to a String; the bytes have to be syntactically valid for the specified character set.

byte getting read wrong from file?

So, I am trying to store 3 longs to a file, but it will a lot of data so I convert them to byte arrays and save them. My current method for saving them:
try (FileOutputStream output = new FileOutputStream(path, true)) {
//Put the data into my format
byte[] data = new byte[24];
main.getLogger().log(Level.INFO, "Saving most sig bits");
System.arraycopy(ByteUtils.longToBytes(uuid.getMostSignificantBits()), 0, data, 0, 8);
System.arraycopy(ByteUtils.longToBytes(uuid.getLeastSignificantBits()), 0, data, 8, 8);
System.arraycopy(ByteUtils.longToBytes(player.getTokens()), 0, data, 16, 8);
//Write data in the format
output.write(data);
}
longToBytes method:
private static ByteBuffer buffer = ByteBuffer.allocate(8);
public static byte[] longToBytes(long x) {
System.out.println(x);
buffer.putLong(0, x);
return buffer.array();
}
The byte array gets saved to the file, but the first byte gets truncated. the print statement in longToByes prints 8 three times.
The original longs are:
-9089798603852198353, -5339652910133477779, 5992
If I print the byte array I get:
-127, -38, -116, 84, 97, -116, 78, 47, -75, -27, -67, -8, 11, -100, -2, 109, 0, 0, 0, 0, 0, 0, 23, 104 (24 bytes)
But in the file I see:
ÚŒTaŒN/µå½ø(VT symbol)œþm(nul)(nul)(nul)(nul)(nul)(nul)(etb)h
which is 23 bytes (the first box doesn't show in notepad++)
but if I read it using
bytes = IOUtils.toByteArray(new FileReader(file));
I see:
64, -38, -116, 84, 97, -116, 78, 47, -75, -27, -67, -8, 11, -100, -2, 109, 0, 0, 0, 0, 0, 0, 23, 104 (24 bytes)
-127 is replaced with 64 somehow.
I concat the byte with "" to print it btw.
Do not use FileReader to read raw bytes from file. Use FileInputStream instead.
The problem with FileReader is that it reads chars, not bytes, from the file, by trying to decode the bytes using some character encoding (the default one if none was given).
bytes = IOUtils.toByteArray(new FileInputStream(file));
Alternatively you can use DataOutputStream to write long directly to an output stream and use DataInputStream to read from an input stream.
try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) {
out.writeLong(uuid.getMostSignificantBits());
out.writeLong(uuid.getLeastSignificantBits());
out.writeLong(player.getTokens());
}
try (DataInputStream in = new DataInputStream(new FileInputStream(file))) {
long uuidMSB = in.readLong();
long uuidLSB = in.readLong();
long tokens = in.readLong();
}

convert string to byte array problem is string not convert to byte array format [duplicate]

This question already has answers here:
How do I print my Java object without getting "SomeType#2f92e0f4"?
(13 answers)
byte array to decimal convertion in java
(4 answers)
Closed 4 years ago.
i want to convert string value that is get as json value.i want to convert this string to byte array but the problem is if i convert into bytearray it showing out in ascii format.
CODE
passenger_sign = assignedJobJson.getJSONObject(position).getString("passenger_sign");
Log.e(TAG, "passenger_sign: "+passenger_sign );
OUTPUT
[-119,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,2,-128,0,0,1,44,8,6,0,0,0,83,-5,2,43,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,-120,0,0,32,0,73,68,65,84,120,-100,-19,-35,119,124,20,117,-2,63,-16,-41,108,54,-101,77,33,100,67,-128,72,75,66,-17,1,-115,-107,34,-120,16,8,93,64,80,84,-70,-46,5,4,41,66,60,-123,-93,-120,-108,3,-63,66,40,-98,8,1,-60,59,77,65,56,79,74,-112,7,114,98,10,-100,119,-118,-102,13,-27,-108,-70,75,47,33,-103,-33,31,126,-15,71,-103,-39,-99,-103,-99,-19,-81,-25,-29,49,127,48,-27,-13,121,-49,102,-39,125,-17,103,62,69,16,69,81,4,17,17,17,17,5,13,-125,-73,3,32,34,34,34,34,-49,98,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,68,68,68,68,65,-122,9,32,17,17,17,81,-112,97,2,72,68,68,68,20,100,-104,0,18,17,17,17,5,25,38,-128,26,-39,-19,118,-40,-19,118,111,-121,65,68,68,68,-92,26,19,64,21,-84,86,43,122,-9,-18,13,-117,-59,114,-57,-42,-69,119,111,88,-83,86,111,-121,71,68,68,68,-92,-120,32,-118,-94,-24,-19,32,-4,-63,-70,117,-21,48,122,-12,104,92,-67,122,85,-14,120,76,76,12,-106,44,89,-126,-63,-125,7,123,54,48,34,34,34,34,-107,-104,0,42,-112,-99,-99,-115,-18,-35,-69,43,58,119,-25,-50,-99,104,-41,-82,-99,123,3,34,34,34,34,114,1,19,64,39,-20,118,59,42,87,-82,-116,-101,55,111,42,58,63,49,49,17,-7,-7,-7,-120,-119,-119,113,115,100,68,68,68,68,-38,-80,15,-96,19,-67,123,-9,86,-100,-4,1,-65,-9,19,-36,-75,107,-105,-5,2,34,34,34,34,114,17,19,64,7,-20,118,-69,-90,100,-82,-96,-96,64,-1,96,-120,-120,-120,-120,116,-62,4,-48,-127,-7,-13,-25,107,-70,-114,45,-128,68,68,68,-28,-53,-104,0,58,-16,-31,-121,31,106,-70,-82,69,-117,22,58,71,66,68,68,68,-92,31,38,-128,14,92,-68,120,81,-45,117,28,5,76,68,68,68,-66,-116,-93,-128,29,48,24,12,80,-5,-14,24,-115,70,-100,62,125,-102,-93,-128,-119,-120,-120,-56,103,-79,5,-48,1,45,-71,113,-97,62,125,-104,-4,17,17,17,-111,79,99,11,-96,-116,-44,-44,84,-20,-40,-79,67,-43,53,102,-77,89,118,-91,16,34,34,34,34,95,-63,22,64,9,69,69,69,-86,-109,63,0,-8,-17,127,-1,-21,-122,104,-120,-120,-120,-120,-12,-59,4,80,66,-113,30,61,84,95,-109,-105,-105,-121,-124,-124,4,55,68,67,68,68,68,-92,47,38,-128,119,89,-70,116,41,74,74,74,84,93,83,-67,122,117,-76,110,-35,-38,77,17,17,17,17,17,-23,-117,125,0,-17,98,50,-103,80,90,90,-86,-22,-102,78,-99,58,97,-5,-10,-19,110,-118,-120,-120,-120,-120,72,95,108,1,-68,77,106,106,-86,-22,-28,15,0,30,121,-28,17,55,68,67,68,68,68,-28,30,108,1,-4,63,69,69,69,72,78,78,-42,116,45,95,66,34,34,34,-14,39,76,0,-1,79,104,104,40,110,-34,-68,-87,-23,90,-66,-124,68,68,68,-28,79,-8,8,24,-64,-3,-9,-33,-81,57,-7,51,24,-8,18,18,17,17,-111,127,9,-6,-20,37,35,35,3,-7,-7,-7,-102,-81,-81,88,-79,-94,-114,-47,16,17,17,17,-71,95,80,63,2,-74,-37,-19,-120,-115,-115,117,-23,17,110,114,114,50,10,10,10,116,-116,-118,-120,-120,-120,-56,-67,-126,-70,5,-80,93,-69,118,14,-109,-65,90,-75,106,57,45,-93,125,-5
this is what i get as json value...its in a string format now.
if i convert into byte array format its showing output in a ascii format.
this is the way i covert string to bytearray:
byte[] bytes = passenger_sign.getBytes();
OUTPUT
[B#37b5539
i want to convert string to bytearray and set it in bitmapfactory. pls anyone help me to get a solution for this.
Try below:
byte[] byteArray = new byte[] {87, 79, 87, 46, 46, 46};
StringBuilder sb = new StringBuilder();
for (byte b : byteArray) {
sb.append(b);
sb.append(",");
}
sb.deleteCharAt(sb.length() - 1);
System.out.println(sb);
Here is test example you can go for Converting String to Byte array
import java.util.Arrays;
public class Test3{
public static void main(String[] afe) {
String str = "Rohit";
byte[] byteArr = str.getBytes();
System.out.println("String to byte array: " + Arrays.toString(byteArr));
}
}
output will be like - [ 82, 111, 104, 105, 116 ]
and this one for vice versa
import java.util.Arrays;
public class Test3{
public static void main(String[] args) {
byte[] byteArray1 = { 82, 111, 104, 105, 116 };
String str1 = new String(byteArray1);
System.out.println(str1);
}
}
here output will be like string - Rohit
When you convert and print out byte[], byte[].toString() returns the hashcode of the byte[] and not how you would like to see it. Try printing out byte[0], byte[1]. It should be the same as what you are expecting.
Try running the below code
public static void main(String[] args) {
byte[] byteArray = new byte[] {87, 79, 87, 46, 46, 46};
String value = new String(byteArray);
byte[] arr = value.getBytes();
// System.out.println(arr) // this will return the hashcode for arr
System.out.println(value);
System.out.println(Arrays.toString(arr));
}
you should get the output of
WOW...
[87, 79, 87, 46, 46, 46]

Java store and read byte array from property file yaml

I am working on an application that reads data from a database. There are already encrypted entries in the DB. I have the key as a byte array and want to load it from a yaml file.
Is there a way i can populate an array like this
private static final byte[] iv = { 13, -11, -88, 20, -110, 113, -2, -8, -15, -99, -23, -10, -10, -74, 1, 11 }
Directly from a yaml file?
yaml file:
iv: 13,-11,-88
Since I cannot autowire the class where I need to use the key, i cannot use #value annotation (from my understanding). So I was looking to use a util class like so:
public static byte[] getKeyFor(Class type) {
return context.getEnvironment().getProperty("iv");
}
Below should work:
application.yml:
iv: 12,32,12,32
In the class where you want the values, bind it like below:
#Value("${iv}") byte[] iv;
You got some string with your byte data in String format.
String iv = someCall(); //"13, -11, -88, 20, -110, 113, -2, -8, -15, -99, -23"
String[] byteStrings = iv.split(",");
byte[] byteData = new byte[byteStrings.length];
for (int i = 0; i < byteData.length; i++){
byteData[i] = Byte.parseByte(byteStrings[i], 8);
}

Reading a wav file java vs matlab

I am trying to read data of a .wav file both in java and matlab and save as an array of bytes.
In java the code looks as follows:
public byte[] readWav2(File file) throws UnsupportedAudioFileException, IOException {
AudioFormat audioFormat;
AudioInputStream inputAIS = AudioSystem.getAudioInputStream(file);
audioFormat = inputAIS.getFormat();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Read the audio data into a memory buffer.
int nBufferSize = BUFFER_LENGTH * audioFormat.getFrameSize();
byte[] abBuffer = new byte[nBufferSize];
while (true) {
int nBytesRead = inputAIS.read(abBuffer);
if (nBytesRead == -1) {
break;
}
baos.write(abBuffer, 0, nBytesRead);
}
byte[] abAudioData = baos.toByteArray();
return abAudioData;
}
In matlab I am using the wavread function:
[Y, FS] = wavread('sound.wav', 'native');
But the results I am getting are different.
In java the first 20 bytes:
53, 0, 19, 0, -71, -1, -80, -1, -99, -1, 10, 0, 87, 0, -69, -1, 123, -1, -77, -1
In matlab:
53, 19, -71, -80, -99, 10, 87, -69, -133, -77, 38, 143, 13, -100, 39, 45, -52, -83, -82, 56
Why every second byte in java is 0 or -1 where in matlab there isn't? Even though I skip the 0's and -1's where in java there is 123 for matlab there is -133? Why is it different?
Java is returning you 16-bit signed PCM data. Since each sample is 16 bits and a byte holds 8 bits, each sample spans two bytes in Java. What Matlab returns you is an array of the 16-bit samples directly.
Basically, the data is the same. It's just laid out differently in memory.
To access the samples in an easier way from Java you could do some bitwise arithmetic, like this:
int firstSample = (abAudioData[0]&0xFF) | (abAudioData[1]<<8);
Another way to read the samples is with the java.nio buffers:
ByteBuffer bb = ByteBuffer.wrap(abAudioData);
bb.order(ByteOrder.LITTLE_ENDIAN);
ShortBuffer sb = bb.asShortBuffer();
int firstSample = sb.get();

Categories