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    
018    package org.apache.commons.ssl;
019    
020    import org.apache.commons.ssl.util.UTF8;
021    
022    import java.math.BigInteger;
023    
024    /**
025     * Provides Base64 encoding and decoding as defined by RFC 2045.
026     *
027     * <p>
028     * This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose
029     * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and Borenstein.
030     * </p>
031     * <p>
032     * The class can be parameterized in the following manner with various constructors:
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     * <p>
041     * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode
042     * character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc).
043     * </p>
044     *
045     * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
046     * @author Apache Software Foundation
047     * @since 1.0
048     * @version $Id: Base64.java 155 2009-09-17 21:00:58Z julius $
049     */
050    public class Base64 {
051        private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;
052    
053        private static final int DEFAULT_BUFFER_SIZE = 8192;
054    
055        /**
056         * Chunk size per RFC 2045 section 6.8.
057         *
058         * <p>
059         * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
060         * equal signs.
061         * </p>
062         *
063         * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a>
064         */
065        static final int CHUNK_SIZE = 76;
066    
067        /**
068         * Chunk separator per RFC 2045 section 2.1.
069         *
070         * <p>
071         * N.B. The next major release may break compatibility and make this field private.
072         * </p>
073         *
074         * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
075         */
076        static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
077    
078        /**
079         * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet"
080         * equivalents as specified in Table 1 of RFC 2045.
081         *
082         * Thanks to "commons" project in ws.apache.org for this code.
083         * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
084         */
085        private static final byte[] STANDARD_ENCODE_TABLE = {
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                'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
089                'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
090                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
091        };
092    
093        /**
094         * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and /
095         * changed to - and _ to make the encoded Base64 results more URL-SAFE.
096         * This table is only used when the Base64's mode is set to URL-SAFE.
097         */
098        private static final byte[] URL_SAFE_ENCODE_TABLE = {
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                'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
102                'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
103                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
104        };
105    
106        /**
107         * Byte used to pad output.
108         */
109        private static final byte PAD = '=';
110    
111        /**
112         * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified in
113         * Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64
114         * alphabet but fall within the bounds of the array are translated to -1.
115         *
116         * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both
117         * URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit).
118         *
119         * Thanks to "commons" project in ws.apache.org for this code.
120         * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
121         */
122        private static final byte[] DECODE_TABLE = {
123                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
124                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
125                -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54,
126                55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
127                5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
128                24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
129                35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
130        };
131    
132        /** Mask used to extract 6 bits, used when encoding */
133        private static final int MASK_6BITS = 0x3f;
134    
135        /** Mask used to extract 8 bits, used in decoding base64 bytes */
136        private static final int MASK_8BITS = 0xff;
137    
138        // The static final fields above are used for the original static byte[] methods on Base64.
139        // The private member fields below are used with the new streaming approach, which requires
140        // some state be preserved between calls of encode() and decode().
141    
142        /**
143         * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able
144         * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch
145         * between the two modes.
146         */
147        private final byte[] encodeTable;
148    
149        /**
150         * Line length for encoding. Not used when decoding. A value of zero or less implies no chunking of the base64
151         * encoded data.
152         */
153        private final int lineLength;
154    
155        /**
156         * Line separator for encoding. Not used when decoding. Only used if lineLength > 0.
157         */
158        private final byte[] lineSeparator;
159    
160        /**
161         * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
162         * <code>decodeSize = 3 + lineSeparator.length;</code>
163         */
164        private final int decodeSize;
165    
166        /**
167         * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
168         * <code>encodeSize = 4 + lineSeparator.length;</code>
169         */
170        private final int encodeSize;
171    
172        /**
173         * Buffer for streaming.
174         */
175        private byte[] buffer;
176    
177        /**
178         * Position where next character should be written in the buffer.
179         */
180        private int pos;
181    
182        /**
183         * Position where next character should be read from the buffer.
184         */
185        private int readPos;
186    
187        /**
188         * Variable tracks how many characters have been written to the current line. Only used when encoding. We use it to
189         * make sure each encoded line never goes beyond lineLength (if lineLength > 0).
190         */
191        private int currentLinePos;
192    
193        /**
194         * Writes to the buffer only occur after every 3 reads when encoding, an every 4 reads when decoding. This variable
195         * helps track that.
196         */
197        private int modulus;
198    
199        /**
200         * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this Base64 object becomes useless,
201         * and must be thrown away.
202         */
203        private boolean eof;
204    
205        /**
206         * Place holder for the 3 bytes we're dealing with for our base64 logic. Bitwise operations store and extract the
207         * base64 encoding or decoding from this variable.
208         */
209        private int x;
210    
211        /**
212         * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
213         * <p>
214         * When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE.
215         * </p>
216         *
217         * <p>
218         * When decoding all variants are supported.
219         * </p>
220         */
221        public Base64() {
222            this(false);
223        }
224    
225        /**
226         * Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode.
227         * <p>
228         * When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE.
229         * </p>
230         *
231         * <p>
232         * When decoding all variants are supported.
233         * </p>
234         *
235         * @param urlSafe
236         *            if <code>true</code>, URL-safe encoding is used. In most cases this should be set to
237         *            <code>false</code>.
238         * @since 1.4
239         */
240        public Base64(boolean urlSafe) {
241            this(CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe);
242        }
243    
244        /**
245         * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
246         * <p>
247         * When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is
248         * STANDARD_ENCODE_TABLE.
249         * </p>
250         * <p>
251         * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
252         * </p>
253         * <p>
254         * When decoding all variants are supported.
255         * </p>
256         *
257         * @param lineLength
258         *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4).
259         *            If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when decoding.
260         * @since 1.4
261         */
262        public Base64(int lineLength) {
263            this(lineLength, CHUNK_SEPARATOR);
264        }
265    
266        /**
267         * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
268         * <p>
269         * When encoding the line length and line separator are given in the constructor, and the encoding table is
270         * STANDARD_ENCODE_TABLE.
271         * </p>
272         * <p>
273         * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
274         * </p>
275         * <p>
276         * When decoding all variants are supported.
277         * </p>
278         *
279         * @param lineLength
280         *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4).
281         *            If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when decoding.
282         * @param lineSeparator
283         *            Each line of encoded data will end with this sequence of bytes.
284         * @throws IllegalArgumentException
285         *             Thrown when the provided lineSeparator included some base64 characters.
286         * @since 1.4
287         */
288        public Base64(int lineLength, byte[] lineSeparator) {
289            this(lineLength, lineSeparator, false);
290        }
291    
292        /**
293         * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
294         * <p>
295         * When encoding the line length and line separator are given in the constructor, and the encoding table is
296         * STANDARD_ENCODE_TABLE.
297         * </p>
298         * <p>
299         * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
300         * </p>
301         * <p>
302         * When decoding all variants are supported.
303         * </p>
304         *
305         * @param lineLength
306         *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4).
307         *            If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when decoding.
308         * @param lineSeparator
309         *            Each line of encoded data will end with this sequence of bytes.
310         * @param urlSafe
311         *            Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode
312         *            operations. Decoding seamlessly handles both modes.
313         * @throws IllegalArgumentException
314         *             The provided lineSeparator included some base64 characters. That's not going to work!
315         * @since 1.4
316         */
317        public Base64(int lineLength, byte[] lineSeparator, boolean urlSafe) {
318            if (lineSeparator == null) {
319                lineLength = 0;  // disable chunk-separating
320                lineSeparator = CHUNK_SEPARATOR;  // this just gets ignored
321            }
322            this.lineLength = lineLength > 0 ? (lineLength / 4) * 4 : 0;
323            this.lineSeparator = new byte[lineSeparator.length];
324            System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
325            if (lineLength > 0) {
326                this.encodeSize = 4 + lineSeparator.length;
327            } else {
328                this.encodeSize = 4;
329            }
330            this.decodeSize = this.encodeSize - 1;
331            if (containsBase64Byte(lineSeparator)) {
332                String sep = UTF8.toString(lineSeparator);
333                throw new IllegalArgumentException("lineSeperator must not contain base64 characters: [" + sep + "]");
334            }
335            this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
336        }
337    
338        /**
339         * Returns our current encode mode. True if we're URL-SAFE, false otherwise.
340         *
341         * @return true if we're in URL-SAFE mode, false otherwise.
342         * @since 1.4
343         */
344        public boolean isUrlSafe() {
345            return this.encodeTable == URL_SAFE_ENCODE_TABLE;
346        }
347    
348        /**
349         * Returns true if this Base64 object has buffered data for reading.
350         *
351         * @return true if there is Base64 object still available for reading.
352         */
353        boolean hasData() {
354            return this.buffer != null;
355        }
356    
357        /**
358         * Returns the amount of buffered data available for reading.
359         *
360         * @return The amount of buffered data available for reading.
361         */
362        int avail() {
363            return buffer != null ? pos - readPos : 0;
364        }
365    
366        /** Doubles our buffer. */
367        private void resizeBuffer() {
368            if (buffer == null) {
369                buffer = new byte[DEFAULT_BUFFER_SIZE];
370                pos = 0;
371                readPos = 0;
372            } else {
373                byte[] b = new byte[buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR];
374                System.arraycopy(buffer, 0, b, 0, buffer.length);
375                buffer = b;
376            }
377        }
378    
379        /**
380         * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail
381         * bytes. Returns how many bytes were actually extracted.
382         *
383         * @param b
384         *            byte[] array to extract the buffered data into.
385         * @param bPos
386         *            position in byte[] array to start extraction at.
387         * @param bAvail
388         *            amount of bytes we're allowed to extract. We may extract fewer (if fewer are available).
389         * @return The number of bytes successfully extracted into the provided byte[] array.
390         */
391        int readResults(byte[] b, int bPos, int bAvail) {
392            if (buffer != null) {
393                int len = Math.min(avail(), bAvail);
394                if (buffer != b) {
395                    System.arraycopy(buffer, readPos, b, bPos, len);
396                    readPos += len;
397                    if (readPos >= pos) {
398                        buffer = null;
399                    }
400                } else {
401                    // Re-using the original consumer's output array is only
402                    // allowed for one round.
403                    buffer = null;
404                }
405                return len;
406            }
407            return eof ? -1 : 0;
408        }
409    
410        /**
411         * Sets the streaming buffer. This is a small optimization where we try to buffer directly to the consumer's output
412         * array for one round (if the consumer calls this method first) instead of starting our own buffer.
413         *
414         * @param out
415         *            byte[] array to buffer directly to.
416         * @param outPos
417         *            Position to start buffering into.
418         * @param outAvail
419         *            Amount of bytes available for direct buffering.
420         */
421        void setInitialBuffer(byte[] out, int outPos, int outAvail) {
422            // We can re-use consumer's original output array under
423            // special circumstances, saving on some System.arraycopy().
424            if (out != null && out.length == outAvail) {
425                buffer = out;
426                pos = outPos;
427                readPos = outPos;
428            }
429        }
430    
431        /**
432         * <p>
433         * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with
434         * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, so flush last
435         * remaining bytes (if not multiple of 3).
436         * </p>
437         * <p>
438         * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
439         * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
440         * </p>
441         *
442         * @param in
443         *            byte[] array of binary data to base64 encode.
444         * @param inPos
445         *            Position to start reading data from.
446         * @param inAvail
447         *            Amount of bytes available from input for encoding.
448         */
449        void encode(byte[] in, int inPos, int inAvail) {
450            if (eof) {
451                return;
452            }
453            // inAvail < 0 is how we're informed of EOF in the underlying data we're
454            // encoding.
455            if (inAvail < 0) {
456                eof = true;
457                if (buffer == null || buffer.length - pos < encodeSize) {
458                    resizeBuffer();
459                }
460                switch (modulus) {
461                    case 1 :
462                        buffer[pos++] = encodeTable[(x >> 2) & MASK_6BITS];
463                        buffer[pos++] = encodeTable[(x << 4) & MASK_6BITS];
464                        // URL-SAFE skips the padding to further reduce size.
465                        if (encodeTable == STANDARD_ENCODE_TABLE) {
466                            buffer[pos++] = PAD;
467                            buffer[pos++] = PAD;
468                        }
469                        break;
470    
471                    case 2 :
472                        buffer[pos++] = encodeTable[(x >> 10) & MASK_6BITS];
473                        buffer[pos++] = encodeTable[(x >> 4) & MASK_6BITS];
474                        buffer[pos++] = encodeTable[(x << 2) & MASK_6BITS];
475                        // URL-SAFE skips the padding to further reduce size.
476                        if (encodeTable == STANDARD_ENCODE_TABLE) {
477                            buffer[pos++] = PAD;
478                        }
479                        break;
480                }
481                if (lineLength > 0 && pos > 0) {
482                    System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
483                    pos += lineSeparator.length;
484                }
485            } else {
486                for (int i = 0; i < inAvail; i++) {
487                    if (buffer == null || buffer.length - pos < encodeSize) {
488                        resizeBuffer();
489                    }
490                    modulus = (++modulus) % 3;
491                    int b = in[inPos++];
492                    if (b < 0) {
493                        b += 256;
494                    }
495                    x = (x << 8) + b;
496                    if (0 == modulus) {
497                        buffer[pos++] = encodeTable[(x >> 18) & MASK_6BITS];
498                        buffer[pos++] = encodeTable[(x >> 12) & MASK_6BITS];
499                        buffer[pos++] = encodeTable[(x >> 6) & MASK_6BITS];
500                        buffer[pos++] = encodeTable[x & MASK_6BITS];
501                        currentLinePos += 4;
502                        if (lineLength > 0 && lineLength <= currentLinePos) {
503                            System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
504                            pos += lineSeparator.length;
505                            currentLinePos = 0;
506                        }
507                    }
508                }
509            }
510        }
511    
512        /**
513         * <p>
514         * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once
515         * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1"
516         * call is not necessary when decoding, but it doesn't hurt, either.
517         * </p>
518         * <p>
519         * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are
520         * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in,
521         * garbage-out philosophy: it will not check the provided data for validity.
522         * </p>
523         * <p>
524         * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
525         * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
526         * </p>
527         *
528         * @param in
529         *            byte[] array of ascii data to base64 decode.
530         * @param inPos
531         *            Position to start reading data from.
532         * @param inAvail
533         *            Amount of bytes available from input for encoding.
534         */
535        void decode(byte[] in, int inPos, int inAvail) {
536            if (eof) {
537                return;
538            }
539            if (inAvail < 0) {
540                eof = true;
541            }
542            for (int i = 0; i < inAvail; i++) {
543                if (buffer == null || buffer.length - pos < decodeSize) {
544                    resizeBuffer();
545                }
546                byte b = in[inPos++];
547                if (b == PAD) {
548                    // We're done.
549                    eof = true;
550                    break;
551                } else {
552                    if (b >= 0 && b < DECODE_TABLE.length) {
553                        int result = DECODE_TABLE[b];
554                        if (result >= 0) {
555                            modulus = (++modulus) % 4;
556                            x = (x << 6) + result;
557                            if (modulus == 0) {
558                                buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
559                                buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
560                                buffer[pos++] = (byte) (x & MASK_8BITS);
561                            }
562                        }
563                    }
564                }
565            }
566    
567            // Two forms of EOF as far as base64 decoder is concerned: actual
568            // EOF (-1) and first time '=' character is encountered in stream.
569            // This approach makes the '=' padding characters completely optional.
570            if (eof && modulus != 0) {
571                x = x << 6;
572                switch (modulus) {
573                    case 2 :
574                        x = x << 6;
575                        buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
576                        break;
577                    case 3 :
578                        buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
579                        buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
580                        break;
581                }
582            }
583        }
584    
585        /**
586         * Returns whether or not the <code>octet</code> is in the base 64 alphabet.
587         *
588         * @param octet
589         *            The value to test
590         * @return <code>true</code> if the value is defined in the the base 64 alphabet, <code>false</code> otherwise.
591         * @since 1.4
592         */
593        public static boolean isBase64(byte octet) {
594            return octet == PAD || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1);
595        }
596    
597        /**
598         * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the
599         * method treats whitespace as valid.
600         *
601         * @param arrayOctet
602         *            byte array to test
603         * @return <code>true</code> if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
604         *         false, otherwise
605         */
606        public static boolean isArrayByteBase64(byte[] arrayOctet) {
607            for (int i = 0; i < arrayOctet.length; i++) {
608                if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) {
609                    return false;
610                }
611            }
612            return true;
613        }
614    
615        /**
616         * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet.
617         *
618         * @param arrayOctet
619         *            byte array to test
620         * @return <code>true</code> if any byte is a valid character in the Base64 alphabet; false herwise
621         */
622        private static boolean containsBase64Byte(byte[] arrayOctet) {
623            for (int i = 0; i < arrayOctet.length; i++) {
624                if (isBase64(arrayOctet[i])) {
625                    return true;
626                }
627            }
628            return false;
629        }
630    
631        /**
632         * Encodes binary data using the base64 algorithm but does not chunk the output.
633         *
634         * @param binaryData
635         *            binary data to encode
636         * @return byte[] containing Base64 characters in their UTF-8 representation.
637         */
638        public static byte[] encodeBase64(byte[] binaryData) {
639            return encodeBase64(binaryData, false);
640        }
641    
642        /**
643         * Encodes binary data using the base64 algorithm into 76 character blocks separated by CRLF.
644         *
645         * @param binaryData
646         *            binary data to encode
647         * @return String containing Base64 characters.
648         * @since 1.4
649         */
650        public static String encodeBase64String(byte[] binaryData) {
651            return UTF8.toString(encodeBase64(binaryData, true));
652        }
653    
654        /**
655         * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
656         * url-safe variation emits - and _ instead of + and / characters.
657         *
658         * @param binaryData
659         *            binary data to encode
660         * @return byte[] containing Base64 characters in their UTF-8 representation.
661         * @since 1.4
662         */
663        public static byte[] encodeBase64URLSafe(byte[] binaryData) {
664            return encodeBase64(binaryData, false, true);
665        }
666    
667        /**
668         * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
669         * url-safe variation emits - and _ instead of + and / characters.
670         *
671         * @param binaryData
672         *            binary data to encode
673         * @return String containing Base64 characters
674         * @since 1.4
675         */
676        public static String encodeBase64URLSafeString(byte[] binaryData) {
677            return UTF8.toString(encodeBase64(binaryData, false, true));
678        }
679    
680        /**
681         * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks
682         *
683         * @param binaryData
684         *            binary data to encode
685         * @return Base64 characters chunked in 76 character blocks
686         */
687        public static byte[] encodeBase64Chunked(byte[] binaryData) {
688            return encodeBase64(binaryData, true);
689        }
690    
691        /**
692         * Decodes an Object using the base64 algorithm. This method is provided in order to satisfy the requirements of the
693         * Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[] or String.
694         *
695         * @param pObject
696         *            Object to decode
697         * @return An object (of type byte[]) containing the binary data which corresponds to the byte[] or String supplied.
698         */
699        public Object decode(Object pObject) {
700            if (pObject instanceof byte[]) {
701                return decode((byte[]) pObject);
702            } else if (pObject instanceof String) {
703                return decode((String) pObject);
704            } else {
705                throw new IllegalArgumentException("Parameter supplied to Base64 decode is not a byte[] or a String");
706            }
707        }
708    
709        /**
710         * Decodes a String containing containing characters in the Base64 alphabet.
711         *
712         * @param pArray
713         *            A String containing Base64 character data
714         * @return a byte array containing binary data
715         * @since 1.4
716         */
717        public byte[] decode(String pArray) {
718            return decode(UTF8.toBytes(pArray));
719        }
720    
721        /**
722         * Decodes a byte[] containing containing characters in the Base64 alphabet.
723         *
724         * @param pArray
725         *            A byte array containing Base64 character data
726         * @return a byte array containing binary data
727         */
728        public byte[] decode(byte[] pArray) {
729            reset();
730            if (pArray == null || pArray.length == 0) {
731                return pArray;
732            }
733            long len = (pArray.length * 3) / 4;
734            byte[] buf = new byte[(int) len];
735            setInitialBuffer(buf, 0, buf.length);
736            decode(pArray, 0, pArray.length);
737            decode(pArray, 0, -1); // Notify decoder of EOF.
738    
739            // Would be nice to just return buf (like we sometimes do in the encode
740            // logic), but we have no idea what the line-length was (could even be
741            // variable).  So we cannot determine ahead of time exactly how big an
742            // array is necessary.  Hence the need to construct a 2nd byte array to
743            // hold the final result:
744    
745            byte[] result = new byte[pos];
746            readResults(result, 0, result.length);
747            return result;
748        }
749    
750        /**
751         * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
752         *
753         * @param binaryData
754         *            Array containing binary data to encode.
755         * @param isChunked
756         *            if <code>true</code> this encoder will chunk the base64 output into 76 character blocks
757         * @return Base64-encoded data.
758         * @throws IllegalArgumentException
759         *             Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
760         */
761        public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) {
762            return encodeBase64(binaryData, isChunked, false);
763        }
764    
765        /**
766         * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
767         *
768         * @param binaryData
769         *            Array containing binary data to encode.
770         * @param isChunked
771         *            if <code>true</code> this encoder will chunk the base64 output into 76 character blocks
772         * @param urlSafe
773         *            if <code>true</code> this encoder will emit - and _ instead of the usual + and / characters.
774         * @return Base64-encoded data.
775         * @throws IllegalArgumentException
776         *             Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
777         * @since 1.4
778         */
779        public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean urlSafe) {
780            return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE);
781        }
782    
783        /**
784         * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
785         *
786         * @param binaryData
787         *            Array containing binary data to encode.
788         * @param isChunked
789         *            if <code>true</code> this encoder will chunk the base64 output into 76 character blocks
790         * @param urlSafe
791         *            if <code>true</code> this encoder will emit - and _ instead of the usual + and / characters.
792         * @param maxResultSize
793         *            The maximum result size to accept.
794         * @return Base64-encoded data.
795         * @throws IllegalArgumentException
796         *             Thrown when the input array needs an output array bigger than maxResultSize
797         * @since 1.4
798         */
799        public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean urlSafe, int maxResultSize) {
800            if (binaryData == null || binaryData.length == 0) {
801                return binaryData;
802            }
803    
804            long len = getEncodeLength(binaryData, CHUNK_SIZE, CHUNK_SEPARATOR);
805            if (len > maxResultSize) {
806                throw new IllegalArgumentException("Input array too big, the output array would be bigger (" +
807                    len +
808                    ") than the specified maxium size of " +
809                    maxResultSize);
810            }
811    
812            Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe);
813            return b64.encode(binaryData);
814        }
815    
816        /**
817         * Decodes a Base64 String into octets
818         *
819         * @param base64String
820         *            String containing Base64 data
821         * @return Array containing decoded data.
822         * @since 1.4
823         */
824        public static byte[] decodeBase64(String base64String) {
825            return new Base64().decode(base64String);
826        }
827    
828        /**
829         * Decodes Base64 data into octets
830         *
831         * @param base64Data
832         *            Byte array containing Base64 data
833         * @return Array containing decoded data.
834         */
835        public static byte[] decodeBase64(byte[] base64Data) {
836            return new Base64().decode(base64Data);
837        }
838    
839        /**
840         * Discards any whitespace from a base-64 encoded block.
841         *
842         * @param data
843         *            The base-64 encoded data to discard the whitespace from.
844         * @return The data, less whitespace (see RFC 2045).
845         * @deprecated This method is no longer needed
846         */
847        static byte[] discardWhitespace(byte[] data) {
848            byte groomedData[] = new byte[data.length];
849            int bytesCopied = 0;
850            for (int i = 0; i < data.length; i++) {
851                switch (data[i]) {
852                    case ' ' :
853                    case '\n' :
854                    case '\r' :
855                    case '\t' :
856                        break;
857                    default :
858                        groomedData[bytesCopied++] = data[i];
859                }
860            }
861            byte packedData[] = new byte[bytesCopied];
862            System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
863            return packedData;
864        }
865    
866        /**
867         * Checks if a byte value is whitespace or not.
868         *
869         * @param byteToCheck
870         *            the byte to check
871         * @return true if byte is whitespace, false otherwise
872         */
873        private static boolean isWhiteSpace(byte byteToCheck) {
874            switch (byteToCheck) {
875                case ' ' :
876                case '\n' :
877                case '\r' :
878                case '\t' :
879                    return true;
880                default :
881                    return false;
882            }
883        }
884    
885        // Implementation of the Encoder Interface
886    
887        /**
888         * Encodes an Object using the base64 algorithm. This method is provided in order to satisfy the requirements of the
889         * Encoder interface, and will throw an EncoderException if the supplied object is not of type byte[].
890         *
891         * @param pObject
892         *            Object to encode
893         * @return An object (of type byte[]) containing the base64 encoded data which corresponds to the byte[] supplied.
894         */
895        public Object encode(Object pObject) {
896            if (!(pObject instanceof byte[])) {
897                throw new IllegalArgumentException("Parameter supplied to Base64 encode is not a byte[]");
898            }
899            return encode((byte[]) pObject);
900        }
901    
902        /**
903         * Encodes a byte[] containing binary data, into a String containing characters in the Base64 alphabet.
904         *
905         * @param pArray
906         *            a byte array containing binary data
907         * @return A String containing only Base64 character data
908         * @since 1.4
909         */
910        public String encodeToString(byte[] pArray) {
911            return UTF8.toString(encode(pArray));
912        }
913    
914        /**
915         * Encodes a byte[] containing binary data, into a byte[] containing characters in the Base64 alphabet.
916         *
917         * @param pArray
918         *            a byte array containing binary data
919         * @return A byte array containing only Base64 character data
920         */
921        public byte[] encode(byte[] pArray) {
922            reset();
923            if (pArray == null || pArray.length == 0) {
924                return pArray;
925            }
926            long len = getEncodeLength(pArray, lineLength, lineSeparator);
927            byte[] buf = new byte[(int) len];
928            setInitialBuffer(buf, 0, buf.length);
929            encode(pArray, 0, pArray.length);
930            encode(pArray, 0, -1); // Notify encoder of EOF.
931            // Encoder might have resized, even though it was unnecessary.
932            if (buffer != buf) {
933                readResults(buf, 0, buf.length);
934            }
935            // In URL-SAFE mode we skip the padding characters, so sometimes our
936            // final length is a bit smaller.
937            if (isUrlSafe() && pos < buf.length) {
938                byte[] smallerBuf = new byte[pos];
939                System.arraycopy(buf, 0, smallerBuf, 0, pos);
940                buf = smallerBuf;
941            }
942            return buf;
943        }
944    
945        /**
946         * Pre-calculates the amount of space needed to base64-encode the supplied array.
947         *
948         * @param pArray byte[] array which will later be encoded
949         * @param chunkSize line-length of the output (<= 0 means no chunking) between each
950         *        chunkSeparator (e.g. CRLF).
951         * @param chunkSeparator the sequence of bytes used to separate chunks of output (e.g. CRLF).
952         *
953         * @return amount of space needed to encoded the supplied array.  Returns
954         *         a long since a max-len array will require Integer.MAX_VALUE + 33%.
955         */
956        private static long getEncodeLength(byte[] pArray, int chunkSize, byte[] chunkSeparator) {
957            // base64 always encodes to multiples of 4.
958            chunkSize = (chunkSize / 4) * 4;
959    
960            long len = (pArray.length * 4) / 3;
961            long mod = len % 4;
962            if (mod != 0) {
963                len += 4 - mod;
964            }
965            if (chunkSize > 0) {
966                boolean lenChunksPerfectly = len % chunkSize == 0;
967                len += (len / chunkSize) * chunkSeparator.length;
968                if (!lenChunksPerfectly) {
969                    len += chunkSeparator.length;
970                }
971            }
972            return len;
973        }
974    
975        // Implementation of integer encoding used for crypto
976        /**
977         * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature
978         *
979         * @param pArray
980         *            a byte array containing base64 character data
981         * @return A BigInteger
982         * @since 1.4
983         */
984        public static BigInteger decodeInteger(byte[] pArray) {
985            return new BigInteger(1, decodeBase64(pArray));
986        }
987    
988        /**
989         * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature
990         *
991         * @param bigInt
992         *            a BigInteger
993         * @return A byte array containing base64 character data
994         * @throws NullPointerException
995         *             if null is passed in
996         * @since 1.4
997         */
998        public static byte[] encodeInteger(BigInteger bigInt) {
999            if (bigInt == null) {
1000                throw new NullPointerException("encodeInteger called with null parameter");
1001            }
1002            return encodeBase64(toIntegerBytes(bigInt), false);
1003        }
1004    
1005        /**
1006         * Returns a byte-array representation of a <code>BigInteger</code> without sign bit.
1007         *
1008         * @param bigInt
1009         *            <code>BigInteger</code> to be converted
1010         * @return a byte array representation of the BigInteger parameter
1011         */
1012        static byte[] toIntegerBytes(BigInteger bigInt) {
1013            int bitlen = bigInt.bitLength();
1014            // round bitlen
1015            bitlen = ((bitlen + 7) >> 3) << 3;
1016            byte[] bigBytes = bigInt.toByteArray();
1017    
1018            if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) {
1019                return bigBytes;
1020            }
1021            // set up params for copying everything but sign bit
1022            int startSrc = 0;
1023            int len = bigBytes.length;
1024    
1025            // if bigInt is exactly byte-aligned, just skip signbit in copy
1026            if ((bigInt.bitLength() % 8) == 0) {
1027                startSrc = 1;
1028                len--;
1029            }
1030            int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec
1031            byte[] resizedBytes = new byte[bitlen / 8];
1032            System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len);
1033            return resizedBytes;
1034        }
1035    
1036        /**
1037         * Resets this Base64 object to its initial newly constructed state.
1038         */
1039        private void reset() {
1040            buffer = null;
1041            pos = 0;
1042            readPos = 0;
1043            currentLinePos = 0;
1044            modulus = 0;
1045            eof = false;
1046        }
1047    
1048    }