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