import org.junit.Test;
import java.util.Base64;
import org.junit.Assert.*;
import java.util.Random;
...
#Test
public void testEncoding(){
byte[] data = new byte[32];
new Random().nextBytes(data);
String base64 = Base64.getEncoder().encodeToString(data);
assertEquals(data, Base64.getDecoder().decode(base64));
}
#Test
public void testDecoding(){
String base64 = "ABCDEFGHIJKLRMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/A==";
byte[] data = Base64.getDecoder().decode(base64);
assertEquals(base64, Base64.getEncoder().encodeToString(data));
}
The testEncoding test fails with an AssertionError:
Expected :[B#6bf2d08e
Actual :[B#5eb5c224
And I can't see why.
The flaw is in then Assertion not in the code.
assertEquals will compare the address of the byte array in memory
assertArrayEquals will compare the content of the byte array
Try this. You should encode a normal String, and decode a normal String, not a byte-array:
#Test
public void verify() throws Exception {
String normalString = "ABCDEFGHIJKLRMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/A==";
byte[] asBytes = normalString.getBytes();
String encoded = Base64.getEncoder().encodeToString(asBytes);
byte[] decodedBytes = Base64.getDecoder().decode(encoded);
String decoded = new String(decodedBytes);
assertEquals(normalString , decoded);
}
Related
this is the encoded string
YjRmYTJhMGEtYjI0ZC00ZjU4LTg2ZDktNTNiN2I2ODM4YjY3IzU1YjFjNGUzZTRiMGQ4OTUxMGM2YWEyNw
i want to generate UUID for this
You can convert as below using 2 functions. apache commons codec jar has some methods to encode and decode UUID using Base64.
Link to download apache commons codec jar: http://www.java2s.com/Code/JarDownload/apache-commons/apache-commons-codec-1.4.jar.zip
import java.nio.ByteBuffer;
import java.util.UUID;
import org.apache.commons.codec.binary.Base64;
public class Solution1 {
public static void main(String[] args) {
String uuid_str = "YjRmYTJhMGEtYjI0ZC00ZjU4LTg2ZDktNTNiN2I2ODM4YjY3IzU1YjFjNGUzZTRiMGQ4OTUxMGM2YWEyNw";
String uuid_as_64 = uuidFromBase64(uuid_str);
System.out.println("as base64: "+uuid_as_64);
System.out.println("as uuid: "+uuidFromBase64(uuid_as_64));
}
private static String uuidToBase64(String str) {
Base64 base64 = new Base64();
UUID uuid = UUID.fromString(str);
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return base64.encodeBase64URLSafeString(bb.array());
}
private static String uuidFromBase64(String str) {
Base64 base64 = new Base64();
byte[] bytes = base64.decodeBase64(str);
ByteBuffer bb = ByteBuffer.wrap(bytes);
UUID uuid = new UUID(bb.getLong(), bb.getLong());
return uuid.toString();
}
}
Output:
as base64: 62346661-3261-3061-2d62-3234642d3466
as uuid: eb6df8eb-aeb5-fb7d-bad7-edf4eb5fb677
For more, you can follow the tutorial:
http://www.baeldung.com/java-base64-encode-and-decode
http://www.tutorialspoint.com/java8/java8_base64.htm
How can I convert a UUID to base64?
Storing UUID as base64 String
The above base64 string decodes to ASCII string "b4fa2a0a-b24d-4f58-86d9-53b7b6838b67#55b1c4e3e4b0d89510c6aa27", so:
import org.apache.commons.codec.binary.Base64;
public class Solution {
private static String uuidFromBase64(String str) {
Base64 base64 = new Base64();
byte[] bytes = base64.decodeBase64(str);
String s = new String(bytes);
String trimmed = s.split("#")[0];
return trimmed;
}
}
i want upgrade jre7 to jre8 in our product, and i got some error. The root cause is that the title said, the result is not stable.
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class Digest {
/**
*
* #param args
* #throws NoSuchAlgorithmException
* #throws UnsupportedEncodingException
*/
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException
{
String userName = "superuser";
String password = "superuser";
byte[] userNameBytes = userName.getBytes(Charset.forName("GBK"));
byte[] passwordBytes = password.getBytes(Charset.forName("GBK"));
byte[] hashedBytes = digest(userNameBytes,passwordBytes);
System.out.println(Arrays.toString(hashedBytes));
String tmp = new String(hashedBytes,Charset.forName("GBK"));
byte[] newHashedBytes = tmp.getBytes(Charset.forName("GBK"));
System.out.println(Arrays.toString(newHashedBytes));
}
public static byte[] digest(byte[] username, byte[] password) throws NoSuchAlgorithmException
{
MessageDigest md = MessageDigest.getInstance("SHA");
md.reset();
md.update(password);
md.update(username);
return md.digest();
}
}
the sample code is legacy logic. And my question is how to use a workaround to get through this issue.
here are my test cases:
userNmae password encoding result
superuser superuser UTF-8 passed
superuser superuser GBK failed
test62 test62 GBK failed
test62 test62 UTF-8 failed
thanks a lot.
A conversion from random bytes to String is potentially a lossy operation (depending on the Charset used):
String tmp = new String(hashedBytes,Charset.forName("GBK"));
Byte values that can't be encoded with the selected CharSet are replaced (usually with a '?'), thus when converting back to byte[] you get a different array of bytes.
In general never convert binary data to String and back using any CharSet (although it may work for certain charsets, it bears a lot of potential for headaches when you want to transmit the data or store it in a database etc.). There are encodings (e.g. Base64) that are specifically designed to be reversible with the smallest common set of characters (ASCII).
Edit:
This little test program shows that not each character reverses to the same byte in the conversion (look at -128 becoming 63)
import java.nio.charset.Charset;
import java.util.Arrays;
public class CSTest {
public static void main(String[] argv) {
Charset cs = Charset.forName("GBK");
byte[] bytes = new byte[256];
for (int i=0; i<bytes.length; ++i)
bytes[i] = (byte) i;
System.out.println(Arrays.toString(bytes));
String s = new String(bytes, cs);
byte[] b2 = s.getBytes(cs);
System.out.println(Arrays.toString(b2));
}
}
This question already has answers here:
Encoding as Base64 in Java
(19 answers)
Closed 7 years ago.
I want to encode a string into base64 and transfer it through a socket and decode it back.
But after decoding it gives different answer.
Following is my code and result is "77+9x6s="
import javax.xml.bind.DatatypeConverter;
public class f{
public static void main(String a[]){
String str = new String(DatatypeConverter.parseBase64Binary("user:123"));
String res = DatatypeConverter.printBase64Binary(str.getBytes());
System.out.println(res);
}
}
Any idea about how to implement this?
You can use following approach:
import org.apache.commons.codec.binary.Base64;
// Encode data on your side using BASE64
byte[] bytesEncoded = Base64.encodeBase64(str.getBytes());
System.out.println("encoded value is " + new String(bytesEncoded));
// Decode data on other side, by processing encoded data
byte[] valueDecoded = Base64.decodeBase64(bytesEncoded);
System.out.println("Decoded value is " + new String(valueDecoded));
Hope this answers your doubt.
Java 8 now supports BASE64 Encoding and Decoding. You can use the following classes:
java.util.Base64, java.util.Base64.Encoder and java.util.Base64.Decoder.
Example usage:
// encode with padding
String encoded = Base64.getEncoder().encodeToString(someByteArray);
// encode without padding
String encoded = Base64.getEncoder().withoutPadding().encodeToString(someByteArray);
// decode a String
byte [] barr = Base64.getDecoder().decode(encoded);
The accepted answer uses the Apache Commons package but this is how I did it using Java's native libraries
Java 11 and up
import java.util.Base64;
public class Base64Encoding {
public static void main(String[] args) {
Base64.Encoder enc = Base64.getEncoder();
Base64.Decoder dec = Base64.getDecoder();
String str = "77+9x6s=";
// encode data using BASE64
String encoded = enc.encodeToString(str.getBytes());
System.out.println("encoded value is \t" + encoded);
// Decode data
String decoded = new String(dec.decode(encoded));
System.out.println("decoded value is \t" + decoded);
System.out.println("original value is \t" + str);
}
}
Java 6 - 10
import java.io.UnsupportedEncodingException;
import javax.xml.bind.DatatypeConverter;
public class EncodeString64 {
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "77+9x6s=";
// encode data using BASE64
String encoded = DatatypeConverter.printBase64Binary(str.getBytes());
System.out.println("encoded value is \t" + encoded);
// Decode data
String decoded = new String(DatatypeConverter.parseBase64Binary(encoded));
System.out.println("decoded value is \t" + decoded);
System.out.println("original value is \t" + str);
}
}
The better way would be to try/catch the encoding/decoding steps but hopefully you get the idea.
For Spring Users , Spring Security has a Base64 class in the org.springframework.security.crypto.codec package that can also be used for encoding and decoding of Base64.
Ex.
public static String base64Encode(String token) {
byte[] encodedBytes = Base64.encode(token.getBytes());
return new String(encodedBytes, Charset.forName("UTF-8"));
}
public static String base64Decode(String token) {
byte[] decodedBytes = Base64.decode(token.getBytes());
return new String(decodedBytes, Charset.forName("UTF-8"));
}
The following is a good solution -
import android.util.Base64;
String converted = Base64.encodeToString(toConvert.toString().getBytes(), Base64.DEFAULT);
String stringFromBase = new String(Base64.decode(converted, Base64.DEFAULT));
That's it. A single line encoding and decoding.
import javax.xml.bind.DatatypeConverter;
public class f{
public static void main(String a[]){
String str = new String(DatatypeConverter.printBase64Binary(new String("user:123").getBytes()));
String res = DatatypeConverter.parseBase64Binary(str);
System.out.println(res);
}
}
PHP Encrypt Function
$privateKey = "1234567812345678";
$iv = "1234567812345678";
$data = "Test string";
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $privateKey, $data, MCRYPT_MODE_CBC, $iv);
echo(base64_encode($encrypted));
Result: iz1qFlQJfs6Ycp+gcc2z4w==
When I try to decrypt this result in Java using the function below, all I get back is ì�š#ÔBKxnfÈ~¯Ô'M while I am expecting "Test string". Any ideas where I am wrong? Thanks
public static String decrypt() throws Exception{
try{
String Base64EncodedText = "iz1qFlQJfs6Ycp+gcc2z4w==";
String decodedText = com.sun.xml.internal.messaging.saaj.util.Base64.base64Decode(Base64EncodedText);
String key = "1234567812345678";
String iv = "1234567812345678";
javax.crypto.spec.SecretKeySpec keyspec = new javax.crypto.spec.SecretKeySpec(key.getBytes(), "AES");
javax.crypto.spec.IvParameterSpec ivspec = new javax.crypto.spec.IvParameterSpec(iv.getBytes());
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] decrypted = cipher.doFinal(decodedText.getBytes());
String str = new String(decrypted);
return str;
}catch(Exception e){
return null;
}
}
EDIT: As of Java 8 Java now includes an acceptable Base64 class, java.util.Base64.
This line
String decodedText = com.sun.xml.internal.messaging.saaj.util.Base64.base64Decode(Base64EncodedText);
looks wrong. Instead, use the apache commons codec classes or the Harder base64 class. Also the default padding used by mcrypt, zero padding, is arguably wrong and makes it difficult to use the results in other languages. The users comments section for the mcrypt_encrypt web pages has examples of how to do this.
Here is small example that uses the apache commons classes to decrypt your string.
import java.nio.charset.Charset;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
public class AESToy3 {
private static final Charset ASCII = Charset.forName("US-ASCII");
public static void main(String[] args) throws Exception {
String base64Cipher = "iz1qFlQJfs6Ycp+gcc2z4w==";
byte [] cipherBytes = Base64.decodeBase64(base64Cipher);
byte [] iv = "1234567812345678".getBytes(ASCII);
byte [] keyBytes = "1234567812345678".getBytes(ASCII);
SecretKey aesKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv));
byte[] result = cipher.doFinal(cipherBytes);
System.out.println(Hex.encodeHexString(result));
}
}
this produces the following output:
5465737420737472696e670000000000
which when decoded as ASCII and removing the trailing zeros gives you Test string
This unit test is failing:
public void testDigest() throws NoSuchAlgorithmException {
String hashExpected = "150a14ed5bea6cc731cf86c41566ac427a8db48ef1b9fd626664b3bfbb99071fa4c922f33dde38719b8c8354e2b7ab9d77e0e67fc12843920a712e73d558e197";
MessageDigest md = new MessageDigest();
String hashActual = new String(md.digest("hi"));
Assert.assertEquals(hashExpected, hashActual);
}
Below is my implementation of my MessageDigest class:
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.io.DigestInputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class MessageDigest {
private Digest messageDigest;
public MessageDigest() throws NoSuchAlgorithmException {
Security.addProvider(new BouncyCastleProvider());
messageDigest = new SHA512Digest();
}
public byte[] digest(String message) {
byte[] retValue = new byte[messageDigest.getDigestSize()];
messageDigest.update(message.getBytes(), 0, message.length());
messageDigest.doFinal(retValue, 0);
return retValue;
}
}
The test fails with the following reason:
junit.framework.ComparisonFailure: expected:<150a14ed5bea6cc731cf86c41566ac427a8db48ef1b9fd626664b3bfbb99071fa4c922f33dde38719b8c8354e2b7ab9d77e0e67fc12843920a712e73d558e197> but was:<
í[êlÇ1φÄf¬Bz�´Žñ¹ýbfd³¿»™¤É"ó=Þ8q›ŒƒTâ·«�wàæÁ(C’
q.sÕXá
I have a feeling I'm not using the right encoding scheme when I convert my byte[] digest into a string. Any help would be appreciated.
The value you're expecting is a Hex-encoded value. You're creating a String based on the raw bytes, which won't work.
You should use the standard Java Crypto API whenever possible instead of BouncyCastle specific APIs.
Try the following (the Hex library comes from commons-codec):
Security.addProvider(new BouncyCastleProvider());
String data = "hello world";
MessageDigest mda = MessageDigest.getInstance("SHA-512", "BC");
byte [] digesta = mda.digest(data.getBytes());
MessageDigest mdb = MessageDigest.getInstance("SHA-512", "BC");
byte [] digestb = mdb.digest(data.getBytes());
System.out.println(MessageDigest.isEqual(digesta, digestb));
System.out.println(Hex.encodeHex(digesta));
Just an addition to Kevin's answer: Since Java 5, you can use String.format("%0128x", new BigInteger(1, digesta)) instead of commons-codec to format the byte array as a 128 digit hex encoded number with leading zeros.
Yes, you need to turn your byte array into a hex string. :-) Look into Apache Commons Codec, especially the Hex class.
Since BouncyCastle 1.49 there is a handful toHexString method in the Hex class. For example:
Hex.toHexString(digest);
will return you the hash digest as a Java String in a hexadecimal format.
For reference see BouncyCastle javadoc or grepcode.