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