KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jgroups > protocols > ENCRYPT


1
2
3 //$Id: ENCRYPT.java,v 1.8 2005/04/11 14:34:13 steview Exp $
4

5 package org.jgroups.protocols;
6
7 import java.io.IOException JavaDoc;
8 import java.io.InputStream JavaDoc;
9 import java.security.InvalidKeyException JavaDoc;
10 import java.security.KeyFactory JavaDoc;
11 import java.security.KeyPair JavaDoc;
12 import java.security.KeyPairGenerator JavaDoc;
13 import java.security.KeyStore JavaDoc;
14 import java.security.KeyStoreException JavaDoc;
15 import java.security.MessageDigest JavaDoc;
16 import java.security.NoSuchAlgorithmException JavaDoc;
17 import java.security.PublicKey JavaDoc;
18 import java.security.SecureRandom JavaDoc;
19 import java.security.UnrecoverableKeyException JavaDoc;
20 import java.security.cert.CertificateException JavaDoc;
21 import java.security.spec.X509EncodedKeySpec JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.Properties JavaDoc;
24 import java.util.WeakHashMap JavaDoc;
25
26 import javax.crypto.BadPaddingException;
27 import javax.crypto.Cipher;
28 import javax.crypto.IllegalBlockSizeException;
29 import javax.crypto.KeyGenerator;
30 import javax.crypto.NoSuchPaddingException;
31 import javax.crypto.SecretKey;
32 import javax.crypto.spec.SecretKeySpec;
33
34 import org.jgroups.Address;
35 import org.jgroups.Event;
36 import org.jgroups.Message;
37 import org.jgroups.View;
38 import org.jgroups.stack.Protocol;
39 import org.jgroups.util.QueueClosedException;
40
41 import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;
42
43
44 /**
45 * ENCRYPT layer. Encrypt and decrypt the group communication in JGroups
46 *
47 * The file can be used in two ways:
48 * <ul>
49 * <li> Option 1. Configured with a secretKey in a keystore so it can be used at any
50 * layer in JGroups without the need for a coordinator, or if you want protection against passive
51 * monitoring but do not want the key exchange overhead and complexity. In this mode all nodes must be distributed with
52 * the same keystore file.
53 * <li> Option 2. Configured with algorithms and key sizes. The Encrypt Layer in this mode sould be used between the
54 * FRAG and PBCast layers in the stack. The coordinator then chooses the
55 * secretkey which it distributes amongst all the peers. In this form no keystore exists as the keys are
56 * distributed using a public/private key exchange. View changes that identify a new controller will result in a new session key
57 * being generated and then distributed to all peers. This overhead can be substantial in a an application with
58 * a reasonable peer churn.
59 * </ul>
60 * <p>
61 * <p>
62 * Each message is identified as encrypted with a specific encryption header which identifies
63 * the type of encrypt header and an MD5 digest that identifies the version of the key being used
64 * to encrypt/decrypt the messages.
65 * <p>
66 * <p>
67 *<h2>Option 1</h2><br>
68 * This is the simplest option and can be used by simply inserting the Encryption layer
69 * at any point in the JGroup stack - it will encrypt all Events of a type MSG that
70 * have a non-null message buffer. The format of the entry in this form is:<br>
71 * &lt;ENCRYPT key_store_name="defaultStore.keystore" store_password="changeit" alias="myKey"/&gt;<br>
72 * An example bare-bones.xml file showing the keystore version can be found in the conf
73 * ina file called EncryptKeyStore.xml - along with a defaultStore.keystore file.<br>
74 * In order to use the Encrypt layer in this manner it is necessary to have the secretKey already generated
75 * in a keystore file. The directory containing the keystore file must be on the application's classpath.
76 * You cannot create a SecretKey keystore file using the keytool application shipped with the JDK.
77 * A java file called KeyStoreGenerator is included in the demo
78 * package that can be used from the command line (or IDE) to generate a suitable keystore.
79 * <p>
80 * <p>
81 *<h2>Option 2</h2><br>
82 * This option is suited to an application that does not ship with a known key but instead it is generated
83 * and distributed by the controller. The secret key is first generated by the Controller (in JGroup terms). When a view change
84 * occurs a peer will request the secret key by sending a key request with its own public key. The controller
85 * encrypts the secret key with this key and sends it back to the peer who then decrypts it and installs the
86 * key as its own secret key.
87 * <br>All encryption and decryption of Messages is done using this key. When a peer receives
88 * a view change that shows a different keyserver it will repeat this process - the view change event
89 * also trigger the encrypt layer to queue up and down messages until the new key is installed.
90 * The previous keys are retained so that messages sent before the view change that are queued can be decrypted
91 * if the key is different.
92 * <br>
93 * An example EncryptNoKeyStore.xml is included in the conf file as a guide.
94 * <p><p>
95 * <br> Note: the current version does not support the concept of perfect forward encryption (PFE)
96 * which means that if a peer leaves the group the keys are re-generated preventing the departed peer from
97 * decrypting future messages if it chooses to listen in on the group. This is not included as it really requires
98 * a suitable authentication scheme as well to make this feature useful as there is nothing to stop the peer rejoining and receiving the new
99 * key. A future release will address this issue.
100 *
101 * @author Steve Woodcock
102 */

