1 package org.apache.fulcrum.crypto.impl;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 /**
23 * Base64 encoder/decoder taken from commons-codec. Copying
24 * and wasting the code allows to minimize the dependencies.
25 *
26 * @author Siegfried Goeschl
27 */
28 public class Base64
29 {
30
31 public Base64() {
32 }
33
34 private static boolean isBase64(byte octect) {
35 if(octect == 61)
36 return true;
37 return base64Alphabet[octect] != -1;
38 }
39
40 public static boolean isArrayByteBase64(byte arrayOctect[]) {
41 arrayOctect = discardWhitespace(arrayOctect);
42 int length = arrayOctect.length;
43 if(length == 0)
44 return true;
45 for(int i = 0; i < length; i++)
46 if(!isBase64(arrayOctect[i]))
47 return false;
48
49 return true;
50 }
51
52 public static byte[] encodeBase64(byte binaryData[]) {
53 return encodeBase64(binaryData, false);
54 }
55
56 public static byte[] encodeBase64Chunked(byte binaryData[]) {
57 return encodeBase64(binaryData, true);
58 }
59
60 public Object decode(Object pObject)
61 throws Exception {
62 if(!(pObject instanceof byte[]))
63 throw new Exception("Parameter supplied to Base64 decode is not a byte[]");
64 else
65 return decode((byte[])pObject);
66 }
67
68 public byte[] decode(byte pArray[]) {
69 return decodeBase64(pArray);
70 }
71
72 public static byte[] encodeBase64(byte binaryData[], boolean isChunked) {
73 int lengthDataBits = binaryData.length * 8;
74 int fewerThan24bits = lengthDataBits % 24;
75 int numberTriplets = lengthDataBits / 24;
76 byte encodedData[] = null;
77 int encodedDataLength = 0;
78 int nbrChunks = 0;
79 if(fewerThan24bits != 0)
80 encodedDataLength = (numberTriplets + 1) * 4;
81 else
82 encodedDataLength = numberTriplets * 4;
83 if(isChunked) {
84 nbrChunks = CHUNK_SEPARATOR.length != 0 ? (int)Math.ceil((float)encodedDataLength / 76F) : 0;
85 encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
86 }
87 encodedData = new byte[encodedDataLength];
88 byte k = 0;
89 byte l = 0;
90 byte b1 = 0;
91 byte b2 = 0;
92 byte b3 = 0;
93 int encodedIndex = 0;
94 int dataIndex = 0;
95 int i = 0;
96 int nextSeparatorIndex = 76;
97 int chunksSoFar = 0;
98 for(i = 0; i < numberTriplets; i++) {
99 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
205
206 case 9:
207 case 10:
208 case 13:
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 }