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