Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/ssttr/crypto/TEA.java


1   /*
2    * TEA.java
3    *
4    * This code is considered Public Domain based on the statement provided with the original code.
5    * See the comments bellow for more details.
6    *
7    * Created on May 2, 2003, 11:46 PM
8    */
9   
10  package com.ssttr.crypto;
11  
12  import com.ssttr.util.Strings;
13  
14  /**
15   * This is a 100% Pure Java implementation of the Tiny Encryption Algorithm which
16   * can be found <a href="http://vader.brad.ac.uk/tea/tea.shtml">http://vader.brad.ac.uk/tea/tea.shtml</a>.
17   * Or at least that's where I originaly found it.  It appears that it is still available
18   * here: <a href="http://www.simonshepherd.supanet.com/tea.htm">http://www.simonshepherd.supanet.com/tea.htm</a>.
19   * <p>
20   * TEA is only capable of using 128 bit keys.  If any other key length is desired
21   * you will have to pad or chop (as appropriate) the key to be 128 bits long.
22   * <p>
23   * It was ported from the ANSI C new variant <a href="http://vader.brad.ac.uk/tea/source.shtml#new_ansi">http://vader.brad.ac.uk/tea/source.shtml#new_ansi</a>.
24   * As I mentioned above, that page seems to have disappeard, so here's the new equivelent:
25   * <a href="http://www.simonshepherd.supanet.com/source.htm#new_ansi">http://www.simonshepherd.supanet.com/source.htm#new_ansi</a>.
26   * In case the original page goes down it's copied below:
27   * <p>
28   * Please feel free to use any of this code in your applications. The TEA
29   * algorithm (including new-variant TEA) has been placed in the public domain, as have my assembly
30   * language implementations. <p><hr>
31   * <p>
32   * <pre>
33   * void encipher(const unsigned long *const v,unsigned long *const w,
34   * const unsigned long * const k)
35   * {
36   *    register unsigned long       y=v[0],z=v[1],sum=0,delta=0x9E3779B9,
37   *         a=k[0],b=k[1],c=k[2],d=k[3],n=32;
38   * 
39   *    while(n--&gt;0)
40   *       {
41   *       sum += delta;
42   *       y += (z &lt;&lt; 4)+a ^ z+sum ^ (z &gt;&gt; 5)+b;
43   *       z += (y &lt;&lt; 4)+c ^ y+sum ^ (y &gt;&gt; 5)+d;
44   *       }
45   * 
46   *    w[0]=y; w[1]=z;
47   * }
48   * 
49   * void decipher(const unsigned long *const v,unsigned long *const w,
50   *    const unsigned long * const k)
51   * {
52   *    register unsigned long       y=v[0],z=v[1],sum=0xC6EF3720,
53   *         delta=0x9E3779B9,a=k[0],b=k[1],
54   *         c=k[2],d=k[3],n=32;
55   * 
56   *    // sum = delta&lt;&lt;5, in general sum = delta * n
57   * 
58   *    while(n--&gt;0)
59   *       {
60   *       z -= (y &lt;&lt; 4)+c ^ y+sum ^ (y &gt;&gt; 5)+d;
61   *       y -= (z &lt;&lt; 4)+a ^ z+sum ^ (z &gt;&gt; 5)+b;
62   *       sum -= delta;
63   *       }
64   *    
65   *    w[0]=y; w[1]=z;
66   * }
67   * 
68   * 
69   * </pre>
70   * @author  smeiners
71   */
72  
73  public class TEA
74  implements SKEncryption
75  {
76      /** Default number of iterations to perform durring encryption/decryption (32). */
77      public static final  int    DEFAULT_ITERATIONS = 32;
78      
79      private int[]               key     = null;
80      private static final int    delta   = 0x9E3779B9;
81      private static final int    SUM     = 0xC6EF3720;
82      private int                 cycles  = DEFAULT_ITERATIONS;
83      
84      /** Creates a new instance of TEA */
85      public TEA ()
86      {
87      }
88      
89      /**
90       * Creates a new instance of TEA.
91       *
92       * @param cycles The number of iterations to perform durring encryption/decryption.  If iterations < 6 the default will be used.
93       */
94      public TEA (int iterations)
95      {
96          if( iterations >= 6 )
97              cycles = iterations;
98      }
99      
100     public int getIterations()
101     { return cycles; }
102     
103     /**
104      * Sets the encryption key to be used.
105      *
106      * @param key The key as a hexidecimal string.
107      * @throws IllegalArgumentException if <code>key.length() != 32</code>.
108      */
109     public void setHexKey(String key)
110     {
111         setKey( Strings.fromHex(key) );
112     }
113     
114     /**
115      * Sets the encryption key to be used.
116      *
117      * @param key The key in raw (non-hex) byte form.
118      * @throws IllegalArgumentException if <code>key.length != 16</code>.
119      */
120     public void setKey (byte[] key)
121     {
122         if( key.length != 16 )
123             throw new IllegalArgumentException("key.length != 16");
124         
125         this.key = toInts(key);
126     }
127     
128     /**
129      * Encrypts some data.
130      *
131      * @param rawData The data to be encrypted (binary data is ok).
132      * @return Encrypted data.
133      * @throws IllegalArgumentException if rawData.length == 0
134      */
135     public byte[] encrypt (byte[] rawData)
136     {
137         if( rawData.length == 0 )
138             throw new IllegalArgumentException("rawData.length == 0");
139         
140         if( rawData.length % 8 != 0 )
141         {
142             // pad the data out to the 8 byte boundry with 0's
143             byte[] tmp = new byte[ rawData.length + ( 8 - (rawData.length % 8) ) ];
144             System.arraycopy( rawData, 0, tmp, 0, rawData.length );
145             for( int i = rawData.length; i < tmp.length; i ++ )
146                 tmp[i] = 0;
147             rawData = tmp;
148         }
149         
150         int[] in = toInts(rawData);
151         int[] out = new int[in.length];
152         
153         for( int i = in.length - 2; i >= 0; i -= 2 )
154             encipher(in, out, i);
155         
156         return toBytes(out);
157     }
158     
159     /**
160      * Decrypts some data.
161      *
162      * @param cryptedData The data to be decrypted.
163      * @return The original rawData that was previously encrypted.
164      * @throws IllegalArgumentException if cryptedData.length == 0
165      */
166     public byte[] decrypt (byte[] cryptedData)
167     {
168         if( cryptedData.length == 0 )
169             throw new IllegalArgumentException("cryptedData.length == 0");
170         
171         int[] in = toInts(cryptedData);
172         int[] out = new int[in.length];
173         
174         for( int i = in.length - 2; i >= 0; i -= 2 )
175             decipher(in, out, i);
176         
177         byte[] data = toBytes(out);
178 
179         int z = data.length - 1;
180         
181         if( data[z] != 0 )
182             return data;
183         
184         for( ; data[z] == 0 && z >= 0; z -- );  // find the end of the 0 padding
185 
186         z++; // add one to change the index to the length
187         
188         byte[] u = new byte[z];
189         System.arraycopy(data, 0, u, 0, z);
190         
191         return u;
192     }
193     
194     private final void encipher(final int[] in, final int[] out, final int offset)
195     {
196         int     y   = in[offset],
197                 z   = in[offset+1],
198                 sum = 0,
199                 n   = cycles;
200 
201         while( n-- > 0 )
202         {
203             y += (z << 4 ^ z >> 5) + z ^ sum + key[sum&3];
204             sum += delta;
205             z += (y << 4 ^ y >> 5) + y ^ sum + key[sum>>11 & 3];
206         }
207 
208         out[offset]      = y;
209         out[offset+1]    = z;
210     }
211 
212     private final void decipher(final int[] in, final int[] out, final int offset)
213     {
214         int     y   = in[offset],
215                 z   = in[offset+1],
216                 sum = SUM,
217                 n = cycles;
218 
219         /* sum = delta<<5, in general sum = delta * n */
220 
221         while( n-- > 0 )
222         {
223             z -= (y << 4 ^ y >> 5) + y ^ sum + key[sum>>11 & 3];
224             sum -= delta;
225             y -= (z << 4 ^ z >> 5) + z ^ sum + key[sum&3];
226         }
227 
228         out[offset]      = y;
229         out[offset+1]    = z;
230     }
231     
232     private static int[] toInts(byte[] bytes)
233     {
234         int i, j;
235         
236         i = bytes.length / 4;
237         int[] ints = new int[i];
238         
239         for( i --, j = bytes.length - 1; i >= 0; i -- )
240         {
241             ints[i] =   ( bytes[j--] & 0xFF ) << 24 |
242                         ( bytes[j--] & 0xFF ) << 16 |
243                         ( bytes[j--] & 0xFF ) << 8  |
244                         ( bytes[j--] & 0xFF );
245         }
246         
247         return ints;
248     }
249     
250     private static byte[] toBytes(int[] ints)
251     {
252         int i, j;
253         
254         i = ints.length * 4;
255         byte[] bytes = new byte[i];
256         
257         for( i --, j = ints.length - 1; j >= 0; j -- )
258         {
259             bytes[i--] = (byte)( ( ints[j] >> 24 ) & 0xFF);
260             bytes[i--] = (byte)( ( ints[j] >> 16 ) & 0xFF);
261             bytes[i--] = (byte)( ( ints[j] >> 8  ) & 0xFF);
262             bytes[i--] = (byte)(   ints[j]         & 0xFF);
263         }
264         
265         return bytes;
266     }
267     
268 }