001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2009 Sun Microsystems, Inc. 015 * Portions copyright 2012-2016 ForgeRock AS. 016 */ 017package org.forgerock.opendj.ldap; 018 019import org.forgerock.util.Reject; 020import static com.forgerock.opendj.ldap.CoreMessages.ERR_BASE64_DECODE_INVALID_CHARACTER; 021import static com.forgerock.opendj.ldap.CoreMessages.ERR_BASE64_DECODE_INVALID_LENGTH; 022 023import org.forgerock.i18n.LocalizableMessage; 024import org.forgerock.i18n.LocalizedIllegalArgumentException; 025 026/** 027 * This class provides methods for performing base64 encoding and decoding. 028 * Base64 is a mechanism for encoding binary data in ASCII form by converting 029 * sets of three bytes with eight significant bits each to sets of four bytes 030 * with six significant bits each. 031 */ 032public final class Base64 { 033 /** 034 * The set of characters that may be used in base64-encoded values. 035 */ 036 private static final char[] BASE64_ALPHABET = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" 037 + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/").toCharArray(); 038 039 /** 040 * Decodes the provided base64 encoded data. 041 * 042 * @param base64 043 * The base64 encoded data. 044 * @return The decoded data. 045 * @throws LocalizedIllegalArgumentException 046 * If a problem occurs while attempting to decode {@code base64} 047 * . 048 * @throws NullPointerException 049 * If {@code base64} was {@code null}. 050 */ 051 public static ByteString decode(final String base64) { 052 Reject.ifNull(base64); 053 054 // The encoded value must have length that is a multiple of four 055 // bytes. 056 final int length = base64.length(); 057 if (length % 4 != 0) { 058 final LocalizableMessage message = ERR_BASE64_DECODE_INVALID_LENGTH.get(base64); 059 throw new LocalizedIllegalArgumentException(message); 060 } 061 062 final ByteStringBuilder builder = new ByteStringBuilder(length); 063 for (int i = 0; i < length; i += 4) { 064 boolean append = true; 065 int value = 0; 066 067 for (int j = 0; j < 4; j++) { 068 switch (base64.charAt(i + j)) { 069 case 'A': 070 value <<= 6; 071 break; 072 case 'B': 073 value = (value << 6) | 0x01; 074 break; 075 case 'C': 076 value = (value << 6) | 0x02; 077 break; 078 case 'D': 079 value = (value << 6) | 0x03; 080 break; 081 case 'E': 082 value = (value << 6) | 0x04; 083 break; 084 case 'F': 085 value = (value << 6) | 0x05; 086 break; 087 case 'G': 088 value = (value << 6) | 0x06; 089 break; 090 case 'H': 091 value = (value << 6) | 0x07; 092 break; 093 case 'I': 094 value = (value << 6) | 0x08; 095 break; 096 case 'J': 097 value = (value << 6) | 0x09; 098 break; 099 case 'K': 100 value = (value << 6) | 0x0A; 101 break; 102 case 'L': 103 value = (value << 6) | 0x0B; 104 break; 105 case 'M': 106 value = (value << 6) | 0x0C; 107 break; 108 case 'N': 109 value = (value << 6) | 0x0D; 110 break; 111 case 'O': 112 value = (value << 6) | 0x0E; 113 break; 114 case 'P': 115 value = (value << 6) | 0x0F; 116 break; 117 case 'Q': 118 value = (value << 6) | 0x10; 119 break; 120 case 'R': 121 value = (value << 6) | 0x11; 122 break; 123 case 'S': 124 value = (value << 6) | 0x12; 125 break; 126 case 'T': 127 value = (value << 6) | 0x13; 128 break; 129 case 'U': 130 value = (value << 6) | 0x14; 131 break; 132 case 'V': 133 value = (value << 6) | 0x15; 134 break; 135 case 'W': 136 value = (value << 6) | 0x16; 137 break; 138 case 'X': 139 value = (value << 6) | 0x17; 140 break; 141 case 'Y': 142 value = (value << 6) | 0x18; 143 break; 144 case 'Z': 145 value = (value << 6) | 0x19; 146 break; 147 case 'a': 148 value = (value << 6) | 0x1A; 149 break; 150 case 'b': 151 value = (value << 6) | 0x1B; 152 break; 153 case 'c': 154 value = (value << 6) | 0x1C; 155 break; 156 case 'd': 157 value = (value << 6) | 0x1D; 158 break; 159 case 'e': 160 value = (value << 6) | 0x1E; 161 break; 162 case 'f': 163 value = (value << 6) | 0x1F; 164 break; 165 case 'g': 166 value = (value << 6) | 0x20; 167 break; 168 case 'h': 169 value = (value << 6) | 0x21; 170 break; 171 case 'i': 172 value = (value << 6) | 0x22; 173 break; 174 case 'j': 175 value = (value << 6) | 0x23; 176 break; 177 case 'k': 178 value = (value << 6) | 0x24; 179 break; 180 case 'l': 181 value = (value << 6) | 0x25; 182 break; 183 case 'm': 184 value = (value << 6) | 0x26; 185 break; 186 case 'n': 187 value = (value << 6) | 0x27; 188 break; 189 case 'o': 190 value = (value << 6) | 0x28; 191 break; 192 case 'p': 193 value = (value << 6) | 0x29; 194 break; 195 case 'q': 196 value = (value << 6) | 0x2A; 197 break; 198 case 'r': 199 value = (value << 6) | 0x2B; 200 break; 201 case 's': 202 value = (value << 6) | 0x2C; 203 break; 204 case 't': 205 value = (value << 6) | 0x2D; 206 break; 207 case 'u': 208 value = (value << 6) | 0x2E; 209 break; 210 case 'v': 211 value = (value << 6) | 0x2F; 212 break; 213 case 'w': 214 value = (value << 6) | 0x30; 215 break; 216 case 'x': 217 value = (value << 6) | 0x31; 218 break; 219 case 'y': 220 value = (value << 6) | 0x32; 221 break; 222 case 'z': 223 value = (value << 6) | 0x33; 224 break; 225 case '0': 226 value = (value << 6) | 0x34; 227 break; 228 case '1': 229 value = (value << 6) | 0x35; 230 break; 231 case '2': 232 value = (value << 6) | 0x36; 233 break; 234 case '3': 235 value = (value << 6) | 0x37; 236 break; 237 case '4': 238 value = (value << 6) | 0x38; 239 break; 240 case '5': 241 value = (value << 6) | 0x39; 242 break; 243 case '6': 244 value = (value << 6) | 0x3A; 245 break; 246 case '7': 247 value = (value << 6) | 0x3B; 248 break; 249 case '8': 250 value = (value << 6) | 0x3C; 251 break; 252 case '9': 253 value = (value << 6) | 0x3D; 254 break; 255 case '+': 256 value = (value << 6) | 0x3E; 257 break; 258 case '/': 259 value = (value << 6) | 0x3F; 260 break; 261 case '=': 262 append = false; 263 switch (j) { 264 case 2: 265 builder.appendByte(value >>> 4); 266 break; 267 case 3: 268 builder.appendByte(value >>> 10); 269 builder.appendByte(value >>> 2); 270 break; 271 } 272 break; 273 default: 274 final LocalizableMessage message = 275 ERR_BASE64_DECODE_INVALID_CHARACTER.get(base64, base64.charAt(i + j)); 276 throw new LocalizedIllegalArgumentException(message); 277 } 278 279 if (!append) { 280 break; 281 } 282 } 283 284 if (append) { 285 builder.appendByte(value >>> 16); 286 builder.appendByte(value >>> 8); 287 builder.appendByte(value); 288 } else { 289 break; 290 } 291 } 292 293 return builder.toByteString(); 294 } 295 296 /** 297 * Encodes the provided data as a base64 string. 298 * 299 * @param bytes 300 * The data to be encoded. 301 * @return The base64 encoded representation of {@code bytes}. 302 * @throws NullPointerException 303 * If {@code bytes} was {@code null}. 304 */ 305 public static String encode(final byte[] bytes) { 306 return encode(ByteString.wrap(bytes)); 307 } 308 309 310 /** 311 * Encodes the provided data as a base64 string. 312 * 313 * @param bytes 314 * The data to be encoded. 315 * @return The base64 encoded representation of {@code bytes}. 316 * @throws NullPointerException 317 * If {@code bytes} was {@code null}. 318 */ 319 public static String encode(final ByteSequence bytes) { 320 Reject.ifNull(bytes); 321 322 if (bytes.isEmpty()) { 323 return ""; 324 } 325 326 final StringBuilder buffer = new StringBuilder(4 * bytes.length() / 3); 327 328 int pos = 0; 329 final int iterations = bytes.length() / 3; 330 for (int i = 0; i < iterations; i++) { 331 final int value = 332 ((bytes.byteAt(pos++) & 0xFF) << 16) | ((bytes.byteAt(pos++) & 0xFF) << 8) 333 | (bytes.byteAt(pos++) & 0xFF); 334 335 buffer.append(BASE64_ALPHABET[(value >>> 18) & 0x3F]); 336 buffer.append(BASE64_ALPHABET[(value >>> 12) & 0x3F]); 337 buffer.append(BASE64_ALPHABET[(value >>> 6) & 0x3F]); 338 buffer.append(BASE64_ALPHABET[value & 0x3F]); 339 } 340 341 switch (bytes.length() % 3) { 342 case 1: 343 buffer.append(BASE64_ALPHABET[(bytes.byteAt(pos) >>> 2) & 0x3F]); 344 buffer.append(BASE64_ALPHABET[(bytes.byteAt(pos) << 4) & 0x3F]); 345 buffer.append("=="); 346 break; 347 case 2: 348 final int value = ((bytes.byteAt(pos++) & 0xFF) << 8) | (bytes.byteAt(pos) & 0xFF); 349 buffer.append(BASE64_ALPHABET[(value >>> 10) & 0x3F]); 350 buffer.append(BASE64_ALPHABET[(value >>> 4) & 0x3F]); 351 buffer.append(BASE64_ALPHABET[(value << 2) & 0x3F]); 352 buffer.append("="); 353 break; 354 } 355 356 return buffer.toString(); 357 } 358 359 /** 360 * Prevent instance creation. 361 */ 362 private Base64() { 363 // No implementation required. 364 } 365}