1 64 65 package com.jcorporate.expresso.core.security.strongencryption; 66 67 import com.jcorporate.expresso.core.misc.ByteArrayCounter; 68 import com.jcorporate.expresso.core.security.AbstractStringEncryption; 69 import com.jcorporate.expresso.kernel.exception.ChainedException; 70 import com.jcorporate.expresso.kernel.util.ClassLocator; 71 import org.apache.log4j.Logger; 72 73 import javax.crypto.BadPaddingException; 74 import javax.crypto.Cipher; 75 import javax.crypto.IllegalBlockSizeException; 76 import javax.crypto.KeyGenerator; 77 import javax.crypto.NoSuchPaddingException; 78 import javax.crypto.SecretKey; 79 import javax.crypto.ShortBufferException; 80 import javax.crypto.spec.IvParameterSpec; 81 import javax.crypto.spec.SecretKeySpec; 82 import java.io.UnsupportedEncodingException ; 83 import java.security.InvalidAlgorithmParameterException ; 84 import java.security.InvalidKeyException ; 85 import java.security.NoSuchAlgorithmException ; 86 import java.security.NoSuchProviderException ; 87 import java.security.Provider ; 88 import java.security.SecureRandom ; 89 import java.security.Security ; 90 import java.util.Hashtable ; 91 92 93 117 public class StringEncryption 118 extends AbstractStringEncryption { 119 static protected ByteArrayCounter ivCounter64 = new ByteArrayCounter(8); 120 static protected ByteArrayCounter ivCounter128 = new ByteArrayCounter(16); 121 122 static final private Logger log = Logger.getLogger(StringEncryption.class); 123 126 private Hashtable keyMap; 127 128 131 private Hashtable modeMap; 132 133 136 static final private String [] modes = { 137 "Rijndael/OFB/PKCS5Padding", "Blowfish/CFB/PKCS5Padding", 138 "Twofish/CFB/PKCS5Padding", "RC6/CBC/PKCS5Padding" 139 }; 140 141 static final private String [] methodKeys = {"AES", "BLO", "TWO", "RC6"}; 142 143 private Hashtable ivMap; 144 145 private static final String PROVIDER_NAME = "org.bouncycastle.jce.provider.BouncyCastleProvider"; 146 147 private Provider theProvider; 150 boolean providerAlreadyInstalled = false; 151 152 159 public StringEncryption() { 160 161 if (log.isDebugEnabled()) { 165 log.debug("Initializing Strong String Encryption"); 166 log.debug("System Provider Dump -----------------------"); 167 Provider allProviders[] = Security.getProviders(); 168 for (int i = 0; i < allProviders.length; i++) { 169 log.debug(allProviders[i].toString()); 170 } 171 log.debug("--------------------------------------------"); 172 } 173 174 theProvider = Security.getProvider(PROVIDER_NAME); 175 if (theProvider != null) { 176 providerAlreadyInstalled = true; 177 } else { 178 try { 179 theProvider = (Provider ) ClassLocator.loadClass(PROVIDER_NAME).newInstance(); 180 } catch (Exception ex) { 181 log.error("Error loading bouncycastle crypto", ex); 182 throw new RuntimeException ("constructor will throw if JCE jar is" + 183 " not found or if the security manager doesn't allow a new provider;" + 184 " see Ant target 'get-crypto' for easy means to download the appropriate" + 185 " crypto library from http://www.bouncycastle.org/download . " + 186 " It is under export restriction, so it cannot be " + 187 "added to the expresso library as publicly distributed.", ex); 188 } 189 } 190 try { 191 jbInit(); 192 } catch (Exception ex) { 193 ex.printStackTrace(); 194 } 195 } 196 197 public void init() throws ChainedException { 198 super.init(); 199 keyMap = new Hashtable (); 200 modeMap = new Hashtable (); 201 ivMap = new Hashtable (); 202 byte[] passKey = this.getPreparedPassKey(); 203 204 if (!providerAlreadyInstalled) { 206 try { 207 Security.addProvider(theProvider); 208 } catch (SecurityException e) { 209 throw new ChainedException("Error Installing Bouncy Castle Provider", 210 e); 211 } 212 } 213 214 SecureRandom random = null; 215 try { 216 random = SecureRandom.getInstance("SHA1PRNG"); 217 } catch (NoSuchAlgorithmException ex1) { 218 throw new ChainedException("Error initiating sha1-random", ex1); 219 } 220 221 for (int i = 0; i < modes.length; i++) { 222 try { 223 Cipher c = Cipher.getInstance(modes[i]); 224 String cipherAlgorithm = modes[i].substring(0, modes[i].indexOf("/")); 225 226 KeyGenerator kg = KeyGenerator.getInstance(cipherAlgorithm); 235 kg.init(random); 236 SecretKey key = kg.generateKey(); 237 byte encoded[] = key.getEncoded(); 238 byte myKey[] = passKey; 239 if (passKey.length > encoded.length) { 240 myKey = new byte[encoded.length]; 241 242 for (int j = 0; j < myKey.length; j++) { 245 myKey[j] = passKey[j]; 246 } 247 } 248 keyMap.put(methodKeys[i], 249 new SecretKeySpec(myKey, cipherAlgorithm)); 250 251 252 modeMap.put(methodKeys[i], modes[i]); 253 254 255 int counterSize = c.getBlockSize(); 256 switch (counterSize) { 257 case 16: 258 ivMap.put(methodKeys[i], ivCounter128); 259 break; 260 case 8: 261 ivMap.put(methodKeys[i], ivCounter64); 262 break; 263 default: 264 throw new IllegalStateException ("Unsupported block size: " + counterSize); 265 } 266 } catch (NoSuchAlgorithmException ex) { 267 log.warn("No such algorithm supported: " + modes[0]); 268 } catch (NoSuchPaddingException ex) { 269 log.warn("Invalid padding: " + modes[0]); 270 } 271 } 272 } 273 274 277 public void destroy() { 278 try { 279 if (!providerAlreadyInstalled) { 280 Security.removeProvider(theProvider.getName()); 281 } 282 keyMap.clear(); 283 ivMap.clear(); 284 modeMap.clear(); 285 keyMap = null; 286 ivMap = null; 287 modeMap = null; 288 } catch (SecurityException e) { 289 e.printStackTrace(); 290 System.err.println(e.getMessage()); 291 } 292 } 293 294 302 public byte[] decrypt(byte[] inputData) 303 throws ChainedException { 304 305 if (inputData.length < 16) { 306 throw new IllegalArgumentException ("Improper Data Header"); 307 } 308 309 int version = inputData[0]; 313 314 if (version > 1) { 315 throw new IllegalArgumentException ("Invalid Crypto Version"); 316 } 317 318 SecretKeySpec theKey = null; 322 Cipher theCipher = null; 323 String theMode = null; 324 325 try { 326 theMode = new String (inputData, 1, 6, "UTF-16BE").toUpperCase(); 327 } catch (UnsupportedEncodingException ex) { 328 throw new ChainedException("Unsupported Encoding", ex); 329 } 330 331 String cipherName = (String ) modeMap.get(theMode); 332 333 if (cipherName == null) { 334 throw new IllegalArgumentException ("Either invalid input data " + 335 "or unsupported key mode: " + cipherName); 336 } 337 338 theKey = (SecretKeySpec) keyMap.get(theMode); 339 340 try { 341 342 theCipher = Cipher.getInstance(cipherName, theProvider.getName()); 344 } catch (NoSuchProviderException ex) { 345 throw new ChainedException("Error Loading BouncyCastle Provider. ", 346 ex); 347 } catch (NoSuchAlgorithmException ex) { 348 throw new ChainedException("Error loading crypto algorithms." + 349 " You may not have installed the" + 350 " Cryptography Extensions Properly", ex); 351 } catch (NoSuchPaddingException ex) { 352 throw new ChainedException("Error loading Padding." + 353 " You may not have installed the" + 354 " Cryptography Extensions Properly", ex); 355 } 356 try { 357 358 ByteArrayCounter bc = (ByteArrayCounter) ivMap.get(theMode); 363 byte[] ivData = new byte[bc.getBytes().length]; 364 int ivLength = ivData.length; 365 366 for (int i = 7; i < ivData.length + 7; i++) { 368 ivData[i - 7] = inputData[i]; 369 } 370 371 IvParameterSpec ivParam = new IvParameterSpec(ivData); 372 theCipher.init(Cipher.DECRYPT_MODE, theKey, ivParam); 373 374 byte[] returnValue = theCipher.doFinal(inputData, 7 + ivLength, 376 inputData.length - 377 (7 + ivLength)); 378 379 return returnValue; 380 } catch (InvalidKeyException ex) { 381 throw new ChainedException("Invalid Key", ex); 382 } catch (BadPaddingException ex) { 383 384 throw new ChainedException("Bad Padding", ex); 387 } catch (IllegalBlockSizeException ex) { 388 return "".getBytes(); 389 } catch (InvalidAlgorithmParameterException ex) { 390 throw new ChainedException("Invalid Algorithm Parameter", ex); 391 } catch (Exception e) { 392 return "".getBytes(); 393 } 394 } 395 396 397 409 public byte[] encrypt(byte[] inputData, String theShortCipherString) 410 throws ChainedException { 411 412 if (inputData.length == 0) { 413 throw new IllegalArgumentException ("inputData must not be zero length"); 414 } 415 if (theShortCipherString == null || 416 theShortCipherString.length() < 3) { 417 throw new IllegalArgumentException ("encryptMethod must be " + 418 "a valid encryption header string"); 419 } 420 421 Cipher theCipher = null; 422 String theCipherString = null; 423 SecretKeySpec theKey = null; 424 IvParameterSpec ivParam = null; 425 byte[] ivBytes; 426 int ivLength; 427 428 try { 429 430 if (theShortCipherString != null) { 432 theCipherString = (String ) modeMap.get(theShortCipherString); 433 } 434 if (theCipherString == null) { 435 throw new IllegalArgumentException ("theShortCipherString " + 436 "must be a valid cipher description. Received :" + 437 theShortCipherString); 438 } 439 440 theCipher = Cipher.getInstance(theCipherString, 442 theProvider.getName()); 443 theKey = (SecretKeySpec) keyMap.get(theShortCipherString); 444 445 ByteArrayCounter bc = (ByteArrayCounter) ivMap.get(theShortCipherString); 446 bc.increment(); 447 ivBytes = bc.getBytes(); 448 ivLength = ivBytes.length; 449 ivParam = new IvParameterSpec(ivBytes); 450 } catch (NoSuchProviderException ex) { 451 throw new ChainedException("Error loading cryptix provider." + 452 " You may not have installed the" + 453 " Cryptography Extensions Properly", ex); 454 } catch (NoSuchAlgorithmException ex) { 455 throw new ChainedException("Error loading crypto algorithms." + 456 " You may not have installed the" + 457 " Cryptography Extensions Properly", ex); 458 } catch (NoSuchPaddingException ex) { 459 throw new ChainedException("Error loading Padding." + 460 " You may not have installed the" + 461 " Cryptography Extensions Properly", ex); 462 } 463 try { 464 theCipher.init(Cipher.ENCRYPT_MODE, theKey, ivParam); 465 466 int dataLength = theCipher.getOutputSize(inputData.length); 467 byte[] finalData = new byte[dataLength + 7 + ivLength]; 468 469 finalData[0] = 1; 473 474 byte[] modeHeader = theShortCipherString.getBytes("UTF-16BE"); 476 477 for (int i = 1; i < 7; i++) { 478 finalData[i] = modeHeader[i - 1]; 479 } 480 for (int i = 7; i < 7 + ivLength; i++) { 482 finalData[i] = ivBytes[i - 7]; 483 } 484 485 theCipher.doFinal(inputData, 0, inputData.length, finalData, 486 (7 + ivLength)); 487 488 return finalData; 489 } catch (ShortBufferException ex) { 490 throw new ChainedException("Short Buffer", ex); 491 } catch (InvalidKeyException ex) { 492 throw new ChainedException("Invalid Key", ex); 493 } catch (InvalidAlgorithmParameterException ex) { 494 throw new ChainedException("Invalid Algorithm", ex); 495 } catch (BadPaddingException ex) { 496 throw new ChainedException("Bad Padding", ex); 497 } catch (IllegalBlockSizeException ex) { 498 throw new ChainedException("Illegal Block Size", ex); 499 } catch (UnsupportedEncodingException ex) { 500 throw new ChainedException("Unsupported Encoding", ex); 501 } 502 } 503 504 505 512 public byte[] encrypt(byte[] inputData) 513 throws ChainedException { 514 515 String theShortCipherString = null; 517 518 theShortCipherString = this.getCryptoManager().getEncryptMode(); 519 520 String theCipherString = null; 521 522 if (theShortCipherString != null) { 523 theCipherString = (String ) modeMap.get(theShortCipherString); 524 } 525 if (theCipherString == null) { 526 theShortCipherString = "AES"; 527 } 528 529 return encrypt(inputData, theShortCipherString); 530 } 531 532 private void jbInit() 533 throws Exception { 534 } 535 536 537 } 538 539 540 | Popular Tags |