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

Quick Search    Search Deep

Source code: com/traxel/crypto/CipherPartner.java


1   /* $Id: CipherPartner.java,v 1.6 2001/04/02 08:42:50 cvsbob Exp $ */
2   
3   /*
4    * CipherPartner.java, class for synching Diffie Hellman partners.
5    * Copyright (C) 2001 Robert Bushman.
6    *
7    * I reserve the right to release this program under seperate license.
8    * If you require a special license grant contact Robert Bushman.
9    *
10   * This program is free software; you can redistribute it and/or
11   * modify it under the terms of the GNU General Public License
12   * as published by the Free Software Foundation; either version 2
13   * of the License, or (at your option) any later version.
14   *
15   * This program is distributed in the hope that it will be useful,
16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   * GNU General Public License for more details.
19   * 
20   * You should have received a copy of the GNU General Public License
21   * along with this program; if not, write to the Free Software
22   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 
23   * 02111-1307, USA.
24   */
25  
26  package com.traxel.crypto;
27  
28  import java.io.FileInputStream;
29  import java.io.FileNotFoundException;
30  import java.io.FileOutputStream;
31  import java.io.IOException;
32  import java.math.BigInteger;
33  import java.security.InvalidAlgorithmParameterException;
34  import java.security.InvalidKeyException;
35  import java.security.KeyFactory;
36  import java.security.KeyPair;
37  import java.security.KeyPairGenerator;
38  import java.security.NoSuchAlgorithmException;
39  import java.security.spec.InvalidKeySpecException;
40  import java.security.spec.X509EncodedKeySpec;
41  import javax.crypto.Cipher;
42  import javax.crypto.KeyAgreement;
43  import javax.crypto.SecretKey;
44  import javax.crypto.NoSuchPaddingException;
45  import javax.crypto.interfaces.DHPublicKey;
46  import javax.crypto.interfaces.DHPrivateKey;
47  import javax.crypto.spec.DHParameterSpec;
48  import javax.crypto.spec.IvParameterSpec;
49  
50  /**
51   * <b>NOTE:</b> TEST_PARAMS are not intended for production use.
52   * <br><br>
53   * <b>Test Usage</b>
54   * <pre>
55   *   // DHParameterSpecs can be safely published to all parties.
56   *   alice = new CipherPartner( "ALICE", CipherPartner.TEST_PARAMS );
57   *   bob = new CipherPartner( "BOB", CipherPartner.TEST_PARAMS );
58   *   
59   *   alicePublicEncoded = alice.getPublicEncoded();
60   *   
61   *   // transmit alicePublicEncoded to bob
62   *   // Alternately, alice could load from disk and bob could
63   *   // already have a copy of alice's public key.
64   *   
65   *   // bob initializes only from alices key, and generates IV
66   *   bob.initFromPartner( alicePublicEncoded );
67   *   bobPublicEncoded = bob.getPublicEncoded();
68   *   bobIv = bob.getIv();
69   *
70   *   // transmit bobPublicEncoded and bobIV to alice
71   *
72   *   // alice requires bobPublicEncoded and bobIv
73   *   alice.initFromPartner( bobPublicEncoded, bobIv );
74   *   aliceEncrypt = alice.getEncryptCipher();
75   *   aliceDecrypt = alice.getDecryptCipher();
76   *   
77   *   bobEncrypt = alice.getEncrypt();
78   *   bobDecrypt = alice.getDecrypt();
79   * </pre>
80   *
81   * @author      Robert Bushman
82   */
83  
84  public class CipherPartner {
85      
86      // -----------------------------------------------------------
87      // CONSTANTS
88      // -----------------------------------------------------------
89      
90      public static final BigInteger TEST_G = new BigInteger
91          ("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676" +
92           "ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08" +
93           "896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb04525" +
94           "0934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf",
95           16);
96      public static final BigInteger TEST_P = new BigInteger
97          ("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c" +
98           "451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f82" +
99           "4e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b1" +
100          "78cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7",
101          16);
102     public static final
103         DHParameterSpec TEST_PARAMS = new DHParameterSpec( TEST_P, TEST_G );
104     
105     public static final String PUBLIC_ALGORITHM = "DH";
106     public static final String PRIVATE_ALGORITHM = "Blowfish";
107     public static final String PRIVATE_TRANSFORM = "Blowfish/OFB8/NoPadding";
108     public static final String SHA1 = "SHA1";
109     public static final String DIGEST_ALGORITHM = SHA1;
110     
111     public static final String DEFAULT_PROVIDER_NAME = 
112         "org.bouncycastle.jce.provider.BouncyCastleProvider";
113     
114     // ----------------------------------------------------------
115     // CONSTRUCTORS AND INITIALIZERS
116     // ----------------------------------------------------------
117     
118     /**
119      * This is typically called by a parent process that is
120      * spawning a number of child processes, all of which
121      * share a common Diffie Hellman key set.
122      */
123     public CipherPartner( String name, CipherPartner copyFrom ) {
124         KeyAgreement            dhKeyAgree;
125         
126         try {
127             setName( name );
128             setDhKeyPair( copyFrom.getDhKeyPair() );
129             dhKeyAgree = KeyAgreement.getInstance( PUBLIC_ALGORITHM );
130             dhKeyAgree.init( getDhKeyPair().getPrivate() );
131             setDhKeyAgree( dhKeyAgree );
132         } catch( Exception e ) {
133             e.printStackTrace();
134             System.exit( 1 );
135         }
136     }
137     
138     /**
139      * This is the first partner initialized. It does not require
140      * a partner public key because it is the first partner. The
141      * other partner *must* be instantiated with this partner's
142      * public key.
143      */
144     public CipherPartner( String name, DHParameterSpec dhParams ) {
145         KeyPairGenerator        dhKeyPairGen;
146         KeyPair                 dhKeyPair;
147         KeyAgreement            dhKeyAgree;
148         
149         setName( name );
150         try {
151             dhKeyAndAgree( dhParams );
152         } catch( Exception e ) {
153             e.printStackTrace();
154             System.exit( 1 );
155         }
156     }
157     
158     public CipherPartner( String name,
159                           DHPublicKey pubKey,
160                           DHPrivateKey privKey ) {
161         
162         KeyPair                 dhKeyPair;
163         KeyAgreement            dhKeyAgree;
164         
165         setName( name );
166         try {
167             dhKeyPair = new KeyPair( pubKey, privKey );
168             dhKeyAgree = KeyAgreement.getInstance( PUBLIC_ALGORITHM );
169             dhKeyAgree.init( dhKeyPair.getPrivate() );
170             
171             setDhKeyPair( dhKeyPair );
172             setDhKeyAgree( dhKeyAgree );
173             
174             System.out.println( "Partner Inititalized From Keys" );
175         } catch( Exception e ) {
176             e.printStackTrace();
177             System.exit( 1 );
178         }
179     }
180     
181     public CipherPartner( String name,
182                           String pubKeyFile,
183                           String privKeyFile )
184         throws FileNotFoundException,
185                SecurityException,
186                IOException,
187                InvalidKeyException,
188                InvalidKeySpecException {
189         
190         FileInputStream         pubIn;
191         FileInputStream         privIn;
192         DHPublicKey             pubKey;
193         DHPrivateKey            privKey;
194         KeyPair                 dhKeyPair;
195         KeyAgreement            dhKeyAgree;
196         
197         try {
198             pubIn = new FileInputStream( pubKeyFile );
199             privIn = new FileInputStream( privKeyFile );
200             pubKey = DHUtil.pubKeyFromBase16( pubIn );
201             privKey = DHUtil.privKeyFromBase16( privIn );
202             dhKeyPair = new KeyPair( pubKey, privKey );
203             dhKeyAgree = KeyAgreement.getInstance( PUBLIC_ALGORITHM );
204             dhKeyAgree.init( dhKeyPair.getPrivate() );
205             
206             setDhKeyPair( dhKeyPair );
207             setDhKeyAgree( dhKeyAgree );
208             setName( name );
209         } catch( NoSuchAlgorithmException e ) {
210             e.printStackTrace();
211             System.out.println
212                 ( "JCE Provider Not Set Or Diffie Hellman Unavailable" );
213             System.out.println
214                 ( "Make sure you have Bouncy Castle installed properly." );
215             System.out.println
216                 ( "Make sure all Bouncy Castle jars are in your classpath." );
217             System.exit( 1 );
218         }
219         
220         System.out.println( "Partner Inititalized From Keys" );
221     }
222     
223     // ----------------------------------------------------------
224     // PUBLIC API
225     // ----------------------------------------------------------
226     
227     /**
228      * This is used when an IV has not yet been generated.
229      * This is the first partner to receive the other partner's
230      * key.
231      */
232     public void initFromPartner( byte[] partnerPublicEncoded )
233         throws InvalidKeyException,
234                InvalidKeySpecException,
235                InvalidAlgorithmParameterException {
236         
237         
238         KeyFactory              dhKeyFac;
239         X509EncodedKeySpec      partner509;
240         DHPublicKey             partnerPublic;
241         DHParameterSpec         partnerDhSpec;
242         
243         SecretKey               blowfishKey;
244         Cipher                  decryptCipher;
245         Cipher                  encryptCipher;
246         byte[]                  iv;
247         IvParameterSpec         ivSpec;
248         
249         try {
250             dhKeyFac = KeyFactory.getInstance( PUBLIC_ALGORITHM );
251             partner509 = new X509EncodedKeySpec( partnerPublicEncoded );
252             partnerPublic = (DHPublicKey)dhKeyFac.generatePublic( partner509 );
253             
254             getDhKeyAgree().doPhase( partnerPublic, true );
255             
256             blowfishKey = getDhKeyAgree().generateSecret( PRIVATE_ALGORITHM );
257             decryptCipher = Cipher.getInstance( PRIVATE_TRANSFORM );
258             encryptCipher = Cipher.getInstance( PRIVATE_TRANSFORM );
259             
260             encryptCipher.init( Cipher.ENCRYPT_MODE, blowfishKey );
261             iv = encryptCipher.getIV();
262             ivSpec = new IvParameterSpec( iv );
263             decryptCipher.init( Cipher.DECRYPT_MODE, blowfishKey, ivSpec );
264             
265             setBlowfishKey( blowfishKey );
266             setEncryptCipher( encryptCipher );
267             setDecryptCipher( decryptCipher );
268             setIv( iv );
269         } catch( NoSuchAlgorithmException e ) {
270             e.printStackTrace();
271             System.exit( 1 );
272         } catch( NoSuchPaddingException e ) {
273             e.printStackTrace();
274             System.exit( 1 );
275         }
276     }
277     
278     public void initFromPartner( byte[] partnerPublicEncoded,
279                                  byte[] partnerIv )
280         throws InvalidKeyException,
281                InvalidAlgorithmParameterException,
282                InvalidKeySpecException {
283         IvParameterSpec         partnerIvSpec;
284         KeyFactory              keyFac;
285         X509EncodedKeySpec      partner509;
286         DHPublicKey             partnerPublic;
287         
288         SecretKey               blowfishKey;
289         Cipher                  encryptCipher;
290         Cipher                  decryptCipher;
291         
292         try {
293             partnerIvSpec = new IvParameterSpec( partnerIv );
294             
295             keyFac = KeyFactory.getInstance( PUBLIC_ALGORITHM );
296             partner509 = new X509EncodedKeySpec( partnerPublicEncoded );
297             partnerPublic = (DHPublicKey)keyFac.generatePublic( partner509 );
298             
299             getDhKeyAgree().doPhase( partnerPublic, true );
300             
301             blowfishKey = getDhKeyAgree().generateSecret( PRIVATE_ALGORITHM );
302             encryptCipher = Cipher.getInstance( PRIVATE_TRANSFORM );
303             decryptCipher = Cipher.getInstance( PRIVATE_TRANSFORM );
304             encryptCipher.init( Cipher.ENCRYPT_MODE, blowfishKey, partnerIvSpec );
305             decryptCipher.init( Cipher.DECRYPT_MODE, blowfishKey, partnerIvSpec );
306             
307             setBlowfishKey( blowfishKey );
308             setEncryptCipher( encryptCipher );
309             setDecryptCipher( decryptCipher );
310             setIv( partnerIv );
311         } catch( NoSuchAlgorithmException e ) {
312             e.printStackTrace();
313             System.exit( 1 );
314         } catch( NoSuchPaddingException e ) {
315             e.printStackTrace();
316             System.exit( 1 );
317         }
318     }
319     
320     // KEY EXPORT, TRANSFER AND AUTHENTICATION
321     
322     public String getPublicBase16() {
323         byte[] encoded = getPublicEncoded();
324         BigInteger bigInt = new BigInteger( encoded );
325         return( bigInt.toString( 16 ) );
326     }
327     
328     public String getPrivateBase16() {
329         byte[] encoded = getPrivateEncoded();
330         BigInteger bigInt = new BigInteger( encoded );
331         return( bigInt.toString( 16 ) );
332     }
333     
334     public String getPublicSha1Base16() {
335         byte[] sha1Bytes;
336         BigInteger bigInt;
337         
338         sha1Bytes = Sha1Util.getSha1( getPublicEncoded() );
339         bigInt = new BigInteger( sha1Bytes );
340         
341         return( bigInt.toString( 16 ) );
342     }
343     
344     public static boolean verify( String publicBase16, String sha1Base16 ) {
345         BigInteger publicBigInt;
346         
347         publicBigInt = new BigInteger( publicBase16, 16 );
348         return( Sha1Util.verify( publicBigInt.toByteArray(), sha1Base16 ) );
349     }
350     
351     public void exportDhKeys( String pubKeyFile,
352                               String privKeyFile,
353                               String pubSha1File )
354         throws FileNotFoundException, IOException, Exception {
355         
356         FileOutputStream pubOut;
357         FileOutputStream privOut;
358         FileOutputStream pubSha1Out;
359         
360         pubOut = new FileOutputStream( pubKeyFile );
361         privOut = new FileOutputStream( privKeyFile );
362         pubSha1Out = new FileOutputStream( pubSha1File );
363         pubOut.write( getPublicBase16().getBytes() );
364         privOut.write( getPrivateBase16().getBytes() );
365         pubSha1Out.write( getPublicSha1Base16().getBytes() );
366     }
367     
368     // ---------------------------------------------------------
369     // INTERNAL API
370     // ---------------------------------------------------------
371     
372     protected void dhKeyAndAgree( DHParameterSpec dhSpec )
373         throws InvalidAlgorithmParameterException {
374         KeyPairGenerator        dhKeyPairGen;
375         KeyPair                 dhKeyPair;
376         KeyAgreement            dhKeyAgree;
377         
378         try {
379             dhKeyPairGen = KeyPairGenerator.getInstance( PUBLIC_ALGORITHM );
380             dhKeyPairGen.initialize( dhSpec );
381             dhKeyPair = dhKeyPairGen.generateKeyPair();
382             dhKeyAgree = KeyAgreement.getInstance( PUBLIC_ALGORITHM );
383             dhKeyAgree.init( dhKeyPair.getPrivate() );
384             
385             setDhKeyPair( dhKeyPair );
386             setDhKeyAgree( dhKeyAgree );
387         } catch( NoSuchAlgorithmException e ) {
388             e.printStackTrace();
389             System.exit( 1 );
390         } catch( InvalidKeyException e ) {
391             e.printStackTrace();
392             System.err.println( "This should never happen" );
393             System.exit( 1 );
394         }
395     }
396     
397     // -----------------------------------------------------------
398     // INSTANCE PARAMETERS AND ACCESSORS
399     // ----------------------------------------------------------
400     
401     // PARAMETERS
402     private String _name;
403     private KeyPair _dhKeyPair;
404     private KeyAgreement _dhKeyAgree;
405     private SecretKey _blowfishKey;
406     private Cipher _encryptCipher;
407     private Cipher _decryptCipher;
408     private byte[] _iv;
409     
410     // SETTERS
411     protected void setName( String name ) { _name = name; }
412     protected void setDhKeyPair( KeyPair dhKeyPair ) { _dhKeyPair = dhKeyPair; }
413     protected void setDhKeyAgree( KeyAgreement dhKeyAgree ) {
414         _dhKeyAgree = dhKeyAgree;
415     }
416     protected void setBlowfishKey( SecretKey blowfishKey ) {
417         _blowfishKey = blowfishKey;
418     }
419     protected void setEncryptCipher( Cipher encryptCipher ) {
420         _encryptCipher = encryptCipher;
421     }
422     protected void setDecryptCipher( Cipher decryptCipher ) {
423         _decryptCipher = decryptCipher;
424     }
425     protected void setIv( byte[] iv ) { _iv = iv; }
426     
427     // GETTERS
428     protected KeyPair getDhKeyPair() { return( _dhKeyPair ); }
429     protected KeyAgreement getDhKeyAgree() { return( _dhKeyAgree ); }
430     protected SecretKey getBlowfishKey() { return( _blowfishKey ); }
431     
432     public String getName() { return( _name ); }
433     public Cipher getEncryptCipher() { return( _encryptCipher ); }
434     public Cipher getDecryptCipher() { return( _decryptCipher ); }
435     public byte[] getIv() { return( _iv ); }
436     
437     // CONVENIENCE METHODS
438     public byte[] getPublicEncoded() {
439         return( getDhKeyPair().getPublic().getEncoded() );
440     }
441     public byte[] getPrivateEncoded() {
442         return( getDhKeyPair().getPrivate().getEncoded() );
443     }
444     
445     // ----------------------------------------------------------
446     // RUNTIME
447     // ----------------------------------------------------------
448     
449     public static void main( String[] args ) throws Exception  {
450         CipherPartner alice;
451         CipherPartner bob;
452         
453         byte[] alicePublicEncoded;
454         byte[] bobPublicEncoded;
455         byte[] bobIv;
456         
457         CryptoUtil.initializeProvider();
458         
459         alice = new CipherPartner( "ALICE", CipherPartner.TEST_PARAMS );
460         bob = new CipherPartner( "BOB", CipherPartner.TEST_PARAMS );
461         
462         // transmit alicePublicEncoded to bob
463         alicePublicEncoded = alice.getPublicEncoded();
464         bob.initFromPartner( alicePublicEncoded );
465         
466         // transmit bobPublicEncoded and bobIV to alice
467         bobPublicEncoded = bob.getPublicEncoded();
468         bobIv = bob.getIv();
469         
470         alice.initFromPartner( bobPublicEncoded, bobIv );
471         
472         System.out.println
473             ( "Stream Test: " + CryptoUtil.streamTest
474               ( alice.getEncryptCipher(), bob.getDecryptCipher() ) );
475         System.out.println
476             ( "Stream Test: " + CryptoUtil.streamTest
477               ( bob.getEncryptCipher(), alice.getDecryptCipher() ) );
478         
479         System.out.println( "Alice Pub Hex\n" + alice.getPublicBase16() );
480         System.out.println( "Alice Priv Hex\n" + alice.getPrivateBase16() );
481         System.out.println( "Alice Sha1 Hex\n" + alice.getPublicSha1Base16() );
482         System.out.println
483             ( "Verify: " + Sha1Util.verify( alice.getPublicEncoded(),
484                                             alice.getPublicSha1Base16() ) );
485         
486         System.out.println( "Bob Pub Hex\n" + bob.getPublicBase16() );
487         System.out.println( "Bob Priv Hex\n" + bob.getPrivateBase16() );
488         System.out.println( "Bob Sha1 Hex\n" + bob.getPublicSha1Base16() );
489         System.out.println
490             ( "Verify: " + Sha1Util.verify( bob.getPublicEncoded(),
491                                             bob.getPublicSha1Base16() ) );
492         
493         System.out.println
494             ( "Cross Verify (should fail): "
495               + Sha1Util.verify( bob.getPublicEncoded(),
496                                  alice.getPublicSha1Base16() ) );
497     }
498 }