1// 2// ======================================================================== 3// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4// ------------------------------------------------------------------------ 5// All rights reserved. This program and the accompanying materials 6// are made available under the terms of the Eclipse Public License v1.0 7// and Apache License v2.0 which accompanies this distribution. 8// 9// The Eclipse Public License is available at 10// http://www.eclipse.org/legal/epl-v10.html 11// 12// The Apache License v2.0 is available at 13// http://www.opensource.org/licenses/apache2.0.php 14// 15// You may elect to redistribute this code under either of these licenses. 16// ======================================================================== 17// 18 19package org.eclipse.jetty.util; 20 21import java.io.ByteArrayOutputStream; 22import java.io.IOException; 23import java.io.UnsupportedEncodingException; 24 25 26/* ------------------------------------------------------------ */ 27/** Fast B64 Encoder/Decoder as described in RFC 1421. 28 * <p>Does not insert or interpret whitespace as described in RFC 29 * 1521. If you require this you must pre/post process your data. 30 * <p> Note that in a web context the usual case is to not want 31 * linebreaks or other white space in the encoded output. 32 * 33 */ 34public class B64Code 35{ 36 // ------------------------------------------------------------------ 37 static final char __pad='='; 38 static final char[] __rfc1421alphabet= 39 { 40 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 41 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 42 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 43 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' 44 }; 45 46 static final byte[] __rfc1421nibbles; 47 48 static 49 { 50 __rfc1421nibbles=new byte[256]; 51 for (int i=0;i<256;i++) 52 __rfc1421nibbles[i]=-1; 53 for (byte b=0;b<64;b++) 54 __rfc1421nibbles[(byte)__rfc1421alphabet[b]]=b; 55 __rfc1421nibbles[(byte)__pad]=0; 56 } 57 58 // ------------------------------------------------------------------ 59 /** 60 * Base 64 encode as described in RFC 1421. 61 * <p>Does not insert whitespace as described in RFC 1521. 62 * @param s String to encode. 63 * @return String containing the encoded form of the input. 64 */ 65 static public String encode(String s) 66 { 67 try 68 { 69 return encode(s,null); 70 } 71 catch (UnsupportedEncodingException e) 72 { 73 throw new IllegalArgumentException(e.toString()); 74 } 75 } 76 77 // ------------------------------------------------------------------ 78 /** 79 * Base 64 encode as described in RFC 1421. 80 * <p>Does not insert whitespace as described in RFC 1521. 81 * @param s String to encode. 82 * @param charEncoding String representing the name of 83 * the character encoding of the provided input String. 84 * @return String containing the encoded form of the input. 85 */ 86 static public String encode(String s,String charEncoding) 87 throws UnsupportedEncodingException 88 { 89 byte[] bytes; 90 if (charEncoding==null) 91 bytes=s.getBytes(StringUtil.__ISO_8859_1); 92 else 93 bytes=s.getBytes(charEncoding); 94 95 return new String(encode(bytes)); 96 } 97 98 // ------------------------------------------------------------------ 99 /** 100 * Fast Base 64 encode as described in RFC 1421. 101 * <p>Does not insert whitespace as described in RFC 1521. 102 * <p> Avoids creating extra copies of the input/output. 103 * @param b byte array to encode. 104 * @return char array containing the encoded form of the input. 105 */ 106 static public char[] encode(byte[] b) 107 { 108 if (b==null) 109 return null; 110 111 int bLen=b.length; 112 int cLen=((bLen+2)/3)*4; 113 char c[]=new char[cLen]; 114 int ci=0; 115 int bi=0; 116 byte b0, b1, b2; 117 int stop=(bLen/3)*3; 118 while (bi<stop) 119 { 120 b0=b[bi++]; 121 b1=b[bi++]; 122 b2=b[bi++]; 123 c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f]; 124 c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f]; 125 c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f|(b2>>>6)&0x03]; 126 c[ci++]=__rfc1421alphabet[b2&077]; 127 } 128 129 if (bLen!=bi) 130 { 131 switch (bLen%3) 132 { 133 case 2: 134 b0=b[bi++]; 135 b1=b[bi++]; 136 c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f]; 137 c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f]; 138 c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f]; 139 c[ci++]=__pad; 140 break; 141 142 case 1: 143 b0=b[bi++]; 144 c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f]; 145 c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f]; 146 c[ci++]=__pad; 147 c[ci++]=__pad; 148 break; 149 150 default: 151 break; 152 } 153 } 154 155 return c; 156 } 157 158 // ------------------------------------------------------------------ 159 /** 160 * Fast Base 64 encode as described in RFC 1421 and RFC2045 161 * <p>Does not insert whitespace as described in RFC 1521, unless rfc2045 is passed as true. 162 * <p> Avoids creating extra copies of the input/output. 163 * @param b byte array to encode. 164 * @param rfc2045 If true, break lines at 76 characters with CRLF 165 * @return char array containing the encoded form of the input. 166 */ 167 static public char[] encode(byte[] b, boolean rfc2045) 168 { 169 if (b==null) 170 return null; 171 if (!rfc2045) 172 return encode(b); 173 174 int bLen=b.length; 175 int cLen=((bLen+2)/3)*4; 176 cLen+=2+2*(cLen/76); 177 char c[]=new char[cLen]; 178 int ci=0; 179 int bi=0; 180 byte b0, b1, b2; 181 int stop=(bLen/3)*3; 182 int l=0; 183 while (bi<stop) 184 { 185 b0=b[bi++]; 186 b1=b[bi++]; 187 b2=b[bi++]; 188 c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f]; 189 c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f]; 190 c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f|(b2>>>6)&0x03]; 191 c[ci++]=__rfc1421alphabet[b2&077]; 192 l+=4; 193 if (l%76==0) 194 { 195 c[ci++]=13; 196 c[ci++]=10; 197 } 198 } 199 200 if (bLen!=bi) 201 { 202 switch (bLen%3) 203 { 204 case 2: 205 b0=b[bi++]; 206 b1=b[bi++]; 207 c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f]; 208 c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f]; 209 c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f]; 210 c[ci++]=__pad; 211 break; 212 213 case 1: 214 b0=b[bi++]; 215 c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f]; 216 c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f]; 217 c[ci++]=__pad; 218 c[ci++]=__pad; 219 break; 220 221 default: 222 break; 223 } 224 } 225 226 c[ci++]=13; 227 c[ci++]=10; 228 return c; 229 } 230 231 // ------------------------------------------------------------------ 232 /** 233 * Base 64 decode as described in RFC 2045. 234 * <p>Unlike {@link #decode(char[])}, extra whitespace is ignored. 235 * @param encoded String to decode. 236 * @param charEncoding String representing the character encoding 237 * used to map the decoded bytes into a String. 238 * @return String decoded byte array. 239 * @throws UnsupportedEncodingException if the encoding is not supported 240 * @throws IllegalArgumentException if the input is not a valid 241 * B64 encoding. 242 */ 243 static public String decode(String encoded,String charEncoding) 244 throws UnsupportedEncodingException 245 { 246 byte[] decoded=decode(encoded); 247 if (charEncoding==null) 248 return new String(decoded); 249 return new String(decoded,charEncoding); 250 } 251 252 /* ------------------------------------------------------------ */ 253 /** 254 * Fast Base 64 decode as described in RFC 1421. 255 * 256 * <p>Unlike other decode methods, this does not attempt to 257 * cope with extra whitespace as described in RFC 1521/2045. 258 * <p> Avoids creating extra copies of the input/output. 259 * <p> Note this code has been flattened for performance. 260 * @param b char array to decode. 261 * @return byte array containing the decoded form of the input. 262 * @throws IllegalArgumentException if the input is not a valid 263 * B64 encoding. 264 */ 265 static public byte[] decode(char[] b) 266 { 267 if (b==null) 268 return null; 269 270 int bLen=b.length; 271 if (bLen%4!=0) 272 throw new IllegalArgumentException("Input block size is not 4"); 273 274 int li=bLen-1; 275 while (li>=0 && b[li]==(byte)__pad) 276 li--; 277 278 if (li<0) 279 return new byte[0]; 280 281 // Create result array of exact required size. 282 int rLen=((li+1)*3)/4; 283 byte r[]=new byte[rLen]; 284 int ri=0; 285 int bi=0; 286 int stop=(rLen/3)*3; 287 byte b0,b1,b2,b3; 288 try 289 { 290 while (ri<stop) 291 { 292 b0=__rfc1421nibbles[b[bi++]]; 293 b1=__rfc1421nibbles[b[bi++]]; 294 b2=__rfc1421nibbles[b[bi++]]; 295 b3=__rfc1421nibbles[b[bi++]]; 296 if (b0<0 || b1<0 || b2<0 || b3<0) 297 throw new IllegalArgumentException("Not B64 encoded"); 298 299 r[ri++]=(byte)(b0<<2|b1>>>4); 300 r[ri++]=(byte)(b1<<4|b2>>>2); 301 r[ri++]=(byte)(b2<<6|b3); 302 } 303 304 if (rLen!=ri) 305 { 306 switch (rLen%3) 307 { 308 case 2: 309 b0=__rfc1421nibbles[b[bi++]]; 310 b1=__rfc1421nibbles[b[bi++]]; 311 b2=__rfc1421nibbles[b[bi++]]; 312 if (b0<0 || b1<0 || b2<0) 313 throw new IllegalArgumentException("Not B64 encoded"); 314 r[ri++]=(byte)(b0<<2|b1>>>4); 315 r[ri++]=(byte)(b1<<4|b2>>>2); 316 break; 317 318 case 1: 319 b0=__rfc1421nibbles[b[bi++]]; 320 b1=__rfc1421nibbles[b[bi++]]; 321 if (b0<0 || b1<0) 322 throw new IllegalArgumentException("Not B64 encoded"); 323 r[ri++]=(byte)(b0<<2|b1>>>4); 324 break; 325 326 default: 327 break; 328 } 329 } 330 } 331 catch (IndexOutOfBoundsException e) 332 { 333 throw new IllegalArgumentException("char "+bi 334 +" was not B64 encoded"); 335 } 336 337 return r; 338 } 339 340 /* ------------------------------------------------------------ */ 341 /** 342 * Base 64 decode as described in RFC 2045. 343 * <p>Unlike {@link #decode(char[])}, extra whitespace is ignored. 344 * @param encoded String to decode. 345 * @return byte array containing the decoded form of the input. 346 * @throws IllegalArgumentException if the input is not a valid 347 * B64 encoding. 348 */ 349 static public byte[] decode(String encoded) 350 { 351 if (encoded==null) 352 return null; 353 354 ByteArrayOutputStream bout = new ByteArrayOutputStream(4*encoded.length()/3); 355 decode(encoded, bout); 356 return bout.toByteArray(); 357 } 358 359 /* ------------------------------------------------------------ */ 360 /** 361 * Base 64 decode as described in RFC 2045. 362 * <p>Unlike {@link #decode(char[])}, extra whitespace is ignored. 363 * @param encoded String to decode. 364 * @param output stream for decoded bytes 365 * @return byte array containing the decoded form of the input. 366 * @throws IllegalArgumentException if the input is not a valid 367 * B64 encoding. 368 */ 369 static public void decode (String encoded, ByteArrayOutputStream bout) 370 { 371 if (encoded==null) 372 return; 373 374 if (bout == null) 375 throw new IllegalArgumentException("No outputstream for decoded bytes"); 376 377 int ci=0; 378 byte nibbles[] = new byte[4]; 379 int s=0; 380 381 while (ci<encoded.length()) 382 { 383 char c=encoded.charAt(ci++); 384 385 if (c==__pad) 386 break; 387 388 if (Character.isWhitespace(c)) 389 continue; 390 391 byte nibble=__rfc1421nibbles[c]; 392 if (nibble<0) 393 throw new IllegalArgumentException("Not B64 encoded"); 394 395 nibbles[s++]=__rfc1421nibbles[c]; 396 397 switch(s) 398 { 399 case 1: 400 break; 401 case 2: 402 bout.write(nibbles[0]<<2|nibbles[1]>>>4); 403 break; 404 case 3: 405 bout.write(nibbles[1]<<4|nibbles[2]>>>2); 406 break; 407 case 4: 408 bout.write(nibbles[2]<<6|nibbles[3]); 409 s=0; 410 break; 411 } 412 413 } 414 415 return; 416 } 417 418 419 /* ------------------------------------------------------------ */ 420 public static void encode(int value,Appendable buf) throws IOException 421 { 422 buf.append(__rfc1421alphabet[0x3f&((0xFC000000&value)>>26)]); 423 buf.append(__rfc1421alphabet[0x3f&((0x03F00000&value)>>20)]); 424 buf.append(__rfc1421alphabet[0x3f&((0x000FC000&value)>>14)]); 425 buf.append(__rfc1421alphabet[0x3f&((0x00003F00&value)>>8)]); 426 buf.append(__rfc1421alphabet[0x3f&((0x000000FC&value)>>2)]); 427 buf.append(__rfc1421alphabet[0x3f&((0x00000003&value)<<4)]); 428 buf.append('='); 429 } 430 431 /* ------------------------------------------------------------ */ 432 public static void encode(long lvalue,Appendable buf) throws IOException 433 { 434 int value=(int)(0xFFFFFFFC&(lvalue>>32)); 435 buf.append(__rfc1421alphabet[0x3f&((0xFC000000&value)>>26)]); 436 buf.append(__rfc1421alphabet[0x3f&((0x03F00000&value)>>20)]); 437 buf.append(__rfc1421alphabet[0x3f&((0x000FC000&value)>>14)]); 438 buf.append(__rfc1421alphabet[0x3f&((0x00003F00&value)>>8)]); 439 buf.append(__rfc1421alphabet[0x3f&((0x000000FC&value)>>2)]); 440 441 buf.append(__rfc1421alphabet[0x3f&((0x00000003&value)<<4) + (0xf&(int)(lvalue>>28))]); 442 443 value=0x0FFFFFFF&(int)lvalue; 444 buf.append(__rfc1421alphabet[0x3f&((0x0FC00000&value)>>22)]); 445 buf.append(__rfc1421alphabet[0x3f&((0x003F0000&value)>>16)]); 446 buf.append(__rfc1421alphabet[0x3f&((0x0000FC00&value)>>10)]); 447 buf.append(__rfc1421alphabet[0x3f&((0x000003F0&value)>>4)]); 448 buf.append(__rfc1421alphabet[0x3f&((0x0000000F&value)<<2)]); 449 } 450} 451