【问题标题】:Decode Base64 data in Java在 Java 中解码 Base64 数据
【发布时间】:2010-10-02 22:50:52
【问题描述】:

我有一张经过 Base64 编码的图像。在 Java 中解码的最佳方法是什么?希望只使用 Sun Java 6 附带的库。

【问题讨论】:

标签: java base64


【解决方案1】:

Java 8 开始,有一个官方支持的用于 Base64 编码和解码的 API。 随着时间的推移,这可能会成为默认选择。

API 包括类java.util.Base64 及其嵌套类。它支持三种不同的风格:基本、URL 安全和 MIME。

使用“基本”编码的示例代码:

import java.util.Base64;

byte[] bytes = "Hello, World!".getBytes("UTF-8");
String encoded = Base64.getEncoder().encodeToString(bytes);
byte[] decoded = Base64.getDecoder().decode(encoded);

documentation for java.util.Base64 包含更多用于配置编码器和解码器以及使用不同类作为输入和输出(字节数组、字符串、ByteBuffers、java.io 流)的方法。

【讨论】:

  • 我正在使用 Java 8。如果使用 Java 8,这是推荐的方法吗?
  • @JohnMerlino 如果不需要与旧 Java 版本兼容,我建议使用此 API,因为 JRE 比大多数库具有更强的兼容性策略。此外,由于包含在 JRE 中,它不会以任何可能的方式限制您的依赖关系。
  • Java 7 已停产,Java 9 即将到来,这就是我的正确答案!
  • 差不多好:它只接受原始 base64 流,不接受 base64 文件。我不得不改用final byte[] decoded = Base64.getMimeDecoder().decode(encoded);。不过还是谢谢! (commons-io FileUtils.readFileToByteArrayFileUtils.writeByteArrayToFile 很好——尤其是当您意识到 encoded 也可以是 byte[] 时。)
【解决方案2】:

从 v6 开始,Java SE 附带 JAXB。 javax.xml.bind.DatatypeConverter 有静态方法可以让这一切变得简单。请参阅parseBase64Binary()printBase64Binary()

【讨论】:

  • 但是,printBase64Binary(..) 方法似乎没有执行 Base64 的 MIME 版本(en.wikipedia.org/wiki/Base64#MIME),而私有 Sun 和 Commons 实现使用它。具体来说,对于大于 76 个字符的字符串,会添加换行符。我没有找到如何为此行为配置 JAXB 的实现... :-(
  • 然而,sun 实现将忽略换行符。所以它们是兼容的。
  • 警告! parseBase64Binary 将静默跳过无效字符,并且不会检查 base64 的有效性。最好使用 Commons Codec 或 Guava Base64。请注意,Guava 拒绝换行符和空格字符,因此您需要解析省略空格的字符串:BaseEncoding.base64().decode(s.replaceAll("\\s", ""))
  • 小心。此函数不适用于超过 65000 的数据。(java 版本 1.6)
  • 不要使用它,因为你会在jdk 9中遇到问题:java.lang.NoClassDefFoundError(javax/xml/bind/DatatypeConverter)
【解决方案3】:

无需使用公共资源——Sun 提供了一个带有 Java 的 base64 编码器。你可以这样导入它:

import sun.misc.BASE64Decoder;

然后像这样使用它:

BASE64Decoder decoder = new BASE64Decoder();
byte[] decodedBytes = decoder.decodeBuffer(encodedBytes);

其中encodedBytesjava.lang.Stringjava.io.InputStream。请注意,sun.* 类不受 Sun 的“官方支持”。

编辑:谁知道这将是我发布过的最具争议的答案?我确实知道 sun.* 软件包不受支持或保证继续存在,而且我确实了解 Commons 并一直使用它。但是,发帖人要求提供一个“包含在 Sun Java 6 中”的类,而这正是我试图回答的问题。我同意 Commons 是总体上最好的方式。

编辑 2: 正如 amir75 在下面指出的那样,Java 6+ 附带 JAXB,其中包含支持的代码来编码/解码 Base64。请参阅下面的Jeremy Ross' answer

【讨论】:

  • -1 - 这是 Sun 内部代码,不是 J2SE 的一部分(它,不可移植),并且可能随时消失 - Sun 明确表示不要在用户代码中使用其内部库
  • 是的,因此我在最后的免责声明。
  • 这是一个短期项目,只是一个实验,不想通过审批新图书馆的过程。所以这是这个问题的正确答案。
  • Bzzt。在专业环境中,使用不受支持的、未记录的功能绝不是正确的决定。在企业环境中,“实验”变成了“生产代码”,没有机会修复这些漏洞。
  • 在一个研究部门,该代码被标记为实验,当它被标记时总是被废弃,这是正确的决定。
【解决方案4】:

具体在Commons Codec:类Base64decode(byte[] array)encode(byte[] array)

【讨论】:

  • 您可以将文本“Commons Codec”链接到项目页面。这样这个答案会比凯文的更好:)
  • 我知道这是一个老问题,但为什么这不是公认的答案?大多数 java 安装中不是都包含公共编解码器,并且使用的代码行数比滚动您自己的版本少得多吗?
  • @LiHaoyi 这个问题询问的是 Sun 的 JDK 附带的库,它不包括 Commons 中的任何内容。
  • 假道。这些方法不存在!
【解决方案5】:

Guava 现在内置了 Base64 解码。

使用BaseEncoding.base64().decode()

至于处理输入使用中可能出现的空格

BaseEncoding.base64().decode(CharMatcher.WHITESPACE.removeFrom(...));

