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 }