103
104
105 public class ENCRYPT extends Protocol {
106
107     public static class EncryptHeader extends org.jgroups.Header {
108         int type;
109         public static final int ENCRYPT = 0;
110         public static final int KEY_REQUEST = 1;
111         public static final int SERVER_PUBKEY = 2;
112         public static final int SECRETKEY = 3;
113         public static final int SECRETKEY_READY = 4;
114
115         // adding key for Message object purpose
116
static final String JavaDoc KEY = "encrypt";
117
118         String JavaDoc version;
119
120
121         public EncryptHeader()
122         {
123             //this(type, 0l);
124
}
125
126
127         public EncryptHeader(int type)
128         {
129             //this(type, 0l);
130
this.type = type;
131             this.version = "";
132         }
133
134
135         public EncryptHeader(int type, String JavaDoc version)
136         {
137             this.type = type;
138             this.version = version;
139         }
140
141
142         public void writeExternal(java.io.ObjectOutput JavaDoc out) throws IOException JavaDoc
143         {
144             out.writeInt(type);
145             out.writeObject(version);
146         }
147
148
149         public void readExternal(java.io.ObjectInput JavaDoc in) throws IOException JavaDoc,
150                 ClassNotFoundException JavaDoc
151         {
152             //System.out.println("reading in int");
153
type = in.readInt();
154             //System.out.println("reading in long");
155
version = (String JavaDoc)in.readObject();
156         }
157
158
159         public String JavaDoc toString()
160         {
161             return "{ENCTYPT:[Type:" + type + " Version:" + version + "]}";
162             // return "{ENCTYPT:[Type:"+type + "]";
163
}
164
165
166         /*
167          * (non-Javadoc)
168          *
169          * @see java.lang.Object#equals(java.lang.Object)
170          */

171         public boolean equals(Object JavaDoc obj)
172         {
173             // TODO Auto-generated method stub
174
if (obj instanceof EncryptHeader)
175             {
176                 boolean res = ((((EncryptHeader) obj).getType() == type) && ((((EncryptHeader) obj)
177                         .getVersion() == version)));
178                 return res;
179             }
180             return false;
181         }
182
183
184         /**
185          * @return Returns the type.
186          */

187         protected int getType()
188         {
189             return type;
190         }
191
192
193         /**
194          * @return Returns the version.
195          */

196         protected String JavaDoc getVersion()
197         {
198             return version;
199         }
200
201     }
202
203     // address info
204
Address local_addr = null;
205     // keyserver address
206
Address keyServerAddr = null;
207
208     //used to see whether we are the key server
209
boolean keyServer = false;
210
211     // encryption properties in no supplied key mode
212
String JavaDoc asymProvider = null;
213     final String JavaDoc symProvider = null;
214     String JavaDoc asymAlgorithm = "RSA";
215     String JavaDoc symAlgorithm = "Blowfish";
216     int asymInit = 512; // initial public/private key length
217
int symInit = 56; // initial shared key length
218

219     // properties for functioning in supplied key mode
220
private boolean suppliedKey = false;
221     private String JavaDoc keyStoreName;
222     private String JavaDoc storePassword ="changeit"; //JDK default
223
private String JavaDoc keyPassword="changeit"; //JDK default
224
private String JavaDoc alias="mykey"; // JDK default
225

226     
227     // public/private Key
228
KeyPair JavaDoc Kpair; // to store own's public/private Key
229

230 // for client to store server's public Key
231
PublicKey JavaDoc serverPubKey = null;
232
233     // needed because we do simultaneous encode/decode with these ciphers - which
234
// would be a threading issue
235
Cipher symEncodingCipher;
236     Cipher symDecodingCipher;
237
238     // version filed for secret key
239
private String JavaDoc symVersion = null;
240     // dhared secret key to encrypt/decrypt messages
241
SecretKey secretKey = null;
242     
243     // map to hold previous keys so we can decrypt some earlier messages if we need to
244
final Map JavaDoc keyMap = new WeakHashMap JavaDoc();
245     // locks for queue access
246
final Object JavaDoc downLock = new Object JavaDoc();
247     final Object JavaDoc upLock = new Object JavaDoc();
248
249     // queues to buffer data while we are swapping shared key
250
// or obtsining key for first time
251

252     private boolean queue_up = true;
253     
254     private boolean queue_down = true;
255     
256     // queue to hold upcoming messages while key negotiation is happening
257
private LinkedQueue upMessageQueue = new LinkedQueue();
258     
259 // queue to hold downcoming messages while key negotiation is happening
260
private LinkedQueue downMessageQueue = new LinkedQueue();
261     // decrypting cypher for secret key requests
262
private Cipher asymCipher;
263     
264     public ENCRYPT()
265     {
266     }
267
268
269     public String JavaDoc getName()
270     {
271         return "ENCRYPT";
272     }
273
274
275     /*
276      * GetAlgorithm: Get the algorithm name from "algorithm/mode/padding"
277      * taken from original ENCRYPT file
278      */

279     private String JavaDoc getAlgorithm(String JavaDoc s)
280     {
281         int index = s.indexOf("/");
282         if (index == -1)
283             return s;
284
285         return s.substring(0, index);
286     }
287
288
289     public boolean setProperties(Properties JavaDoc props)
290     {
291         String JavaDoc str;
292
293         super.setProperties(props);
294         // asymmetric key length
295
str = props.getProperty("asym_init");
296         if (str != null)
297         {
298             asymInit = Integer.parseInt(str);
299             props.remove("asym_init");
300
301             if (log.isInfoEnabled())
302                 log.info("Asym algo bits used is " + asymInit);
303         }
304
305         // symmetric key length
306
str = props.getProperty("sym_init");
307         if (str != null)
308         {
309             symInit = Integer.parseInt(str);
310             props.remove("sym_init");
311
312             if (log.isInfoEnabled())
313                 log.info("Sym algo bits used is " + symInit);
314         }
315
316         // asymmetric algorithm name
317
str = props.getProperty("asym_algorithm");
318         if (str != null)
319         {
320             asymAlgorithm = str;
321             props.remove("asym_algorithm");
322
323             if (log.isInfoEnabled())
324                 log.info("Asym algo used is " + asymAlgorithm);
325         }
326
327         // symmetric algorithm name
328
str = props.getProperty("sym_algorithm");
329         if (str != null)
330         {
331             symAlgorithm = str;
332             props.remove("sym_algorithm");
333
334             if (log.isInfoEnabled())
335                 log.info("Sym algo used is " + symAlgorithm);
336         }
337
338         // symmetric algorithm name
339
str = props.getProperty("asym_provider");
340         if (str != null)
341         {
342             asymProvider = str;
343             props.remove("asym_provider");
344
345             if (log.isInfoEnabled())
346                 log.info("asymProvider used is " + asymProvider);
347         }
348
349         //symmetric algorithm name
350
str = props.getProperty("key_store_name");
351         if (str != null)
352         {
353             keyStoreName = str;
354             props.remove("key_store_name");
355
356             if (log.isInfoEnabled())
357                 log.info("key_store_name used is " + keyStoreName);
358         }
359
360         // symmetric algorithm name
361
str = props.getProperty("store_password");
362         if (str != null)
363         {
364             storePassword = str;
365             props.remove("store_password");
366
367             if (log.isInfoEnabled())
368                 log.info("store_password used is not null");
369         }
370
371         // symmetric algorithm name
372
str = props.getProperty("key_password");
373         if (str != null)
374         {
375             keyPassword = str;
376             props.remove("key_password");
377
378             if (log.isInfoEnabled())
379                 log.info("key_password used is not null");
380         } else if (storePassword != null)
381         {
382             keyPassword = storePassword;
383
384             if (log.isInfoEnabled())
385                 log.info("key_password used is same as store_password");
386         }
387
388         // symmetric algorithm name
389
str = props.getProperty("alias");
390         if (str != null)
391         {
392             alias = str;
393             props.remove("alias");
394
395             if (log.isInfoEnabled())
396                 log.info("alias used is " + alias);
397         }
398
399         if (props.size() > 0)
400         {
401
402             if (log.isErrorEnabled())
403                 log.error("these properties are not recognized:" + props);
404             return false;
405         }
406
407         return true;
408     }
409
410
411     public void init() throws Exception JavaDoc
412     {
413         if (keyStoreName == null)
414         {
415             initSymKey();
416             initKeyPair();
417         } else
418         {
419             initConfiguredKey();
420         }
421         initSymCiphers(symAlgorithm, getSecretKey());
422     }
423
424
425     /**
426      * Initialisation if a supplied key is defined in the properties. This
427      * supplied key must be in a keystore which can be generated using the
428      * keystoreGenerator file in demos. The keystore must be on the classpath
429      * to find it.
430      *
431      * @throws KeyStoreException
432      * @throws Exception
433      * @throws IOException
434      * @throws NoSuchAlgorithmException
435      * @throws CertificateException
436      * @throws UnrecoverableKeyException
437      */

438     private void initConfiguredKey() throws KeyStoreException JavaDoc, Exception JavaDoc,
439             IOException JavaDoc, NoSuchAlgorithmException JavaDoc, CertificateException JavaDoc,
440             UnrecoverableKeyException JavaDoc
441     {
442         InputStream JavaDoc inputStream = null;
443         // must not use default keystore type - as does not support secret keys
444
KeyStore JavaDoc store = KeyStore.getInstance("JCEKS");
445         
446         SecretKey tempKey = null;
447         try
448         {
449             // load in keystore using this thread's classloader
450
inputStream = Thread.currentThread().getContextClassLoader()
451                     .getResourceAsStream(keyStoreName);
452             // we can't find a keystore here -
453
if (inputStream == null)
454             {
455                 throw new Exception JavaDoc("Unable to load keystore " + keyStoreName +
456                         " ensure file is on classpath");
457             }
458             // we have located a file lets load the keystore
459
try{
460             store.load(inputStream, storePassword.toCharArray());
461             // loaded keystore - get the key
462
tempKey = (SecretKey) store
463                     .getKey(alias, keyPassword.toCharArray());
464             } catch (IOException JavaDoc e){
465                 throw new Exception JavaDoc("Unable to load keystore "+ keyStoreName + ": " + e);
466             }catch (NoSuchAlgorithmException JavaDoc e){
467                 throw new Exception JavaDoc("No Such algorithm "+ keyStoreName + ": " + e);
468             }catch(CertificateException JavaDoc e){
469                 throw new Exception JavaDoc("Certificate exception "+ keyStoreName + ": " + e);
470             }
471             
472             if (tempKey == null)
473             {
474                 throw new Exception JavaDoc("Unable to retrieve key '" + alias
475                         + "' from keystore " + keyStoreName);
476             }
477             //set the key here
478
setSecretKey(tempKey);
479             symAlgorithm = tempKey.getAlgorithm();
480             
481             // set the fact we are using a supplied key
482

483             suppliedKey = true;
484             queue_down =false;
485             queue_up =false;
486         } finally
487         {
488             // close the input stream
489
try
490             {
491                 inputStream.close();
492             } catch (Exception JavaDoc e)
493             {
494
495             }
496         }
497
498     }
499
500
501     /**
502      * Used to initialise the symmetric key if none is supplied in a keystore.
503      * @throws Exception
504      */

505     public void initSymKey() throws Exception JavaDoc
506     {
507         KeyGenerator keyGen = null;
508         // see if we have a provider specified
509
if (symProvider != null && symProvider.trim().length() > 0)
510         {
511             keyGen = KeyGenerator.getInstance(getAlgorithm(symAlgorithm),
512                     symProvider);
513         } else
514         {
515             keyGen = KeyGenerator.getInstance(getAlgorithm(symAlgorithm));
516         }
517         // generate the key using the defined init properties
518
keyGen.init(symInit);
519         secretKey = keyGen.generateKey();
520         
521         setSecretKey(secretKey);
522
523         if (log.isInfoEnabled())
524             log.info(" Symmetric key generated ");
525     }
526
527
528     /**
529      * Initialises the Ciphers for both encryption and decryption using the
530      * generated or supplied secret key.
531      *
532      * @param algorithm
533      * @param secret
534      * @throws Exception
535      */

536     private void initSymCiphers(String JavaDoc algorithm, SecretKey secret) throws Exception JavaDoc
537     {
538         
539         if (log.isInfoEnabled())
540             log.info(" Initializing symmetric ciphers");
541         
542         symEncodingCipher = Cipher.getInstance(algorithm);
543         symDecodingCipher = Cipher.getInstance(algorithm);
544         symEncodingCipher.init(Cipher.ENCRYPT_MODE, secret);
545         symDecodingCipher.init(Cipher.DECRYPT_MODE, secret);
546         
547         //set the version
548
MessageDigest JavaDoc digest = MessageDigest.getInstance("MD5");
549         digest.reset();
550         digest.update(secret.getEncoded());
551          
552         symVersion = new String JavaDoc(digest.digest());
553         if (log.isInfoEnabled())
554             log.info(" Initialized symmetric ciphers with secret key version " +symVersion);
555     }
556
557
558     /**
559      * Generates the public/private key pair from the init params
560      * @throws Exception
561      */

562     public void initKeyPair() throws Exception JavaDoc
563     {
564         // generate keys according to the specified algorithms
565
// generate publicKey and Private Key
566
KeyPairGenerator JavaDoc KpairGen = null;
567         if (asymProvider != null && asymProvider.trim().length() > 0)
568         {
569             KpairGen = KeyPairGenerator.getInstance(
570                     getAlgorithm(asymAlgorithm), asymProvider);
571         } else
572         {
573             KpairGen = KeyPairGenerator
574                     .getInstance(getAlgorithm(asymAlgorithm));
575
576         }
577         KpairGen.initialize(asymInit, new SecureRandom JavaDoc());
578         Kpair = KpairGen.generateKeyPair();
579
580         // set up the Cipher to decrypt secret key responses encrypted with our key
581

582         asymCipher = Cipher.getInstance(asymAlgorithm);
583         asymCipher.init(Cipher.DECRYPT_MODE,Kpair.getPrivate());
584
585         if (log.isInfoEnabled())
586             log.info(" asym algo initialized");
587     }
588
589
590     /** Just remove if you don't need to reset any state */
591     public void reset()
592     {
593     }
594
595
596     /* (non-Javadoc)
597      * @see org.jgroups.stack.Protocol#up(org.jgroups.Event)
598      */

599     public void up(Event evt)
600     {
601
602         if (log.isDebugEnabled())
603         {
604             log.debug("Event going up is " + evt);
605         }
606         
607         switch (evt.getType()) {
608
609             // we need to know what our address is
610
case Event.SET_LOCAL_ADDRESS :
611                 if (log.isDebugEnabled())
612                     log.debug("Set local address ");
613                 local_addr = (Address) evt.getArg();
614                 break;
615                 // used to log out whether we are the key server
616
case Event.FIND_INITIAL_MBRS_OK :
617                 if (!suppliedKey){
618                     if (!keyServer)
619                     {
620                         if (log.isInfoEnabled())
621                             log.info("FIND_INIT_MBRS_OK called - I am not the keyserver");
622                     } else
623                     {
624                         if (log.isInfoEnabled())
625                             log.info("FIND_INIT_MBRS_OK called -I am keyserver ");
626                     }
627                 }
628                 break;
629                 // the event used to control the key exchange
630
case Event.VIEW_CHANGE:
631                 if (log.isInfoEnabled())
632                     log.info("handling view change event");
633                 if (!suppliedKey){
634                     handleViewChange(evt);
635                 }
636                 break;
637             // we try and decrypt all messages
638
case Event.MSG :
639                 // if empty just pass up
640
if (evt.getArg() == null || ((Message)evt.getArg()).getBuffer() == null){
641                     if (log.isDebugEnabled())
642                         log.debug("passing up message as is empty buffer ");
643                     break;
644                 }
645                 // try and handle message
646
try
647                 {
648                     
649                         handleUpMessage(evt);
650                     
651                 } catch (Exception JavaDoc e)
652                 {
653                     log.warn("Exception occurred decrypting up message",e);
654                 }
655                 return;
656             default :
657                 break;
658         }
659         
660         if (log.isDebugEnabled())
661             log.debug("passing event up " +evt);
662         passUp(evt);
663         return;
664     }
665
666
667     private synchronized void handleViewChange(Event evt){
668         View view = (View)evt.getArg();
669         
670         // if view is a bit broken set me as keyserver
671
if (view.getMembers() == null || view.getMembers().get(0) == null){
672             becomeKeyServer(local_addr);
673             return;
674         }
675         // otherwise get keyserver from view controller
676
Address tmpKeyServer = (Address)view.getMembers().get(0);
677         
678         //I am new keyserver - either first member of group or old key server is no more and
679
// I have been voted new controller
680
if (tmpKeyServer.equals(local_addr) && (keyServerAddr == null || (! tmpKeyServer.equals(keyServerAddr)))){
681             becomeKeyServer(tmpKeyServer);
682             // a new keyserver has been set and it is not me
683
}else if (keyServerAddr == null || (! tmpKeyServer.equals(keyServerAddr))){
684             handleNewKeyServer(tmpKeyServer);
685         } else{
686             if (log.isDebugEnabled())
687                 log.debug("Membership has changed but I do not care");
688         }
689         
690
691     }
692     
693     /**
694      * Handles becoming server - resetting queue settings
695      * and setting keyserver address to be local address.
696      *
697      * @param tmpKeyServer
698      */

699     private void becomeKeyServer(Address tmpKeyServer){
700         keyServerAddr = tmpKeyServer;
701         keyServer =true;
702         if (log.isInfoEnabled())
703             log.info("I have become key server " + keyServerAddr);
704         queue_down = false;
705         queue_up = false;
706     }
707     
708     /**
709      * Sets up the peer for a new keyserver - this is
710      * setting queueing to buffer messages until we have a new
711      * secret key from the key server and sending a key request
712      * to the new keyserver.
713      *
714      * @param newKeyServer
715      */

716     private void handleNewKeyServer(Address newKeyServer){
717         // start queueing until we have new key
718
// to make sure we are not sending with old key
719
queue_up =true;
720         queue_down = true;
721         // set new keyserver address
722
keyServerAddr = newKeyServer;
723         keyServer =false;
724         if (log.isInfoEnabled())
725             log.info("Sending key request");
726         
727         // create a key request message
728
sendKeyRequest();
729         
730         
731     }
732
733     /**
734      * @param evt
735      */

736     private void handleUpMessage(Event evt) throws Exception JavaDoc
737     {
738         if (log.isDebugEnabled())
739             log.debug("Handling up message " + evt);
740
741         Message msg = (Message) evt.getArg();
742
743         if (msg == null)
744         {
745             if (log.isDebugEnabled())
746                 log.debug("Null message - passing straight up");
747             passUp(evt);
748             return;
749         }
750
751         Object JavaDoc obj = msg.getHeader(EncryptHeader.KEY);
752
753         // try and get the encryption header
754
if (obj == null || !(obj instanceof EncryptHeader))
755         {
756             if (log.isInfoEnabled())
757                 log.info("Dropping message as ENCRYPT header is null or has not been recognized, msg will not be passed up");
758             return;
759         }
760
761         EncryptHeader hdr = (EncryptHeader) obj;
762
763         
764         if (log.isDebugEnabled())
765             log.debug("Header received " + hdr);
766
767         // if a normal message try and decrypt it
768
if (hdr.getType() == EncryptHeader.ENCRYPT)
769         {
770             // if queueing then pass into queue to be dealt with later
771
if (queue_up){
772                 if (log.isDebugEnabled())
773                     log.debug("queueing up message as no session key established");
774                     upMessageQueue.put(evt);
775             }else{
776                 // make sure we pass up any queued messages first
777
// could be more optimised but this can wait
778
// we only need this if not using supplied key
779
if (!suppliedKey) {
780                     drainUpQueue();
781                 }
782                 // try and decrypt the message
783
Message tmpMsg =decryptMessage(symDecodingCipher, msg);
784                 if (tmpMsg != null){
785                     //log.info("normal message passup " + msg);
786
passUp(evt);
787                 } else {
788                     log.warn("Unrecognised cipher discarding message");
789                 }
790             }
791         } else
792         {
793             // check if we had some sort of encrypt control
794
// header if using supplied key we should not
795
// process it
796
if (suppliedKey)
797             {
798                 if (log.isWarnEnabled())
799                 {
800                     log.warn("We received an encrypt header of "
801                             + hdr.getType() + " while in configured mode");
802                 }
803             } else{
804                 // see what sort of encrypt control message we
805
// have received
806
switch (hdr.getType()){
807                     // if a key request
808
case EncryptHeader.KEY_REQUEST:
809                         if (log.isInfoEnabled()) {
810                             log.info("received a key request from peer");
811                         }
812                         
813                         //if a key request send response key back
814
try {
815                             // extract peer's public key
816
PublicKey JavaDoc tmpKey = generatePubKey(msg.getBuffer());
817                             // send back the secret key we have
818
sendSecretKey(getSecretKey(), tmpKey, msg.getSrc());
819                         } catch (Exception JavaDoc e){
820                             log.warn("unable to reconstitute peer's public key");
821                         }
822                         break;
823                     case EncryptHeader.SECRETKEY:
824                         if (log.isInfoEnabled()) {
825                             log.info("received a secretkey response from keyserver");
826                         }
827                         
828                         try {
829                             SecretKey tmp = decodeKey(msg.getBuffer());
830                             if (tmp == null) {
831                                 // unable to understand response
832
// lets try again
833
sendKeyRequest();
834                             }else{
835                                 // otherwise lets set the reurned key
836
// as the shared key
837
setKeys(tmp, hdr.getVersion());
838                                 if (log.isInfoEnabled()) {
839                                     log.info("Decoded secretkey response");
840                                 }
841                             }
842                         } catch (Exception JavaDoc e){
843                             log.warn("unable to process received public key");
844                             log.fatal(e);
845                         }
846                        &n