| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | */ |
| | | package com.forgerock.opendj.util; |
| | | |
| | | |
| | | |
| | | import static com.forgerock.opendj.util.Validator.ensureNotNull; |
| | | import static org.forgerock.opendj.ldap.CoreMessages.ERR_BASE64_DECODE_INVALID_CHARACTER; |
| | | import static org.forgerock.opendj.ldap.CoreMessages.ERR_BASE64_DECODE_INVALID_LENGTH; |
| | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ByteStringBuilder; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class provides methods for performing base64 encoding and decoding. |
| | | * Base64 is a mechanism for encoding binary data in ASCII form by converting |
| | | * sets of three bytes with eight significant bits each to sets of four bytes |
| | | * with six significant bits each. |
| | | */ |
| | | public final class Base64 |
| | | { |
| | | /** |
| | | * The set of characters that may be used in base64-encoded values. |
| | | */ |
| | | private static final char[] BASE64_ALPHABET = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| | | + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/").toCharArray(); |
| | | public final class Base64 { |
| | | /** |
| | | * The set of characters that may be used in base64-encoded values. |
| | | */ |
| | | private static final char[] BASE64_ALPHABET = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| | | + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/").toCharArray(); |
| | | |
| | | /** |
| | | * Decodes the provided base64 encoded data. |
| | | * |
| | | * @param base64 |
| | | * The base64 encoded data. |
| | | * @return The decoded data. |
| | | * @throws LocalizedIllegalArgumentException |
| | | * If a problem occurs while attempting to decode {@code base64} |
| | | * . |
| | | * @throws NullPointerException |
| | | * If {@code base64} was {@code null}. |
| | | */ |
| | | public static ByteString decode(final String base64) { |
| | | ensureNotNull(base64); |
| | | |
| | | |
| | | /** |
| | | * Decodes the provided base64 encoded data. |
| | | * |
| | | * @param base64 |
| | | * The base64 encoded data. |
| | | * @return The decoded data. |
| | | * @throws LocalizedIllegalArgumentException |
| | | * If a problem occurs while attempting to decode {@code base64}. |
| | | * @throws NullPointerException |
| | | * If {@code base64} was {@code null}. |
| | | */ |
| | | public static ByteString decode(final String base64) |
| | | { |
| | | ensureNotNull(base64); |
| | | |
| | | // The encoded value must have length that is a multiple of four |
| | | // bytes. |
| | | final int length = base64.length(); |
| | | if ((length % 4) != 0) |
| | | { |
| | | final LocalizableMessage message = ERR_BASE64_DECODE_INVALID_LENGTH |
| | | .get(base64); |
| | | throw new LocalizedIllegalArgumentException(message); |
| | | } |
| | | |
| | | final ByteStringBuilder builder = new ByteStringBuilder(length); |
| | | for (int i = 0; i < length; i += 4) |
| | | { |
| | | boolean append = true; |
| | | int value = 0; |
| | | |
| | | for (int j = 0; j < 4; j++) |
| | | { |
| | | switch (base64.charAt(i + j)) |
| | | { |
| | | case 'A': |
| | | value <<= 6; |
| | | break; |
| | | case 'B': |
| | | value = (value << 6) | 0x01; |
| | | break; |
| | | case 'C': |
| | | value = (value << 6) | 0x02; |
| | | break; |
| | | case 'D': |
| | | value = (value << 6) | 0x03; |
| | | break; |
| | | case 'E': |
| | | value = (value << 6) | 0x04; |
| | | break; |
| | | case 'F': |
| | | value = (value << 6) | 0x05; |
| | | break; |
| | | case 'G': |
| | | value = (value << 6) | 0x06; |
| | | break; |
| | | case 'H': |
| | | value = (value << 6) | 0x07; |
| | | break; |
| | | case 'I': |
| | | value = (value << 6) | 0x08; |
| | | break; |
| | | case 'J': |
| | | value = (value << 6) | 0x09; |
| | | break; |
| | | case 'K': |
| | | value = (value << 6) | 0x0A; |
| | | break; |
| | | case 'L': |
| | | value = (value << 6) | 0x0B; |
| | | break; |
| | | case 'M': |
| | | value = (value << 6) | 0x0C; |
| | | break; |
| | | case 'N': |
| | | value = (value << 6) | 0x0D; |
| | | break; |
| | | case 'O': |
| | | value = (value << 6) | 0x0E; |
| | | break; |
| | | case 'P': |
| | | value = (value << 6) | 0x0F; |
| | | break; |
| | | case 'Q': |
| | | value = (value << 6) | 0x10; |
| | | break; |
| | | case 'R': |
| | | value = (value << 6) | 0x11; |
| | | break; |
| | | case 'S': |
| | | value = (value << 6) | 0x12; |
| | | break; |
| | | case 'T': |
| | | value = (value << 6) | 0x13; |
| | | break; |
| | | case 'U': |
| | | value = (value << 6) | 0x14; |
| | | break; |
| | | case 'V': |
| | | value = (value << 6) | 0x15; |
| | | break; |
| | | case 'W': |
| | | value = (value << 6) | 0x16; |
| | | break; |
| | | case 'X': |
| | | value = (value << 6) | 0x17; |
| | | break; |
| | | case 'Y': |
| | | value = (value << 6) | 0x18; |
| | | break; |
| | | case 'Z': |
| | | value = (value << 6) | 0x19; |
| | | break; |
| | | case 'a': |
| | | value = (value << 6) | 0x1A; |
| | | break; |
| | | case 'b': |
| | | value = (value << 6) | 0x1B; |
| | | break; |
| | | case 'c': |
| | | value = (value << 6) | 0x1C; |
| | | break; |
| | | case 'd': |
| | | value = (value << 6) | 0x1D; |
| | | break; |
| | | case 'e': |
| | | value = (value << 6) | 0x1E; |
| | | break; |
| | | case 'f': |
| | | value = (value << 6) | 0x1F; |
| | | break; |
| | | case 'g': |
| | | value = (value << 6) | 0x20; |
| | | break; |
| | | case 'h': |
| | | value = (value << 6) | 0x21; |
| | | break; |
| | | case 'i': |
| | | value = (value << 6) | 0x22; |
| | | break; |
| | | case 'j': |
| | | value = (value << 6) | 0x23; |
| | | break; |
| | | case 'k': |
| | | value = (value << 6) | 0x24; |
| | | break; |
| | | case 'l': |
| | | value = (value << 6) | 0x25; |
| | | break; |
| | | case 'm': |
| | | value = (value << 6) | 0x26; |
| | | break; |
| | | case 'n': |
| | | value = (value << 6) | 0x27; |
| | | break; |
| | | case 'o': |
| | | value = (value << 6) | 0x28; |
| | | break; |
| | | case 'p': |
| | | value = (value << 6) | 0x29; |
| | | break; |
| | | case 'q': |
| | | value = (value << 6) | 0x2A; |
| | | break; |
| | | case 'r': |
| | | value = (value << 6) | 0x2B; |
| | | break; |
| | | case 's': |
| | | value = (value << 6) | 0x2C; |
| | | break; |
| | | case 't': |
| | | value = (value << 6) | 0x2D; |
| | | break; |
| | | case 'u': |
| | | value = (value << 6) | 0x2E; |
| | | break; |
| | | case 'v': |
| | | value = (value << 6) | 0x2F; |
| | | break; |
| | | case 'w': |
| | | value = (value << 6) | 0x30; |
| | | break; |
| | | case 'x': |
| | | value = (value << 6) | 0x31; |
| | | break; |
| | | case 'y': |
| | | value = (value << 6) | 0x32; |
| | | break; |
| | | case 'z': |
| | | value = (value << 6) | 0x33; |
| | | break; |
| | | case '0': |
| | | value = (value << 6) | 0x34; |
| | | break; |
| | | case '1': |
| | | value = (value << 6) | 0x35; |
| | | break; |
| | | case '2': |
| | | value = (value << 6) | 0x36; |
| | | break; |
| | | case '3': |
| | | value = (value << 6) | 0x37; |
| | | break; |
| | | case '4': |
| | | value = (value << 6) | 0x38; |
| | | break; |
| | | case '5': |
| | | value = (value << 6) | 0x39; |
| | | break; |
| | | case '6': |
| | | value = (value << 6) | 0x3A; |
| | | break; |
| | | case '7': |
| | | value = (value << 6) | 0x3B; |
| | | break; |
| | | case '8': |
| | | value = (value << 6) | 0x3C; |
| | | break; |
| | | case '9': |
| | | value = (value << 6) | 0x3D; |
| | | break; |
| | | case '+': |
| | | value = (value << 6) | 0x3E; |
| | | break; |
| | | case '/': |
| | | value = (value << 6) | 0x3F; |
| | | break; |
| | | case '=': |
| | | append = false; |
| | | switch (j) |
| | | { |
| | | case 2: |
| | | builder.append((byte) ((value >>> 4) & 0xFF)); |
| | | break; |
| | | case 3: |
| | | builder.append((byte) ((value >>> 10) & 0xFF)); |
| | | builder.append((byte) ((value >>> 2) & 0xFF)); |
| | | break; |
| | | } |
| | | break; |
| | | default: |
| | | final LocalizableMessage message = ERR_BASE64_DECODE_INVALID_CHARACTER |
| | | .get(base64, base64.charAt(i + j)); |
| | | throw new LocalizedIllegalArgumentException(message); |
| | | // The encoded value must have length that is a multiple of four |
| | | // bytes. |
| | | final int length = base64.length(); |
| | | if ((length % 4) != 0) { |
| | | final LocalizableMessage message = ERR_BASE64_DECODE_INVALID_LENGTH.get(base64); |
| | | throw new LocalizedIllegalArgumentException(message); |
| | | } |
| | | |
| | | if (!append) |
| | | { |
| | | break; |
| | | final ByteStringBuilder builder = new ByteStringBuilder(length); |
| | | for (int i = 0; i < length; i += 4) { |
| | | boolean append = true; |
| | | int value = 0; |
| | | |
| | | for (int j = 0; j < 4; j++) { |
| | | switch (base64.charAt(i + j)) { |
| | | case 'A': |
| | | value <<= 6; |
| | | break; |
| | | case 'B': |
| | | value = (value << 6) | 0x01; |
| | | break; |
| | | case 'C': |
| | | value = (value << 6) | 0x02; |
| | | break; |
| | | case 'D': |
| | | value = (value << 6) | 0x03; |
| | | break; |
| | | case 'E': |
| | | value = (value << 6) | 0x04; |
| | | break; |
| | | case 'F': |
| | | value = (value << 6) | 0x05; |
| | | break; |
| | | case 'G': |
| | | value = (value << 6) | 0x06; |
| | | break; |
| | | case 'H': |
| | | value = (value << 6) | 0x07; |
| | | break; |
| | | case 'I': |
| | | value = (value << 6) | 0x08; |
| | | break; |
| | | case 'J': |
| | | value = (value << 6) | 0x09; |
| | | break; |
| | | case 'K': |
| | | value = (value << 6) | 0x0A; |
| | | break; |
| | | case 'L': |
| | | value = (value << 6) | 0x0B; |
| | | break; |
| | | case 'M': |
| | | value = (value << 6) | 0x0C; |
| | | break; |
| | | case 'N': |
| | | value = (value << 6) | 0x0D; |
| | | break; |
| | | case 'O': |
| | | value = (value << 6) | 0x0E; |
| | | break; |
| | | case 'P': |
| | | value = (value << 6) | 0x0F; |
| | | break; |
| | | case 'Q': |
| | | value = (value << 6) | 0x10; |
| | | break; |
| | | case 'R': |
| | | value = (value << 6) | 0x11; |
| | | break; |
| | | case 'S': |
| | | value = (value << 6) | 0x12; |
| | | break; |
| | | case 'T': |
| | | value = (value << 6) | 0x13; |
| | | break; |
| | | case 'U': |
| | | value = (value << 6) | 0x14; |
| | | break; |
| | | case 'V': |
| | | value = (value << 6) | 0x15; |
| | | break; |
| | | case 'W': |
| | | value = (value << 6) | 0x16; |
| | | break; |
| | | case 'X': |
| | | value = (value << 6) | 0x17; |
| | | break; |
| | | case 'Y': |
| | | value = (value << 6) | 0x18; |
| | | break; |
| | | case 'Z': |
| | | value = (value << 6) | 0x19; |
| | | break; |
| | | case 'a': |
| | | value = (value << 6) | 0x1A; |
| | | break; |
| | | case 'b': |
| | | value = (value << 6) | 0x1B; |
| | | break; |
| | | case 'c': |
| | | value = (value << 6) | 0x1C; |
| | | break; |
| | | case 'd': |
| | | value = (value << 6) | 0x1D; |
| | | break; |
| | | case 'e': |
| | | value = (value << 6) | 0x1E; |
| | | break; |
| | | case 'f': |
| | | value = (value << 6) | 0x1F; |
| | | break; |
| | | case 'g': |
| | | value = (value << 6) | 0x20; |
| | | break; |
| | | case 'h': |
| | | value = (value << 6) | 0x21; |
| | | break; |
| | | case 'i': |
| | | value = (value << 6) | 0x22; |
| | | break; |
| | | case 'j': |
| | | value = (value << 6) | 0x23; |
| | | break; |
| | | case 'k': |
| | | value = (value << 6) | 0x24; |
| | | break; |
| | | case 'l': |
| | | value = (value << 6) | 0x25; |
| | | break; |
| | | case 'm': |
| | | value = (value << 6) | 0x26; |
| | | break; |
| | | case 'n': |
| | | value = (value << 6) | 0x27; |
| | | break; |
| | | case 'o': |
| | | value = (value << 6) | 0x28; |
| | | break; |
| | | case 'p': |
| | | value = (value << 6) | 0x29; |
| | | break; |
| | | case 'q': |
| | | value = (value << 6) | 0x2A; |
| | | break; |
| | | case 'r': |
| | | value = (value << 6) | 0x2B; |
| | | break; |
| | | case 's': |
| | | value = (value << 6) | 0x2C; |
| | | break; |
| | | case 't': |
| | | value = (value << 6) | 0x2D; |
| | | break; |
| | | case 'u': |
| | | value = (value << 6) | 0x2E; |
| | | break; |
| | | case 'v': |
| | | value = (value << 6) | 0x2F; |
| | | break; |
| | | case 'w': |
| | | value = (value << 6) | 0x30; |
| | | break; |
| | | case 'x': |
| | | value = (value << 6) | 0x31; |
| | | break; |
| | | case 'y': |
| | | value = (value << 6) | 0x32; |
| | | break; |
| | | case 'z': |
| | | value = (value << 6) | 0x33; |
| | | break; |
| | | case '0': |
| | | value = (value << 6) | 0x34; |
| | | break; |
| | | case '1': |
| | | value = (value << 6) | 0x35; |
| | | break; |
| | | case '2': |
| | | value = (value << 6) | 0x36; |
| | | break; |
| | | case '3': |
| | | value = (value << 6) | 0x37; |
| | | break; |
| | | case '4': |
| | | value = (value << 6) | 0x38; |
| | | break; |
| | | case '5': |
| | | value = (value << 6) | 0x39; |
| | | break; |
| | | case '6': |
| | | value = (value << 6) | 0x3A; |
| | | break; |
| | | case '7': |
| | | value = (value << 6) | 0x3B; |
| | | break; |
| | | case '8': |
| | | value = (value << 6) | 0x3C; |
| | | break; |
| | | case '9': |
| | | value = (value << 6) | 0x3D; |
| | | break; |
| | | case '+': |
| | | value = (value << 6) | 0x3E; |
| | | break; |
| | | case '/': |
| | | value = (value << 6) | 0x3F; |
| | | break; |
| | | case '=': |
| | | append = false; |
| | | switch (j) { |
| | | case 2: |
| | | builder.append((byte) ((value >>> 4) & 0xFF)); |
| | | break; |
| | | case 3: |
| | | builder.append((byte) ((value >>> 10) & 0xFF)); |
| | | builder.append((byte) ((value >>> 2) & 0xFF)); |
| | | break; |
| | | } |
| | | break; |
| | | default: |
| | | final LocalizableMessage message = |
| | | ERR_BASE64_DECODE_INVALID_CHARACTER.get(base64, base64.charAt(i + j)); |
| | | throw new LocalizedIllegalArgumentException(message); |
| | | } |
| | | |
| | | if (!append) { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (append) { |
| | | builder.append((byte) ((value >>> 16) & 0xFF)); |
| | | builder.append((byte) ((value >>> 8) & 0xFF)); |
| | | builder.append((byte) (value & 0xFF)); |
| | | } else { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (append) |
| | | { |
| | | builder.append((byte) ((value >>> 16) & 0xFF)); |
| | | builder.append((byte) ((value >>> 8) & 0xFF)); |
| | | builder.append((byte) (value & 0xFF)); |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | return builder.toByteString(); |
| | | } |
| | | |
| | | return builder.toByteString(); |
| | | } |
| | | /** |
| | | * Encodes the provided data as a base64 string. |
| | | * |
| | | * @param bytes |
| | | * The data to be encoded. |
| | | * @return The base64 encoded representation of {@code bytes}. |
| | | * @throws NullPointerException |
| | | * If {@code bytes} was {@code null}. |
| | | */ |
| | | public static String encode(final ByteSequence bytes) { |
| | | ensureNotNull(bytes); |
| | | |
| | | final StringBuilder buffer = new StringBuilder(4 * bytes.length() / 3); |
| | | |
| | | int pos = 0; |
| | | final int iterations = bytes.length() / 3; |
| | | for (int i = 0; i < iterations; i++) { |
| | | final int value = |
| | | ((bytes.byteAt(pos++) & 0xFF) << 16) | ((bytes.byteAt(pos++) & 0xFF) << 8) |
| | | | (bytes.byteAt(pos++) & 0xFF); |
| | | |
| | | /** |
| | | * Encodes the provided data as a base64 string. |
| | | * |
| | | * @param bytes |
| | | * The data to be encoded. |
| | | * @return The base64 encoded representation of {@code bytes}. |
| | | * @throws NullPointerException |
| | | * If {@code bytes} was {@code null}. |
| | | */ |
| | | public static String encode(final ByteSequence bytes) |
| | | { |
| | | ensureNotNull(bytes); |
| | | buffer.append(BASE64_ALPHABET[(value >>> 18) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[(value >>> 12) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[(value >>> 6) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[value & 0x3F]); |
| | | } |
| | | |
| | | final StringBuilder buffer = new StringBuilder(4 * bytes.length() / 3); |
| | | switch (bytes.length() % 3) { |
| | | case 1: |
| | | buffer.append(BASE64_ALPHABET[(bytes.byteAt(pos) >>> 2) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[(bytes.byteAt(pos) << 4) & 0x3F]); |
| | | buffer.append("=="); |
| | | break; |
| | | case 2: |
| | | final int value = ((bytes.byteAt(pos++) & 0xFF) << 8) | (bytes.byteAt(pos) & 0xFF); |
| | | buffer.append(BASE64_ALPHABET[(value >>> 10) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[(value >>> 4) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[(value << 2) & 0x3F]); |
| | | buffer.append("="); |
| | | break; |
| | | } |
| | | |
| | | int pos = 0; |
| | | final int iterations = bytes.length() / 3; |
| | | for (int i = 0; i < iterations; i++) |
| | | { |
| | | final int value = ((bytes.byteAt(pos++) & 0xFF) << 16) |
| | | | ((bytes.byteAt(pos++) & 0xFF) << 8) | (bytes.byteAt(pos++) & 0xFF); |
| | | |
| | | buffer.append(BASE64_ALPHABET[(value >>> 18) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[(value >>> 12) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[(value >>> 6) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[value & 0x3F]); |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | switch (bytes.length() % 3) |
| | | { |
| | | case 1: |
| | | buffer.append(BASE64_ALPHABET[(bytes.byteAt(pos) >>> 2) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[(bytes.byteAt(pos) << 4) & 0x3F]); |
| | | buffer.append("=="); |
| | | break; |
| | | case 2: |
| | | final int value = ((bytes.byteAt(pos++) & 0xFF) << 8) |
| | | | (bytes.byteAt(pos) & 0xFF); |
| | | buffer.append(BASE64_ALPHABET[(value >>> 10) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[(value >>> 4) & 0x3F]); |
| | | buffer.append(BASE64_ALPHABET[(value << 2) & 0x3F]); |
| | | buffer.append("="); |
| | | break; |
| | | /** |
| | | * Prevent instance creation. |
| | | */ |
| | | private Base64() { |
| | | // No implementation required. |
| | | } |
| | | |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Prevent instance creation. |
| | | */ |
| | | private Base64() |
| | | { |
| | | // No implementation required. |
| | | } |
| | | } |