更多信息请见this discussion

【讨论】:

  • Guava 14 仍然是一个候选版本,但这仍然得到我的支持——当它达到任何体面的位置时,它应该是金色的 :-)
  • Guava base64 解码器拒绝换行符和空格字符,因此您必须事先删除它们。
【解决方案6】:

我的解决方案是最快最简单的。

public class MyBase64 {

    private final static char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();

    private static int[]  toInt   = new int[128];

    static {
        for(int i=0; i< ALPHABET.length; i++){
            toInt[ALPHABET[i]]= i;
        }
    }

    /**
     * Translates the specified byte array into Base64 string.
     *
     * @param buf the byte array (not null)
     * @return the translated Base64 string (not null)
     */
    public static String encode(byte[] buf){
        int size = buf.length;
        char[] ar = new char[((size + 2) / 3) * 4];
        int a = 0;
        int i=0;
        while(i < size){
            byte b0 = buf[i++];
            byte b1 = (i < size) ? buf[i++] : 0;
            byte b2 = (i < size) ? buf[i++] : 0;

            int mask = 0x3F;
            ar[a++] = ALPHABET[(b0 >> 2) & mask];
            ar[a++] = ALPHABET[((b0 << 4) | ((b1 & 0xFF) >> 4)) & mask];
            ar[a++] = ALPHABET[((b1 << 2) | ((b2 & 0xFF) >> 6)) & mask];
            ar[a++] = ALPHABET[b2 & mask];
        }
        switch(size % 3){
            case 1: ar[--a]  = '=';
            case 2: ar[--a]  = '=';
        }
        return new String(ar);
    }

    /**
     * Translates the specified Base64 string into a byte array.
     *
     * @param s the Base64 string (not null)
     * @return the byte array (not null)
     */
    public static byte[] decode(String s){
        int delta = s.endsWith( "==" ) ? 2 : s.endsWith( "=" ) ? 1 : 0;
        byte[] buffer = new byte[s.length()*3/4 - delta];
        int mask = 0xFF;
        int index = 0;
        for(int i=0; i< s.length(); i+=4){
            int c0 = toInt[s.charAt( i )];
            int c1 = toInt[s.charAt( i + 1)];
            buffer[index++]= (byte)(((c0 << 2) | (c1 >> 4)) & mask);
            if(index >= buffer.length){
                return buffer;
            }
            int c2 = toInt[s.charAt( i + 2)];
            buffer[index++]= (byte)(((c1 << 4) | (c2 >> 2)) & mask);
            if(index >= buffer.length){
                return buffer;
            }
            int c3 = toInt[s.charAt( i + 3 )];
            buffer[index++]= (byte)(((c2 << 6) | c3) & mask);
        }
        return buffer;
    } 

}

【讨论】:

  • 这不是越野车! - 阅读 javadoc cmets... decode(..) 的参数是 base64 字符串,而不仅仅是任何字符串。 byte[] b1 = {1,2,3}; byte[] b2 = decode(encode(b1)); System.out.println(Arrays.equals( b1, b2 )); // => 真的
  • 最快最简单的??重新发明轮子?!
  • 我进行了一些测试,将这个类与 commons-codec 进行了比较,它似乎工作正常。我需要像这样简单的东西,因为我只需要 base64 编码并且不需要 commons-codec 提供的所有额外内容,谢谢。
  • 这可信吗?如果您不想导入外部库,这似乎是最简单的。
  • 它不适用于从 AES 算法获得的字节
【解决方案7】:

这是我自己的实现,如果对某人有用的话:

public class Base64Coder {

    // The line separator string of the operating system.
    private static final String systemLineSeparator = System.getProperty("line.separator");

    // Mapping table from 6-bit nibbles to Base64 characters.
    private static final char[] map1 = new char[64];
       static {
          int i=0;
          for (char c='A'; c<='Z'; c++) map1[i++] = c;
          for (char c='a'; c<='z'; c++) map1[i++] = c;
          for (char c='0'; c<='9'; c++) map1[i++] = c;
          map1[i++] = '+'; map1[i++] = '/'; }

    // Mapping table from Base64 characters to 6-bit nibbles.
    private static final byte[] map2 = new byte[128];
       static {
          for (int i=0; i<map2.length; i++) map2[i] = -1;
          for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; }

    /**
    * Encodes a string into Base64 format.
    * No blanks or line breaks are inserted.
    * @param s  A String to be encoded.
    * @return   A String containing the Base64 encoded data.
    */
    public static String encodeString (String s) {
       return new String(encode(s.getBytes())); }

    /**
    * Encodes a byte array into Base 64 format and breaks the output into lines of 76 characters.
    * This method is compatible with <code>sun.misc.BASE64Encoder.encodeBuffer(byte[])</code>.
    * @param in  An array containing the data bytes to be encoded.
    * @return    A String containing the Base64 encoded data, broken into lines.
    */
    public static String encodeLines (byte[] in) {
       return encodeLines(in, 0, in.length, 76, systemLineSeparator); }

