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