001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.codec.binary;
019
020import java.math.BigInteger;
021import java.util.Objects;
022
023/**
024 * Provides Base64 encoding and decoding as defined by <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
025 *
026 * <p>
027 * This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose
028 * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and Borenstein.
029 * </p>
030 * <p>
031 * The class can be parameterized in the following manner with various constructors:
032 * </p>
033 * <ul>
034 * <li>URL-safe mode: Default off.</li>
035 * <li>Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of
036 * 4 in the encoded data.
037 * <li>Line separator: Default is CRLF ("\r\n")</li>
038 * </ul>
039 * <p>
040 * The URL-safe parameter is only applied to encode operations. Decoding seamlessly handles both modes.
041 * </p>
042 * <p>
043 * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only
044 * encode/decode character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252,
045 * UTF-8, etc).
046 * </p>
047 * <p>
048 * This class is thread-safe.
049 * </p>
050 *
051 * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
052 * @since 1.0
053 */
054public class Base64 extends BaseNCodec {
055
056    /**
057     * BASE32 characters are 6 bits in length.
058     * They are formed by taking a block of 3 octets to form a 24-bit string,
059     * which is converted into 4 BASE64 characters.
060     */
061    private static final int BITS_PER_ENCODED_BYTE = 6;
062    private static final int BYTES_PER_UNENCODED_BLOCK = 3;
063    private static final int BYTES_PER_ENCODED_BLOCK = 4;
064
065    /**
066     * Chunk separator per RFC 2045 section 2.1.
067     *
068     * <p>
069     * N.B. The next major release may break compatibility and make this field private.
070     * </p>
071     *
072     * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
073     */
074    static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
075
076    /**
077     * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet"
078     * equivalents as specified in Table 1 of RFC 2045.
079     *
080     * Thanks to "commons" project in ws.apache.org for this code.
081     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
082     */
083    private static final byte[] STANDARD_ENCODE_TABLE = {
084            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
085            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
086            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
087            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
088            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
089    };
090
091    /**
092     * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and /
093     * changed to - and _ to make the encoded Base64 results more URL-SAFE.
094     * This table is only used when the Base64's mode is set to URL-SAFE.
095     */
096    private static final byte[] URL_SAFE_ENCODE_TABLE = {
097            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
098            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
099            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
100            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
101            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
102    };
103
104    /**
105     * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified
106     * in Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64
107     * alphabet but fall within the bounds of the array are translated to -1.
108     *
109     * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both
110     * URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit).
111     *
112     * Thanks to "commons" project in ws.apache.org for this code.
113     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
114     */
115    private static final byte[] DECODE_TABLE = {
116        //   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
117            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f
118            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f
119            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, // 20-2f + - /
120            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 30-3f 0-9
121            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, // 40-4f A-O
122            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, // 50-5f P-Z _
123            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6f a-o
124            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51                      // 70-7a p-z
125    };
126
127    /**
128     * Base64 uses 6-bit fields.
129     */
130    /** Mask used to extract 6 bits, used when encoding */
131    private static final int MASK_6BITS = 0x3f;
132    /** Mask used to extract 4 bits, used when decoding final trailing character. */
133    private static final int MASK_4BITS = 0xf;
134    /** Mask used to extract 2 bits, used when decoding final trailing character. */
135    private static final int MASK_2BITS = 0x3;
136
137    // The static final fields above are used for the original static byte[] methods on Base64.
138    // The private member fields below are used with the new streaming approach, which requires
139    // some state be preserved between calls of encode() and decode().
140
141    /**
142     * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able
143     * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch
144     * between the two modes.
145     */
146    private final byte[] encodeTable;
147
148    // Only one decode table currently; keep for consistency with Base32 code
149    private final byte[] decodeTable = DECODE_TABLE;
150
151    /**
152     * Line separator for encoding. Not used when decoding. Only used if lineLength &gt; 0.
153     */
154    private final byte[] lineSeparator;
155
156    /**
157     * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
158     * {@code decodeSize = 3 + lineSeparator.length;}
159     */
160    private final int decodeSize;
161
162    /**
163     * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
164     * {@code encodeSize = 4 + lineSeparator.length;}
165     */
166    private final int encodeSize;
167
168    /**
169     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
170     * <p>
171     * When encoding the line length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE.
172     * </p>
173     *
174     * <p>
175     * When decoding all variants are supported.
176     * </p>
177     */
178    public Base64() {
179        this(0);
180    }
181
182    /**
183     * Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode.
184     * <p>
185     * When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE.
186     * </p>
187     *
188     * <p>
189     * When decoding all variants are supported.
190     * </p>
191     *
192     * @param urlSafe
193     *            if {@code true}, URL-safe encoding is used. In most cases this should be set to
194     *            {@code false}.
195     * @since 1.4
196     */
197    public Base64(final boolean urlSafe) {
198        this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe);
199    }
200
201    /**
202     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
203     * <p>
204     * When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is
205     * STANDARD_ENCODE_TABLE.
206     * </p>
207     * <p>
208     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
209     * </p>
210     * <p>
211     * When decoding all variants are supported.
212     * </p>
213     *
214     * @param lineLength
215     *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
216     *            4). If lineLength &lt;= 0, then the output will not be divided into lines (chunks). Ignored when
217     *            decoding.
218     * @since 1.4
219     */
220    public Base64(final int lineLength) {
221        this(lineLength, CHUNK_SEPARATOR);
222    }
223
224    /**
225     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
226     * <p>
227     * When encoding the line length and line separator are given in the constructor, and the encoding table is
228     * STANDARD_ENCODE_TABLE.
229     * </p>
230     * <p>
231     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
232     * </p>
233     * <p>
234     * When decoding all variants are supported.
235     * </p>
236     *
237     * @param lineLength
238     *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
239     *            4). If lineLength &lt;= 0, then the output will not be divided into lines (chunks). Ignored when
240     *            decoding.
241     * @param lineSeparator
242     *            Each line of encoded data will end with this sequence of bytes.
243     * @throws IllegalArgumentException
244     *             Thrown when the provided lineSeparator included some base64 characters.
245     * @since 1.4
246     */
247    public Base64(final int lineLength, final byte[] lineSeparator) {
248        this(lineLength, lineSeparator, false);
249    }
250
251    /**
252     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
253     * <p>
254     * When encoding the line length and line separator are given in the constructor, and the encoding table is
255     * STANDARD_ENCODE_TABLE.
256     * </p>
257     * <p>
258     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
259     * </p>
260     * <p>
261     * When decoding all variants are supported.
262     * </p>
263     *
264     * @param lineLength
265     *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
266     *            4). If lineLength &lt;= 0, then the output will not be divided into lines (chunks). Ignored when
267     *            decoding.
268     * @param lineSeparator
269     *            Each line of encoded data will end with this sequence of bytes.
270     * @param urlSafe
271     *            Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode
272     *            operations. Decoding seamlessly handles both modes.
273     *            <b>Note: no padding is added when using the URL-safe alphabet.</b>
274     * @throws IllegalArgumentException
275     *             The provided lineSeparator included some base64 characters. That's not going to work!
276     * @since 1.4
277     */
278    public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) {
279        super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK,
280                lineLength,
281                lineSeparator == null ? 0 : lineSeparator.length);
282        // TODO could be simplified if there is no requirement to reject invalid line sep when length <=0
283        // @see test case Base64Test.testConstructors()
284        if (lineSeparator != null) {
285            if (containsAlphabetOrPad(lineSeparator)) {
286                final String sep = StringUtils.newStringUtf8(lineSeparator);
287                throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]");
288            }
289            if (lineLength > 0){ // null line-sep forces no chunking rather than throwing IAE
290                this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length;
291                this.lineSeparator = new byte[lineSeparator.length];
292                System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
293            } else {
294                this.encodeSize = BYTES_PER_ENCODED_BLOCK;
295                this.lineSeparator = null;
296            }
297        } else {
298            this.encodeSize = BYTES_PER_ENCODED_BLOCK;
299            this.lineSeparator = null;
300        }
301        this.decodeSize = this.encodeSize - 1;
302        this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
303    }
304
305    /**
306     * Returns our current encode mode. True if we're URL-SAFE, false otherwise.
307     *
308     * @return true if we're in URL-SAFE mode, false otherwise.
309     * @since 1.4
310     */
311    public boolean isUrlSafe() {
312        return this.encodeTable == URL_SAFE_ENCODE_TABLE;
313    }
314
315    /**
316     * <p>
317     * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with
318     * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, to flush last
319     * remaining bytes (if not multiple of 3).
320     * </p>
321     * <p><b>Note: no padding is added when encoding using the URL-safe alphabet.</b></p>
322     * <p>
323     * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
324     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
325     * </p>
326     *
327     * @param in
328     *            byte[] array of binary data to base64 encode.
329     * @param inPos
330     *            Position to start reading data from.
331     * @param inAvail
332     *            Amount of bytes available from input for encoding.
333     * @param context
334     *            the context to be used
335     */
336    @Override
337    void encode(final byte[] in, int inPos, final int inAvail, final Context context) {
338        if (context.eof) {
339            return;
340        }
341        // inAvail < 0 is how we're informed of EOF in the underlying data we're
342        // encoding.
343        if (inAvail < 0) {
344            context.eof = true;
345            if (0 == context.modulus && lineLength == 0) {
346                return; // no leftovers to process and not using chunking
347            }
348            final byte[] buffer = ensureBufferSize(encodeSize, context);
349            final int savedPos = context.pos;
350            switch (context.modulus) { // 0-2
351                case 0 : // nothing to do here
352                    break;
353                case 1 : // 8 bits = 6 + 2
354                    // top 6 bits:
355                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 2) & MASK_6BITS];
356                    // remaining 2:
357                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 4) & MASK_6BITS];
358                    // URL-SAFE skips the padding to further reduce size.
359                    if (encodeTable == STANDARD_ENCODE_TABLE) {
360                        buffer[context.pos++] = pad;
361                        buffer[context.pos++] = pad;
362                    }
363                    break;
364
365                case 2 : // 16 bits = 6 + 6 + 4
366                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 10) & MASK_6BITS];
367                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 4) & MASK_6BITS];
368                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 2) & MASK_6BITS];
369                    // URL-SAFE skips the padding to further reduce size.
370                    if (encodeTable == STANDARD_ENCODE_TABLE) {
371                        buffer[context.pos++] = pad;
372                    }
373                    break;
374                default:
375                    throw new IllegalStateException("Impossible modulus "+context.modulus);
376            }
377            context.currentLinePos += context.pos - savedPos; // keep track of current line position
378            // if currentPos == 0 we are at the start of a line, so don't add CRLF
379            if (lineLength > 0 && context.currentLinePos > 0) {
380                System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
381                context.pos += lineSeparator.length;
382            }
383        } else {
384            for (int i = 0; i < inAvail; i++) {
385                final byte[] buffer = ensureBufferSize(encodeSize, context);
386                context.modulus = (context.modulus+1) % BYTES_PER_UNENCODED_BLOCK;
387                int b = in[inPos++];
388                if (b < 0) {
389                    b += 256;
390                }
391                context.ibitWorkArea = (context.ibitWorkArea << 8) + b; //  BITS_PER_BYTE
392                if (0 == context.modulus) { // 3 bytes = 24 bits = 4 * 6 bits to extract
393                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 18) & MASK_6BITS];
394                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 12) & MASK_6BITS];
395                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 6) & MASK_6BITS];
396                    buffer[context.pos++] = encodeTable[context.ibitWorkArea & MASK_6BITS];
397                    context.currentLinePos += BYTES_PER_ENCODED_BLOCK;
398                    if (lineLength > 0 && lineLength <= context.currentLinePos) {
399                        System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
400                        context.pos += lineSeparator.length;
401                        context.currentLinePos = 0;
402                    }
403                }
404            }
405        }
406    }
407
408    /**
409     * <p>
410     * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once
411     * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1"
412     * call is not necessary when decoding, but it doesn't hurt, either.
413     * </p>
414     * <p>
415     * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are
416     * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in,
417     * garbage-out philosophy: it will not check the provided data for validity.
418     * </p>
419     * <p>
420     * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
421     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
422     * </p>
423     *
424     * @param in
425     *            byte[] array of ascii data to base64 decode.
426     * @param inPos
427     *            Position to start reading data from.
428     * @param inAvail
429     *            Amount of bytes available from input for decoding.
430     * @param context
431     *            the context to be used
432     */
433    @Override
434    void decode(final byte[] in, int inPos, final int inAvail, final Context context) {
435        if (context.eof) {
436            return;
437        }
438        if (inAvail < 0) {
439            context.eof = true;
440        }
441        for (int i = 0; i < inAvail; i++) {
442            final byte[] buffer = ensureBufferSize(decodeSize, context);
443            final byte b = in[inPos++];
444            if (b == pad) {
445                // We're done.
446                context.eof = true;
447                break;
448            }
449            if (b >= 0 && b < DECODE_TABLE.length) {
450                final int result = DECODE_TABLE[b];
451                if (result >= 0) {
452                    context.modulus = (context.modulus+1) % BYTES_PER_ENCODED_BLOCK;
453                    context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result;
454                    if (context.modulus == 0) {
455                        buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 16) & MASK_8BITS);
456                        buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
457                        buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS);
458                    }
459                }
460            }
461        }
462
463        // Two forms of EOF as far as base64 decoder is concerned: actual
464        // EOF (-1) and first time '=' character is encountered in stream.
465        // This approach makes the '=' padding characters completely optional.
466        if (context.eof && context.modulus != 0) {
467            final byte[] buffer = ensureBufferSize(decodeSize, context);
468
469            // We have some spare bits remaining
470            // Output all whole multiples of 8 bits and ignore the rest
471            switch (context.modulus) {
472//              case 0 : // impossible, as excluded above
473                case 1 : // 6 bits - ignore entirely
474                    // TODO not currently tested; perhaps it is impossible?
475                    break;
476                case 2 : // 12 bits = 8 + 4
477                    validateCharacter(MASK_4BITS, context);
478                    context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits
479                    buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
480                    break;
481                case 3 : // 18 bits = 8 + 8 + 2
482                    validateCharacter(MASK_2BITS, context);
483                    context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits
484                    buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
485                    buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
486                    break;
487                default:
488                    throw new IllegalStateException("Impossible modulus "+context.modulus);
489            }
490        }
491    }
492
493    /**
494     * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the
495     * method treats whitespace as valid.
496     *
497     * @param arrayOctet
498     *            byte array to test
499     * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
500     *         {@code false}, otherwise
501     * @deprecated 1.5 Use {@link #isBase64(byte[])}, will be removed in 2.0.
502     */
503    @Deprecated
504    public static boolean isArrayByteBase64(final byte[] arrayOctet) {
505        return isBase64(arrayOctet);
506    }
507
508    /**
509     * Returns whether or not the {@code octet} is in the base 64 alphabet.
510     *
511     * @param octet
512     *            The value to test
513     * @return {@code true} if the value is defined in the the base 64 alphabet, {@code false} otherwise.
514     * @since 1.4
515     */
516    public static boolean isBase64(final byte octet) {
517        return octet == PAD_DEFAULT || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1);
518    }
519
520    /**
521     * Tests a given String to see if it contains only valid characters within the Base64 alphabet. Currently the
522     * method treats whitespace as valid.
523     *
524     * @param base64
525     *            String to test
526     * @return {@code true} if all characters in the String are valid characters in the Base64 alphabet or if
527     *         the String is empty; {@code false}, otherwise
528     *  @since 1.5
529     */
530    public static boolean isBase64(final String base64) {
531        return isBase64(StringUtils.getBytesUtf8(base64));
532    }
533
534    /**
535     * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the
536     * method treats whitespace as valid.
537     *
538     * @param arrayOctet
539     *            byte array to test
540     * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
541     *         {@code false}, otherwise
542     * @since 1.5
543     */
544    public static boolean isBase64(final byte[] arrayOctet) {
545        for (int i = 0; i < arrayOctet.length; i++) {
546            if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) {
547                return false;
548            }
549        }
550        return true;
551    }
552
553    /**
554     * Encodes binary data using the base64 algorithm but does not chunk the output.
555     *
556     * @param binaryData
557     *            binary data to encode
558     * @return byte[] containing Base64 characters in their UTF-8 representation.
559     */
560    public static byte[] encodeBase64(final byte[] binaryData) {
561        return encodeBase64(binaryData, false);
562    }
563
564    /**
565     * Encodes binary data using the base64 algorithm but does not chunk the output.
566     *
567     * NOTE:  We changed the behaviour of this method from multi-line chunking (commons-codec-1.4) to
568     * single-line non-chunking (commons-codec-1.5).
569     *
570     * @param binaryData
571     *            binary data to encode
572     * @return String containing Base64 characters.
573     * @since 1.4 (NOTE:  1.4 chunked the output, whereas 1.5 does not).
574     */
575    public static String encodeBase64String(final byte[] binaryData) {
576        return StringUtils.newStringUsAscii(encodeBase64(binaryData, false));
577    }
578
579    /**
580     * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
581     * url-safe variation emits - and _ instead of + and / characters.
582     * <b>Note: no padding is added.</b>
583     * @param binaryData
584     *            binary data to encode
585     * @return byte[] containing Base64 characters in their UTF-8 representation.
586     * @since 1.4
587     */
588    public static byte[] encodeBase64URLSafe(final byte[] binaryData) {
589        return encodeBase64(binaryData, false, true);
590    }
591
592    /**
593     * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
594     * url-safe variation emits - and _ instead of + and / characters.
595     * <b>Note: no padding is added.</b>
596     * @param binaryData
597     *            binary data to encode
598     * @return String containing Base64 characters
599     * @since 1.4
600     */
601    public static String encodeBase64URLSafeString(final byte[] binaryData) {
602        return StringUtils.newStringUsAscii(encodeBase64(binaryData, false, true));
603    }
604
605    /**
606     * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks
607     *
608     * @param binaryData
609     *            binary data to encode
610     * @return Base64 characters chunked in 76 character blocks
611     */
612    public static byte[] encodeBase64Chunked(final byte[] binaryData) {
613        return encodeBase64(binaryData, true);
614    }
615
616    /**
617     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
618     *
619     * @param binaryData
620     *            Array containing binary data to encode.
621     * @param isChunked
622     *            if {@code true} this encoder will chunk the base64 output into 76 character blocks
623     * @return Base64-encoded data.
624     * @throws IllegalArgumentException
625     *             Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
626     */
627    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked) {
628        return encodeBase64(binaryData, isChunked, false);
629    }
630
631    /**
632     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
633     *
634     * @param binaryData
635     *            Array containing binary data to encode.
636     * @param isChunked
637     *            if {@code true} this encoder will chunk the base64 output into 76 character blocks
638     * @param urlSafe
639     *            if {@code true} this encoder will emit - and _ instead of the usual + and / characters.
640     *            <b>Note: no padding is added when encoding using the URL-safe alphabet.</b>
641     * @return Base64-encoded data.
642     * @throws IllegalArgumentException
643     *             Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
644     * @since 1.4
645     */
646    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe) {
647        return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE);
648    }
649
650    /**
651     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
652     *
653     * @param binaryData
654     *            Array containing binary data to encode.
655     * @param isChunked
656     *            if {@code true} this encoder will chunk the base64 output into 76 character blocks
657     * @param urlSafe
658     *            if {@code true} this encoder will emit - and _ instead of the usual + and / characters.
659     *            <b>Note: no padding is added when encoding using the URL-safe alphabet.</b>
660     * @param maxResultSize
661     *            The maximum result size to accept.
662     * @return Base64-encoded data.
663     * @throws IllegalArgumentException
664     *             Thrown when the input array needs an output array bigger than maxResultSize
665     * @since 1.4
666     */
667    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked,
668                                      final boolean urlSafe, final int maxResultSize) {
669        if (binaryData == null || binaryData.length == 0) {
670            return binaryData;
671        }
672
673        // Create this so can use the super-class method
674        // Also ensures that the same roundings are performed by the ctor and the code
675        final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe);
676        final long len = b64.getEncodedLength(binaryData);
677        if (len > maxResultSize) {
678            throw new IllegalArgumentException("Input array too big, the output array would be bigger (" +
679                len +
680                ") than the specified maximum size of " +
681                maxResultSize);
682        }
683
684        return b64.encode(binaryData);
685    }
686
687    /**
688     * Decodes a Base64 String into octets.
689     * <p>
690     * <b>Note:</b> this method seamlessly handles data encoded in URL-safe or normal mode.
691     * </p>
692     *
693     * @param base64String
694     *            String containing Base64 data
695     * @return Array containing decoded data.
696     * @since 1.4
697     */
698    public static byte[] decodeBase64(final String base64String) {
699        return new Base64().decode(base64String);
700    }
701
702    /**
703     * Decodes Base64 data into octets.
704     * <p>
705     * <b>Note:</b> this method seamlessly handles data encoded in URL-safe or normal mode.
706     * </p>
707     *
708     * @param base64Data
709     *            Byte array containing Base64 data
710     * @return Array containing decoded data.
711     */
712    public static byte[] decodeBase64(final byte[] base64Data) {
713        return new Base64().decode(base64Data);
714    }
715
716    // Implementation of the Encoder Interface
717
718    // Implementation of integer encoding used for crypto
719    /**
720     * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature.
721     *
722     * @param pArray
723     *            a byte array containing base64 character data
724     * @return A BigInteger
725     * @since 1.4
726     */
727    public static BigInteger decodeInteger(final byte[] pArray) {
728        return new BigInteger(1, decodeBase64(pArray));
729    }
730
731    /**
732     * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature.
733     *
734     * @param bigInteger
735     *            a BigInteger
736     * @return A byte array containing base64 character data
737     * @throws NullPointerException
738     *             if null is passed in
739     * @since 1.4
740     */
741    public static byte[] encodeInteger(final BigInteger bigInteger) {
742        Objects.requireNonNull(bigInteger, "bigInteger");
743        return encodeBase64(toIntegerBytes(bigInteger), false);
744    }
745
746    /**
747     * Returns a byte-array representation of a {@code BigInteger} without sign bit.
748     *
749     * @param bigInt
750     *            {@code BigInteger} to be converted
751     * @return a byte array representation of the BigInteger parameter
752     */
753    static byte[] toIntegerBytes(final BigInteger bigInt) {
754        int bitlen = bigInt.bitLength();
755        // round bitlen
756        bitlen = ((bitlen + 7) >> 3) << 3;
757        final byte[] bigBytes = bigInt.toByteArray();
758
759        if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) {
760            return bigBytes;
761        }
762        // set up params for copying everything but sign bit
763        int startSrc = 0;
764        int len = bigBytes.length;
765
766        // if bigInt is exactly byte-aligned, just skip signbit in copy
767        if ((bigInt.bitLength() % 8) == 0) {
768            startSrc = 1;
769            len--;
770        }
771        final int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec
772        final byte[] resizedBytes = new byte[bitlen / 8];
773        System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len);
774        return resizedBytes;
775    }
776
777    /**
778     * Returns whether or not the {@code octet} is in the Base64 alphabet.
779     *
780     * @param octet
781     *            The value to test
782     * @return {@code true} if the value is defined in the the Base64 alphabet {@code false} otherwise.
783     */
784    @Override
785    protected boolean isInAlphabet(final byte octet) {
786        return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
787    }
788
789    /**
790     * Validates whether decoding the final trailing character is possible in the context
791     * of the set of possible base 64 values.
792     *
793     * <p>The character is valid if the lower bits within the provided mask are zero. This
794     * is used to test the final trailing base-64 digit is zero in the bits that will be discarded.
795     *
796     * @param emptyBitsMask The mask of the lower bits that should be empty
797     * @param context the context to be used
798     *
799     * @throws IllegalArgumentException if the bits being checked contain any non-zero value
800     */
801    private static void validateCharacter(final int emptyBitsMask, final Context context) {
802        if ((context.ibitWorkArea & emptyBitsMask) != 0) {
803            throw new IllegalArgumentException(
804                "Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible value. " +
805                "Expected the discarded bits to be zero.");
806        }
807    }
808}