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