| 1 2 3 5 package org.jgroups.protocols; 6 7 import java.io.IOException ; 8 import java.io.InputStream ; 9 import java.security.InvalidKeyException ; 10 import java.security.KeyFactory ; 11 import java.security.KeyPair ; 12 import java.security.KeyPairGenerator ; 13 import java.security.KeyStore ; 14 import java.security.KeyStoreException ; 15 import java.security.MessageDigest ; 16 import java.security.NoSuchAlgorithmException ; 17 import java.security.PublicKey ; 18 import java.security.SecureRandom ; 19 import java.security.UnrecoverableKeyException ; 20 import java.security.cert.CertificateException ; 21 import java.security.spec.X509EncodedKeySpec ; 22 import java.util.Map ; 23 import java.util.Properties ; 24 import java.util.WeakHashMap ; 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 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 static final String KEY = "encrypt"; 117 118 String version; 119 120 121 public EncryptHeader() 122 { 123 } 125 126 127 public EncryptHeader(int type) 128 { 129 this.type = type; 131 this.version = ""; 132 } 133 134 135 public EncryptHeader(int type, String version) 136 { 137 this.type = type; 138 this.version = version; 139 } 140 141 142 public void writeExternal(java.io.ObjectOutput out) throws IOException  143 { 144 out.writeInt(type); 145 out.writeObject(version); 146 } 147 148 149 public void readExternal(java.io.ObjectInput in) throws IOException , 150 ClassNotFoundException  151 { 152 type = in.readInt(); 154 version = (String )in.readObject(); 156 } 157 158 159 public String toString() 160 { 161 return "{ENCTYPT:[Type:" + type + " Version:" + version + "]}"; 162 } 164 165 166 171 public boolean equals(Object obj) 172 { 173 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 187 protected int getType() 188 { 189 return type; 190 } 191 192 193 196 protected String getVersion() 197 { 198 return version; 199 } 200 201 } 202 203 Address local_addr = null; 205 Address keyServerAddr = null; 207 208 boolean keyServer = false; 210 211 String asymProvider = null; 213 final String symProvider = null; 214 String asymAlgorithm = "RSA"; 215 String symAlgorithm = "Blowfish"; 216 int asymInit = 512; int symInit = 56; 219 private boolean suppliedKey = false; 221 private String keyStoreName; 222 private String storePassword ="changeit"; private String keyPassword="changeit"; private String alias="mykey"; 226 227 KeyPair Kpair; 230 PublicKey serverPubKey = null; 232 233 Cipher symEncodingCipher; 236 Cipher symDecodingCipher; 237 238 private String symVersion = null; 240 SecretKey secretKey = null; 242 243 final Map keyMap = new WeakHashMap (); 245 final Object downLock = new Object (); 247 final Object upLock = new Object (); 248 249 252 private boolean queue_up = true; 253 254 private boolean queue_down = true; 255 256 private LinkedQueue upMessageQueue = new LinkedQueue(); 258 259 private LinkedQueue downMessageQueue = new LinkedQueue(); 261 private Cipher asymCipher; 263 264 public ENCRYPT() 265 { 266 } 267 268 269 public String getName() 270 { 271 return "ENCRYPT"; 272 } 273 274 275 279 private String getAlgorithm(String 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 props) 290 { 291 String str; 292 293 super.setProperties(props); 294 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 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 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 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 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 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 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 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 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  412 { 413 if (keyStoreName == null) 414 { 415 initSymKey(); 416 initKeyPair(); 417 } else 418 { 419 initConfiguredKey(); 420 } 421 initSymCiphers(symAlgorithm, getSecretKey()); 422 } 423 424 425 438 private void initConfiguredKey() throws KeyStoreException , Exception , 439 IOException , NoSuchAlgorithmException , CertificateException , 440 UnrecoverableKeyException  441 { 442 InputStream inputStream = null; 443 KeyStore store = KeyStore.getInstance("JCEKS"); 445 446 SecretKey tempKey = null; 447 try 448 { 449 inputStream = Thread.currentThread().getContextClassLoader() 451 .getResourceAsStream(keyStoreName); 452 if (inputStream == null) 454 { 455 throw new Exception ("Unable to load keystore " + keyStoreName + 456 " ensure file is on classpath"); 457 } 458 try{ 460 store.load(inputStream, storePassword.toCharArray()); 461 tempKey = (SecretKey) store 463 .getKey(alias, keyPassword.toCharArray()); 464 } catch (IOException e){ 465 throw new Exception ("Unable to load keystore "+ keyStoreName + ": " + e); 466 }catch (NoSuchAlgorithmException e){ 467 throw new Exception ("No Such algorithm "+ keyStoreName + ": " + e); 468 }catch(CertificateException e){ 469 throw new Exception ("Certificate exception "+ keyStoreName + ": " + e); 470 } 471 472 if (tempKey == null) 473 { 474 throw new Exception ("Unable to retrieve key '" + alias 475 + "' from keystore " + keyStoreName); 476 } 477 setSecretKey(tempKey); 479 symAlgorithm = tempKey.getAlgorithm(); 480 481 483 suppliedKey = true; 484 queue_down =false; 485 queue_up =false; 486 } finally 487 { 488 try 490 { 491 inputStream.close(); 492 } catch (Exception e) 493 { 494 495 } 496 } 497 498 } 499 500 501 505 public void initSymKey() throws Exception  506 { 507 KeyGenerator keyGen = null; 508 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 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 536 private void initSymCiphers(String algorithm, SecretKey secret) throws Exception  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 MessageDigest digest = MessageDigest.getInstance("MD5"); 549 digest.reset(); 550 digest.update(secret.getEncoded()); 551 552 symVersion = new String (digest.digest()); 553 if (log.isInfoEnabled()) 554 log.info(" Initialized symmetric ciphers with secret key version " +symVersion); 555 } 556 557 558 562 public void initKeyPair() throws Exception  563 { 564 KeyPairGenerator 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 ()); 578 Kpair = KpairGen.generateKeyPair(); 579 580 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 591 public void reset() 592 { 593 } 594 595 596 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 case Event.SET_LOCAL_ADDRESS : 611 if (log.isDebugEnabled()) 612 log.debug("Set local address "); 613 local_addr = (Address) evt.getArg(); 614 break; 615 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 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 case Event.MSG : 639 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 647 { 648 649 handleUpMessage(evt); 650 651 } catch (Exception 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.getMembers() == null || view.getMembers().get(0) == null){ 672 becomeKeyServer(local_addr); 673 return; 674 } 675 Address tmpKeyServer = (Address)view.getMembers().get(0); 677 678 if (tmpKeyServer.equals(local_addr) && (keyServerAddr == null || (! tmpKeyServer.equals(keyServerAddr)))){ 681 becomeKeyServer(tmpKeyServer); 682 }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 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 716 private void handleNewKeyServer(Address newKeyServer){ 717 queue_up =true; 720 queue_down = true; 721 keyServerAddr = newKeyServer; 723 keyServer =false; 724 if (log.isInfoEnabled()) 725 log.info("Sending key request"); 726 727 sendKeyRequest(); 729 730 731 } 732 733 736 private void handleUpMessage(Event evt) throws Exception  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 obj = msg.getHeader(EncryptHeader.KEY); 752 753 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 (hdr.getType() == EncryptHeader.ENCRYPT) 769 { 770 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 if (!suppliedKey) { 780 drainUpQueue(); 781 } 782 Message tmpMsg =decryptMessage(symDecodingCipher, msg); 784 if (tmpMsg != null){ 785 passUp(evt); 787 } else { 788 log.warn("Unrecognised cipher discarding message"); 789 } 790 } 791 } else 792 { 793 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 switch (hdr.getType()){ 807 case EncryptHeader.KEY_REQUEST: 809 if (log.isInfoEnabled()) { 810 log.info("received a key request from peer"); 811 } 812 813 try { 815 PublicKey tmpKey = generatePubKey(msg.getBuffer()); 817 sendSecretKey(getSecretKey(), tmpKey, msg.getSrc()); 819 } catch (Exception 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 sendKeyRequest(); 834 }else{ 835 setKeys(tmp, hdr.getVersion()); 838 if (log.isInfoEnabled()) { 839 log.info("Decoded secretkey response"); 840 } 841 } 842 } catch (Exception e){ 843 log.warn("unable to process received public key"); 844 log.fatal(e); 845 } 846 &n
|