1 // Copyright (C) 2004, Brian Enigma <enigma at netninja.com>
2 // This file is part of MagicCodes.
3 //
4 // MagicCodes is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // MagicCodes is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Foobar; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 package org.ninjasoft.magiccodes.plugins;
18
19
20 /***
21 * Decodes BASE-64 data
22 * @author enigma
23 */
24 public class Base64Decoder implements Plugin {
25
26 public String getName() {
27 return "BASE-64 Decoder";
28 }
29
30 public String getDescription() {
31 return "Decodes BASE-64 text to original data";
32 }
33
34 public boolean usesKey() {
35 return false;
36 }
37
38 public boolean isInformational() {
39 return false;
40 }
41
42 /***
43 * Convert a Base64 character to its 6 bit value as defined by the mapping.
44 * @param c Base64 character to decode
45 * @return int representation of 6 bit value
46 */
47 private int mapCharToInt( char c ) {
48 if ( c >= 'A' && c <= 'Z' ) {
49 return c - 'A';
50 }
51
52 if ( c >= 'a' && c <= 'z' ) {
53 return ( c - 'a' ) + Base64Encoder.LOWER_CASE_A_VALUE;
54 }
55
56 if ( c >= '0' && c <= '9' ) {
57 return ( c - '0' ) + Base64Encoder.ZERO_VALUE;
58 }
59
60 if ( c == '+' ) {
61 return Base64Encoder.PLUS_VALUE;
62 }
63
64 if ( c == '/' ) {
65 return Base64Encoder.SLASH_VALUE;
66 }
67
68 throw new IllegalArgumentException( c + " is not a valid Base64 character." );
69 }
70
71 /***
72 * Simple class to wrap around the String input to ignore all of the
73 * non-Base64 characters in the input. Note that although '=' is
74 * a valid character, it does not contribute to the total number
75 * of output bytes, and is therefore ignored
76 */
77 private class StringWrapper {
78
79 /***
80 * The input String to be decoded
81 */
82 private int[] mString;
83
84 /***
85 * Current position in the String
86 */
87 private int mIndex = 0;
88
89 /***
90 * Total number of Base64 characters in the input
91 */
92 private int mUsefulLength;
93
94 /***
95 * @param c Character to be examined
96 * @return Whether or not the character is a Base64 character
97 */
98 private boolean isUsefulChar( int i ) {
99 char c = (char) i;
100 return ( c >= 'A' && c <= 'Z' ) ||
101 ( c >= 'a' && c <= 'z' ) ||
102 ( c >= '0' && c <= '9' ) ||
103 ( c == '+' ) ||
104 ( c == '/' );
105 }
106
107 /***
108 * Create the wrapper and determine the number of Base64 characters in
109 * the input
110 * @param s Input String to be decoded
111 */
112 public StringWrapper( int[] in ) {
113 mString = in;
114 mUsefulLength = 0;
115 for( int i = 0; i < in.length; i++ ) {
116 if( isUsefulChar( mString[i] ) ){
117 mUsefulLength++;
118 }
119 }
120 }
121
122 /***
123 * @return Total number of Base64 characters in the input. Does
124 * not include '='
125 */
126 public int getUsefulLength() {
127 return mUsefulLength;
128 }
129
130 /***
131 * Traverse the String until hitting the next Base64 character.
132 * Assumes that there is still another valid Base64 character
133 * left in the String.
134 */
135 public char getNextUsefulChar() {
136 char result = '_'; // Start with a non-Base64 character
137 while ( !isUsefulChar( result ) ) {
138 result = (char) mString[mIndex++];
139 }
140
141 return result;
142 }
143 }
144
145 /***
146 * Bit mask for one byte worth of bits in Base64 encoding.
147 * Equivalent to binary value 11111111b.
148 */
149 private static final int EIGHT_BIT_MASK = 0xFF;
150
151 public int[] doAction(int[] in, int[] key) {
152 // Create a wrapper around the input to screen out non-Base64 characters
153 StringWrapper wrapper = new StringWrapper( in );
154 // A Base64 byte array is 75% the size of its String representation
155 int byteArrayLength = wrapper.getUsefulLength() * 3 / 4;
156
157 int result[] = new int[ byteArrayLength ];
158
159 int byteTriplet = 0;
160 int byteIndex = 0;
161
162 // Continue until we have less than 4 full characters left to
163 // decode in the input.
164 while ( byteIndex + 2 < byteArrayLength ) {
165
166 // Package a set of four characters into a byte triplet
167 // Each character contributes 6 bits of useful information
168 byteTriplet = mapCharToInt( wrapper.getNextUsefulChar() );
169 byteTriplet <<= 6;
170 byteTriplet |= mapCharToInt( wrapper.getNextUsefulChar() );
171 byteTriplet <<= 6;
172 byteTriplet |= mapCharToInt( wrapper.getNextUsefulChar() );
173 byteTriplet <<= 6;
174 byteTriplet |= mapCharToInt( wrapper.getNextUsefulChar() );
175
176 // Grab a normal byte (eight bits) out of the byte triplet
177 // and put it in the byte array
178 result[ byteIndex + 2 ] = (byte)( byteTriplet & EIGHT_BIT_MASK );
179 byteTriplet >>= 8;
180 result[ byteIndex + 1 ] = (byte)( byteTriplet & EIGHT_BIT_MASK );
181 byteTriplet >>= 8;
182 result[ byteIndex ] = (byte)( byteTriplet & EIGHT_BIT_MASK );
183 byteIndex += 3;
184 }
185
186 // Check if we have one byte left to decode
187 if ( byteIndex == byteArrayLength - 1 ) {
188 // Take out the last two characters from the String
189 byteTriplet = mapCharToInt( wrapper.getNextUsefulChar() );
190 byteTriplet <<= 6;
191 byteTriplet |= mapCharToInt( wrapper.getNextUsefulChar() );
192
193 // Remove the padded zeros
194 byteTriplet >>= 4;
195 result[ byteIndex ] = (byte)( byteTriplet & EIGHT_BIT_MASK );
196 }
197
198 // Check if we have two bytes left to decode
199 if ( byteIndex == byteArrayLength - 2 ) {
200 // Take out the last three characters from the String
201 byteTriplet = mapCharToInt( wrapper.getNextUsefulChar() );
202 byteTriplet <<= 6;
203 byteTriplet |= mapCharToInt( wrapper.getNextUsefulChar() );
204 byteTriplet <<= 6;
205 byteTriplet |= mapCharToInt( wrapper.getNextUsefulChar() );
206
207 // Remove the padded zeros
208 byteTriplet >>= 2;
209 result[ byteIndex + 1 ] = (byte)( byteTriplet & EIGHT_BIT_MASK );
210 byteTriplet >>= 8;
211 result[ byteIndex ] = (byte)( byteTriplet & EIGHT_BIT_MASK );
212 }
213
214 return result;
215 }
216
217 }
This page was automatically generated by Maven