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

Quick Search    Search Deep

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


1   /*
2    * DH.java
3    * 
4    * This code is considered to be Public Domain as it was originaly posted anonymously to
5    * Usenet.  See the comments below for details.
6    *
7    * Created on July 3, 2003, 9:24 PM
8    */
9   
10  package com.ssttr.crypto;
11  
12  import com.ssttr.util.Strings;
13  
14  /**
15   * This class performs the basic essential functions for Diffie-Hellman key genereration.
16   * Specifily, given a generator (g), exponent (x), and prime modulus (m), it performs:
17   * <code>g<sup>x</sup> mod m</code>.  Of course this could also be done just as easily
18   * with the java.math.BigInteger.modPow() method, but that class is rarely included
19   * in J2ME and embeded JVMs this can still be usefull.
20   * <p>
21   * It is worth noting that this class has been tested to reliably work on key sizes >= 64 bits.
22   * It will often fail on a keys < 64 bits.  This could (in theory) be fixed but since key sizes
23   * less than 64 bits are generally considered worthless (due to the ability to brute force the
24   * entire keyspace in short order) this has been classified as a featurenotbug.
25   * <p>
26   * To generate a shared private key:<br>
27   * Jack performs:<br>
28   * <pre>
29   * int keySize = 128;
30   * DH dh = new DH(keySize);
31   * Random rnd = new Random();
32   * String gen = "3";
33   * String jacksExp = Long.toString( Math.abs(rnd.nextLong()), 16 ).toUpperCase();
34   * String prime = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61";
35   * String publicKey = dh.generateKey( gen, jacksExp, prime);
36   * </pre>
37   * <br>
38   * Then sends keySize, gen, prime, and publicKey to Jill (but exp MUST be kept secret!).<br>
39   * Then Jill:<br>
40   * <pre>
41   * DH dh = new DH(jacksKeySize);
42   * Random rnd = new Random();
43   * String jillsExp = Long.toString( Math.abs(rnd.nextLong()), 16 ).toUpperCase();
44   * String publicKey = dh.generateKey( jacksGen,       jillsExp, jacksPrime);
45   * String jillsSecretKey = dh.generateKey( jacksPublicKey, jillsExp, jacksPrime);
46   * </pre>
47   * <br>
48   * And sends publicKey to Jack.<br>
49   * Who then:<br>
50   * <pre>
51   * String jacksSecretKey = dh.generateKey( jillsPublicKey, jacksExp, prime);
52   * </pre>
53   * Now if everything worked properly (and it should have) jacksSecretKey == jillsSecretKey
54   * and they can now use a shared-secret algorithm (like {@link TEA}) to communicate.
55   * <p>
56   * Most of the code for this class was blatently stollen (and subsequently ported to Java) from
57   * <a href="http://www.cypherspace.org/~adam/rsa/dh-in-C.html">http://www.cypherspace.org/~adam/rsa/dh-in-C.html</a>.
58   * Which is copied here in case the page goes down:
59   * <p>
60   * <p>
61   * <xmp>
62   * Diffie-Hellman Key Exchange
63   * This 10 line C program was written by an anonymous poster to sci.crypt. Possibly the poster is located in the US,
64   * though there is no way of telling. Anyway nobody's code includes a beautifully compacted big num implementation,
65   * so all you need is a C compiler.
66   *
67   * If you are trying this out with the example nobody gives in his message you should note that you must change the
68   * initialisation of S=129 on the first line to be S=3 (size of key in bytes + 1) - nobody says this in the text,
69   * it just caught me out first time.
70   *
71   * I posted a follow up to this message to sci.crypt in which I mail dropped nobody a message using the 1024 bit
72   * Diffie-Hellman key exchange he/she initiated. This message includes the Diffie-Hellman in perl I wrote (it's
73   * very similar to RSA in it's use of modular exponentiation) inspired by nobody's code.
74   *
75   * My perl-diffie-hellman plus examples of use (inspired by nobody's C code)
76   *
77   * Here is nobody's posting to sci.crypt (it was cross posted to talk.politics.crypto and alt.anonymous.messages also):
78   *
79   * Newsgroups: sci.crypt,talk.politics.crypto,alt.anonymous.messages
80   * From: nobody@replay.com (Name withheld by request)
81   * Organization: Replay and Company UnLimited.
82   * X-Warning: This message was forwarded by an Anonymous Remailer.
83   * X-Comment: Replay does not necessarily approve of the contents of this posting.
84   * X-Comment: Please report inappropriate use to &lt;postmaster@replay.com&gt;
85   * Subject: Export-a-crypto-system: Diffie-Hellman
86   * X-Posting-Host: xs1.xs4all.nl
87   * Date: Sun, 2 Apr 1995 02:25:08 +0000
88   * Sender: usenet@demon.co.uk
89   * Lines: 88
90   *
91   * Inspired by Adam Back's RSA code...
92   *
93   * The export-a-crypto-system sig II - Diffie-Hellman in 10 lines of C:
94   *
95   * #include &lt;stdio.h&gt; // Usage: dh base exponent modulus
96   * typedef unsigned char u;u m[1024],g[1024],e[1024],b[1024];int n,v,d,z,S=129;a(
97   * u *x,u *y,int o){d=0;for(v=S;v--;){d+=x[v]+y[v]*o;x[v]=d;d=d>>8;}}s(u *x){for(
98   * v=0;(v<S-1)&&(x[v]==m[v]);)v++;if(x[v]>=m[v])a(x,m,-1);}r(u *x){d=0;for(v=0;v<
99   * S;){d|=x[v];x[v++]=d/2;d=(d&1)<<8;}}M(u *x,u *y){u X[1024],Y[1024];bcopy(x,X,S
100  * );bcopy(y,Y,S);bzero(x,S);for(z=S*8;z--;){if(X[S-1]&1){a(x,Y,1);s(x);}r(X);a(Y
101  * ,Y,1);s(Y);}}h(char *x,u *y){bzero(y,S);for(n=0;x[n]>0;n++){for(z=4;z--;)a(y,y
102  * ,1);x[n]|=32;y[S-1]|=x[n]-48-(x[n]>96)*39;}}p(u *x){for(n=0;!x[n];)n++;for(;n<
103  * S;n++)printf("%c%c",48+x[n]/16+(x[n]>159)*7,48+(x[n]&15)+7*((x[n]&15)>9));
104  * printf("\n");}main(int c,char **v){h(v[1],g);h(v[2],e);h(v[3],m);bzero(b,S);b[
105  * S-1]=1;for(n=S*8;n--;){if(e[S-1]&1)M(b,g);M(g,g);r(e);}p(b);}
106  * </code>
107  *
108  * To compile it, type: gcc dh.c -o dh
109 
110  * The program is somewhat slow, but it works, and it's almost small enough to
111  * attach to your posts as a signature.  It's set up for 1024-bit numbers, but
112  * you can allow bigger numbers by setting the value of the S variable.  To
113  * allow for carry digits, the value set for S must be one greater than the
114  * maximum length in bytes of the modulus that you wish to use.  The time to
115  * calculate a modular exponent is roughly proportional to the cube of the
116  * number of bits, so if a 1024-bit number takes 5 minutes, a 2048-bit number
117  * will take 40 minutes, and a 4096-bit number would take about 5 hours.
118  * All numbers are entered and printed in hexadecimal.  Because of the minimal
119  * size, the program doesn't check for human error; it may do strange things
120  * if you give it bad data.
121  * 
122  * For example purposes, the numbers used below are small, any practical
123  * use would require numbers of 512-1024 bits in length.
124  * 
125  * To generate a key, Joe selects a public generator (3 in this example), a
126  * public prime modulus (10001 hexadecimal), and a secret exponent (9A2E hex).
127  * Joe then calculates the following:
128  * 
129  * joe% dh 3 9A2E 10001
130  * C366
131  * 
132  * This is his public key.  Joe sends these three numbers (3,10001,C366)
133  * to Alice.
134  * 
135  * To encrypt a message to Joe, Alice picks a secret random number (4C20 in
136  * this example) and using Joe's generator and modulus, calculates:
137  * 
138  * alice% dh 3 4C20 10001
139  * 6246
140  * 
141  * She sends this result to Joe.  Alice then takes Joe's public key and her
142  * secret random number and calculates:
143  * 
144  * alice% dh C366 4C20 10001
145  * DED4
146  * 
147  * She uses this result as a session key to encrypt her message to Joe.
148  * 
149  * To decrypt the message, Joe uses the number Alice sent him, and his
150  * secret key to calculate:
151  * 
152  * joe% dh 6246 9A2E 10001
153  * DED4
154  * 
155  * Joe now has the session key and can decrypt Alice's message.
156  * 
157  * An eavesdropper sees Joe send Alice three numbers (3,10001,C366), and
158  * sees Alice send Joe '6246'.  But the eavesdropper can not use these
159  * numbers to calculate the secret session key (DED4), and thus can not
160  * decrypt the message.
161  * 
162  * 
163  * You can use this program to do RSA also, but generating a key is more
164  * difficult.
165  * 
166  * I wonder if the USA ITAR law covers integer math programs?
167  * 
168  * 
169  * Here is my key:
170  * 
171  * g=2
172  * X=28D4FEFED5CC1ACDBE7D550813A1518DB56812855014EFDDD9E038A15BE52FD524D6FFA9C9E3
173  * 1E59DDFEF705EAB75DD031908F10B584F5A2495BC2C1433ACB6FA065FB0850ECCF139993BA4564
174  * B97A289FBCD59524FC30F377060366077378288F93173AC508D1DC5B4D9DAE0AFECFFA9E5494C5
175  * 3EED74C4E29DEBAF0C08B720
176  * m=DE9B707D4C5A4633C0290C95FF30A605AEB7AE864FF48370F13CF01D49ADB9F23D19A439F753
177  * EE7703CF342D87F431105C843C78CA4DF639931F3458FAE8A94D1687E99A76ED99D0BA87189F42
178  * FD31AD8262C54A8CF5914AE6C28C540D714A5F6087A171FB74F4814C6F968D72386EF356A05180
179  * C3BEC7DDD5EF6FE76B0531C3
180  * </xmp>
181  *
182  * <p>
183  * @author  anonymous
184  */
185 public class DH
186 {
187     Object lock = new Object();
188     
189     byte[] m,g,e,b,key,tmp;
190     
191     int n,v,d,z,S,keySize;
192     
193     /**
194      * Creates a new instance of DH.  Each instance of DH is threadsafe in that
195      * it uses a lock to guarentee that all calls to generateKey() are serialized.
196      *
197      * @param keySize The size of the key(s) to be generated, in bits.
198      *
199      * @throws IllegalArgumentException if keySize < 64
200      */
201     public DH (final int keySize)
202     {
203         if( keySize < 64 )
204             throw new IllegalArgumentException("keySize < 64");
205         
206         this.keySize = keySize;
207         S = keySize / 8 + 1;
208     }
209     
210     private final void initialize()
211     {
212         m = new byte[S];
213         g = new byte[S];
214         e = new byte[S];
215         b = new byte[S];
216         key = new byte[S*2];
217     }
218     
219     public String generateKey (String generator, String exponent, String prime)
220     {
221         synchronized ( lock )
222         {
223             initialize();
224 
225             h (generator.getBytes(),g);
226             h (exponent.getBytes(),e);
227             h (prime.getBytes(),m);
228 
229             generateKey();
230 
231             tmp = trim(b);
232             final String k = Strings.toHex(tmp);
233             // Save a little memory
234             m = g = e = b = key = tmp = null;
235             return k;
236             
237             /*
238             p (b);
239 
240             tmp = new byte[(S-1)*2];
241             System.arraycopy(key,0,tmp,0,tmp.length);
242 
243             final String k = new String(tmp);
244             // Save a little memory
245             m = g = e = b = key = tmp = null;
246             
247             return k;
248             */
249         }
250     }
251     
252     public byte[] generateKey (byte[] generator, byte[] exponent, byte[] prime)
253     {
254         synchronized ( lock )
255         {
256             initialize();
257 
258             int l;
259             l = Math.min(S,generator.length);
260             System.arraycopy( generator, 0, g, S - l, l );
261             l = Math.min(S,exponent.length);
262             System.arraycopy( exponent, 0, e, S - l, l );
263             l = Math.min(S,prime.length);
264             System.arraycopy( prime, 0, m, S - l, l );
265 
266             generateKey();
267 
268             final byte[] k = trim(b);
269             // Save a little memory
270             m = g = e = b = key = tmp = null;
271 
272             return k;
273         }
274     }
275     
276     private final void generateKey()
277     {
278         bzero (b,S);
279         
280         b[S-1] = 1;
281         
282         for( n = keySize; n-- > 0; )
283         {
284             if( (e[S-1] & 1) != 0 )
285                 M (b,g);
286             M (g,g);
287             r (e);
288         }
289     }
290     
291     private void s (byte[] x)
292     {
293         for( v = 0; (v < S - 1) && (x[v] == m[v]); v++ );
294 
295         if( (x[v] & 0xFF) >= (m[v] & 0xFF) )
296             a (x,m,-1);
297     }
298     
299     private void r (byte[] x)
300     {
301         d = 0;
302         for( v = 0; v < S; )
303         {
304             d |= (x[v] & 0xFF);
305             x[v++] = (byte)(d / 2);
306             d = ( d & 1 ) << 8;
307         }
308     }
309     
310     private void M (byte[] x,byte[] y)
311     {
312         byte[] X = new byte[S], Y = new byte[S];
313         
314         System.arraycopy (x,0,X,0,S);
315         System.arraycopy (y,0,Y,0,S);
316         bzero (x,S);
317         
318         for( z = keySize; z > 0; z-- )
319         {
320             if( (X[S-1] & 1) != 0 )
321             {
322                 a (x,Y,1);
323                 s (x);
324             }
325             r (X);
326             a (Y,Y,1);
327             s (Y);
328         }
329     }
330     
331     private void a ( byte[] x,byte[] y,int o)
332     {
333         d = 0;
334         for( v = S - 1; v >= 0; v -- )
335         {
336             d += (x[v] & 0xFF) + (y[v] & 0xFF) * o;
337             x[v] = (byte)d;
338             d >>= 8;
339         }
340     }
341     
342     private void h (byte[] x,byte[] y)
343     {
344         int j;
345         bzero (y,S);
346         for( n = 0; n < x.length && x[n] > 0; n++ )
347         {
348             for( z = 4; z-- > 0; )
349                 a (y,y,1);
350             x[n] |= 0x20;
351             j = x[n] & 0xFF;
352             y[S-1] |= (byte)(j - 48 - (j > 0x60 ? 39 : 0));
353         }
354     }
355 /*    
356     private void p (byte[] x)
357     {
358         for( n = 0; x[n] == 0;)
359             n++;
360         
361         bzero(key,key.length);
362         
363         int i = 0, j;
364 
365         for( ; n < S; n++ )
366         {
367             j = x[n] & 0xFF;
368             key[i++] = (byte)(48 +  j / 0x10 + (    j        > 0x9f ? 0x7 : 0) );
369             key[i++] = (byte)(48 + (j & 0xF) + ( ( (j & 0xf) > 0x9) ? 0x7 : 0) );
370         }
371     }
372 */    
373     private void bzero(final byte[] a, int len)
374     {
375         while( --len >= 0 )
376             a[len] = 0;
377     }
378     
379     private static byte[] trim(final byte[] bytes)
380     {
381         int i;
382         for( i = 0; i < bytes.length && bytes[i] == 0; i ++ );
383         
384         byte[] tmp = new byte[ bytes.length - i ];
385         System.arraycopy( bytes, i, tmp, 0, tmp.length );
386         
387         return tmp;
388     }
389     
390 }