    /**
    * Encodes a byte array into Base 64 format and breaks the output into lines.
    * @param in            An array containing the data bytes to be encoded.
    * @param iOff          Offset of the first byte in <code>in</code> to be processed.
    * @param iLen          Number of bytes to be processed in <code>in</code>, starting at <code>iOff</code>.
    * @param lineLen       Line length for the output data. Should be a multiple of 4.
    * @param lineSeparator The line separator to be used to separate the output lines.
    * @return              A String containing the Base64 encoded data, broken into lines.
    */
    public static String encodeLines (byte[] in, int iOff, int iLen, int lineLen, String lineSeparator) {
       int blockLen = (lineLen*3) / 4;
       if (blockLen <= 0) throw new IllegalArgumentException();
       int lines = (iLen+blockLen-1) / blockLen;
       int bufLen = ((iLen+2)/3)*4 + lines*lineSeparator.length();
       StringBuilder buf = new StringBuilder(bufLen);
       int ip = 0;
       while (ip < iLen) {
          int l = Math.min(iLen-ip, blockLen);
          buf.append (encode(in, iOff+ip, l));
          buf.append (lineSeparator);
          ip += l; }
       return buf.toString(); }

    /**
    * Encodes a byte array into Base64 format.
    * No blanks or line breaks are inserted in the output.
    * @param in  An array containing the data bytes to be encoded.
    * @return    A character array containing the Base64 encoded data.
    */
    public static char[] encode (byte[] in) {
       return encode(in, 0, in.length); }

    /**
    * Encodes a byte array into Base64 format.
    * No blanks or line breaks are inserted in the output.
    * @param in    An array containing the data bytes to be encoded.
    * @param iLen  Number of bytes to process in <code>in</code>.
    * @return      A character array containing the Base64 encoded data.
    */
    public static char[] encode (byte[] in, int iLen) {
       return encode(in, 0, iLen); }

    /**
    * Encodes a byte array into Base64 format.
    * No blanks or line breaks are inserted in the output.
    * @param in    An array containing the data bytes to be encoded.
    * @param iOff  Offset of the first byte in <code>in</code> to be processed.
    * @param iLen  Number of bytes to process in <code>in</code>, starting at <code>iOff</code>.
    * @return      A character array containing the Base64 encoded data.
    */
    public static char[] encode (byte[] in, int iOff, int iLen) {
       int oDataLen = (iLen*4+2)/3;       // output length without padding
       int oLen = ((iLen+2)/3)*4;         // output length including padding
       char[] out = new char[oLen];
       int ip = iOff;
       int iEnd = iOff + iLen;
       int op = 0;
       while (ip < iEnd) {
          int i0 = in[ip++] & 0xff;
          int i1 = ip < iEnd ? in[ip++] & 0xff : 0;
          int i2 = ip < iEnd ? in[ip++] & 0xff : 0;
          int o0 = i0 >>> 2;
          int o1 = ((i0 &   3) << 4) | (i1 >>> 4);
          int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
          int o3 = i2 & 0x3F;
          out[op++] = map1[o0];
          out[op++] = map1[o1];
          out[op] = op < oDataLen ? map1[o2] : '='; op++;
          out[op] = op < oDataLen ? map1[o3] : '='; op++; }
       return out; }

    /**
    * Decodes a string from Base64 format.
    * No blanks or line breaks are allowed within the Base64 encoded input data.
    * @param s  A Base64 String to be decoded.
    * @return   A String containing the decoded data.
    * @throws   IllegalArgumentException If the input is not valid Base64 encoded data.
    */
    public static String decodeString (String s) {
       return new String(decode(s)); }

    /**
    * Decodes a byte array from Base64 format and ignores line separators, tabs and blanks.
    * CR, LF, Tab and Space characters are ignored in the input data.
    * This method is compatible with <code>sun.misc.BASE64Decoder.decodeBuffer(String)</code>.
    * @param s  A Base64 String to be decoded.
    * @return   An array containing the decoded data bytes.
    * @throws   IllegalArgumentException If the input is not valid Base64 encoded data.
    */
    public static byte[] decodeLines (String s) {
       char[] buf = new char[s.length()];
       int p = 0;
       for (int ip = 0; ip < s.length(); ip++) {
          char c = s.charAt(ip);
          if (c != ' ' && c != '\r' && c != '\n' && c != '\t')
             buf[p++] = c; }
       return decode(buf, 0, p); }

    /**
    * Decodes a byte array from Base64 format.
    * No blanks or line breaks are allowed within the Base64 encoded input data.
    * @param s  A Base64 String to be decoded.
    * @return   An array containing the decoded data bytes.
    * @throws   IllegalArgumentException If the input is not valid Base64 encoded data.
    */
    public static byte[] decode (String s) {
       return decode(s.toCharArray()); }

    /**
    * Decodes a byte array from Base64 format.
    * No blanks or line breaks are allowed within the Base64 encoded input data.
    * @param in  A character array containing the Base64 encoded data.
    * @return    An array containing the decoded data bytes.
    * @throws    IllegalArgumentException If the input is not valid Base64 encoded data.
    */
    public static byte[] decode (char[] in) {
       return decode(in, 0, in.length); }

    /**
    * Decodes a byte array from Base64 format.
    * No blanks or line breaks are allowed within the Base64 encoded input data.
    * @param in    A character array containing the Base64 encoded data.
    * @param iOff  Offset of the first character in <code>in</code> to be processed.
    * @param iLen  Number of characters to process in <code>in</code>, starting at <code>iOff</code>.
    * @return      An array containing the decoded data bytes.
    * @throws      IllegalArgumentException If the input is not valid Base64 encoded data.
    */
    public static byte[] decode (char[] in, int iOff, int iLen) {
       if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4.");
       while (iLen > 0 && in[iOff+iLen-1] == '=') iLen--;
       int oLen = (iLen*3) / 4;
       byte[] out = new byte[oLen];
       int ip = iOff;
       int iEnd = iOff + iLen;
       int op = 0;
       while (ip < iEnd) {
          int i0 = in[ip++];
          int i1 = in[ip++];
          int i2 = ip < iEnd ? in[ip++] : 'A';
          int i3 = ip < iEnd ? in[ip++] : 'A';
          if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
             throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
          int b0 = map2[i0];
          int b1 = map2[i1];
          int b2 = map2[i2];
          int b3 = map2[i3];
          if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
             throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
          int o0 = ( b0       <<2) | (b1>>>4);
          int o1 = ((b1 & 0xf)<<4) | (b2>>>2);
          int o2 = ((b2 &   3)<<6) |  b3;
          out[op++] = (byte)o0;
          if (op<oLen) out[op++] = (byte)o1;
          if (op<oLen) out[op++] = (byte)o2; }
       return out; }

