org.mortbay.jetty.security.B64Code Maven / Gradle / Ivy
// ========================================================================
// Copyright 1999-2005 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
package org.mortbay.jetty.security;
import java.io.UnsupportedEncodingException;
import org.mortbay.util.StringUtil;
/* ------------------------------------------------------------ */
/** Fast B64 Encoder/Decoder as described in RFC 1421.
* Does not insert or interpret whitespace as described in RFC
* 1521. If you require this you must pre/post process your data.
*
Note that in a web context the usual case is to not want
* linebreaks or other white space in the encoded output.
*
* @author Brett Sealey (bretts)
* @author Greg Wilkins (gregw)
*/
public class B64Code
{
// ------------------------------------------------------------------
static final char pad='=';
static final char[] nibble2code=
{
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
};
static byte[] code2nibble=null;
static
{
code2nibble=new byte[256];
for (int i=0;i<256;i++)
code2nibble[i]=-1;
for (byte b=0;b<64;b++)
code2nibble[(byte)nibble2code[b]]=b;
code2nibble[(byte)pad]=0;
}
// ------------------------------------------------------------------
/**
* Base 64 encode as described in RFC 1421.
*
Does not insert whitespace as described in RFC 1521.
* @param s String to encode.
* @return String containing the encoded form of the input.
*/
static public String encode(String s)
{
try
{
return encode(s,null);
}
catch (UnsupportedEncodingException e)
{
throw new IllegalArgumentException(e.toString());
}
}
// ------------------------------------------------------------------
/**
* Base 64 encode as described in RFC 1421.
*
Does not insert whitespace as described in RFC 1521.
* @param s String to encode.
* @param charEncoding String representing the name of
* the character encoding of the provided input String.
* @return String containing the encoded form of the input.
*/
static public String encode(String s,String charEncoding)
throws UnsupportedEncodingException
{
byte[] bytes;
if (charEncoding==null)
bytes=s.getBytes(StringUtil.__ISO_8859_1);
else
bytes=s.getBytes(charEncoding);
return new String(encode(bytes));
}
// ------------------------------------------------------------------
/**
* Fast Base 64 encode as described in RFC 1421.
*
Does not insert whitespace as described in RFC 1521.
*
Avoids creating extra copies of the input/output.
* @param b byte array to encode.
* @return char array containing the encoded form of the input.
*/
static public char[] encode(byte[] b)
{
if (b==null)
return null;
int bLen=b.length;
char r[]=new char[((bLen+2)/3)*4];
int ri=0;
int bi=0;
byte b0, b1, b2;
int stop=(bLen/3)*3;
while (bi>>2)&0x3f];
r[ri++]=nibble2code[(b0<<4)&0x3f|(b1>>>4)&0x0f];
r[ri++]=nibble2code[(b1<<2)&0x3f|(b2>>>6)&0x03];
r[ri++]=nibble2code[b2&077];
}
if (bLen!=bi)
{
switch (bLen%3)
{
case 2:
b0=b[bi++];
b1=b[bi++];
r[ri++]=nibble2code[(b0>>>2)&0x3f];
r[ri++]=nibble2code[(b0<<4)&0x3f|(b1>>>4)&0x0f];
r[ri++]=nibble2code[(b1<<2)&0x3f];
r[ri++]=pad;
break;
case 1:
b0=b[bi++];
r[ri++]=nibble2code[(b0>>>2)&0x3f];
r[ri++]=nibble2code[(b0<<4)&0x3f];
r[ri++]=pad;
r[ri++]=pad;
break;
default:
break;
}
}
return r;
}
// ------------------------------------------------------------------
/**
* Base 64 decode as described in RFC 1421.
* Does not attempt to cope with extra whitespace
* as described in RFC 1521.
* @param s String to decode
* @return String decoded byte array.
*/
static public String decode(String s)
{
try
{
return decode(s,StringUtil.__ISO_8859_1);
}
catch (UnsupportedEncodingException e)
{
throw new IllegalArgumentException(e.toString());
}
}
// ------------------------------------------------------------------
/**
* Base 64 decode as described in RFC 1421.
*
Does not attempt to cope with extra whitespace
* as described in RFC 1521.
* @param s String to decode
* @param charEncoding String representing the character encoding
* used to map the decoded bytes into a String.
* @return String decoded byte array.
*/
static public String decode(String s,String charEncoding)
throws UnsupportedEncodingException
{
byte[] decoded=decode(s.toCharArray());
if (charEncoding==null)
return new String(decoded);
return new String(decoded,charEncoding);
}
/* ------------------------------------------------------------ */
/**
* Fast Base 64 decode as described in RFC 1421.
*
Does not attempt to cope with extra whitespace
* as described in RFC 1521.
*
Avoids creating extra copies of the input/output.
*
Note this code has been flattened for performance.
* @param b char array to decode.
* @return byte array containing the decoded form of the input.
* @throws IllegalArgumentException if the input is not a valid
* B64 encoding.
*/
static public byte[] decode(char[] b)
{
if (b==null)
return null;
int bLen=b.length;
if (bLen%4!=0)
throw new IllegalArgumentException("Input block size is not 4");
int li=bLen-1;
while (li>=0 && b[li]==(byte)pad)
li--;
if (li<0)
return new byte[0];
// Create result array of exact required size.
int rLen=((li+1)*3)/4;
byte r[]=new byte[rLen];
int ri=0;
int bi=0;
int stop=(rLen/3)*3;
byte b0,b1,b2,b3;
try
{
while (ri>>4);
r[ri++]=(byte)(b1<<4|b2>>>2);
r[ri++]=(byte)(b2<<6|b3);
}
if (rLen!=ri)
{
switch (rLen%3)
{
case 2:
b0=code2nibble[b[bi++]];
b1=code2nibble[b[bi++]];
b2=code2nibble[b[bi++]];
if (b0<0 || b1<0 || b2<0)
throw new IllegalArgumentException("Not B64 encoded");
r[ri++]=(byte)(b0<<2|b1>>>4);
r[ri++]=(byte)(b1<<4|b2>>>2);
break;
case 1:
b0=code2nibble[b[bi++]];
b1=code2nibble[b[bi++]];
if (b0<0 || b1<0)
throw new IllegalArgumentException("Not B64 encoded");
r[ri++]=(byte)(b0<<2|b1>>>4);
break;
default:
break;
}
}
}
catch (IndexOutOfBoundsException e)
{
throw new IllegalArgumentException("char "+bi
+" was not B64 encoded");
}
return r;
}
}