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 889935 2013-12-11 05:05:13Z 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(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(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(int lineLength, 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 * @throws IllegalArgumentException 265 * The provided lineSeparator included some base64 characters. That's not going to work! 266 * @since 1.4 267 */ 268 public Base64(int lineLength, byte[] lineSeparator, boolean urlSafe) { 269 super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, 270 lineLength, 271 lineSeparator == null ? 0 : lineSeparator.length); 272 // TODO could be simplified if there is no requirement to reject invalid line sep when length <=0 273 // @see test case Base64Test.testConstructors() 274 if (lineSeparator != null) { 275 if (containsAlphabetOrPad(lineSeparator)) { 276 String sep = StringUtils.newStringUtf8(lineSeparator); 277 throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]"); 278 } 279 if (lineLength > 0){ // null line-sep forces no chunking rather than throwing IAE 280 this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length; 281 this.lineSeparator = new byte[lineSeparator.length]; 282 System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length); 283 } else { 284 this.encodeSize = BYTES_PER_ENCODED_BLOCK; 285 this.lineSeparator = null; 286 } 287 } else { 288 this.encodeSize = BYTES_PER_ENCODED_BLOCK; 289 this.lineSeparator = null; 290 } 291 this.decodeSize = this.encodeSize - 1; 292 this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE; 293 } 294 295 /** 296 * Returns our current encode mode. True if we're URL-SAFE, false otherwise. 297 * 298 * @return true if we're in URL-SAFE mode, false otherwise. 299 * @since 1.4 300 */ 301 public boolean isUrlSafe() { 302 return this.encodeTable == URL_SAFE_ENCODE_TABLE; 303 } 304 305 /** 306 * <p> 307 * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with 308 * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, so flush last 309 * remaining bytes (if not multiple of 3). 310 * </p> 311 * <p> 312 * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. 313 * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ 314 * </p> 315 * 316 * @param in 317 * byte[] array of binary data to base64 encode. 318 * @param inPos 319 * Position to start reading data from. 320 * @param inAvail 321 * Amount of bytes available from input for encoding. 322 * @param context 323 * the context to be used 324 */ 325 @Override 326 void encode(byte[] in, int inPos, int inAvail, Context context) { 327 if (context.eof) { 328 return; 329 } 330 // inAvail < 0 is how we're informed of EOF in the underlying data we're 331 // encoding. 332 if (inAvail < 0) { 333 context.eof = true; 334 if (0 == context.modulus && lineLength == 0) { 335 return; // no leftovers to process and not using chunking 336 } 337 final byte[] buffer = ensureBufferSize(encodeSize, context); 338 final int savedPos = context.pos; 339 switch (context.modulus) { // 0-2 340 case 0 : // nothing to do here 341 break; 342 case 1 : // 8 bits = 6 + 2 343 // top 6 bits: 344 buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 2) & MASK_6BITS]; 345 // remaining 2: 346 buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 4) & MASK_6BITS]; 347 // URL-SAFE skips the padding to further reduce size. 348 if (encodeTable == STANDARD_ENCODE_TABLE) { 349 buffer[context.pos++] = PAD; 350 buffer[context.pos++] = PAD; 351 } 352 break; 353 354 case 2 : // 16 bits = 6 + 6 + 4 355 buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 10) & MASK_6BITS]; 356 buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 4) & MASK_6BITS]; 357 buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 2) & MASK_6BITS]; 358 // URL-SAFE skips the padding to further reduce size. 359 if (encodeTable == STANDARD_ENCODE_TABLE) { 360 buffer[context.pos++] = PAD; 361 } 362 break; 363 default: 364 throw new IllegalStateException("Impossible modulus "+context.modulus); 365 } 366 context.currentLinePos += context.pos - savedPos; // keep track of current line position 367 // if currentPos == 0 we are at the start of a line, so don't add CRLF 368 if (lineLength > 0 && context.currentLinePos > 0) { 369 System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length); 370 context.pos += lineSeparator.length; 371 } 372 } else { 373 for (int i = 0; i < inAvail; i++) { 374 final byte[] buffer = ensureBufferSize(encodeSize, context); 375 context.modulus = (context.modulus+1) % BYTES_PER_UNENCODED_BLOCK; 376 int b = in[inPos++]; 377 if (b < 0) { 378 b += 256; 379 } 380 context.ibitWorkArea = (context.ibitWorkArea << 8) + b; // BITS_PER_BYTE 381 if (0 == context.modulus) { // 3 bytes = 24 bits = 4 * 6 bits to extract 382 buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 18) & MASK_6BITS]; 383 buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 12) & MASK_6BITS]; 384 buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 6) & MASK_6BITS]; 385 buffer[context.pos++] = encodeTable[context.ibitWorkArea & MASK_6BITS]; 386 context.currentLinePos += BYTES_PER_ENCODED_BLOCK; 387 if (lineLength > 0 && lineLength <= context.currentLinePos) { 388 System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length); 389 context.pos += lineSeparator.length; 390 context.currentLinePos = 0; 391 } 392 } 393 } 394 } 395 } 396 397 /** 398 * <p> 399 * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once 400 * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1" 401 * call is not necessary when decoding, but it doesn't hurt, either. 402 * </p> 403 * <p> 404 * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are 405 * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in, 406 * garbage-out philosophy: it will not check the provided data for validity. 407 * </p> 408 * <p> 409 * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. 410 * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ 411 * </p> 412 * 413 * @param in 414 * byte[] array of ascii data to base64 decode. 415 * @param inPos 416 * Position to start reading data from. 417 * @param inAvail 418 * Amount of bytes available from input for encoding. 419 * @param context 420 * the context to be used 421 */ 422 @Override 423 void decode(byte[] in, int inPos, int inAvail, Context context) { 424 if (context.eof) { 425 return; 426 } 427 if (inAvail < 0) { 428 context.eof = true; 429 } 430 for (int i = 0; i < inAvail; i++) { 431 final byte[] buffer = ensureBufferSize(decodeSize, context); 432 final byte b = in[inPos++]; 433 if (b == PAD) { 434 // We're done. 435 context.eof = true; 436 break; 437 } else { 438 if (b >= 0 && b < DECODE_TABLE.length) { 439 final int result = DECODE_TABLE[b]; 440 if (result >= 0) { 441 context.modulus = (context.modulus+1) % BYTES_PER_ENCODED_BLOCK; 442 context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result; 443 if (context.modulus == 0) { 444 buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 16) & MASK_8BITS); 445 buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS); 446 buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS); 447 } 448 } 449 } 450 } 451 } 452 453 // Two forms of EOF as far as base64 decoder is concerned: actual 454 // EOF (-1) and first time '=' character is encountered in stream. 455 // This approach makes the '=' padding characters completely optional. 456 if (context.eof && context.modulus != 0) { 457 final byte[] buffer = ensureBufferSize(decodeSize, context); 458 459 // We have some spare bits remaining 460 // Output all whole multiples of 8 bits and ignore the rest 461 switch (context.modulus) { 462 // case 0 : // impossible, as excluded above 463 case 1 : // 6 bits - ignore entirely 464 // TODO not currently tested; perhaps it is impossible? 465 break; 466 case 2 : // 12 bits = 8 + 4 467 context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits 468 buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS); 469 break; 470 case 3 : // 18 bits = 8 + 8 + 2 471 context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits 472 buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS); 473 buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS); 474 break; 475 default: 476 throw new IllegalStateException("Impossible modulus "+context.modulus); 477 } 478 } 479 } 480 481 /** 482 * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the 483 * method treats whitespace as valid. 484 * 485 * @param arrayOctet 486 * byte array to test 487 * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; 488 * {@code false}, otherwise 489 * @deprecated 1.5 Use {@link #isBase64(byte[])}, will be removed in 2.0. 490 */ 491 @Deprecated 492 public static boolean isArrayByteBase64(byte[] arrayOctet) { 493 return isBase64(arrayOctet); 494 } 495 496 /** 497 * Returns whether or not the <code>octet</code> is in the base 64 alphabet. 498 * 499 * @param octet 500 * The value to test 501 * @return {@code true} if the value is defined in the the base 64 alphabet, {@code false} otherwise. 502 * @since 1.4 503 */ 504 public static boolean isBase64(byte octet) { 505 return octet == PAD_DEFAULT || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1); 506 } 507 508 /** 509 * Tests a given String to see if it contains only valid characters within the Base64 alphabet. Currently the 510 * method treats whitespace as valid. 511 * 512 * @param base64 513 * String to test 514 * @return {@code true} if all characters in the String are valid characters in the Base64 alphabet or if 515 * the String is empty; {@code false}, otherwise 516 * @since 1.5 517 */ 518 public static boolean isBase64(String base64) { 519 return isBase64(StringUtils.getBytesUtf8(base64)); 520 } 521 522 /** 523 * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the 524 * method treats whitespace as valid. 525 * 526 * @param arrayOctet 527 * byte array to test 528 * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; 529 * {@code false}, otherwise 530 * @since 1.5 531 */ 532 public static boolean isBase64(byte[] arrayOctet) { 533 for (int i = 0; i < arrayOctet.length; i++) { 534 if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) { 535 return false; 536 } 537 } 538 return true; 539 } 540 541 /** 542 * Encodes binary data using the base64 algorithm but does not chunk the output. 543 * 544 * @param binaryData 545 * binary data to encode 546 * @return byte[] containing Base64 characters in their UTF-8 representation. 547 */ 548 public static byte[] encodeBase64(byte[] binaryData) { 549 return encodeBase64(binaryData, false); 550 } 551 552 /** 553 * Encodes binary data using the base64 algorithm but does not chunk the output. 554 * 555 * NOTE: We changed the behaviour of this method from multi-line chunking (commons-codec-1.4) to 556 * single-line non-chunking (commons-codec-1.5). 557 * 558 * @param binaryData 559 * binary data to encode 560 * @return String containing Base64 characters. 561 * @since 1.4 (NOTE: 1.4 chunked the output, whereas 1.5 does not). 562 */ 563 public static String encodeBase64String(byte[] binaryData) { 564 return StringUtils.newStringUtf8(encodeBase64(binaryData, false)); 565 } 566 567 /** 568 * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The 569 * url-safe variation emits - and _ instead of + and / characters. 570 * 571 * @param binaryData 572 * binary data to encode 573 * @return byte[] containing Base64 characters in their UTF-8 representation. 574 * @since 1.4 575 */ 576 public static byte[] encodeBase64URLSafe(byte[] binaryData) { 577 return encodeBase64(binaryData, false, true); 578 } 579 580 /** 581 * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The 582 * url-safe variation emits - and _ instead of + and / characters. 583 * 584 * @param binaryData 585 * binary data to encode 586 * @return String containing Base64 characters 587 * @since 1.4 588 */ 589 public static String encodeBase64URLSafeString(byte[] binaryData) { 590 return StringUtils.newStringUtf8(encodeBase64(binaryData, false, true)); 591 } 592 593 /** 594 * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks 595 * 596 * @param binaryData 597 * binary data to encode 598 * @return Base64 characters chunked in 76 character blocks 599 */ 600 public static byte[] encodeBase64Chunked(byte[] binaryData) { 601 return encodeBase64(binaryData, true); 602 } 603 604 /** 605 * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. 606 * 607 * @param binaryData 608 * Array containing binary data to encode. 609 * @param isChunked 610 * if {@code true} this encoder will chunk the base64 output into 76 character blocks 611 * @return Base64-encoded data. 612 * @throws IllegalArgumentException 613 * Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE} 614 */ 615 public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) { 616 return encodeBase64(binaryData, isChunked, false); 617 } 618 619 /** 620 * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. 621 * 622 * @param binaryData 623 * Array containing binary data to encode. 624 * @param isChunked 625 * if {@code true} this encoder will chunk the base64 output into 76 character blocks 626 * @param urlSafe 627 * if {@code true} this encoder will emit - and _ instead of the usual + and / characters. 628 * @return Base64-encoded data. 629 * @throws IllegalArgumentException 630 * Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE} 631 * @since 1.4 632 */ 633 public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean urlSafe) { 634 return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE); 635 } 636 637 /** 638 * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. 639 * 640 * @param binaryData 641 * Array containing binary data to encode. 642 * @param isChunked 643 * if {@code true} this encoder will chunk the base64 output into 76 character blocks 644 * @param urlSafe 645 * if {@code true} this encoder will emit - and _ instead of the usual + and / characters. 646 * @param maxResultSize 647 * The maximum result size to accept. 648 * @return Base64-encoded data. 649 * @throws IllegalArgumentException 650 * Thrown when the input array needs an output array bigger than maxResultSize 651 * @since 1.4 652 */ 653 public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean urlSafe, int maxResultSize) { 654 if (binaryData == null || binaryData.length == 0) { 655 return binaryData; 656 } 657 658 // Create this so can use the super-class method 659 // Also ensures that the same roundings are performed by the ctor and the code 660 Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe); 661 long len = b64.getEncodedLength(binaryData); 662 if (len > maxResultSize) { 663 throw new IllegalArgumentException("Input array too big, the output array would be bigger (" + 664 len + 665 ") than the specified maximum size of " + 666 maxResultSize); 667 } 668 669 return b64.encode(binaryData); 670 } 671 672 /** 673 * Decodes a Base64 String into octets 674 * 675 * @param base64String 676 * String containing Base64 data 677 * @return Array containing decoded data. 678 * @since 1.4 679 */ 680 public static byte[] decodeBase64(String base64String) { 681 return new Base64().decode(base64String); 682 } 683 684 /** 685 * Decodes Base64 data into octets 686 * 687 * @param base64Data 688 * Byte array containing Base64 data 689 * @return Array containing decoded data. 690 */ 691 public static byte[] decodeBase64(byte[] base64Data) { 692 return new Base64().decode(base64Data); 693 } 694 695 // Implementation of the Encoder Interface 696 697 // Implementation of integer encoding used for crypto 698 /** 699 * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature 700 * 701 * @param pArray 702 * a byte array containing base64 character data 703 * @return A BigInteger 704 * @since 1.4 705 */ 706 public static BigInteger decodeInteger(byte[] pArray) { 707 return new BigInteger(1, decodeBase64(pArray)); 708 } 709 710 /** 711 * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature 712 * 713 * @param bigInt 714 * a BigInteger 715 * @return A byte array containing base64 character data 716 * @throws NullPointerException 717 * if null is passed in 718 * @since 1.4 719 */ 720 public static byte[] encodeInteger(BigInteger bigInt) { 721 if (bigInt == null) { 722 throw new NullPointerException("encodeInteger called with null parameter"); 723 } 724 return encodeBase64(toIntegerBytes(bigInt), false); 725 } 726 727 /** 728 * Returns a byte-array representation of a <code>BigInteger</code> without sign bit. 729 * 730 * @param bigInt 731 * <code>BigInteger</code> to be converted 732 * @return a byte array representation of the BigInteger parameter 733 */ 734 static byte[] toIntegerBytes(BigInteger bigInt) { 735 int bitlen = bigInt.bitLength(); 736 // round bitlen 737 bitlen = ((bitlen + 7) >> 3) << 3; 738 byte[] bigBytes = bigInt.toByteArray(); 739 740 if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) { 741 return bigBytes; 742 } 743 // set up params for copying everything but sign bit 744 int startSrc = 0; 745 int len = bigBytes.length; 746 747 // if bigInt is exactly byte-aligned, just skip signbit in copy 748 if ((bigInt.bitLength() % 8) == 0) { 749 startSrc = 1; 750 len--; 751 } 752 int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec 753 byte[] resizedBytes = new byte[bitlen / 8]; 754 System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len); 755 return resizedBytes; 756 } 757 758 /** 759 * Returns whether or not the <code>octet</code> is in the Base32 alphabet. 760 * 761 * @param octet 762 * The value to test 763 * @return {@code true} if the value is defined in the the Base32 alphabet {@code false} otherwise. 764 */ 765 @Override 766 protected boolean isInAlphabet(byte octet) { 767 return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1; 768 } 769 770 }