blob: 9606d299cc53051cdc3b805bce0004b9770166c6 [file] [log] [blame]
package org.apache.fulcrum.crypto.impl;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
/**
* Base64 encoder/decoder taken from commons-codec. Copying
* and wasting the code allows to minimize the dependencies.
*
* @author Siegfried Goeschl
*/
public class Base64
{
public Base64() {
}
private static boolean isBase64(byte octect) {
if(octect == 61)
return true;
return base64Alphabet[octect] != -1;
}
public static boolean isArrayByteBase64(byte arrayOctect[]) {
arrayOctect = discardWhitespace(arrayOctect);
int length = arrayOctect.length;
if(length == 0)
return true;
for(int i = 0; i < length; i++)
if(!isBase64(arrayOctect[i]))
return false;
return true;
}
public static byte[] encodeBase64(byte binaryData[]) {
return encodeBase64(binaryData, false);
}
public static byte[] encodeBase64Chunked(byte binaryData[]) {
return encodeBase64(binaryData, true);
}
public Object decode(Object pObject)
throws Exception {
if(!(pObject instanceof byte[]))
throw new Exception("Parameter supplied to Base64 decode is not a byte[]");
else
return decode((byte[])pObject);
}
public byte[] decode(byte pArray[]) {
return decodeBase64(pArray);
}
public static byte[] encodeBase64(byte binaryData[], boolean isChunked) {
int lengthDataBits = binaryData.length * 8;
int fewerThan24bits = lengthDataBits % 24;
int numberTriplets = lengthDataBits / 24;
byte encodedData[] = null;
int encodedDataLength = 0;
int nbrChunks = 0;
if(fewerThan24bits != 0)
encodedDataLength = (numberTriplets + 1) * 4;
else
encodedDataLength = numberTriplets * 4;
if(isChunked) {
nbrChunks = CHUNK_SEPARATOR.length != 0 ? (int)Math.ceil((float)encodedDataLength / 76F) : 0;
encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
}
encodedData = new byte[encodedDataLength];
byte k = 0;
byte l = 0;
byte b1 = 0;
byte b2 = 0;
byte b3 = 0;
int encodedIndex = 0;
int dataIndex = 0;
int i = 0;
int nextSeparatorIndex = 76;
int chunksSoFar = 0;
for(i = 0; i < numberTriplets; i++) {
dataIndex = i * 3;
b1 = binaryData[dataIndex];
b2 = binaryData[dataIndex + 1];
b3 = binaryData[dataIndex + 2];
l = (byte)(b2 & 0xf);
k = (byte)(b1 & 3);
byte val1 = (b1 & 0xffffff80) != 0 ? (byte)(b1 >> 2 ^ 0xc0) : (byte)(b1 >> 2);
byte val2 = (b2 & 0xffffff80) != 0 ? (byte)(b2 >> 4 ^ 0xf0) : (byte)(b2 >> 4);
byte val3 = (b3 & 0xffffff80) != 0 ? (byte)(b3 >> 6 ^ 0xfc) : (byte)(b3 >> 6);
encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | k << 4];
encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2 | val3];
encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
encodedIndex += 4;
if(isChunked && encodedIndex == nextSeparatorIndex) {
System.arraycopy(CHUNK_SEPARATOR, 0, encodedData, encodedIndex, CHUNK_SEPARATOR.length);
chunksSoFar++;
nextSeparatorIndex = 76 * (chunksSoFar + 1) + chunksSoFar * CHUNK_SEPARATOR.length;
encodedIndex += CHUNK_SEPARATOR.length;
}
}
dataIndex = i * 3;
if(fewerThan24bits == 8) {
b1 = binaryData[dataIndex];
k = (byte)(b1 & 3);
byte val1 = (b1 & 0xffffff80) != 0 ? (byte)(b1 >> 2 ^ 0xc0) : (byte)(b1 >> 2);
encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
encodedData[encodedIndex + 2] = 61;
encodedData[encodedIndex + 3] = 61;
} else
if(fewerThan24bits == 16) {
b1 = binaryData[dataIndex];
b2 = binaryData[dataIndex + 1];
l = (byte)(b2 & 0xf);
k = (byte)(b1 & 3);
byte val1 = (b1 & 0xffffff80) != 0 ? (byte)(b1 >> 2 ^ 0xc0) : (byte)(b1 >> 2);
byte val2 = (b2 & 0xffffff80) != 0 ? (byte)(b2 >> 4 ^ 0xf0) : (byte)(b2 >> 4);
encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | k << 4];
encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
encodedData[encodedIndex + 3] = 61;
}
if(isChunked && chunksSoFar < nbrChunks)
System.arraycopy(CHUNK_SEPARATOR, 0, encodedData, encodedDataLength - CHUNK_SEPARATOR.length, CHUNK_SEPARATOR.length);
return encodedData;
}
public static byte[] decodeBase64(byte base64Data[]) {
base64Data = discardNonBase64(base64Data);
if(base64Data.length == 0)
return new byte[0];
int numberQuadruple = base64Data.length / 4;
byte decodedData[] = null;
byte b1 = 0;
byte b2 = 0;
byte b3 = 0;
byte b4 = 0;
byte marker0 = 0;
byte marker1 = 0;
int encodedIndex = 0;
int dataIndex = 0;
int lastData;
for(lastData = base64Data.length; base64Data[lastData - 1] == 61;)
if(--lastData == 0)
return new byte[0];
decodedData = new byte[lastData - numberQuadruple];
for(int i = 0; i < numberQuadruple; i++) {
dataIndex = i * 4;
marker0 = base64Data[dataIndex + 2];
marker1 = base64Data[dataIndex + 3];
b1 = base64Alphabet[base64Data[dataIndex]];
b2 = base64Alphabet[base64Data[dataIndex + 1]];
if(marker0 != 61 && marker1 != 61) {
b3 = base64Alphabet[marker0];
b4 = base64Alphabet[marker1];
decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4);
decodedData[encodedIndex + 1] = (byte)((b2 & 0xf) << 4 | b3 >> 2 & 0xf);
decodedData[encodedIndex + 2] = (byte)(b3 << 6 | b4);
} else
if(marker0 == 61)
decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4);
else
if(marker1 == 61) {
b3 = base64Alphabet[marker0];
decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4);
decodedData[encodedIndex + 1] = (byte)((b2 & 0xf) << 4 | b3 >> 2 & 0xf);
}
encodedIndex += 3;
}
return decodedData;
}
static byte[] discardWhitespace(byte data[]) {
byte groomedData[] = new byte[data.length];
int bytesCopied = 0;
int i = 0;
do
if(i < data.length) {
switch(data[i]) {
default:
groomedData[bytesCopied++] = data[i];
// fall through
case 9: // '\t'
case 10: // '\n'
case 13: // '\r'
case 32: // ' '
i++;
break;
}
} else {
byte packedData[] = new byte[bytesCopied];
System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
return packedData;
}
while(true);
}
static byte[] discardNonBase64(byte data[]) {
byte groomedData[] = new byte[data.length];
int bytesCopied = 0;
for(int i = 0; i < data.length; i++)
if(isBase64(data[i]))
groomedData[bytesCopied++] = data[i];
byte packedData[] = new byte[bytesCopied];
System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
return packedData;
}
public Object encode(Object pObject)
throws Exception {
if(!(pObject instanceof byte[]))
throw new Exception("Parameter supplied to Base64 encode is not a byte[]");
else
return encode((byte[])pObject);
}
public byte[] encode(byte pArray[]) {
return encodeBase64(pArray, false);
}
static final int CHUNK_SIZE = 76;
static final byte CHUNK_SEPARATOR[] = "\r\n".getBytes();
static final int BASELENGTH = 255;
static final int LOOKUPLENGTH = 64;
static final int EIGHTBIT = 8;
static final int SIXTEENBIT = 16;
static final int TWENTYFOURBITGROUP = 24;
static final int FOURBYTE = 4;
static final int SIGN = -128;
static final byte PAD = 61;
private static byte base64Alphabet[];
private static byte lookUpBase64Alphabet[];
static {
base64Alphabet = new byte[255];
lookUpBase64Alphabet = new byte[64];
int i;
for(i = 0; i < 255; i++)
base64Alphabet[i] = -1;
for(i = 90; i >= 65; i--)
base64Alphabet[i] = (byte)(i - 65);
for(i = 122; i >= 97; i--)
base64Alphabet[i] = (byte)((i - 97) + 26);
for(i = 57; i >= 48; i--)
base64Alphabet[i] = (byte)((i - 48) + 52);
base64Alphabet[43] = 62;
base64Alphabet[47] = 63;
for(i = 0; i <= 25; i++)
lookUpBase64Alphabet[i] = (byte)(65 + i);
i = 26;
for(int j = 0; i <= 51; j++) {
lookUpBase64Alphabet[i] = (byte)(97 + j);
i++;
}
i = 52;
for(int j = 0; i <= 61; j++) {
lookUpBase64Alphabet[i] = (byte)(48 + j);
i++;
}
lookUpBase64Alphabet[62] = 43;
lookUpBase64Alphabet[63] = 47;
}
}