Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Java 8 java.util.Base64 a drop-in replacement for sun.misc.BASE64?

Question

Are the Java 8 java.util.Base64 MIME Encoder and Decoder a drop-in replacement for the unsupported, internal Java API sun.misc.BASE64Encoder and sun.misc.BASE64Decoder?

EDIT (Clarification): By drop-in replacement I mean that I can switch legacy code using sun.misc.BASE64Encoder and sun.misc.BASE64Decoder to Java 8 MIME Base64 Encoder/Decoder for any existing other client code transparently.

What I think so far and why

Based on my investigation and quick tests (see code below) it should be a drop-in replacement because

  • sun.misc.BASE64Encoder based on its JavaDoc is a BASE64 Character encoder as specified in RFC1521. This RFC is part of the MIME specification...
  • java.util.Base64 based on its JavaDoc Uses the "The Base64 Alphabet" as specified in Table 1 of RFC 2045 for encoding and decoding operation... under MIME

Assuming no significant changes in the RFC 1521 and 2045 (I could not find any) and based on my quick test using the Java 8 Base64 MIME Encoder/Decoder should be fine.

What I am looking for

  • an authoritative source confirming or disproving the "drop-in replacement" point OR
  • a counterexample which shows a case where java.util.Base64 has different behaviour than the sun.misc.BASE64Encoder OpenJDK Java 8 implementation (8u40-b25) (BASE64Decoder) OR
  • whatever you think answers above question definitely

For reference

My test code

public class Base64EncodingDecodingRoundTripTest {      public static void main(String[] args) throws IOException {         String test1 = " ~!@#$%^& *()_+=`| }{[]\\;: \"?><,./ ";         String test2 = test1 + test1;          encodeDecode(test1);         encodeDecode(test2);     }      static void encodeDecode(final String testInputString) throws IOException {         sun.misc.BASE64Encoder unsupportedEncoder = new sun.misc.BASE64Encoder();         sun.misc.BASE64Decoder unsupportedDecoder = new sun.misc.BASE64Decoder();          Base64.Encoder mimeEncoder = java.util.Base64.getMimeEncoder();         Base64.Decoder mimeDecoder = java.util.Base64.getMimeDecoder();          String sunEncoded = unsupportedEncoder.encode(testInputString.getBytes());         System.out.println("sun.misc encoded: " + sunEncoded);          String mimeEncoded = mimeEncoder.encodeToString(testInputString.getBytes());         System.out.println("Java 8 Base64 MIME encoded: " + mimeEncoded);          byte[] mimeDecoded = mimeDecoder.decode(sunEncoded);         String mimeDecodedString = new String(mimeDecoded, Charset.forName("UTF-8"));          byte[] sunDecoded = unsupportedDecoder.decodeBuffer(mimeEncoded); // throws IOException         String sunDecodedString = new String(sunDecoded, Charset.forName("UTF-8"));          System.out.println(String.format("sun.misc decoded: %s | Java 8 Base64 decoded:  %s", sunDecodedString, mimeDecodedString));          System.out.println("Decoded results are both equal: " + Objects.equals(sunDecodedString, mimeDecodedString));         System.out.println("Mime decoded result is equal to test input string: " + Objects.equals(testInputString, mimeDecodedString));         System.out.println("\n");     } } 
like image 210
Ivo Mori Avatar asked Feb 09 '16 20:02

Ivo Mori


People also ask

Is Java Util Base64 thread safe?

Instances of Base64. Encoder class are safe for use by multiple concurrent threads. Unless otherwise noted, passing a null argument to a method of this class will cause a NullPointerException to be thrown.

What is import Java Util Base64?

You can encrypt and decrypt your data by using provided methods. You need to import java. util. Base64 in your source file to use its methods. This class provides three different encoders and decoders to encrypt information at each level.


2 Answers

I had same issue, when i moved from sun to java.util.base64, but then org.apache.commons.codec.binary.Base64 solved my problem

like image 25
AKS Avatar answered Oct 05 '22 21:10

AKS


Here's a small test program that illustrates a difference in the encoded strings:

byte[] bytes = new byte[57]; String enc1 = new sun.misc.BASE64Encoder().encode(bytes); String enc2 = new String(java.util.Base64.getMimeEncoder().encode(bytes),                          StandardCharsets.UTF_8);  System.out.println("enc1 = <" + enc1 + ">"); System.out.println("enc2 = <" + enc2 + ">"); System.out.println(enc1.equals(enc2)); 

Its output is:

enc1 = <AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > enc2 = <AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA> false 

Note that the encoded output of sun.misc.BASE64Encoder has a newline at the end. It doesn't always append a newline, but it happens to do so if the encoded string has exactly 76 characters on its last line. (The author of java.util.Base64 considered this to be a small bug in the sun.misc.BASE64Encoder implementation – see the review thread).

This might seem like a triviality, but if you had a program that relied on this specific behavior, switching encoders might result in malformed output. Therefore, I conclude that java.util.Base64 is not a drop-in replacement for sun.misc.BASE64Encoder.

Of course, the intent of java.util.Base64 is that it's a functionally equivalent, RFC-conformant, high-performance, fully supported and specified replacement that's intended to support migration of code away from sun.misc.BASE64Encoder. You need to be aware of some edge cases like this when migrating, though.

like image 103
Stuart Marks Avatar answered Oct 05 '22 21:10

Stuart Marks