001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.codec.binary; 019 020import java.math.BigInteger; 021import java.util.Arrays; 022import java.util.Objects; 023 024import org.apache.commons.codec.CodecPolicy; 025 026/** 027 * Provides Base64 encoding and decoding as defined by <a href="https://www.ietf.org/rfc/rfc2045">RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part 028 * One: Format of Internet Message Bodies</a> and portions of <a href="https://datatracker.ietf.org/doc/html/rfc4648">RFC 4648 The Base16, Base32, and Base64 029 * Data Encodings</a> 030 * 031 * <p> 032 * This class implements <a href="https://www.ietf.org/rfc/rfc2045#section-6.8">RFC 2045 6.8. Base64 Content-Transfer-Encoding</a>. 033 * </p> 034 * <p> 035 * The class can be parameterized in the following manner with its {@link Builder}: 036 * </p> 037 * <ul> 038 * <li>URL-safe mode: Default off.</li> 039 * <li>Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. 040 * <li>Line separator: Default is CRLF ({@code "\r\n"})</li> 041 * <li>Strict or lenient decoding policy; default is {@link CodecPolicy#LENIENT}.</li> 042 * <li>Custom decoding table.</li> 043 * <li>Custom encoding table.</li> 044 * <li>Padding; defaults is {@code '='}.</li> 045 * </ul> 046 * <p> 047 * The URL-safe parameter is only applied to encode operations. Decoding seamlessly handles both modes, see also 048 * {@code Builder#setDecodeTableFormat(DecodeTableFormat)}. 049 * </p> 050 * <p> 051 * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode character encodings which are 052 * compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc). 053 * </p> 054 * <p> 055 * This class is thread-safe. 056 * </p> 057 * <p> 058 * To configure a new instance, use a {@link Builder}. For example: 059 * </p> 060 * 061 * <pre> 062 * Base64 base64 = Base64.builder() 063 * .setDecodingPolicy(CodecPolicy.LENIENT) // default is lenient, null resets to default 064 * .setEncodeTable(customEncodeTable) // default is built in, null resets to default 065 * .setLineLength(0) // default is none 066 * .setLineSeparator('\r', '\n') // default is CR LF, null resets to default 067 * .setPadding('=') // default is '=' 068 * .setUrlSafe(false) // default is false 069 * .get() 070 * </pre> 071 * 072 * @see Base64InputStream 073 * @see Base64OutputStream 074 * @see <a href="https://www.ietf.org/rfc/rfc2045">RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</a> 075 * @see <a href="https://datatracker.ietf.org/doc/html/rfc4648">RFC 4648 The Base16, Base32, and Base64 Data Encodings</a> 076 * @since 1.0 077 */ 078public class Base64 extends BaseNCodec { 079 080 /** 081 * Builds {@link Base64} instances. 082 * 083 * <p> 084 * To configure a new instance, use a {@link Builder}. For example: 085 * </p> 086 * 087 * <pre> 088 * Base64 base64 = Base64.builder() 089 * .setCodecPolicy(CodecPolicy.LENIENT) // default is lenient, null resets to default 090 * .setEncodeTable(customEncodeTable) // default is built in, null resets to default 091 * .setLineLength(0) // default is none 092 * .setLineSeparator('\r', '\n') // default is CR LF, null resets to default 093 * .setPadding('=') // default is '=' 094 * .setUrlSafe(false) // default is false 095 * .get() 096 * </pre> 097 * 098 * @since 1.17.0 099 */ 100 public static class Builder extends AbstractBuilder<Base64, Builder> { 101 102 /** 103 * Constructs a new instance. 104 */ 105 public Builder() { 106 super(STANDARD_ENCODE_TABLE); 107 setDecodeTableRaw(DECODE_TABLE); 108 setEncodeTableRaw(STANDARD_ENCODE_TABLE); 109 setEncodedBlockSize(BYTES_PER_ENCODED_BLOCK); 110 setUnencodedBlockSize(BYTES_PER_UNENCODED_BLOCK); 111 } 112 113 @Override 114 public Base64 get() { 115 return new Base64(this); 116 } 117 118 /** 119 * Sets the format of the decoding table. This method allows to explicitly state whether a standard or URL-safe Base64 decoding is expected. This method 120 * does not modify behavior on encoding operations. For configuration of the encoding behavior, please use {@link #setUrlSafe(boolean)} method. 121 * <p> 122 * By default, the implementation uses the {@link DecodeTableFormat#MIXED} approach, allowing a seamless handling of both 123 * {@link DecodeTableFormat#URL_SAFE} and {@link DecodeTableFormat#STANDARD} base64. 124 * </p> 125 * 126 * @param format table format to be used on Base64 decoding. Use {@link DecodeTableFormat#MIXED} or null to reset to the default behavior. 127 * @return {@code this} instance. 128 * @since 1.21 129 */ 130 public Builder setDecodeTableFormat(final DecodeTableFormat format) { 131 if (format == null) { 132 return setDecodeTableRaw(DECODE_TABLE); 133 } 134 switch (format) { 135 case STANDARD: 136 return setDecodeTableRaw(STANDARD_DECODE_TABLE); 137 case URL_SAFE: 138 return setDecodeTableRaw(URL_SAFE_DECODE_TABLE); 139 case MIXED: 140 default: 141 return setDecodeTableRaw(DECODE_TABLE); 142 } 143 } 144 145 /** 146 * Sets the encode table. 147 * 148 * @param encodeTable The encode table with exactly 64 unique entries, null resets to the default. 149 * @return {@code this} instance. 150 * @throws IllegalArgumentException if {@code encodeTable} does not contain exactly 64 unique entries. 151 */ 152 @Override 153 public Builder setEncodeTable(final byte... encodeTable) { 154 setDecodeTableRaw(toDecodeTable(encodeTable)); 155 return super.setEncodeTable(encodeTable); 156 } 157 158 /** 159 * Sets the URL-safe encoding policy. 160 * <p> 161 * This method does not modify behavior on decoding operations. For configuration of the decoding behavior, please use 162 * {@code Builder.setDecodeTableFormat(DecodeTableFormat)} method. 163 * </p> 164 * 165 * @param urlSafe URL-safe encoding policy. 166 * @return {@code this} instance. 167 */ 168 public Builder setUrlSafe(final boolean urlSafe) { 169 // Javadoc 8 can't find {@link #setDecodeTableFormat(DecodeTableFormat)} 170 return setEncodeTable(toUrlSafeEncodeTable(urlSafe)); 171 } 172 173 } 174 175 /** 176 * Enumerates the Base64 table format to be used on decoding. 177 * <p> 178 * By default, the method uses {@link DecodeTableFormat#MIXED} approach, allowing a seamless handling of both {@link DecodeTableFormat#URL_SAFE} and 179 * {@link DecodeTableFormat#STANDARD} base64 options. 180 * </p> 181 * 182 * @since 1.21 183 */ 184 public enum DecodeTableFormat { 185 186 /** 187 * Corresponds to the standard Base64 coding table, as specified in 188 * <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The Base64 Alphabet</a>. 189 */ 190 STANDARD, 191 192 /** 193 * Corresponds to the URL-safe Base64 coding table, as specified in 194 * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 195 * 4648 Table 2: The "URL and Filename safe" Base 64 Alphabet</a>. 196 */ 197 URL_SAFE, 198 199 /** 200 * Represents a joint approach, allowing a seamless decoding of both character sets, corresponding to either 201 * <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The Base64 Alphabet</a> or 202 * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 203 * 4648 Table 2: The "URL and Filename safe" Base 64 Alphabet</a>. This decoding table is used by default. 204 */ 205 MIXED 206 } 207 208 /** 209 * BASE64 characters are 6 bits in length. 210 * They are formed by taking a block of 3 octets to form a 24-bit string, 211 * which is converted into 4 BASE64 characters. 212 */ 213 private static final int BITS_PER_ENCODED_BYTE = 6; 214 private static final int BYTES_PER_UNENCODED_BLOCK = 3; 215 private static final int BYTES_PER_ENCODED_BLOCK = 4; 216 private static final int DECODING_TABLE_LENGTH = 256; 217 218 /** 219 * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet" equivalents as specified in 220 * <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The Base64 Alphabet</a>. 221 * <p> 222 * Thanks to "commons" project in ws.apache.org for this code. https://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ 223 * </p> 224 */ 225 // @formatter:off 226 private static final byte[] STANDARD_ENCODE_TABLE = { 227 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 228 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 229 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 230 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 231 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' 232 }; 233 234 /** 235 * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and / changed to - and _ to make the encoded Base64 results more URL-SAFE. This table is 236 * only used when the Base64's mode is set to URL-SAFE. 237 */ 238 // @formatter:off 239 private static final byte[] URL_SAFE_ENCODE_TABLE = { 240 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 241 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 242 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 243 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 244 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' 245 }; 246 // @formatter:on 247 248 /** 249 * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified in 250 * <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The Base64 Alphabet</a>) into their 6-bit 251 * positive integer equivalents. Characters that are not in the Base64 or Base64 URL-safe alphabets but fall within the bounds of the array are translated 252 * to -1. 253 * <p> 254 * The characters '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both URL_SAFE and STANDARD base64. 255 * (The encoder, on the other hand, needs to know ahead of time what to emit). 256 * </p> 257 * <p> 258 * Thanks to "commons" project in ws.apache.org for this code. https://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ 259 * </p> 260 */ 261 private static final byte[] DECODE_TABLE = { 262 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 263 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f 264 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f 265 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, // 20-2f + - / 266 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 30-3f 0-9 267 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40-4f A-O 268 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, // 50-5f P-Z _ 269 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6f a-o 270 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 // 70-7a p-z 271 }; 272 273 /** 274 * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified in 275 * <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The Base64 Alphabet</a>) into their 6-bit 276 * positive integer equivalents. Characters that are not in the Base64 alphabet but fall within the bounds of the array are translated to -1. This decoding 277 * table handles only the standard base64 characters, such as '+' and '/'. The "url-safe" characters such as '-' and '_' are not supported by the table. 278 */ 279 private static final byte[] STANDARD_DECODE_TABLE = { 280 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 281 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f 282 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f 283 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 20-2f + / 284 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 30-3f 0-9 285 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40-4f A-O 286 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 50-5f P-Z 287 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6f a-o 288 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 // 70-7a p-z 289 }; 290 291 /** 292 * This array is a lookup table that translates Unicode characters drawn from the "Base64 URL-safe Alphabet" (as specified in 293 * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648 294 * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>) into their 6-bit positive integer equivalents. Characters that are not in the Base64 URL-safe 295 * alphabet but fall within the bounds of the array are translated to -1. This decoding table handles only the URL-safe base64 characters, such as '-' and 296 * '_'. The standard characters such as '+' and '/' are not supported by the table. 297 */ 298 private static final byte[] URL_SAFE_DECODE_TABLE = { 299 // 0 1 2 3 4 5 6 7 8 9 A B C D E F 300 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f 301 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f 302 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, // 20-2f - 303 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 30-3f 0-9 304 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40-4f A-O 305 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, // 50-5f P-Z _ 306 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6f a-o 307 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 // 70-7a p-z 308 }; 309 310 /** 311 * Base64 uses 6-bit fields. 312 */ 313 314 /** Mask used to extract 6 bits, used when encoding */ 315 private static final int MASK_6_BITS = 0x3f; 316 317 // The static final fields above are used for the original static byte[] methods on Base64. 318 // The private member fields below are used with the new streaming approach, which requires 319 // some state be preserved between calls of encode() and decode(). 320 321 /** Mask used to extract 4 bits, used when decoding final trailing character. */ 322 private static final int MASK_4_BITS = 0xf; 323 324 /** Mask used to extract 2 bits, used when decoding final trailing character. */ 325 private static final int MASK_2_BITS = 0x3; 326 327 /** 328 * Creates a new Builder. 329 * 330 * <p> 331 * To configure a new instance, use a {@link Builder}. For example: 332 * </p> 333 * 334 * <pre> 335 * Base64 base64 = Base64.builder() 336 * .setDecodingPolicy(CodecPolicy.LENIENT) // default is lenient, null resets to default 337 * .setEncodeTable(customEncodeTable) // default is built in, null resets to default 338 * .setLineLength(0) // default is none 339 * .setLineSeparator('\r', '\n') // default is CR LF, null resets to default 340 * .setPadding('=') // default is '=' 341 * .setUrlSafe(false) // default is false 342 * .get() 343 * </pre> 344 * 345 * @return A new Builder. 346 * @since 1.17.0 347 */ 348 public static Builder builder() { 349 return new Builder(); 350 } 351 352 /** 353 * Calculates a decode table for a given encode table. 354 * 355 * @param encodeTable that is used to determine decode lookup table. 356 * @return A new decode table. 357 */ 358 private static byte[] calculateDecodeTable(final byte[] encodeTable) { 359 if (encodeTable.length != STANDARD_ENCODE_TABLE.length) { 360 throw new IllegalArgumentException("encodeTable must have exactly 64 entries."); 361 } 362 final byte[] decodeTable = new byte[DECODING_TABLE_LENGTH]; 363 Arrays.fill(decodeTable, (byte) -1); 364 for (int i = 0; i < encodeTable.length; i++) { 365 final int encodedByte = encodeTable[i] & 0xff; 366 if (decodeTable[encodedByte] != -1) { 367 throw new IllegalArgumentException("encodeTable must not contain duplicate entries."); 368 } 369 decodeTable[encodedByte] = (byte) i; 370 } 371 return decodeTable; 372 } 373 374 private static boolean contains(final byte[] bytes, final byte value) { 375 for (final byte element : bytes) { 376 if (element == value) { 377 return true; 378 } 379 } 380 return false; 381 } 382 383 /** 384 * Decodes Base64 data into octets. 385 * <p> 386 * This method seamlessly handles data encoded in URL-safe or normal mode. For enforcing verification against strict standard Base64 or Base64 URL-safe 387 * tables, please use {@link #decodeBase64Standard(byte[])} or {@link #decodeBase64UrlSafe(byte[])} methods respectively. This method skips unknown or 388 * unsupported bytes. 389 * </p> 390 * 391 * @param base64Data Byte array containing Base64 data. 392 * @return New array containing decoded data. 393 */ 394 public static byte[] decodeBase64(final byte[] base64Data) { 395 return new Base64().decode(base64Data); 396 } 397 398 /** 399 * Decodes a Base64 String into octets. 400 * <p> 401 * This method seamlessly handles data encoded in URL-safe or normal mode. For enforcing verification against strict standard Base64 or Base64 URL-safe 402 * tables, please use {@link #decodeBase64Standard(String)} or {@link #decodeBase64UrlSafe(String)} methods respectively. This method skips unknown or 403 * unsupported bytes. 404 * </p> 405 * 406 * @param base64String String containing Base64 data. 407 * @return New array containing decoded data. 408 * @since 1.4 409 */ 410 public static byte[] decodeBase64(final String base64String) { 411 return new Base64().decode(base64String); 412 } 413 414 /** 415 * Decodes standard Base64 data into octets. 416 * <p> 417 * This implementation is aligned with the <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The 418 * Base64 Alphabet</a>. This method skips unknown or unsupported bytes. 419 * </p> 420 * 421 * @param base64Data Byte array containing Base64 data. 422 * @return New array containing decoded data. 423 * @since 1.21 424 */ 425 public static byte[] decodeBase64Standard(final byte[] base64Data) { 426 return builder().setDecodeTableFormat(DecodeTableFormat.STANDARD).get().decode(base64Data); 427 } 428 429 /** 430 * Decodes a standard Base64 String into octets. 431 * <p> 432 * This implementation is aligned with the <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The 433 * Base64 Alphabet</a>. This method skips unknown or unsupported characters. 434 * </p> 435 * 436 * @param base64String String containing Base64 data. 437 * @return New array containing decoded data. 438 * @since 1.21 439 */ 440 public static byte[] decodeBase64Standard(final String base64String) { 441 return builder().setDecodeTableFormat(DecodeTableFormat.STANDARD).get().decode(base64String); 442 } 443 444 /** 445 * Decodes URL-safe Base64 data into octets. 446 * <p> 447 * This implementation is aligned with 448 * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648 449 * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>. This method skips unknown or unsupported characters. 450 * </p> 451 * 452 * @param base64Data Byte array containing Base64 data. 453 * @return New array containing decoded data. 454 * @since 1.21 455 */ 456 public static byte[] decodeBase64UrlSafe(final byte[] base64Data) { 457 return builder().setDecodeTableFormat(DecodeTableFormat.URL_SAFE).get().decode(base64Data); 458 } 459 460 /** 461 * Decodes a URL-safe Base64 String into octets. 462 * <p> 463 * This implementation is aligned with 464 * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648 465 * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>. This method skips unknown or unsupported characters. 466 * </p> 467 * 468 * @param base64String String containing Base64 data. 469 * @return New array containing decoded data. 470 * @since 1.21 471 */ 472 public static byte[] decodeBase64UrlSafe(final String base64String) { 473 return builder().setDecodeTableFormat(DecodeTableFormat.URL_SAFE).get().decode(base64String); 474 } 475 476 /** 477 * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature. 478 * 479 * @param array A byte array containing base64 character data. 480 * @return A BigInteger. 481 * @since 1.4 482 */ 483 public static BigInteger decodeInteger(final byte[] array) { 484 return new BigInteger(1, decodeBase64(array)); 485 } 486 487 /** 488 * Encodes binary data using the base64 algorithm but does not chunk the output. 489 * 490 * @param binaryData binary data to encode. 491 * @return byte[] containing Base64 characters in their UTF-8 representation. 492 */ 493 public static byte[] encodeBase64(final byte[] binaryData) { 494 return encodeBase64(binaryData, false); 495 } 496 497 /** 498 * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. 499 * 500 * @param binaryData Array containing binary data to encode. 501 * @param isChunked if {@code true} this encoder will chunk the base64 output into 76 character blocks. 502 * @return Base64-encoded data. 503 * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}. 504 */ 505 public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked) { 506 return encodeBase64(binaryData, isChunked, false); 507 } 508 509 /** 510 * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. 511 * 512 * @param binaryData Array containing binary data to encode. 513 * @param isChunked if {@code true} this encoder will chunk the base64 output into 76 character blocks. 514 * @param urlSafe if {@code true} this encoder will emit - and _ instead of the usual + and / characters. <strong>No padding is added when encoding using 515 * the URL-safe alphabet.</strong> 516 * @return Base64-encoded data. 517 * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}. 518 * @since 1.4 519 */ 520 public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe) { 521 return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE); 522 } 523 524 /** 525 * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. 526 * 527 * @param binaryData Array containing binary data to encode. 528 * @param isChunked if {@code true} this encoder will chunk the base64 output into 76 character blocks. 529 * @param urlSafe if {@code true} this encoder will emit - and _ instead of the usual + and / characters. <strong>No padding is added when encoding 530 * using the URL-safe alphabet.</strong> 531 * @param maxResultSize The maximum result size to accept. 532 * @return Base64-encoded data. 533 * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than maxResultSize. 534 * @since 1.4 535 */ 536 public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe, final int maxResultSize) { 537 if (BinaryCodec.isEmpty(binaryData)) { 538 return binaryData; 539 } 540 // Create this so can use the super-class method 541 // Also ensures that the same roundings are performed by the ctor and the code 542 final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe); 543 final long len = b64.getEncodedLength(binaryData); 544 if (len > maxResultSize) { 545 throw new IllegalArgumentException( 546 "Input array too big, the output array would be bigger (" + len + ") than the specified maximum size of " + maxResultSize); 547 } 548 return b64.encode(binaryData); 549 } 550 551 /** 552 * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks 553 * 554 * @param binaryData binary data to encode. 555 * @return Base64 characters chunked in 76 character blocks. 556 */ 557 public static byte[] encodeBase64Chunked(final byte[] binaryData) { 558 return encodeBase64(binaryData, true); 559 } 560 561 /** 562 * Encodes binary data using the base64 algorithm but does not chunk the output. 563 * <p> 564 * <strong> We changed the behavior of this method from multi-line chunking (1.4) to single-line non-chunking (1.5).</strong> 565 * </p> 566 * 567 * @param binaryData binary data to encode. 568 * @return String containing Base64 characters. 569 * @since 1.4 (NOTE: 1.4 chunked the output, whereas 1.5 does not). 570 */ 571 public static String encodeBase64String(final byte[] binaryData) { 572 return StringUtils.newStringUsAscii(encodeBase64(binaryData, false)); 573 } 574 575 /** 576 * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The url-safe variation emits - and _ instead of + 577 * and / characters. <strong>No padding is added.</strong> 578 * 579 * @param binaryData binary data to encode. 580 * @return byte[] containing Base64 characters in their UTF-8 representation. 581 * @since 1.4 582 */ 583 public static byte[] encodeBase64URLSafe(final byte[] binaryData) { 584 return encodeBase64(binaryData, false, true); 585 } 586 587 /** 588 * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The url-safe variation emits - and _ instead of + 589 * and / characters. <strong>No padding is added.</strong> 590 * 591 * @param binaryData 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 to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature. 601 * 602 * @param bigInteger A BigInteger. 603 * @return A byte array containing base64 character data. 604 * @throws NullPointerException if null is passed in. 605 * @since 1.4 606 */ 607 public static byte[] encodeInteger(final BigInteger bigInteger) { 608 Objects.requireNonNull(bigInteger, "bigInteger"); 609 return encodeBase64(toUnsignedBytes(bigInteger), false); 610 } 611 612 /** 613 * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the method treats whitespace as valid. 614 * 615 * @param arrayOctet byte array to test. 616 * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; {@code false}, otherwise. 617 * @deprecated 1.5 Use {@link #isBase64(byte[])}, will be removed in 2.0. 618 */ 619 @Deprecated 620 public static boolean isArrayByteBase64(final byte[] arrayOctet) { 621 return isBase64(arrayOctet); 622 } 623 624 /** 625 * Tests whether or not the {@code octet} is in the Base64 alphabet. 626 * <p> 627 * This method threats all characters included within standard base64 and base64url encodings as valid base64 characters. This includes the '+' and '/' 628 * (standard base64), as well as '-' and '_' (URL-safe base64) characters. For enforcing verification against strict standard Base64 or Base64 URL-safe 629 * tables, please use {@link #isBase64Standard(byte)} or {@link #isBase64Url(byte)} methods respectively. 630 * </p> 631 * 632 * @param octet The value to test. 633 * @return {@code true} if the value is defined in the Base64 alphabet, {@code false} otherwise. 634 * @since 1.4 635 */ 636 public static boolean isBase64(final byte octet) { 637 return octet == PAD_DEFAULT || octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1; 638 } 639 640 /** 641 * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the method treats whitespace as valid. 642 * <p> 643 * This method treats all characters included within standard base64 and base64url encodings as valid base64 characters. This includes the '+' and '/' 644 * (standard base64), as well as '-' and '_' (URL-safe base64) characters. For enforcing verification against strict standard Base64 or Base64 URL-safe 645 * tables, please use {@link #isBase64Standard(byte[])} or {@link #isBase64Url(byte[])} methods respectively. 646 * </p> 647 * 648 * @param arrayOctet byte array to test. 649 * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; {@code false}, otherwise. 650 * @since 1.5 651 */ 652 public static boolean isBase64(final byte[] arrayOctet) { 653 for (final byte element : arrayOctet) { 654 if (!isBase64(element) && !Character.isWhitespace(element)) { 655 return false; 656 } 657 } 658 return true; 659 } 660 661 /** 662 * Tests a given String to see if it contains only valid characters within the Base64 alphabet. Currently the method treats whitespace as valid. 663 * <p> 664 * This method threats all characters included within standard base64 and base64url encodings as valid base64 characters. This includes the '+' and '/' 665 * (standard base64), as well as '-' and '_' (URL-safe base64) characters. For enforcing verification against strict standard Base64 or Base64 URL-safe 666 * tables, please use {@link #isBase64Standard(String)} or {@link #isBase64Url(String)} methods respectively. 667 * </p> 668 * 669 * @param base64 String to test. 670 * @return {@code true} if all characters in the String are valid characters in the Base64 alphabet or if the String is empty; {@code false}, otherwise. 671 * @since 1.5 672 */ 673 public static boolean isBase64(final String base64) { 674 return isBase64(StringUtils.getBytesUtf8(base64)); 675 } 676 677 /** 678 * Tests whether or not the {@code octet} is in the standard Base64 alphabet. 679 * <p> 680 * This implementation is aligned with <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The 681 * Base64 Alphabet</a>. 682 * </p> 683 * 684 * @param octet The value to test. 685 * @return {@code true} if the value is defined in the standard Base64 alphabet, {@code false} otherwise. 686 * @since 1.21 687 */ 688 public static boolean isBase64Standard(final byte octet) { 689 return octet == PAD_DEFAULT || octet >= 0 && octet < STANDARD_DECODE_TABLE.length && STANDARD_DECODE_TABLE[octet] != -1; 690 } 691 692 /** 693 * Tests a given byte array to see if it contains only valid characters within the standard Base64 alphabet. The method treats whitespace as valid. 694 * <p> 695 * This implementation is aligned with <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The 696 * Base64 Alphabet</a>. 697 * </p> 698 * 699 * @param arrayOctet byte array to test. 700 * @return {@code true} if all bytes are valid characters in the standard Base64 alphabet. {@code false}, otherwise. 701 * @since 1.21 702 */ 703 public static boolean isBase64Standard(final byte[] arrayOctet) { 704 for (final byte element : arrayOctet) { 705 if (!isBase64Standard(element) && !Character.isWhitespace(element)) { 706 return false; 707 } 708 } 709 return true; 710 } 711 712 /** 713 * Tests a given String to see if it contains only valid characters within the standard Base64 alphabet. The method treats whitespace as valid. 714 * <p> 715 * This implementation is aligned with <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The 716 * Base64 Alphabet</a>. 717 * </p> 718 * 719 * @param base64 String to test. 720 * @return {@code true} if all characters in the String are valid characters in the standard Base64 alphabet or if the String is empty; {@code false}, 721 * otherwise. 722 * @since 1.21 723 */ 724 public static boolean isBase64Standard(final String base64) { 725 return isBase64Standard(StringUtils.getBytesUtf8(base64)); 726 } 727 728 /** 729 * Tests whether or not the {@code octet} is in the URL-safe Base64 alphabet. 730 * <p> 731 * This implementation is aligned with 732 * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648 733 * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>. 734 * </p> 735 * 736 * @param octet The value to test. 737 * @return {@code true} if the value is defined in the URL-safe Base64 alphabet, {@code false} otherwise. 738 * @since 1.21 739 */ 740 public static boolean isBase64Url(final byte octet) { 741 return octet == PAD_DEFAULT || octet >= 0 && octet < URL_SAFE_DECODE_TABLE.length && URL_SAFE_DECODE_TABLE[octet] != -1; 742 } 743 744 /** 745 * Tests a given byte array to see if it contains only valid characters within the URL-safe Base64 alphabet. The method treats whitespace as valid. 746 * <p> 747 * This implementation is aligned with 748 * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648 749 * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>. 750 * </p> 751 * 752 * @param arrayOctet byte array to test. 753 * @return {@code true} if all bytes are valid characters in the URL-safe Base64 alphabet, {@code false}, otherwise. 754 * @since 1.21 755 */ 756 public static boolean isBase64Url(final byte[] arrayOctet) { 757 for (final byte element : arrayOctet) { 758 if (!isBase64Url(element) && !Character.isWhitespace(element)) { 759 return false; 760 } 761 } 762 return true; 763 } 764 765 /** 766 * Tests a given String to see if it contains only valid characters within the URL-safe Base64 alphabet. The method treats whitespace as valid. 767 * <p> 768 * This implementation is aligned with 769 * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648 770 * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>. 771 * </p> 772 * 773 * @param base64 String to test. 774 * @return {@code true} if all characters in the String are valid characters in the URL-safe Base64 alphabet or if the String is empty; {@code false}, 775 * otherwise. 776 * @since 1.21 777 */ 778 public static boolean isBase64Url(final String base64) { 779 return isBase64Url(StringUtils.getBytesUtf8(base64)); 780 } 781 782 private static byte[] toDecodeTable(final byte[] encodeTable) { 783 final byte[] table = encodeTable != null ? encodeTable : STANDARD_ENCODE_TABLE; 784 if (Arrays.equals(table, STANDARD_ENCODE_TABLE) || Arrays.equals(table, URL_SAFE_ENCODE_TABLE)) { 785 return DECODE_TABLE; 786 } 787 return calculateDecodeTable(table); 788 } 789 790 static byte[] toUrlSafeEncodeTable(final boolean urlSafe) { 791 return urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE; 792 } 793 794 /** 795 * Line separator for encoding. Not used when decoding. Only used if lineLength > 0. 796 */ 797 private final byte[] lineSeparator; 798 799 /** 800 * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. {@code encodeSize = 4 + lineSeparator.length;} 801 */ 802 private final int encodeSize; 803 private final boolean isUrlSafe; 804 private final boolean isStandardEncodeTable; 805 806 /** 807 * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. 808 * <p> 809 * When encoding the line length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE. 810 * </p> 811 * <p> 812 * When decoding all variants are supported. 813 * </p> 814 */ 815 public Base64() { 816 this(0); 817 } 818 819 /** 820 * Constructs a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode. 821 * <p> 822 * When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE. 823 * </p> 824 * <p> 825 * When decoding all variants are supported. 826 * </p> 827 * 828 * @param urlSafe if {@code true}, URL-safe encoding is used. In most cases this should be set to {@code false}. 829 * @since 1.4 830 * @deprecated Use {@link #builder()} and {@link Builder}. 831 */ 832 @Deprecated 833 public Base64(final boolean urlSafe) { 834 this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe); 835 } 836 837 private Base64(final Builder builder) { 838 super(builder); 839 final byte[] encTable = builder.getEncodeTable(); 840 if (encTable.length != STANDARD_ENCODE_TABLE.length) { 841 throw new IllegalArgumentException("encodeTable must have exactly 64 entries."); 842 } 843 if (contains(encTable, pad)) { 844 throw new IllegalArgumentException("encodeTable must not contain the padding byte."); 845 } 846 this.isStandardEncodeTable = Arrays.equals(encTable, STANDARD_ENCODE_TABLE); 847 this.isUrlSafe = Arrays.equals(encTable, URL_SAFE_ENCODE_TABLE); 848 // TODO could be simplified if there is no requirement to reject invalid line sep when length <=0 849 // @see test case Base64Test.testConstructors() 850 if (builder.getLineSeparator().length > 0) { 851 final byte[] lineSeparatorB = builder.getLineSeparator(); 852 if (containsAlphabetOrPad(lineSeparatorB)) { 853 final String sep = StringUtils.newStringUtf8(lineSeparatorB); 854 throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]"); 855 } 856 if (builder.getLineLength() > 0) { // null line-sep forces no chunking rather than throwing IAE 857 this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparatorB.length; 858 this.lineSeparator = lineSeparatorB; 859 } else { 860 this.encodeSize = BYTES_PER_ENCODED_BLOCK; 861 this.lineSeparator = null; 862 } 863 } else { 864 this.encodeSize = BYTES_PER_ENCODED_BLOCK; 865 this.lineSeparator = null; 866 } 867 } 868 869 /** 870 * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. 871 * <p> 872 * When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE. 873 * </p> 874 * <p> 875 * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. 876 * </p> 877 * <p> 878 * When decoding all variants are supported. 879 * </p> 880 * 881 * @param lineLength Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of 4). If lineLength <= 0, then 882 * the output will not be divided into lines (chunks). Ignored when decoding. 883 * @since 1.4 884 * @deprecated Use {@link #builder()} and {@link Builder}. 885 */ 886 @Deprecated 887 public Base64(final int lineLength) { 888 this(lineLength, CHUNK_SEPARATOR); 889 } 890 891 /** 892 * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. 893 * <p> 894 * When encoding the line length and line separator are given in the constructor, and the encoding table is STANDARD_ENCODE_TABLE. 895 * </p> 896 * <p> 897 * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. 898 * </p> 899 * <p> 900 * When decoding all variants are supported. 901 * </p> 902 * 903 * @param lineLength Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of 4). If lineLength <= 0, 904 * then the output will not be divided into lines (chunks). Ignored when decoding. 905 * @param lineSeparator Each line of encoded data will end with this sequence of bytes. 906 * @throws IllegalArgumentException Thrown when the provided lineSeparator included some base64 characters. 907 * @since 1.4 908 * @deprecated Use {@link #builder()} and {@link Builder}. 909 */ 910 @Deprecated 911 public Base64(final int lineLength, final byte[] lineSeparator) { 912 this(lineLength, lineSeparator, false); 913 } 914 915 /** 916 * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. 917 * <p> 918 * When encoding the line length and line separator are given in the constructor, and the encoding table is STANDARD_ENCODE_TABLE. 919 * </p> 920 * <p> 921 * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. 922 * </p> 923 * <p> 924 * When decoding all variants are supported. 925 * </p> 926 * 927 * @param lineLength Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of 4). If lineLength <= 0, 928 * then the output will not be divided into lines (chunks). Ignored when decoding. 929 * @param lineSeparator Each line of encoded data will end with this sequence of bytes. 930 * @param urlSafe Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode operations. Decoding seamlessly 931 * handles both modes. <strong>No padding is added when using the URL-safe alphabet.</strong> 932 * @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base64 characters. 933 * @since 1.4 934 * @deprecated Use {@link #builder()} and {@link Builder}. 935 */ 936 @Deprecated 937 public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) { 938 this(builder().setLineLength(lineLength).setLineSeparator(lineSeparator != null ? lineSeparator : EMPTY_BYTE_ARRAY).setPadding(PAD_DEFAULT) 939 .setEncodeTableRaw(toUrlSafeEncodeTable(urlSafe)).setDecodingPolicy(DECODING_POLICY_DEFAULT)); 940 } 941 942 /** 943 * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. 944 * <p> 945 * When encoding the line length and line separator are given in the constructor, and the encoding table is STANDARD_ENCODE_TABLE. 946 * </p> 947 * <p> 948 * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. 949 * </p> 950 * <p> 951 * When decoding all variants are supported. 952 * </p> 953 * 954 * @param lineLength Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of 4). If lineLength <= 0, 955 * then the output will not be divided into lines (chunks). Ignored when decoding. 956 * @param lineSeparator Each line of encoded data will end with this sequence of bytes. 957 * @param urlSafe Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode operations. Decoding seamlessly 958 * handles both modes. <strong>No padding is added when using the URL-safe alphabet.</strong> 959 * @param decodingPolicy The decoding policy. 960 * @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base64 characters. 961 * @since 1.15 962 * @deprecated Use {@link #builder()} and {@link Builder}. 963 */ 964 @Deprecated 965 public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe, final CodecPolicy decodingPolicy) { 966 this(builder().setLineLength(lineLength).setLineSeparator(lineSeparator).setPadding(PAD_DEFAULT).setEncodeTableRaw(toUrlSafeEncodeTable(urlSafe)) 967 .setDecodingPolicy(decodingPolicy)); 968 } 969 970 /** 971 * <p> 972 * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once with the data to decode, and once with 973 * inAvail set to "-1" to alert decoder that EOF has been reached. The "-1" call is not necessary when decoding, but it doesn't hurt, either. 974 * </p> 975 * <p> 976 * Ignores all non-base64 characters. This is how chunked (for example 76 character) data is handled, since CR and LF are silently ignored, but has 977 * implications for other bytes, too. This method subscribes to the garbage-in, garbage-out philosophy: it will not check the provided data for validity. 978 * </p> 979 * <p> 980 * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. 981 * https://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ 982 * </p> 983 * 984 * @param input byte[] array of ASCII data to base64 decode. 985 * @param inPos Position to start reading data from. 986 * @param inAvail Amount of bytes available from input for decoding. 987 * @param context The context to be used. 988 */ 989 @Override 990 void decode(final byte[] input, int inPos, final int inAvail, final Context context) { 991 if (context.eof) { 992 return; 993 } 994 if (inAvail < 0) { 995 context.eof = true; 996 } 997 final int decodeSize = this.encodeSize - 1; 998 for (int i = 0; i < inAvail; i++) { 999 final int b = input[inPos++] & 0xff; 1000 if (b == (pad & 0xff)) { 1001 // We're done. 1002 context.eof = true; 1003 break; 1004 } 1005 final byte[] buffer = ensureBufferSize(decodeSize, context); 1006 if (b < decodeTable.length) { 1007 final int result = decodeTable[b]; 1008 if (result >= 0) { 1009 context.modulus = (context.modulus + 1) % BYTES_PER_ENCODED_BLOCK; 1010 context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result; 1011 if (context.modulus == 0) { 1012 buffer[context.pos++] = (byte) (context.ibitWorkArea >> 16 & MASK_8BITS); 1013 buffer[context.pos++] = (byte) (context.ibitWorkArea >> 8 & MASK_8BITS); 1014 buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS); 1015 } 1016 } 1017 } 1018 } 1019 1020 // Two forms of EOF as far as base64 decoder is concerned: actual 1021 // EOF (-1) and first time '=' character is encountered in stream. 1022 // This approach makes the '=' padding characters completely optional. 1023 if (context.eof && context.modulus != 0) { 1024 final byte[] buffer = ensureBufferSize(decodeSize, context); 1025 1026 // We have some spare bits remaining 1027 // Output all whole multiples of 8 bits and ignore the rest 1028 switch (context.modulus) { 1029// case 0 : // impossible, as excluded above 1030 case 1 : // 6 bits - either ignore entirely, or raise an exception 1031 validateTrailingCharacter(); 1032 break; 1033 case 2 : // 12 bits = 8 + 4 1034 validateCharacter(MASK_4_BITS, context); 1035 context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits 1036 buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS); 1037 break; 1038 case 3 : // 18 bits = 8 + 8 + 2 1039 validateCharacter(MASK_2_BITS, context); 1040 context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits 1041 buffer[context.pos++] = (byte) (context.ibitWorkArea >> 8 & MASK_8BITS); 1042 buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS); 1043 break; 1044 default: 1045 throw new IllegalStateException("Impossible modulus " + context.modulus); 1046 } 1047 } 1048 } 1049 1050 /** 1051 * <p> 1052 * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with the data to encode, and once with 1053 * inAvail set to "-1" to alert encoder that EOF has been reached, to flush last remaining bytes (if not multiple of 3). 1054 * </p> 1055 * <p> 1056 * <strong>No padding is added when encoding using the URL-safe alphabet.</strong> 1057 * </p> 1058 * <p> 1059 * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. 1060 * https://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ 1061 * </p> 1062 * 1063 * @param in byte[] array of binary data to base64 encode. 1064 * @param inPos Position to start reading data from. 1065 * @param inAvail Amount of bytes available from input for encoding. 1066 * @param context The context to be used. 1067 */ 1068 @Override 1069 void encode(final byte[] in, int inPos, final int inAvail, final Context context) { 1070 if (context.eof) { 1071 return; 1072 } 1073 // inAvail < 0 is how we're informed of EOF in the underlying data we're 1074 // encoding. 1075 if (inAvail < 0) { 1076 context.eof = true; 1077 if (0 == context.modulus && lineLength == 0) { 1078 return; // no leftovers to process and not using chunking 1079 } 1080 final byte[] buffer = ensureBufferSize(encodeSize, context); 1081 final int savedPos = context.pos; 1082 switch (context.modulus) { // 0-2 1083 case 0 : // nothing to do here 1084 break; 1085 case 1 : // 8 bits = 6 + 2 1086 // top 6 bits: 1087 buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 2 & MASK_6_BITS]; 1088 // remaining 2: 1089 buffer[context.pos++] = encodeTable[context.ibitWorkArea << 4 & MASK_6_BITS]; 1090 // URL-SAFE skips the padding to further reduce size. 1091 if (isStandardEncodeTable) { 1092 buffer[context.pos++] = pad; 1093 buffer[context.pos++] = pad; 1094 } 1095 break; 1096 1097 case 2 : // 16 bits = 6 + 6 + 4 1098 buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 10 & MASK_6_BITS]; 1099 buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 4 & MASK_6_BITS]; 1100 buffer[context.pos++] = encodeTable[context.ibitWorkArea << 2 & MASK_6_BITS]; 1101 // URL-SAFE skips the padding to further reduce size. 1102 if (isStandardEncodeTable) { 1103 buffer[context.pos++] = pad; 1104 } 1105 break; 1106 default: 1107 throw new IllegalStateException("Impossible modulus " + context.modulus); 1108 } 1109 context.currentLinePos += context.pos - savedPos; // keep track of current line position 1110 // if currentPos == 0 we are at the start of a line, so don't add CRLF 1111 if (lineLength > 0 && context.currentLinePos > 0) { 1112 System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length); 1113 context.pos += lineSeparator.length; 1114 } 1115 } else { 1116 for (int i = 0; i < inAvail; i++) { 1117 final byte[] buffer = ensureBufferSize(encodeSize, context); 1118 context.modulus = (context.modulus + 1) % BYTES_PER_UNENCODED_BLOCK; 1119 int b = in[inPos++]; 1120 if (b < 0) { 1121 b += 256; 1122 } 1123 context.ibitWorkArea = (context.ibitWorkArea << 8) + b; // BITS_PER_BYTE 1124 if (0 == context.modulus) { // 3 bytes = 24 bits = 4 * 6 bits to extract 1125 buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 18 & MASK_6_BITS]; 1126 buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 12 & MASK_6_BITS]; 1127 buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 6 & MASK_6_BITS]; 1128 buffer[context.pos++] = encodeTable[context.ibitWorkArea & MASK_6_BITS]; 1129 context.currentLinePos += BYTES_PER_ENCODED_BLOCK; 1130 if (lineLength > 0 && lineLength <= context.currentLinePos) { 1131 System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length); 1132 context.pos += lineSeparator.length; 1133 context.currentLinePos = 0; 1134 } 1135 } 1136 } 1137 } 1138 } 1139 1140 /** 1141 * Gets the line separator (for testing only). 1142 * 1143 * @return The line separator. 1144 */ 1145 byte[] getLineSeparator() { 1146 return lineSeparator; 1147 } 1148 1149 /** 1150 * Returns whether or not the {@code octet} is in the Base64 alphabet. 1151 * 1152 * @param octet The value to test. 1153 * @return {@code true} if the value is defined in the Base64 alphabet {@code false} otherwise. 1154 */ 1155 @Override 1156 protected boolean isInAlphabet(final byte octet) { 1157 final int value = octet & 0xff; 1158 return value < decodeTable.length && decodeTable[value] != -1; 1159 } 1160 1161 /** 1162 * Returns our current encode mode. True if we're URL-safe, false otherwise. 1163 * 1164 * @return true if we're in URL-safe mode, false otherwise. 1165 * @since 1.4 1166 */ 1167 public boolean isUrlSafe() { 1168 return isUrlSafe; 1169 } 1170 1171 /** 1172 * Validates whether decoding the final trailing character is possible in the context of the set of possible Base64 values. 1173 * <p> 1174 * The character is valid if the lower bits within the provided mask are zero. This is used to test the final trailing base-64 digit is zero in the bits 1175 * that will be discarded. 1176 * </p> 1177 * 1178 * @param emptyBitsMask The mask of the lower bits that should be empty. 1179 * @param context The context to be used. 1180 * @throws IllegalArgumentException if the bits being checked contain any non-zero value. 1181 */ 1182 private void validateCharacter(final int emptyBitsMask, final Context context) { 1183 if (isStrictDecoding() && (context.ibitWorkArea & emptyBitsMask) != 0) { 1184 throw new IllegalArgumentException("Strict decoding: Last encoded character (before the paddings if any) is a valid " + 1185 "Base64 alphabet but not a possible encoding. Expected the discarded bits from the character to be zero."); 1186 } 1187 } 1188 1189 /** 1190 * Validates whether decoding allows an entire final trailing character that cannot be used for a complete byte. 1191 * 1192 * @throws IllegalArgumentException if strict decoding is enabled. 1193 */ 1194 private void validateTrailingCharacter() { 1195 if (isStrictDecoding()) { 1196 throw new IllegalArgumentException("Strict decoding: Last encoded character (before the paddings if any) is a valid " + 1197 "Base64 alphabet but not a possible encoding. Decoding requires at least two trailing 6-bit characters to create bytes."); 1198 } 1199 } 1200 1201}