001 package org.apache.fulcrum.crypto.impl;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 /**
023 * Base64 encoder/decoder taken from commons-codec. Copying
024 * and wasting the code allows to minimize the dependencies.
025 *
026 * @author Siegfried Goeschl
027 */
028 public class Base64
029 {
030
031 public Base64() {
032 }
033
034 private static boolean isBase64(byte octect) {
035 if(octect == 61)
036 return true;
037 return base64Alphabet[octect] != -1;
038 }
039
040 public static boolean isArrayByteBase64(byte arrayOctect[]) {
041 arrayOctect = discardWhitespace(arrayOctect);
042 int length = arrayOctect.length;
043 if(length == 0)
044 return true;
045 for(int i = 0; i < length; i++)
046 if(!isBase64(arrayOctect[i]))
047 return false;
048
049 return true;
050 }
051
052 public static byte[] encodeBase64(byte binaryData[]) {
053 return encodeBase64(binaryData, false);
054 }
055
056 public static byte[] encodeBase64Chunked(byte binaryData[]) {
057 return encodeBase64(binaryData, true);
058 }
059
060 public Object decode(Object pObject)
061 throws Exception {
062 if(!(pObject instanceof byte[]))
063 throw new Exception("Parameter supplied to Base64 decode is not a byte[]");
064 else
065 return decode((byte[])pObject);
066 }
067
068 public byte[] decode(byte pArray[]) {
069 return decodeBase64(pArray);
070 }
071
072 public static byte[] encodeBase64(byte binaryData[], boolean isChunked) {
073 int lengthDataBits = binaryData.length * 8;
074 int fewerThan24bits = lengthDataBits % 24;
075 int numberTriplets = lengthDataBits / 24;
076 byte encodedData[] = null;
077 int encodedDataLength = 0;
078 int nbrChunks = 0;
079 if(fewerThan24bits != 0)
080 encodedDataLength = (numberTriplets + 1) * 4;
081 else
082 encodedDataLength = numberTriplets * 4;
083 if(isChunked) {
084 nbrChunks = CHUNK_SEPARATOR.length != 0 ? (int)Math.ceil((float)encodedDataLength / 76F) : 0;
085 encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
086 }
087 encodedData = new byte[encodedDataLength];
088 byte k = 0;
089 byte l = 0;
090 byte b1 = 0;
091 byte b2 = 0;
092 byte b3 = 0;
093 int encodedIndex = 0;
094 int dataIndex = 0;
095 int i = 0;
096 int nextSeparatorIndex = 76;
097 int chunksSoFar = 0;
098 for(i = 0; i < numberTriplets; i++) {
099 dataIndex = i * 3;
100 b1 = binaryData[dataIndex];
101 b2 = binaryData[dataIndex + 1];
102 b3 = binaryData[dataIndex + 2];
103 l = (byte)(b2 & 0xf);
104 k = (byte)(b1 & 3);
105 byte val1 = (b1 & 0xffffff80) != 0 ? (byte)(b1 >> 2 ^ 0xc0) : (byte)(b1 >> 2);
106 byte val2 = (b2 & 0xffffff80) != 0 ? (byte)(b2 >> 4 ^ 0xf0) : (byte)(b2 >> 4);
107 byte val3 = (b3 & 0xffffff80) != 0 ? (byte)(b3 >> 6 ^ 0xfc) : (byte)(b3 >> 6);
108 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
109 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | k << 4];
110 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2 | val3];
111 encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
112 encodedIndex += 4;
113 if(isChunked && encodedIndex == nextSeparatorIndex) {
114 System.arraycopy(CHUNK_SEPARATOR, 0, encodedData, encodedIndex, CHUNK_SEPARATOR.length);
115 chunksSoFar++;
116 nextSeparatorIndex = 76 * (chunksSoFar + 1) + chunksSoFar * CHUNK_SEPARATOR.length;
117 encodedIndex += CHUNK_SEPARATOR.length;
118 }
119 }
120
121 dataIndex = i * 3;
122 if(fewerThan24bits == 8) {
123 b1 = binaryData[dataIndex];
124 k = (byte)(b1 & 3);
125 byte val1 = (b1 & 0xffffff80) != 0 ? (byte)(b1 >> 2 ^ 0xc0) : (byte)(b1 >> 2);
126 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
127 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
128 encodedData[encodedIndex + 2] = 61;
129 encodedData[encodedIndex + 3] = 61;
130 } else
131 if(fewerThan24bits == 16) {
132 b1 = binaryData[dataIndex];
133 b2 = binaryData[dataIndex + 1];
134 l = (byte)(b2 & 0xf);
135 k = (byte)(b1 & 3);
136 byte val1 = (b1 & 0xffffff80) != 0 ? (byte)(b1 >> 2 ^ 0xc0) : (byte)(b1 >> 2);
137 byte val2 = (b2 & 0xffffff80) != 0 ? (byte)(b2 >> 4 ^ 0xf0) : (byte)(b2 >> 4);
138 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
139 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | k << 4];
140 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
141 encodedData[encodedIndex + 3] = 61;
142 }
143 if(isChunked && chunksSoFar < nbrChunks)
144 System.arraycopy(CHUNK_SEPARATOR, 0, encodedData, encodedDataLength - CHUNK_SEPARATOR.length, CHUNK_SEPARATOR.length);
145 return encodedData;
146 }
147
148 public static byte[] decodeBase64(byte base64Data[]) {
149 base64Data = discardNonBase64(base64Data);
150 if(base64Data.length == 0)
151 return new byte[0];
152 int numberQuadruple = base64Data.length / 4;
153 byte decodedData[] = null;
154 byte b1 = 0;
155 byte b2 = 0;
156 byte b3 = 0;
157 byte b4 = 0;
158 byte marker0 = 0;
159 byte marker1 = 0;
160 int encodedIndex = 0;
161 int dataIndex = 0;
162 int lastData;
163 for(lastData = base64Data.length; base64Data[lastData - 1] == 61;)
164 if(--lastData == 0)
165 return new byte[0];
166
167 decodedData = new byte[lastData - numberQuadruple];
168 for(int i = 0; i < numberQuadruple; i++) {
169 dataIndex = i * 4;
170 marker0 = base64Data[dataIndex + 2];
171 marker1 = base64Data[dataIndex + 3];
172 b1 = base64Alphabet[base64Data[dataIndex]];
173 b2 = base64Alphabet[base64Data[dataIndex + 1]];
174 if(marker0 != 61 && marker1 != 61) {
175 b3 = base64Alphabet[marker0];
176 b4 = base64Alphabet[marker1];
177 decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4);
178 decodedData[encodedIndex + 1] = (byte)((b2 & 0xf) << 4 | b3 >> 2 & 0xf);
179 decodedData[encodedIndex + 2] = (byte)(b3 << 6 | b4);
180 } else
181 if(marker0 == 61)
182 decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4);
183 else
184 if(marker1 == 61) {
185 b3 = base64Alphabet[marker0];
186 decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4);
187 decodedData[encodedIndex + 1] = (byte)((b2 & 0xf) << 4 | b3 >> 2 & 0xf);
188 }
189 encodedIndex += 3;
190 }
191
192 return decodedData;
193 }
194
195 static byte[] discardWhitespace(byte data[]) {
196 byte groomedData[] = new byte[data.length];
197 int bytesCopied = 0;
198 int i = 0;
199 do
200 if(i < data.length) {
201 switch(data[i]) {
202 default:
203 groomedData[bytesCopied++] = data[i];
204 // fall through
205
206 case 9: // '\t'
207 case 10: // '\n'
208 case 13: // '\r'
209 case 32: // ' '
210 i++;
211 break;
212 }
213 } else {
214 byte packedData[] = new byte[bytesCopied];
215 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
216 return packedData;
217 }
218 while(true);
219 }
220
221 static byte[] discardNonBase64(byte data[]) {
222 byte groomedData[] = new byte[data.length];
223 int bytesCopied = 0;
224 for(int i = 0; i < data.length; i++)
225 if(isBase64(data[i]))
226 groomedData[bytesCopied++] = data[i];
227
228 byte packedData[] = new byte[bytesCopied];
229 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
230 return packedData;
231 }
232
233 public Object encode(Object pObject)
234 throws Exception {
235 if(!(pObject instanceof byte[]))
236 throw new Exception("Parameter supplied to Base64 encode is not a byte[]");
237 else
238 return encode((byte[])pObject);
239 }
240
241 public byte[] encode(byte pArray[]) {
242 return encodeBase64(pArray, false);
243 }
244
245 static final int CHUNK_SIZE = 76;
246 static final byte CHUNK_SEPARATOR[] = "\r\n".getBytes();
247 static final int BASELENGTH = 255;
248 static final int LOOKUPLENGTH = 64;
249 static final int EIGHTBIT = 8;
250 static final int SIXTEENBIT = 16;
251 static final int TWENTYFOURBITGROUP = 24;
252 static final int FOURBYTE = 4;
253 static final int SIGN = -128;
254 static final byte PAD = 61;
255 private static byte base64Alphabet[];
256 private static byte lookUpBase64Alphabet[];
257
258 static {
259 base64Alphabet = new byte[255];
260 lookUpBase64Alphabet = new byte[64];
261 int i;
262 for(i = 0; i < 255; i++)
263 base64Alphabet[i] = -1;
264
265 for(i = 90; i >= 65; i--)
266 base64Alphabet[i] = (byte)(i - 65);
267
268 for(i = 122; i >= 97; i--)
269 base64Alphabet[i] = (byte)((i - 97) + 26);
270
271 for(i = 57; i >= 48; i--)
272 base64Alphabet[i] = (byte)((i - 48) + 52);
273
274 base64Alphabet[43] = 62;
275 base64Alphabet[47] = 63;
276 for(i = 0; i <= 25; i++)
277 lookUpBase64Alphabet[i] = (byte)(65 + i);
278
279 i = 26;
280 for(int j = 0; i <= 51; j++) {
281 lookUpBase64Alphabet[i] = (byte)(97 + j);
282 i++;
283 }
284
285 i = 52;
286 for(int j = 0; i <= 61; j++) {
287 lookUpBase64Alphabet[i] = (byte)(48 + j);
288 i++;
289 }
290
291 lookUpBase64Alphabet[62] = 43;
292 lookUpBase64Alphabet[63] = 47;
293 }
294 }