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