    // Dummy constructor.
    private Base64Coder() {}
}

【讨论】:

    【解决方案8】:

    作为sun.misc.BASE64Decoder 或非核心库的替代方案,请查看javax.mail.internet.MimeUtility.decode()

    public static byte[] encode(byte[] b) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        OutputStream b64os = MimeUtility.encode(baos, "base64");
        b64os.write(b);
        b64os.close();
        return baos.toByteArray();
    }
    public static byte[] decode(byte[] b) throws Exception {
        ByteArrayInputStream bais = new ByteArrayInputStream(b);
        InputStream b64is = MimeUtility.decode(bais, "base64");
        byte[] tmp = new byte[b.length];
        int n = b64is.read(tmp);
        byte[] res = new byte[n];
        System.arraycopy(tmp, 0, res, 0, n);
        return res;
    }
    

    完整代码链接:Encode/Decode to/from Base64

    【讨论】:

    • javax.mail 不是核心的一部分。
    • javax.mail.internet.MimeUtility 包含在 appengine-api.jar 中
    【解决方案9】:

    另一个迟到的答案,但我的基准测试显示Jetty's implementation of Base64 编码器非常快。不如MiGBase64 快,但比iHarder Base64 快。

    import org.eclipse.jetty.util.B64Code;
    
    final String decoded = B64Code.decode(encoded, "UTF-8");
    

    我也做了一些基准测试:

          library     |    encode    |    decode   
    ------------------+--------------+-------------
     'MiGBase64'      |  10146001.00 |  6426446.00
     'Jetty B64Code'  |   8846191.00 |  3101361.75
     'iHarder Base64' |   3259590.50 |  2505280.00
     'Commons-Codec'  |    241318.04 |   255179.96
    

    这些是运行/秒,所以越高越好。

    【讨论】:

      【解决方案10】:

      鉴于javax.xml.bind.DatatypeConverter 使用方法parseBase64Binary()printBase64Binary() 参考@jeremy-ross 和@nightfirecat 答案的测试 编码/解码示例。

      @Test
      public void EncodeDecode() {
          //ENCODE
          String hello = "Hello World";
          byte[] helloBytes = hello.getBytes(StandardCharsets.UTF_8);
          String encodedHello = DatatypeConverter.printBase64Binary(helloBytes);
          LOGGER.info(hello + " encoded=> " + encodedHello);
      
          //DECODE
          byte[] encodedHelloBytes = DatatypeConverter.parseBase64Binary(encodedHello);
          String helloAgain = new String(encodedHelloBytes, StandardCharsets.UTF_8) ;
          LOGGER.info(encodedHello + " decoded=> " + helloAgain);
      
          Assert.assertEquals(hello, helloAgain);
      }
      

      结果:

      INFO - Hello World encoded=> SGVsbG8gV29ybGQ=
      INFO - SGVsbG8gV29ybGQ= decoded=> Hello World
      

      【讨论】:

        【解决方案11】:

        使用 Java 8 -

            public static String encodeString(String plainString) {
                return  Base64.getEncoder().encodeToString(plainString.getBytes());
            }
        
            public static String decodeString(String encodedString) {
                byte[] bytes = Base64.getDecoder().decode(encodedString);
                return new String(bytes);
            }
        

        【讨论】:

          【解决方案12】:

          如果您更喜欢基于性能的解决方案,那么您可以使用“MiGBase64”

          http://migbase64.sourceforge.net/

          public class Base64Test {
              public static void main(String[] args) {
              String encodeToString = Base64.encodeToString("JavaTips.net".getBytes(), true);
              System.out.println("encodeToString " + encodeToString);
              byte[] decodedBytes = Base64.decode(encodeToString.getBytes());
              System.out.println("decodedBytes " + new String(decodedBytes));
              }
          }
          

          【讨论】:

          • MiGBase64 易于使用、编码良好且速度极快。很好的发现,Imby。
          • 根据this benchmark MiGBase64 不再是最快的实现,现在它明显落后于 Apache Commons 和 sun.misc.BASE64Decoder。
          【解决方案13】:

          你可以试试这个。

          byte[] data = Base64.getDecoder().decode(base64fileContent);
          

          Base64.getDecode() 返回一个可以解码的 Base64 解码器。然后你需要使用.decode(&lt;your base64&gt;)再次解码。

          【讨论】:

            【解决方案14】:

            这是一个迟到的答案,但 Joshua Bloch 在 java.util.prefs 包下提交了他的 Base64 课程(当时他为 Sun、ahem、Oracle 工作)。这个类从 JDK 1.4 开始就存在了。

            例如

            String currentString = "Hello World";
            String base64String = java.util.prefs.Base64.byteArrayToBase64(currentString.getBytes("UTF-8"));
            

            【讨论】:

            • 不幸的是 Base64 类具有默认可见性,因此它几乎不是公共 API。
            • 为什么不直接参考java.util.Base64
            • @LukasEder,这是因为java.util.Base64 是在 JDK 8(及更高版本)中发布的。它在早期版本中不存在。
            【解决方案15】:

            希望对你有帮助:

            import com.sun.org.apache.xml.internal.security.utils.Base64;
            String str="Hello World";
            String base64_str=Base64.encode(str.getBytes("UTF-8"));
            

            或者:

            String str="Hello World";
            String base64_str="";
            try
               {base64_str=(String)Class.forName("java.util.prefs.Base64").getDeclaredMethod("byteArrayToBase64", new Class[]{byte[].class}).invoke(null, new Object[]{str.getBytes("UTF-8")});
               }
            catch (Exception ee) {}
            

            java.util.prefs.Base64 在本地 rt.jar 上工作,

            但它不在The JRE Class White List

            而不是Available classes not listed in the GAE/J white-list

            真可惜!

            附言。在 android 中,这很容易,因为 android.util.Base64 自 Android API 级别 8 起已包含在内。

            【讨论】:

              【解决方案16】:

              您可以从编码的 Base64 字符串写入或下载文件:

              Base64 base64 = new Base64(); 
              String encodedFile="JVBERi0xLjUKJeLjz9MKMSAwIG9iago8PCAKICAgL1R5cGUgL0NhdGFsb2cKICAgL1BhZ2VzIDIgMCBSCiAgIC9QYWdlTGF5b3V0IC9TaW5"; 
                            byte[] dd=encodedFile.getBytes();
                          byte[] bytes = Base64.decodeBase64(dd);
              
               response.setHeader("Content-disposition", "attachment; filename=\""+filename+"\"");
                          response.setHeader("Cache-Control", "no-cache");
                          response.setHeader("Expires", "-1");
              
                          // actually send result bytes
                          response.getOutputStream().write(bytes);
              

              为我工作,希望也为你工作......

              【讨论】:

                【解决方案17】:

                java.util.Base64 的 Java 8 实现不依赖于其他 Java 8 特定类。

                我不确定这是否适用于 Java 6 项目,但可以将 Base64.java 文件复制并粘贴到 Java 7 项目中,然后除了导入 java.util.Arrays 和 @ 之外无需修改即可编译它987654323@.

                注意 Base64.java 文件被 GNU GPL2 覆盖

                【讨论】:

                  【解决方案18】:

                  我使用了android.util.base64,它在没有任何依赖的情况下工作得很好:

                  用法:

                  byte[] decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT);
                  

                  包 com.test;

                  import java.io.UnsupportedEncodingException;
                  
                  /**
                   * Utilities for encoding and decoding the Base64 representation of
                   * binary data.  See RFCs <a
                   * href="http://www.ietf.org/rfc/rfc2045.txt">2045</a> and <a
                   * href="http://www.ietf.org/rfc/rfc3548.txt">3548</a>.
                   */
                  public class Base64 {
                  
                      public static final int DEFAULT = 0;
                  
                  
                      public static final int NO_PADDING = 1;
                  
                  
                      public static final int NO_WRAP = 2;
                  
                  
                      public static final int CRLF = 4;
                  
                  
                      public static final int URL_SAFE = 8;
                  
                  
                      public static final int NO_CLOSE = 16;
                  
                      //  --------------------------------------------------------
                      //  shared code
                      //  --------------------------------------------------------
                  
                      /* package */ static abstract class Coder {
                          public byte[] output;
                          public int op;
                  
                          public abstract boolean process(byte[] input, int offset, int len, boolean finish);
                  
                  
                          public abstract int maxOutputSize(int len);
                      }
                  
                      //  --------------------------------------------------------
                      //  decoding
                      //  --------------------------------------------------------
                  
                  
                      public static byte[] decode(String str, int flags) {
                          return decode(str.getBytes(), flags);
                      }
                  
                      public static byte[] decode(byte[] input, int flags) {
                          return decode(input, 0, input.length, flags);
                      }
                  
                  
                      public static byte[] decode(byte[] input, int offset, int len, int flags) {
                          // Allocate space for the most data the input could represent.
                          // (It could contain less if it contains whitespace, etc.)
                          Decoder decoder = new Decoder(flags, new byte[len*3/4]);
                  
                          if (!decoder.process(input, offset, len, true)) {
                              throw new IllegalArgumentException("bad base-64");
                          }
                  
                          // Maybe we got lucky and allocated exactly enough output space.
                          if (decoder.op == decoder.output.length) {
                              return decoder.output;
                          }
                  
                          // Need to shorten the array, so allocate a new one of the
                          // right size and copy.
                          byte[] temp = new byte[decoder.op];
                          System.arraycopy(decoder.output, 0, temp, 0, decoder.op);
                          return temp;
                      }
                  
                     static class Decoder extends Coder {       
                          private static final int DECODE[] = {
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
                              52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
                              -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
                              15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
                              -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
                              41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                          };
                  
                          /**
                           * Decode lookup table for the "web safe" variant (RFC 3548
                           * sec. 4) where - and _ replace + and /.
                           */
                          private static final int DECODE_WEBSAFE[] = {
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
                              52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
                              -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
                              15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
                              -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
                              41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                          };
                  
                          /** Non-data values in the DECODE arrays. */
                          private static final int SKIP = -1;
                          private static final int EQUALS = -2;
                  
                  
                          private int state;   // state number (0 to 6)
                          private int value;
                  
                          final private int[] alphabet;
                  
                          public Decoder(int flags, byte[] output) {
                              this.output = output;
                  
                              alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
                              state = 0;
                              value = 0;
                          }
                  
                  
                          public int maxOutputSize(int len) {
                              return len * 3/4 + 10;
                          }
                  
                          /**
                           * Decode another block of input data.
                           *
                           * @return true if the state machine is still healthy.  false if
                           *         bad base-64 data has been detected in the input stream.
                           */
                          public boolean process(byte[] input, int offset, int len, boolean finish) {
                              if (this.state == 6) return false;
                  
                              int p = offset;
                              len += offset;
                  
                              int state = this.state;
                              int value = this.value;
                              int op = 0;
                              final byte[] output = this.output;
                              final int[] alphabet = this.alphabet;
                  
                              while (p < len) {                
                                  if (state == 0) {
                                      while (p+4 <= len &&
                                             (value = ((alphabet[input[p] & 0xff] << 18) |
                                                       (alphabet[input[p+1] & 0xff] << 12) |
                                                       (alphabet[input[p+2] & 0xff] << 6) |
                                                       (alphabet[input[p+3] & 0xff]))) >= 0) {
                                          output[op+2] = (byte) value;
                                          output[op+1] = (byte) (value >> 8);
                                          output[op] = (byte) (value >> 16);
                                          op += 3;
                                          p += 4;
                                      }
                                      if (p >= len) break;
                                  }
                  
                                  int d = alphabet[input[p++] & 0xff];
                  
                                  switch (state) {
                                  case 0:
                                      if (d >= 0) {
                                          value = d;
                                          ++state;
                                      } else if (d != SKIP) {
                                          this.state = 6;
                                          return false;
                                      }
                                      break;
                  
                                  case 1:
                                      if (d >= 0) {
                                          value = (value << 6) | d;
                                          ++state;
                                      } else if (d != SKIP) {
                                          this.state = 6;
                                          return false;
                                      }
                                      break;
                  
                                  case 2:
                                      if (d >= 0) {
                                          value = (value << 6) | d;
                                          ++state;
                                      } else if (d == EQUALS) {
                                          // Emit the last (partial) output tuple;
                                          // expect exactly one more padding character.
                                          output[op++] = (byte) (value >> 4);
                                          state = 4;
                                      } else if (d != SKIP) {
                                          this.state = 6;
                                          return false;
                                      }
                                      break;
                  
                                  case 3:
                                      if (d >= 0) {
                                          // Emit the output triple and return to state 0.
                                          value = (value << 6) | d;
                                          output[op+2] = (byte) value;
                                          output[op+1] = (byte) (value >> 8);
                                          output[op] = (byte) (value >> 16);
                                          op += 3;
                                          state = 0;
                                      } else if (d == EQUALS) {
                                          // Emit the last (partial) output tuple;
                                          // expect no further data or padding characters.
                                          output[op+1] = (byte) (value >> 2);
                                          output[op] = (byte) (value >> 10);
                                          op += 2;
                                          state = 5;
                                      } else if (d != SKIP) {
                                          this.state = 6;
                                          return false;
                                      }
                                      break;
                  
                                  case 4:
                                      if (d == EQUALS) {
                                          ++state;
                                      } else if (d != SKIP) {
                                          this.state = 6;
                                          return false;
                                      }
                                      break;
                  
                                  case 5:
                                      if (d != SKIP) {
                                          this.state = 6;
                                          return false;
                                      }
                                      break;
                                  }
                              }
                  
                              if (!finish) {
                                  // We're out of input, but a future call could provide
                                  // more.
                                  this.state = state;
                                  this.value = value;
                                  this.op = op;
                                  return true;
                              }
                  
                  
                              switch (state) {
                              case 0:
                                  break;
                              case 1:
                                  this.state = 6;
                                  return false;
                              case 2:
                                  output[op++] = (byte) (value >> 4);
                                  break;
                              case 3:
                                 output[op++] = (byte) (value >> 10);
                                  output[op++] = (byte) (value >> 2);
                                  break;
                              case 4:
                                  this.state = 6;
                                  return false;
                              case 5:
                                  break;
                              }
                  
                              this.state = state;
                              this.op = op;
                              return true;
                          }
                      }
                  
                      //  --------------------------------------------------------
                      //  encoding
                      //  --------------------------------------------------------    
                      public static String encodeToString(byte[] input, int flags) {
                          try {
                              return new String(encode(input, flags), "US-ASCII");
                          } catch (UnsupportedEncodingException e) {
                              // US-ASCII is guaranteed to be available.
                              throw new AssertionError(e);
                          }
                      }
                  
                  
                      public static String encodeToString(byte[] input, int offset, int len, int flags) {
                          try {
                              return new String(encode(input, offset, len, flags), "US-ASCII");
                          } catch (UnsupportedEncodingException e) {
                              // US-ASCII is guaranteed to be available.
                              throw new AssertionError(e);
                          }
                      }
                  
                  
                      public static byte[] encode(byte[] input, int flags) {
                          return encode(input, 0, input.length, flags);
                      }
                  
                  
                      public static byte[] encode(byte[] input, int offset, int len, int flags) {
                          Encoder encoder = new Encoder(flags, null);
                  
                          // Compute the exact length of the array we will produce.
                          int output_len = len / 3 * 4;
                  
                          // Account for the tail of the data and the padding bytes, if any.
                          if (encoder.do_padding) {
                              if (len % 3 > 0) {
                                  output_len += 4;
                              }
                          } else {
                              switch (len % 3) {
                                  case 0: break;
                                  case 1: output_len += 2; break;
                                  case 2: output_len += 3; break;
                              }
                          }
                  
                          // Account for the newlines, if any.
                          if (encoder.do_newline && len > 0) {
                              output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) *
                                  (encoder.do_cr ? 2 : 1);
                          }
                  
                          encoder.output = new byte[output_len];
                          encoder.process(input, offset, len, true);
                  
                          assert encoder.op == output_len;
                  
                          return encoder.output;
                      }
                  
                      /* package */ static class Encoder extends Coder {
                          /**
                           * Emit a new line every this many output tuples.  Corresponds to
                           * a 76-character line length (the maximum allowable according to
                           * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>).
                           */
                          public static final int LINE_GROUPS = 19;
                  
                          /**
                           * Lookup table for turning Base64 alphabet positions (6 bits)
                           * into output bytes.
                           */
                          private static final byte ENCODE[] = {
                              'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
                              'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
                              'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                              'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
                          };
                  
                          /**
                           * Lookup table for turning Base64 alphabet positions (6 bits)
                           * into output bytes.
                           */
                          private static final byte ENCODE_WEBSAFE[] = {
                              'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
                              'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
                              'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                              'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
                          };
                  
                          final private byte[] tail;
                          /* package */ int tailLen;
                          private int count;
                  
                          final public boolean do_padding;
                          final public boolean do_newline;
                          final public boolean do_cr;
                          final private byte[] alphabet;
                  
                          public Encoder(int flags, byte[] output) {
                              this.output = output;
                  
                              do_padding = (flags & NO_PADDING) == 0;
                              do_newline = (flags & NO_WRAP) == 0;
                              do_cr = (flags & CRLF) != 0;
                              alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
                  
                              tail = new byte[2];
                              tailLen = 0;
                  
                              count = do_newline ? LINE_GROUPS : -1;
                          }
                  
                          /**
                           * @return an overestimate for the number of bytes {@code
                           * len} bytes could encode to.
                           */
                          public int maxOutputSize(int len) {
                              return len * 8/5 + 10;
                          }
                  
                          public boolean process(byte[] input, int offset, int len, boolean finish) {
                              // Using local variables makes the encoder about 9% faster.
                              final byte[] alphabet = this.alphabet;
                              final byte[] output = this.output;
                              int op = 0;
                              int count = this.count;
                  
                              int p = offset;
                              len += offset;
                              int v = -1;
                  
                              // First we need to concatenate the tail of the previous call
                              // with any input bytes available now and see if we can empty
                              // the tail.
                  
                              switch (tailLen) {
                                  case 0:
                                      // There was no tail.
                                      break;
                  
                                  case 1:
                                      if (p+2 <= len) {
                                          // A 1-byte tail with at least 2 bytes of
                                          // input available now.
                                          v = ((tail[0] & 0xff) << 16) |
                                              ((input[p++] & 0xff) << 8) |
                                              (input[p++] & 0xff);
                                          tailLen = 0;
                                      };
                                      break;
                  
                                  case 2:
                                      if (p+1 <= len) {
                                          // A 2-byte tail with at least 1 byte of input.
                                          v = ((tail[0] & 0xff) << 16) |
                                              ((tail[1] & 0xff) << 8) |
                                              (input[p++] & 0xff);
                                          tailLen = 0;
                                      }
                                      break;
                              }
                  
                              if (v != -1) {
                                  output[op++] = alphabet[(v >> 18) & 0x3f];
                                  output[op++] = alphabet[(v >> 12) & 0x3f];
                                  output[op++] = alphabet[(v >> 6) & 0x3f];
                                  output[op++] = alphabet[v & 0x3f];
                                  if (--count == 0) {
                                      if (do_cr) output[op++] = '\r';
                                      output[op++] = '\n';
                                      count = LINE_GROUPS;
                                  }
                              }
                  
                              // At this point either there is no tail, or there are fewer
                              // than 3 bytes of input available.
                  
                              // The main loop, turning 3 input bytes into 4 output bytes on
                              // each iteration.
                              while (p+3 <= len) {
                                  v = ((input[p] & 0xff) << 16) |
                                      ((input[p+1] & 0xff) << 8) |
                                      (input[p+2] & 0xff);
                                  output[op] = alphabet[(v >> 18) & 0x3f];
                                  output[op+1] = alphabet[(v >> 12) & 0x3f];
                                  output[op+2] = alphabet[(v >> 6) & 0x3f];
                                  output[op+3] = alphabet[v & 0x3f];
                                  p += 3;
                                  op += 4;
                                  if (--count == 0) {
                                      if (do_cr) output[op++] = '\r';
                                      output[op++] = '\n';
                                      count = LINE_GROUPS;
                                  }
                              }
                  
                              if (finish) {
                  
                                  if (p-tailLen == len-1) {
                                      int t = 0;
                                      v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4;
                                      tailLen -= t;
                                      output[op++] = alphabet[(v >> 6) & 0x3f];
                                      output[op++] = alphabet[v & 0x3f];
                                      if (do_padding) {
                                          output[op++] = '=';
                                          output[op++] = '=';
                                      }
                                      if (do_newline) {
                                          if (do_cr) output[op++] = '\r';
                                          output[op++] = '\n';
                                      }
                                  } else if (p-tailLen == len-2) {
                                      int t = 0;
                                      v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) |
                                          (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2);
                                      tailLen -= t;
                                      output[op++] = alphabet[(v >> 12) & 0x3f];
                                      output[op++] = alphabet[(v >> 6) & 0x3f];
                                      output[op++] = alphabet[v & 0x3f];
                                      if (do_padding) {
                                          output[op++] = '=';
                                      }
                                      if (do_newline) {
                                          if (do_cr) output[op++] = '\r';
                                          output[op++] = '\n';
                                      }
                                  } else if (do_newline && op > 0 && count != LINE_GROUPS) {
                                      if (do_cr) output[op++] = '\r';
                                      output[op++] = '\n';
                                  }
                  
                                  assert tailLen == 0;
                                  assert p == len;
                              } else {
                                  // Save the leftovers in tail to be consumed on the next
                                  // call to encodeInternal.
                  
                                  if (p == len-1) {
                                      tail[tailLen++] = input[p];
                                  } else if (p == len-2) {
                                      tail[tailLen++] = input[p];
                                      tail[tailLen++] = input[p+1];
                                  }
                              }
                  
                              this.op = op;
                              this.count = count;
                  
                              return true;
                          }
                      }
                  
                      private Base64() { }   // don't instantiate
                  }
                  

                  【讨论】:

                    【解决方案19】:

                    在使用 Java 7 编译但可能在更高 Java 版本中运行的代码中,检测 java.util.Base64 类的存在并使用最适合此处其他问题中提到的给定 JVM 的方法似乎很有用。

                    我使用了这个代码:

                    private static final Method JAVA_UTIL_BASE64_GETENCODER;
                    
                    static {
                        Method getEncoderMethod;
                        try {
                            final Class<?> base64Class = Class.forName("java.util.Base64");
                            getEncoderMethod = base64Class.getMethod("getEncoder");
                        } catch (ClassNotFoundException | NoSuchMethodException e) {
                            getEncoderMethod = null;
                        }
                        JAVA_UTIL_BASE64_GETENCODER = getEncoderMethod;
                    }
                    
                    static String base64EncodeToString(String s) {
                        final byte[] bytes = s.getBytes(StandardCharsets.ISO_8859_1);
                        if (JAVA_UTIL_BASE64_GETENCODER == null) {
                            // Java 7 and older // TODO: remove this branch after switching to Java 8
                            return DatatypeConverter.printBase64Binary(bytes);
                        } else {
                            // Java 8 and newer
                            try {
                                final Object encoder = JAVA_UTIL_BASE64_GETENCODER.invoke(null);
                                final Class<?> encoderClass = encoder.getClass();
                                final Method encodeMethod = encoderClass.getMethod("encode", byte[].class);
                                final byte[] encodedBytes = (byte[]) encodeMethod.invoke(encoder, bytes);
                                return new String(encodedBytes);
                            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                                throw new IllegalStateException(e);
                            }
                        }
                    }
                    

                    【讨论】:

                      【解决方案20】:
                      import java.io.UnsupportedEncodingException;
                      import java.security.MessageDigest;
                      import java.security.NoSuchAlgorithmException;
                      import java.util.Arrays;
                      import java.util.Base64;
                      
                      import javax.crypto.Cipher;
                      import javax.crypto.spec.SecretKeySpec;
                      /***
                       * 
                       * @author Vaquar khan
                       * 
                       *
                       */
                      public class AES {
                      
                          private static SecretKeySpec secretKey;
                          private static final String VK_secretKey = "VaquarKhan-secrate-key!!!!";
                          private static byte[] key;
                      
                          /**
                           * 
                           * @param myKey
                           */
                          public static void setKey(String myKey) {
                              MessageDigest sha = null;
                              try {
                                  key = myKey.getBytes("UTF-8");
                                  sha = MessageDigest.getInstance("SHA-1");
                                  key = sha.digest(key);
                                  key = Arrays.copyOf(key, 16);
                                  secretKey = new SecretKeySpec(key, "AES");
                              } catch (NoSuchAlgorithmException e) {
                                  e.printStackTrace();
                              } catch (UnsupportedEncodingException e) {
                                  e.printStackTrace();
                              }
                          }
                      /**
                       * encrypt
                       * @param strToEncrypt
                       * @param secret
                       * @return
                       */
                          public static String encrypt(String strToEncrypt, String secret) {
                              try {
                                  setKey(secret);
                                  Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                                  cipher.init(Cipher.ENCRYPT_MODE, secretKey);
                                  return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
                              } catch (Exception e) {
                                  System.out.println("Error while encrypting: " + e.toString());
                              }
                              return null;
                          }
                      /**
                       * decrypt
                       * @param strToDecrypt
                       * @param secret
                       * @return
                       */
                          public static String decrypt(String strToDecrypt, String secret) {
                              try {
                                  setKey(secret);
                                  Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
                                  cipher.init(Cipher.DECRYPT_MODE, secretKey);
                                  return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
                              } catch (Exception e) {
                                  System.out.println("Error while decrypting: " + e.toString());
                              }
                              return null;
                          }
                      
                          public static void main(String[] args) {
                              final String secretKey = VK_secretKey;
                              String password = "VKhan@12";
                              //
                              String encryptedString = AES.encrypt(password, secretKey);
                              String decryptedString = AES.decrypt(encryptedString, secretKey);
                              //
                              System.out.println(password);
                              System.out.println(encryptedString);
                              System.out.println(decryptedString);
                          }
                      
                      }
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2015-07-21
                        • 2016-07-25
                        • 1970-01-01
                        相关资源
                        最近更新 更多