View Javadoc
1 /* 2 * $Id: CryptoTools.java,v 1.24 2004/08/26 01:06:36 pelle Exp $ 3 * $Log: CryptoTools.java,v $ 4 * Revision 1.24 2004/08/26 01:06:36 pelle 5 * Fixed a bug in CryptoTools with regards to seeding the srng 6 * 7 * Revision 1.23 2004/05/21 19:24:05 pelle 8 * Changed name of Neuclear Personal Signer to NeuClear Personal Trader 9 * More changes from Personality to Account 10 * Moved hibernates.properties out from the jar file and to the test directory and where ever it gets used, to avoid conflicts between multiple files. 11 * 12 * Revision 1.22 2004/04/19 18:45:26 pelle 13 * Changed default signer store to use correct path seperators. 14 * 15 * Revision 1.21 2004/04/14 00:10:52 pelle 16 * Added a MessageLabel for handling errors, validation and info 17 * Save works well now. 18 * It's pretty much there I think. 19 * 20 * Revision 1.20 2004/04/09 20:02:54 pelle 21 * Added PrivateKey wrapping and unwrapping to CryptoTools with the methods: 22 * byte [] wrapKey(char passphrase[], PrivateKey key) 23 * and 24 * PrivateKey unWrapKey(char passphrase[],byte wrapped[],String algorithm) 25 * PrivateKey unWrapRSAKey(char passphrase[],byte wrapped[]) 26 * 27 * Revision 1.19 2004/03/31 18:48:25 pelle 28 * Added various Streams for simplified crypto operations. 29 * 30 * Revision 1.18 2004/03/19 22:21:24 pelle 31 * Changes in the XMLSignature class, which is now Abstract there are currently 3 implementations for: 32 * - Enveloped 33 * - DataObjects - (Enveloping) 34 * - Any for interop testing mainly. 35 * 36 * Revision 1.17 2004/03/18 21:31:26 pelle 37 * Some fixups in SignedInfo 38 * 39 * Revision 1.16 2004/03/08 23:50:34 pelle 40 * More improvements on the XMLSignature. Now uses the Transforms properly, References properly. 41 * All the major elements have been refactored to be cleaner and more correct. 42 * 43 * Revision 1.15 2004/03/05 23:43:06 pelle 44 * New Channels package with nio based channels for various crypto related tasks such as digests, signing, verifying and encoding. 45 * DigestsChannel, SigningChannel and VerifyingChannel are complete, but not tested. 46 * AbstractEncodingChannel will be used for a Base64/Base32 Channel as well as possibly an xml canonicalization channel in the xmlsig library. 47 * 48 * Revision 1.14 2004/02/19 15:29:10 pelle 49 * Various cleanups and corrections 50 * 51 * Revision 1.13 2004/02/18 00:13:41 pelle 52 * Many, many clean ups. I've readded Targets in a new method. 53 * Gotten rid of NamedObjectBuilder and revamped Identity and Resolvers 54 * 55 * Revision 1.12 2004/01/18 21:20:20 pelle 56 * Created Base32 encoder that now fully complies with Tyler's spec. 57 * 58 * Revision 1.11 2004/01/16 23:41:59 pelle 59 * Added Base32 class. The Base32 encoding used wasnt following the standards. 60 * Added user creatable Identity for Public Keys 61 * 62 * Revision 1.10 2004/01/09 16:34:32 pelle 63 * changed use of base36 encoding to base32 to ensure compatibility with other schemes. 64 * 65 * Revision 1.9 2003/12/19 00:31:16 pelle 66 * Lots of usability changes through out all the passphrase agents and end user tools. 67 * 68 * Revision 1.8 2003/12/18 17:40:07 pelle 69 * You can now create keys that get stored with a X509 certificate in the keystore. These can be saved as well. 70 * IdentityCreator has been modified to allow creation of keys. 71 * Note The actual Creation of Certificates still have a problem that will be resolved later today. 72 * 73 * Revision 1.7 2003/12/10 23:55:45 pelle 74 * Did some cleaning up in the builders 75 * Fixed some stuff in IdentityCreator 76 * New maven goal to create executable jarapp 77 * We are close to 0.8 final of ID, 0.11 final of XMLSIG and 0.5 of commons. 78 * Will release shortly. 79 * 80 * Revision 1.6 2003/12/06 00:16:35 pelle 81 * Updated various areas in NSTools. 82 * Updated URI Validation in particular to support new expanded format 83 * Updated createUniqueID and friends to be a lot more unique and more efficient. 84 * In CryptoTools updated getRandom() to finally use a SecureRandom. 85 * Changed CryptoTools.getFormatURLSafe to getBase36 because that is what it really is. 86 * 87 * Revision 1.5 2003/11/21 04:43:41 pelle 88 * EncryptedFileStore now works. It uses the PBECipher with DES3 afair. 89 * Otherwise You will Finaliate. 90 * Anything that can be final has been made final throughout everyting. We've used IDEA's Inspector tool to find all instance of variables that could be final. 91 * This should hopefully make everything more stable (and secure). 92 * 93 * Revision 1.4 2003/11/20 23:41:36 pelle 94 * Getting all the tests to work in id 95 * Removing usage of BC in CryptoTools as it was causing issues. 96 * First version of EntityLedger that will use OFB's EntityEngine. This will allow us to support a vast amount databases without 97 * writing SQL. (Yipee) 98 * 99 * Revision 1.3 2003/11/19 23:32:50 pelle 100 * Signers now can generatekeys via the generateKey() method. 101 * Refactored the relationship between SignedNamedObject and NamedObjectBuilder a bit. 102 * SignedNamedObject now contains the full xml which is returned with getEncoded() 103 * This means that it is now possible to further receive on or process a SignedNamedObject, leaving 104 * NamedObjectBuilder for its original purposes of purely generating new Contracts. 105 * NamedObjectBuilder.sign() now returns a SignedNamedObject which is the prefered way of processing it. 106 * Updated all major interfaces that used the old model to use the new model. 107 * 108 * Revision 1.2 2003/11/18 23:34:55 pelle 109 * Payment Web Application is getting there. 110 * 111 * Revision 1.1 2003/11/11 21:17:48 pelle 112 * Further vital reshuffling. 113 * org.neudist.crypto.* and org.neudist.utils.* have been moved to respective areas under org.neuclear.commons 114 * org.neuclear.signers.* as well as org.neuclear.passphraseagents have been moved under org.neuclear.commons.crypto as well. 115 * Did a bit of work on the Canonicalizer and changed a few other minor bits. 116 * 117 * Revision 1.13 2003/11/09 03:27:01 pelle 118 * More house keeping and shuffling about mainly pay 119 * 120 * Revision 1.12 2003/10/29 21:15:53 pelle 121 * Refactored the whole signing process. Now we have an interface called Signer which is the old SignerStore. 122 * To use it you pass a byte array and an alias. The sign method then returns the signature. 123 * If a Signer needs a passphrase it uses a PassPhraseAgent to present a dialogue box, read it from a command line etc. 124 * This new Signer pattern allows us to use secure signing hardware such as N-Cipher in the future for server applications as well 125 * as SmartCards for end user applications. 126 * 127 * Revision 1.11 2003/10/28 23:44:15 pelle 128 * The GuiDialogAgent now works. It simply presents itself as a simple modal dialog box asking for a passphrase. 129 * The two Signer implementations both use it for the passphrase. 130 * 131 * Revision 1.10 2003/10/21 22:30:32 pelle 132 * Renamed NeudistException to NeuClearException and moved it to org.neuclear.commons where it makes more sense. 133 * Unhooked the XMLException in the xmlsig library from NeuClearException to make all of its exceptions an independent hierarchy. 134 * Obviously had to perform many changes throughout the code to support these changes. 135 * 136 * Revision 1.9 2003/09/29 23:44:44 pelle 137 * Trying to tweak Canonicalizer to function better. 138 * Apparently the built in Sun JCE doesnt like the Keysizes of NSROOT 139 * So now CryptoTools forces the use of BouncyCastle 140 * 141 * Revision 1.8 2003/09/26 23:52:38 pelle 142 * Changes mainly in receiver and related fun. 143 * First real neuclear stuff in the payment package. Added TransferContract and AssetControllerReceiver. 144 * 145 * Revision 1.7 2003/02/22 23:18:54 pelle 146 * Additional fixes to the encoding problem. 147 * 148 * Revision 1.6 2003/02/22 16:54:10 pelle 149 * Major structural changes in the whole processing framework. 150 * Verification now supports Enveloping and detached signatures. 151 * The reference element is a lot more important at the moment and handles much of the logic. 152 * Replaced homegrown Base64 with Blackdowns. 153 * Still experiencing problems with decoding foreign signatures. I reall dont understand it. I'm going to have 154 * to reread the specs a lot more and study other implementations sourcecode. 155 * 156 * Revision 1.5 2003/02/21 22:48:10 pelle 157 * New Test Infrastructure 158 * Added test keys in src/testdata/keys 159 * Modified tools to handle these keys 160 * 161 * Revision 1.4 2003/02/20 13:26:41 pelle 162 * Adding all of the modification from Rams?s Morales ramses@computer.org to support DSASHA1 Signatures 163 * Thanks Rams?s good work. 164 * So this means there is now support for: 165 * - DSA KeyInfo blocks 166 * - DSA Key Generation within CryptoTools 167 * - Signing using DSASHA1 168 * 169 * Revision 1.3 2003/02/18 00:03:03 pelle 170 * Moved the Signer classes from neuclearframework into neuclear-xmlsig 171 * 172 * Revision 1.2 2003/02/11 14:47:02 pelle 173 * Added benchmarking code. 174 * DigestValue is now a required part. 175 * If you pass a keypair when you sign, you get the PublicKey included as a KeyInfo block within the signature. 176 * 177 * Revision 1.1 2003/02/08 20:55:02 pelle 178 * Some documentation changes. 179 * Major reorganization of code. The code is slowly being cleaned up in such a way that we can 180 * get rid of the org.neuclear.utils package and split out the org.neuclear.xml.soap package. 181 * Got rid of tons of unnecessary dependencies. 182 * 183 * Revision 1.2 2003/01/21 03:14:11 pelle 184 * Mainly clean ups through out and further documentation. 185 * 186 * Revision 1.1 2003/01/18 18:12:29 pelle 187 * First Independent commit of the Independent XML-Signature API for NeuDist. 188 * 189 * Revision 1.5 2003/01/16 22:20:03 pelle 190 * First Draft of new generalised Ledger Interface. 191 * Currently we have a Book and Transaction class. 192 * We also need a Ledger class and a Ledger Factory. 193 * 194 * Revision 1.4 2002/12/17 21:41:01 pelle 195 * First part of refactoring of SignedNamedObject and SignedObject Interface/Class parings. 196 * 197 * Revision 1.3 2002/12/17 20:34:43 pelle 198 * Lots of changes to core functionality. 199 * First of all I've refactored most of the Resolving and verification code. I have a few more things to do 200 * on it before I'm happy. 201 * There is now a NSResolver class, which handles all the namespace resolution. I took most of the functionality 202 * for this out of SignedNamedObject. 203 * Then there is the veriifer, which verifies a given SignedNamedObject using the NSResolver. 204 * This has simplified the SignedNamedObject classes drastically, leaving them as mainly data objects, which is what they 205 * should be. 206 * I have also gone around and tightened up security on many different classes, making clases and/or methods final where appropriate. 207 * NSCache now operates using http://www.waterken.com's fantastic ADT collections library. 208 * Something important has been added, which is a SignRequest named object. This signed object, embeds an unsigned 209 * named object for signing by an end users' signing service. 210 * Now were almost ready to start seriously implementing AssetIssuers and Transfers, which will be the most important 211 * part of the framework. 212 * 213 * Revision 1.2 2002/09/23 15:09:18 pelle 214 * Got the SimpleSigner working properly. 215 * I couldn't get SealedObjects working with BouncyCastle's Symmetric keys. 216 * Don't know what I was doing, so I reimplemented it. Encrypting 217 * and decrypting it my self. 218 * 219 * Revision 1.1.1.1 2002/09/18 10:55:55 pelle 220 * First release in new CVS structure. 221 * Also first public release. 222 * This implemnts simple named objects. 223 * - Identity Objects 224 * - NSAuth Objects 225 * 226 * Storage systems 227 * - In Memory Storage 228 * - Clear text file based storage 229 * - Encrypted File Storage (with SHA256 digested filenames) 230 * - CachedStorage 231 * - SoapStorage 232 * 233 * Simple SOAP client/server 234 * - Simple Single method call SOAP client, for arbitrary dom4j based requests 235 * - Simple Abstract SOAP Servlet for implementing http based SOAP Servers 236 * 237 * Simple XML-Signature Implementation 238 * - Based on dom4j 239 * - SHA-RSA only 240 * - Very simple (likely imperfect) highspeed canonicalizer 241 * - Zero support for X509 (We dont like that anyway) 242 * - Super Simple 243 * 244 * 245 * Revision 1.4 2002/06/17 20:48:33 pelle 246 * The NS functionality should now work. FileStore is working properly. 247 * The example .ns objects in the neuspace folder have been updated with the 248 * latest version of the format. 249 * "neuspace/root.ns" should now be considered the universal parent of the 250 * neuclear system. 251 * Still more to go, but we're getting there. I will now focus on a quick 252 * Web interface. After which Contracts will be added. 253 * 254 * Revision 1.3 2002/06/13 19:04:07 pelle 255 * A start to a web interface into the architecture. 256 * We're getting a bit further now with functionality. 257 * 258 * Revision 1.2 2002/06/05 23:42:05 pelle 259 * The Throw clauses of several method definitions were getting out of hand, so I have 260 * added a new wrapper exception NeuClearException, to keep things clean in the ledger. 261 * This is used as a catchall wrapper for all Exceptions in the underlying API's such as IOExceptions, 262 * XML Exceptions etc. 263 * You can catch any Exception and rethrow it using Utility.rethrowException(e) as a quick way of handling 264 * exceptions. 265 * Otherwise the Store framework and the NameSpaces are really comming along quite well. I added a CachedStore 266 * which wraps around any other Store and caches the access to the store. 267 * 268 * Revision 1.1.1.1 2002/05/29 10:02:23 pelle 269 * Lets try one more time. This is the first rev of the next gen of Neudist 270 * 271 * 272 */ 273 package org.neuclear.commons.crypto; 274 275 import org.bouncycastle.crypto.BlockCipher; 276 import org.bouncycastle.crypto.BufferedBlockCipher; 277 import org.bouncycastle.crypto.Digest; 278 import org.bouncycastle.crypto.InvalidCipherTextException; 279 import org.bouncycastle.crypto.digests.SHA256Digest; 280 import org.bouncycastle.crypto.digests.SHA512Digest; 281 import org.bouncycastle.crypto.engines.AESEngine; 282 import org.bouncycastle.crypto.modes.CBCBlockCipher; 283 import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; 284 import org.bouncycastle.crypto.params.KeyParameter; 285 import org.bouncycastle.jce.X509Principal; 286 import org.bouncycastle.jce.X509V3CertificateGenerator; 287 import org.bouncycastle.jce.interfaces.ECPrivateKey; 288 import org.bouncycastle.jce.interfaces.ECPublicKey; 289 import org.bouncycastle.jce.provider.BouncyCastleProvider; 290 import org.neuclear.commons.time.TimeTools; 291 292 import javax.crypto.BadPaddingException; 293 import javax.crypto.Cipher; 294 import javax.crypto.NoSuchPaddingException; 295 import javax.crypto.SecretKeyFactory; 296 import javax.crypto.spec.PBEKeySpec; 297 import javax.crypto.spec.PBEParameterSpec; 298 import javax.crypto.spec.SecretKeySpec; 299 import java.io.File; 300 import java.io.IOException; 301 import java.io.InputStream; 302 import java.math.BigInteger; 303 import java.security.*; 304 import java.security.cert.Certificate; 305 import java.security.interfaces.DSAPrivateKey; 306 import java.security.interfaces.DSAPublicKey; 307 import java.security.interfaces.RSAPrivateKey; 308 import java.security.interfaces.RSAPublicKey; 309 import java.security.spec.InvalidKeySpecException; 310 import java.security.spec.KeySpec; 311 import java.security.spec.RSAPublicKeySpec; 312 import java.security.spec.X509EncodedKeySpec; 313 import java.util.Date; 314 315 // TODO Implement some code to automatically BC Provider if not installed 316 317 public final class CryptoTools { 318 private CryptoTools() { 319 } 320 321 322 /*** 323 * Call this method at the beginning of an executable. To ensure that BouncyCastle gets installed properly. 324 */ 325 public static void ensureProvider() { 326 if (Security.getProvider("BC") == null) { 327 System.err.println("Adding BouncyCastleProvider"); 328 Security.addProvider(new BouncyCastleProvider()); 329 System.err.println("Added BouncyCastleProvider"); 330 331 } 332 } 333 334 public static KeyPair getKeyPair(final KeyStore ks, final String s, final char[] password) throws CryptoException { 335 try { 336 final Certificate cert = ks.getCertificate(s); 337 final PrivateKey priv = (PrivateKey) ks.getKey(s, password); 338 if (cert == null || priv == null) 339 throw new CryptoException("They KeyStore Doesn't Contain an entry for: " + s); 340 return new KeyPair(cert.getPublicKey(), priv); 341 } catch (KeyStoreException e) { 342 rethrowException(e); 343 } catch (NoSuchAlgorithmException e) { 344 rethrowException(e); 345 } catch (UnrecoverableKeyException e) { 346 rethrowException(e); 347 } 348 return null; 349 } 350 351 352 public static String formatKeyAsHex(final Key key) { 353 return formatByteArrayAsHex(key.getEncoded()); 354 } 355 356 public static PublicKey getPublicKeyFromHex(final String hex) throws CryptoException { 357 try { 358 final byte[] barray = convertHexToByteArray(hex); 359 final X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(barray); 360 final KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 361 return keyFactory.generatePublic(pubKeySpec); 362 } catch (NoSuchAlgorithmException e) { 363 rethrowException(e); 364 } catch (InvalidKeySpecException e) { 365 rethrowException(e); 366 } 367 368 return null; 369 } 370 371 public static PublicKey getPublicKeyFromBase64(final String b64) throws CryptoException { 372 try { 373 final byte[] barray = Base64.decode(b64); 374 final X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(barray); 375 final KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 376 return keyFactory.generatePublic(pubKeySpec); 377 } catch (NoSuchAlgorithmException e) { 378 rethrowException(e); 379 } catch (InvalidKeySpecException e) { 380 rethrowException(e); 381 } 382 383 return null; 384 } 385 386 public static String formatByteArrayAsHex(final byte[] barray) { 387 final byte[] hexarray = new byte[2 * barray.length]; 388 int h = 0; 389 for (int i = 0; i < barray.length; i++) { 390 h = 2 * i; 391 final byte src = barray[i]; 392 hexarray[h] = HEX_TABLE[(src & 0xF0) >> 4]; 393 hexarray[h + 1] = HEX_TABLE[src & 0x0F]; 394 395 } 396 return new String(hexarray); 397 398 } 399 400 public static byte[] convertHexToByteArray(final String hex) { 401 final byte[] hexarray = hex.getBytes(); 402 final byte[] bytearray = new byte[(hexarray.length / 2)]; 403 for (int i = 0; i < hexarray.length; i += 2) { 404 final byte result; 405 byte high = hexarray[i]; 406 byte low = hexarray[i + 1]; 407 high = mapHexChar((char) high); 408 low = mapHexChar((char) low); 409 result = (byte) ((high << 4) | low); 410 bytearray[(i == 0 ? 0 : (i / 2))] = result; 411 } 412 return bytearray; 413 } 414 415 416 //Quick Hack. Not very efficient I know. 417 public static byte[] pad(final byte[] value, final Cipher c) { 418 final int blockSize = c.getBlockSize(); 419 return pad(value, blockSize); 420 } 421 422 public static byte[] pad(final byte[] value, final int blockSize) { 423 final int mod = value.length % blockSize; 424 final int diff = blockSize - mod; 425 final byte[] output = new byte[value.length + diff]; 426 System.arraycopy(value, 0, output, 0, value.length); 427 for (int i = value.length; i < output.length; i++) 428 output[i] = (byte) 0; 429 return output; 430 } 431 432 public static byte[] encrypt(final byte[] key, final String value) throws CryptoException { 433 return encrypt(key, value.getBytes()); 434 } 435 436 public static byte[] encrypt(final String key, final byte[] value) throws CryptoException { 437 return encrypt(key.getBytes(), value); 438 } 439 440 public static byte[] encrypt(final String key, final String value) throws CryptoException { 441 return encrypt(key.getBytes(), value.getBytes()); 442 } 443 444 public static byte[] encrypt(final byte[] key, final byte[] value) throws CryptoException { 445 return cipherProcess(key, value, true); 446 } 447 448 public static byte[] decrypt(final String key, final String value) throws CryptoException { 449 return decrypt(key.getBytes(), value.getBytes()); 450 } 451 452 public static byte[] decrypt(final byte[] key, final byte[] value) throws CryptoException { 453 return cipherProcess(key, value, false); 454 } 455 456 private static byte[] cipherProcess(final byte[] key, final byte[] value, final boolean doencrypt) throws CryptoException { 457 try { 458 final BlockCipher engine = new AESEngine(); 459 final BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(engine)); 460 cipher.init(doencrypt, new KeyParameter(digest256(key))); 461 462 final byte[] cipherText = new byte[cipher.getOutputSize(value.length)]; 463 464 final int outputLen = cipher.processBytes(value, 0, value.length, cipherText, 0); 465 cipher.doFinal(cipherText, outputLen); 466 return cipherText; 467 } catch (InvalidCipherTextException e) { 468 rethrowException(e); 469 } 470 return new byte[0]; 471 } 472 473 public static Cipher getCipher(final byte[] key, final boolean doencrypt) throws CryptoException { 474 try { 475 final Cipher cipher = Cipher.getInstance("AES"); 476 final KeySpec keyspec = new SecretKeySpec(key, "AES"); 477 final SecretKeyFactory kf = SecretKeyFactory.getInstance("AES"); 478 final Key skey = kf.generateSecret(keyspec); 479 cipher.init(doencrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, skey); 480 return cipher; 481 } catch (NoSuchAlgorithmException e) { 482 rethrowException(e); 483 } catch (NoSuchPaddingException e) { 484 rethrowException(e); 485 } catch (InvalidKeySpecException e) { 486 rethrowException(e); 487 } catch (InvalidKeyException e) { 488 rethrowException(e); 489 } 490 return null; 491 } 492 493 public static byte[] sign(final KeyPair kp, final byte[] value) throws CryptoException { 494 return sign(kp.getPrivate(), value); 495 } 496 497 public static byte[] sign(final PrivateKey key, final byte[] value) throws CryptoException { 498 try { 499 final Signature sig = getSignatureCipher(key); 500 sig.update(value); // put plain text of lock data into signature. 501 byte[] raw = sig.sign(); 502 if (key instanceof DSAPrivateKey) { 503 raw = convertASN1toXMLDSIG(raw); 504 } 505 return raw; 506 } catch (GeneralSecurityException e) { 507 rethrowException(e); 508 } catch (IOException e) { 509 rethrowException(e); 510 } 511 return new byte[0]; 512 } 513 514 public static Signature getSignatureCipher(final PrivateKey key) throws NoSuchAlgorithmException, InvalidKeyException { 515 Signature sig = null; 516 if (key instanceof RSAPrivateKey) 517 sig = Signature.getInstance("SHA1withRSA"); // Set up signature object. 518 else if (key instanceof DSAPrivateKey) 519 sig = Signature.getInstance("SHA1withDSA"); 520 else if (key instanceof ECPrivateKey) 521 sig = Signature.getInstance("SHA1withECDSA"); 522 523 sig.initSign(key); // Initialize with my private signing key. 524 return sig; 525 } 526 527 public static Signature getSignatureCipher(final PublicKey key) throws NoSuchAlgorithmException, InvalidKeyException { 528 Signature sig = null; 529 if (key instanceof RSAPublicKey) 530 sig = Signature.getInstance("SHA1withRSA"); // Set up signature object. 531 else if (key instanceof DSAPublicKey) 532 sig = Signature.getInstance("SHA1withDSA"); 533 else if (key instanceof ECPublicKey) 534 sig = Signature.getInstance("SHA1withECDSA"); 535 536 sig.initVerify(key); // Initialize with my public key. 537 return sig; 538 } 539 540 public static boolean verify(final PublicKey pk, final byte[] value, byte sigvalue[]) throws CryptoException { 541 try { 542 Signature sig = null; 543 if (pk instanceof DSAPublicKey) { 544 sig = Signature.getInstance("SHA1withDSA"); // Set up signature object. 545 sigvalue = convertXMLDSIGtoASN1(sigvalue); 546 } else if (pk instanceof RSAPublicKey) { 547 sig = Signature.getInstance("SHA1withRSA"); 548 } 549 sig.initVerify(pk); // Initialize with my private signing key. 550 sig.update(value); 551 return sig.verify(sigvalue); 552 } catch (GeneralSecurityException e) { 553 // e.printStackTrace(); 554 rethrowException(e); 555 } catch (IOException e) { 556 // e.printStackTrace(); //To change body of catch statement use Options | File Templates. 557 rethrowException(e); 558 } 559 return false; 560 } 561 562 public static byte[] digest(final InputStream is) throws IOException { 563 Digest digest = new org.bouncycastle.crypto.digests.SHA1Digest(); 564 byte buf[] = new byte[digest.getDigestSize()]; 565 int length = 0; 566 while ((length = is.read(buf)) >= 0) 567 digest.update(buf, 0, length); 568 digest.doFinal(buf, 0); 569 is.close(); 570 return buf; 571 } 572 573 public static byte[] digest(final byte[] value) { 574 final Digest dig = new org.bouncycastle.crypto.digests.SHA1Digest(); 575 return digest(dig, value); 576 } 577 578 public static byte[] digest(final String value) { 579 return digest(value.getBytes()); 580 } 581 582 public static byte[] digest256(final byte[] value) { 583 final Digest dig = new SHA256Digest(); 584 return digest(dig, value); 585 } 586 587 public static byte[] digest512(final byte[] value) { 588 final Digest dig = new SHA512Digest(); 589 return digest(dig, value); 590 } 591 592 private static byte[] digest(final Digest dig, final byte[] value) { 593 final byte[] output = new byte[dig.getDigestSize()]; 594 dig.update(value, 0, value.length); 595 dig.doFinal(output, 0); 596 return output; 597 } 598 599 public static boolean equalByteArrays(final byte[] one, final byte[] two) { 600 if ((one == null && two != null) || (one != null && two == null)) 601 return false; 602 if (one == null && two == null) 603 return true; 604 if (one.length != two.length) 605 return false; 606 for (int i = 0; i < one.length; i++) { 607 if (one[i] != two[i]) 608 return false; 609 } 610 return true; 611 } 612 613 /*** 614 * Unpadded Base32 Encoding as defined in: 615 * <a href="http://www.waterken.com/dev/Enc/base32/">http://www.waterken.com/dev/Enc/base32/</a> 616 * 617 * @param val 618 * @return 619 */ 620 public static String encodeBase32(final byte[] val) { 621 return Base32.encode(val); 622 } 623 624 public static String createRandomID() { 625 return createRandomID(RAND_BIT_LENGTH); 626 627 } 628 629 public static String createRandomID(int length) { 630 final BigInteger big = new BigInteger(length, getRandomInstance()); 631 return big.toString(32); 632 } 633 634 private static synchronized SecureRandom getRandomInstance() { 635 if (randSource == null) 636 try { 637 randSource = SecureRandom.getInstance("SHA1PRNG"); 638 } catch (NoSuchAlgorithmException e) { 639 throw new RuntimeException(e); 640 } 641 return randSource; 642 } 643 644 private static byte mapHexChar(char hex) { 645 hex = Character.toUpperCase(hex); 646 switch (hex) { 647 case 'A': 648 return (byte) 10; 649 case 'B': 650 return (byte) 11; 651 case 'C': 652 return (byte) 12; 653 case 'D': 654 return (byte) 13; 655 case 'E': 656 return (byte) 14; 657 case 'F': 658 return (byte) 15; 659 } 660 if (Character.isDigit(hex)) 661 return (byte) Character.getNumericValue(hex); 662 else 663 return (byte) 0; 664 } 665 666 /*** 667 * Adapted from BouncyCastle's JDKKeyStore class 668 * 669 * @param algorithm 670 * @param mode 671 * @param password 672 * @param salt 673 * @param iterationCount 674 * @param provider 675 * @return 676 * @throws java.security.GeneralSecurityException 677 * 678 */ 679 public static Cipher makePBECipher(final String algorithm, 680 final int mode, 681 final char[] password, 682 final byte[] salt, 683 final int iterationCount, 684 final String provider) throws GeneralSecurityException { 685 final PBEKeySpec pbeSpec = new PBEKeySpec(password); 686 final SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm); 687 final PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); 688 689 final Cipher cipher = Cipher.getInstance(algorithm); 690 691 cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams); 692 693 return cipher; 694 } 695 696 /*** 697 * Adapted from BouncyCastle's JDKKeyStore class.<p> 698 * This one is setup with some meaningful JCE and Algorithm Defaults 699 * 700 * @param mode 701 * @param password 702 * @param salt 703 * @param iterationCount 704 * @return 705 * @throws java.security.GeneralSecurityException 706 * 707 */ 708 public static Cipher makePBECipher(final int mode, 709 final char[] password, 710 final byte[] salt, 711 final int iterationCount) throws GeneralSecurityException { 712 return makePBECipher(DEFAULT_PBE_ALGORITHM, mode, password, salt, iterationCount, DEFAULT_JCE_PROVIDER); 713 } 714 715 716 /*** 717 * Adapted from BouncyCastle's JDKKeyStore class.<p> 718 * This one is setup with some meaningful JCE and Algorithm Defaults as well as general simple defaults 719 * 720 * @param mode 721 * @param password 722 * @return 723 * @throws java.security.GeneralSecurityException 724 * 725 */ 726 public static Cipher makePBECipher(final int mode, 727 final char[] password) throws GeneralSecurityException { 728 return makePBECipher(DEFAULT_PBE_ALGORITHM, mode, password, DEFAULT_SALT, DEFAULT_ITERATION_COUNT, DEFAULT_JCE_PROVIDER); 729 } 730 731 public static byte[] wrapKey(final char password[], final PrivateKey key) throws CryptoException { 732 try { 733 Cipher cipher = makePBECipher(Cipher.WRAP_MODE, password); 734 return cipher.wrap(key); 735 } catch (BadPaddingException e) { 736 throw new CryptoException(e); 737 } catch (GeneralSecurityException e) { 738 throw new CryptoException(e); 739 } 740 } 741 742 public static PrivateKey unWrapKey(final char password[], final byte data[], final String algorithm) throws CryptoException { 743 try { 744 Cipher cipher = makePBECipher(Cipher.UNWRAP_MODE, password); 745 return (PrivateKey) cipher.unwrap(data, algorithm, Cipher.PRIVATE_KEY); 746 } catch (BadPaddingException e) { 747 throw new CryptoException(e); 748 } catch (GeneralSecurityException e) { 749 throw new CryptoException(e); 750 } 751 } 752 753 public static PrivateKey unWrapRSAKey(final char password[], final byte data[]) throws CryptoException { 754 return unWrapKey(password, data, "RSA"); 755 } 756 757 public static PublicKey createPK(final String mod, final String exp) throws CryptoException { 758 try { 759 final KeyFactory rsaFactory = KeyFactory.getInstance("RSA"); 760 final RSAPublicKeySpec rsaKeyspec = new RSAPublicKeySpec(new BigInteger(Base64.decode(mod)), new BigInteger(Base64.decode(exp))); 761 return rsaFactory.generatePublic(rsaKeyspec); 762 } catch (NoSuchAlgorithmException e) { 763 e.printStackTrace(System.err); 764 throw new CryptoException(e); 765 } catch (InvalidKeySpecException e) { 766 e.printStackTrace(System.err); 767 throw new CryptoException(e); 768 } 769 } 770 771 public static KeyPair createKeyPair() throws NoSuchAlgorithmException { 772 return getKeyPairGenerator().generateKeyPair(); 773 } 774 775 public static KeyPair createTinyRSAKeyPair() throws NoSuchAlgorithmException { 776 return getTinyRSAKeyPairGenerator().generateKeyPair(); 777 } 778 779 public static KeyPair createTinyDSAKeyPair() throws NoSuchAlgorithmException { 780 return getTinyDSAKeyPairGenerator().generateKeyPair(); 781 } 782 783 public static KeyPair createKeyPair(final String algorithm) 784 throws NoSuchAlgorithmException { 785 return getKeyPairGenerator(algorithm).generateKeyPair(); 786 } 787 788 public static KeyPairGenerator getKeyPairGenerator() throws NoSuchAlgorithmException { 789 if (kg == null) { 790 kg = KeyPairGenerator.getInstance("RSA"); 791 792 kg.initialize(1024, getRandomInstance()); 793 } 794 return kg; 795 796 } 797 798 public static KeyPairGenerator getTinyRSAKeyPairGenerator() throws NoSuchAlgorithmException { 799 if (tkg == null) { 800 tkg = KeyPairGenerator.getInstance("RSA"); 801 802 tkg.initialize(512, getRandomInstance()); 803 } 804 return tkg; 805 806 } 807 808 public static KeyPairGenerator getTinyDSAKeyPairGenerator() throws NoSuchAlgorithmException { 809 if (tdkg == null) { 810 tdkg = KeyPairGenerator.getInstance("DSA"); 811 812 tdkg.initialize(512, getRandomInstance()); 813 } 814 return tdkg; 815 816 } 817 818 public static KeyPairGenerator getKeyPairGenerator(final String algorithm) 819 throws NoSuchAlgorithmException { 820 if (!algorithm.equals(RSA) && !algorithm.equals(DSA)) 821 throw new NoSuchAlgorithmException(algorithm + " is not supported"); 822 823 if (null == dkg) { 824 dkg = KeyPairGenerator.getInstance(algorithm); 825 826 dkg.initialize(1024, getRandomInstance()); 827 } 828 return dkg; 829 } 830 831 public static void rethrowException(final Throwable e) throws CryptoException { 832 throw new CryptoException(e); 833 } 834 835 /*** 836 * Converts an ASN.1 DSA value to a XML Signature DSA Value. 837 * <p/> 838 * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value 839 * pairs; the XML Signature requires the core BigInteger values. 840 * 841 * @see <A HREF="http://www.w3.org/TR/xmldsig-core/#dsa-sha1">6.4.1 DSA</A> 842 */ 843 public static byte[] convertASN1toXMLDSIG(final byte[] asn1Bytes) throws IOException { 844 845 final byte rLength = asn1Bytes[3]; 846 int i; 847 848 for (i = rLength; (i > 0) && (asn1Bytes[(4 + rLength) - i] == 0); i--) ; 849 850 final byte sLength = asn1Bytes[5 + rLength]; 851 int j; 852 853 for (j = sLength; (j > 0) && (asn1Bytes[(6 + rLength + sLength) - j] == 0); j--) ; 854 855 if ((asn1Bytes[0] != 48) || (asn1Bytes[1] != asn1Bytes.length - 2) 856 || (asn1Bytes[2] != 2) || (i > 20) || (asn1Bytes[4 + rLength] != 2) 857 || (j > 20)) { 858 859 throw new IOException("Invalid ASN.1 format of DSA signature"); 860 } else { 861 final byte[] xmldsigBytes = new byte[40]; 862 863 System.arraycopy(asn1Bytes, (4 + rLength) - i, xmldsigBytes, 20 - i, i); 864 System.arraycopy(asn1Bytes, (6 + rLength + sLength) - j, xmldsigBytes, 40 - j, j); 865 866 return xmldsigBytes; 867 } 868 } 869 870 /*** 871 * Converts a XML Signature DSA Value to an ASN.1 DSA value. 872 * <p/> 873 * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value 874 * pairs; the XML Signature requires the core BigInteger values. 875 * 876 * @see <A HREF="http://www.w3.org/TR/xmldsig-core/#dsa-sha1">6.4.1 DSA</A> 877 */ 878 public static byte[] convertXMLDSIGtoASN1(final byte[] xmldsigBytes) throws IOException { 879 880 if (xmldsigBytes.length != 40) { 881 throw new IOException("Invalid XMLDSIG format of DSA signature"); 882 } 883 884 int i; 885 for (i = 20; (i > 0) && (xmldsigBytes[20 - i] == 0); i--) ; 886 887 int j = i; 888 if (xmldsigBytes[20 - i] < 0) { 889 j += 1; 890 } 891 892 int k; 893 for (k = 20; (k > 0) && (xmldsigBytes[40 - k] == 0); k--) ; 894 895 int l = k; 896 if (xmldsigBytes[40 - k] < 0) { 897 l += 1; 898 } 899 900 final byte[] asn1Bytes = new byte[6 + j + l]; 901 902 asn1Bytes[0] = 48; 903 asn1Bytes[1] = (byte) (4 + j + l); 904 asn1Bytes[2] = 2; 905 asn1Bytes[3] = (byte) j; 906 907 System.arraycopy(xmldsigBytes, 20 - i, asn1Bytes, (4 + j) - i, i); 908 909 asn1Bytes[4 + j] = 2; 910 asn1Bytes[5 + j] = (byte) l; 911 912 System.arraycopy(xmldsigBytes, 40 - k, asn1Bytes, (6 + j + l) - k, k); 913 914 return asn1Bytes; 915 } 916 917 public final static Certificate createCertificate(String name, KeyPair kp) throws SignatureException, InvalidKeyException { 918 X509V3CertificateGenerator gen = new X509V3CertificateGenerator(); 919 // Vector code=new Vector(1); 920 // code.add(0,"CN"); 921 // Vector names=new Vector(1); 922 // names.add(0,name); 923 // final X509Name x509Name = new X509Name(code,names); 924 // gen.setIssuerDN(x509Name); 925 final X509Principal x509 = new X509Principal("CN=" + name + ", OU=NEU, O=NEU, L=NEU, ST=NEU, C=PA"); 926 gen.setSubjectDN(x509); 927 gen.setIssuerDN(x509); 928 gen.setPublicKey(kp.getPublic()); 929 gen.setNotBefore(new Date()); 930 gen.setNotAfter(TimeTools.get2020()); 931 gen.setSignatureAlgorithm("SHA1withRSA"); 932 gen.setSerialNumber(new BigInteger(digest(kp.getPublic().getEncoded()))); 933 return gen.generateX509Certificate(kp.getPrivate()); 934 } 935 936 { 937 ensureProvider(); 938 } 939 940 private static final String RSA = "RSA", DSA = "DSA"; 941 private static KeyPairGenerator kg; 942 private static KeyPairGenerator dkg; 943 private static KeyPairGenerator tkg; 944 private static KeyPairGenerator tdkg; 945 public static final String DEFAULT_PBE_ALGORITHM = "PBEWithMD5AndDES"; 946 public static final String DEFAULT_JCE_PROVIDER = "BC"; 947 private static final byte DEFAULT_SALT[] = "LiquidNi".getBytes(); 948 private static final int DEFAULT_ITERATION_COUNT = 2048; 949 private static final byte[] HEX_TABLE = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 950 951 private static SecureRandom randSource; 952 953 public final static String DEFAULT_KEYSTORE = System.getProperty("user.home") + File.separatorChar + ".neuclear" + File.separatorChar + "accounts.jks"; 954 public static final int RAND_BIT_LENGTH = 128; 955 private static final long YPLUS20 = 20 * 365 * 24 * 60 * 60; 956 }

This page was automatically generated by Maven