View Javadoc

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   * Encodes data as BASE64
22   * @author enigma
23   */
24  public class Base64Encoder implements Plugin {
25      public String getName() {
26          return "BASE-64 Encoder";
27      }
28  
29      public String getDescription() {
30          return "Encodes data as BASE-64 text";
31      }
32  
33      public boolean usesKey() {
34          return false;
35      }
36  
37      public boolean isInformational() {
38          return false;
39      }
40  
41      /***
42        * Byte value that maps to 'a' in Base64 encoding
43        */
44      final static int LOWER_CASE_A_VALUE = 26;   
45  
46      /***
47        * Byte value that maps to '0' in Base64 encoding
48        */
49      final static int ZERO_VALUE = 52;
50  
51      /***
52        * Byte value that maps to '+' in Base64 encoding
53        */
54      final static int PLUS_VALUE = 62;
55  
56      /***
57        * Byte value that maps to '/' in Base64 encoding
58        */
59      final static int SLASH_VALUE = 63;
60      
61      /***
62        * Bit mask for one character worth of bits in Base64 encoding.
63        * Equivalent to binary value 111111b.
64        */
65      private final static int SIX_BIT_MASK = 63;
66      
67      /***
68        * Convert a byte between 0 and 63 to its Base64 character equivalent
69          * @param b Byte value to be converted
70          * @return Base64 char value
71          */
72      private char mapByteToChar( byte b ) {
73          if ( b < LOWER_CASE_A_VALUE ) {
74              return (char)( 'A' + b );
75          }
76          
77          if ( b < ZERO_VALUE ) {
78              return (char)( 'a' + ( b - LOWER_CASE_A_VALUE ) );
79          }
80          
81          if ( b < PLUS_VALUE ) {
82              return (char)( '0' + ( b - ZERO_VALUE ) );
83          }
84          
85          if ( b == PLUS_VALUE ) {
86              return '+';
87          }
88          
89          if ( b == SLASH_VALUE ) {
90              return '/';
91          }
92          
93          throw new IllegalArgumentException( "Byte " + new Integer( b ) + " is not a valid Base64 value" );
94      }
95  
96      public int[] doAction(int[] in, int[] key) {
97          // Base64 encoding yields a String that is 33% longer than the byte array
98          int charCount = ( ( in.length * 4 ) / 3 ) + 4;
99          
100         // New lines will also be needed for every 76 charactesr, so allocate a
101         // StringBuffer that is long enough to hold the full result without
102         // having to expand later
103         StringBuffer result = new StringBuffer( ( charCount * 77 ) / 76 );
104         
105         int byteArrayLength = in.length;
106         int byteArrayIndex = 0;
107         int byteTriplet = 0;
108         while ( byteArrayIndex < byteArrayLength - 2 ) {
109             // Build the 24 bit byte triplet from the input data
110             byteTriplet = in[ byteArrayIndex++ ];
111             // Each input byte contributes 8 bits to the triplet
112             byteTriplet <<= 8;
113             byteTriplet |= in[ byteArrayIndex++ ];
114             byteTriplet <<= 8;
115             byteTriplet |= in[ byteArrayIndex++ ];
116 
117             // Look at the lowest order six bits and remember them
118             byte b4 = (byte)( SIX_BIT_MASK & byteTriplet );
119             // Move the byte triplet to get the next 6 bit value
120             byteTriplet >>= 6;
121             byte b3 = (byte)( SIX_BIT_MASK & byteTriplet );
122             byteTriplet >>= 6;
123             byte b2 = (byte)( SIX_BIT_MASK & byteTriplet );
124             byteTriplet >>= 6;
125             byte b1 = (byte)( SIX_BIT_MASK & byteTriplet );
126             
127             // Add the Base64 encoded character to the result String
128             result.append( mapByteToChar( b1 ) );
129             result.append( mapByteToChar( b2 ) );
130             result.append( mapByteToChar( b3 ) );
131             result.append( mapByteToChar( b4 ) );
132 
133             // There are 57 bytes for every 76 characters, so wrap the line when needed
134             if ( byteArrayIndex % 57 == 0 ) {
135                 result.append( "\n" );
136             }
137         }
138         
139         // Check if we have one byte left over
140         if ( byteArrayIndex == byteArrayLength - 1 ) {
141             // Convert our one byte to an int
142             byteTriplet = in[ byteArrayIndex++ ];
143             // Right pad the second 6 bit value with zeros
144             byteTriplet <<= 4;
145             
146             byte b2 = (byte)( SIX_BIT_MASK & byteTriplet );
147             byteTriplet >>= 6;
148             byte b1 = (byte)( SIX_BIT_MASK & byteTriplet );
149             
150             result.append( mapByteToChar( b1 ) );
151             result.append( mapByteToChar( b2 ) );
152             
153             // Add "==" to the output to make it a multiple of 4 Base64 characters
154             result.append( "==" );
155         }
156         
157         // Check if we have two byte left over
158         if ( byteArrayIndex == byteArrayLength - 2 ) {
159             // Convert our two bytes to an int
160             byteTriplet = in[ byteArrayIndex++ ];
161             byteTriplet <<= 8;
162             byteTriplet |= in[ byteArrayIndex++ ];
163             // Right pad the third 6 bit value with zeros
164             byteTriplet <<= 2;
165 
166             byte b3 = (byte)( SIX_BIT_MASK & byteTriplet );
167             byteTriplet >>= 6;
168             byte b2 = (byte)( SIX_BIT_MASK & byteTriplet );
169             byteTriplet >>= 6;
170             byte b1 = (byte)( SIX_BIT_MASK & byteTriplet );
171 
172             result.append( mapByteToChar( b1 ) );
173             result.append( mapByteToChar( b2 ) );
174             result.append( mapByteToChar( b3 ) );
175 
176             // Add "==" to the output to make it a multiple of 4 Base64 characters
177             result.append( "=" );           
178         }
179         int resultArray[] = new int[result.length()];
180         for (int i=0; i<resultArray.length; i++)
181             resultArray[i] = result.charAt(i);
182         return resultArray;
183     }
184 
185 }