View Javadoc

1   package org.apache.fulcrum.crypto.impl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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                     // 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 }