View Javadoc
1 /* 2 * $Id: SimpleSigner.java,v 1.11 2004/07/21 23:07:16 pelle Exp $ 3 * $Log: SimpleSigner.java,v $ 4 * Revision 1.11 2004/07/21 23:07:16 pelle 5 * Updated the Signer interface with a new generateKey() method, which doesn't take any parameters. 6 * It stores the generated key using the Base32 encoded SHA1 digest as it's alias. 7 * 8 * Revision 1.10 2004/01/19 17:53:14 pelle 9 * Various clean ups 10 * 11 * Revision 1.9 2003/12/19 18:02:53 pelle 12 * Revamped a lot of exception handling throughout the framework, it has been simplified in most places: 13 * - For most cases the main exception to worry about now is InvalidNamedObjectException. 14 * - Most lowerlevel exception that cant be handled meaningful are now wrapped in the LowLevelException, a 15 * runtime exception. 16 * - Source and Store patterns each now have their own exceptions that generalizes the various physical 17 * exceptions that can happen in that area. 18 * 19 * Revision 1.8 2003/12/19 00:31:15 pelle 20 * Lots of usability changes through out all the passphrase agents and end user tools. 21 * 22 * Revision 1.7 2003/12/18 17:40:07 pelle 23 * You can now create keys that get stored with a X509 certificate in the keystore. These can be saved as well. 24 * IdentityCreator has been modified to allow creation of keys. 25 * Note The actual Creation of Certificates still have a problem that will be resolved later today. 26 * 27 * Revision 1.6 2003/12/16 23:16:40 pelle 28 * Work done on the SigningServlet. The two phase web model is now only an option. 29 * Allowing much quicker signing, using the GuiDialogueAgent. 30 * The screen has also been cleaned up and displays the xml to be signed. 31 * The GuiDialogueAgent now optionally remembers passphrases and has a checkbox to support this. 32 * The PassPhraseAgent's now have a UserCancellationException, which allows the agent to tell the application if the user specifically 33 * cancels the signing process. 34 * 35 * Revision 1.5 2003/12/10 23:55:45 pelle 36 * Did some cleaning up in the builders 37 * Fixed some stuff in IdentityCreator 38 * New maven goal to create executable jarapp 39 * We are close to 0.8 final of ID, 0.11 final of XMLSIG and 0.5 of commons. 40 * Will release shortly. 41 * 42 * Revision 1.4 2003/11/21 04:43:41 pelle 43 * EncryptedFileStore now works. It uses the PBECipher with DES3 afair. 44 * Otherwise You will Finaliate. 45 * 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. 46 * This should hopefully make everything more stable (and secure). 47 * 48 * Revision 1.3 2003/11/19 23:32:50 pelle 49 * Signers now can generatekeys via the generateKey() method. 50 * Refactored the relationship between SignedNamedObject and NamedObjectBuilder a bit. 51 * SignedNamedObject now contains the full xml which is returned with getEncoded() 52 * This means that it is now possible to further receive on or process a SignedNamedObject, leaving 53 * NamedObjectBuilder for its original purposes of purely generating new Contracts. 54 * NamedObjectBuilder.sign() now returns a SignedNamedObject which is the prefered way of processing it. 55 * Updated all major interfaces that used the old model to use the new model. 56 * 57 * Revision 1.2 2003/11/12 18:54:42 pelle 58 * Updated SimpleSignerStoreTest to use a StoredPassPhraseAgent eliminating the popup during testing. 59 * Created SigningBenchmark for running comparative performance benchmarks on various key algorithms. 60 * 61 * Revision 1.1 2003/11/11 21:17:47 pelle 62 * Further vital reshuffling. 63 * org.neudist.crypto.* and org.neudist.utils.* have been moved to respective areas under org.neuclear.commons 64 * org.neuclear.signers.* as well as org.neuclear.passphraseagents have been moved under org.neuclear.commons.crypto as well. 65 * Did a bit of work on the Canonicalizer and changed a few other minor bits. 66 * 67 * Revision 1.3 2003/11/08 20:27:06 pelle 68 * Updated the Signer interface to return a key type to be used for XML SignatureInfo. Thus we now support DSA sigs yet again. 69 * 70 * Revision 1.2 2003/10/29 23:17:53 pelle 71 * Updated some javadocs 72 * Added a neuclear specific maven repository at: 73 * http://neuclear.org/maven/ and updated the properties files to reflect that. 74 * 75 * Revision 1.1 2003/10/29 21:16:28 pelle 76 * Refactored the whole signing process. Now we have an interface called Signer which is the old SignerStore. 77 * To use it you pass a byte array and an alias. The sign method then returns the signature. 78 * If a Signer needs a passphrase it uses a PassPhraseAgent to present a dialogue box, read it from a command line etc. 79 * This new Signer pattern allows us to use secure signing hardware such as N-Cipher in the future for server applications as well 80 * as SmartCards for end user applications. 81 * 82 * Revision 1.4 2003/10/28 23:44:03 pelle 83 * The GuiDialogAgent now works. It simply presents itself as a simple modal dialog box asking for a passphrase. 84 * The two Signer implementations both use it for the passphrase. 85 * 86 * Revision 1.3 2003/10/21 22:29:59 pelle 87 * Renamed NeudistException to NeuClearException and moved it to org.neuclear.commons where it makes more sense. 88 * Unhooked the XMLException in the xmlsig library from NeuClearException to make all of its exceptions an independent hierarchy. 89 * Obviously had to perform many changes throughout the code to support these changes. 90 * 91 * Revision 1.2 2003/02/20 13:26:41 pelle 92 * Adding all of the modification from Rams?s Morales ramses@computer.org to support DSASHA1 Signatures 93 * Thanks Rams?s good work. 94 * So this means there is now support for: 95 * - DSA KeyInfo blocks 96 * - DSA Key Generation within CryptoTools 97 * - Signing using DSASHA1 98 * 99 * Revision 1.1 2003/02/18 00:03:32 pelle 100 * Moved the Signer classes from neuclearframework into neuclear-xmlsig 101 * 102 * Revision 1.5 2003/02/10 22:30:13 pelle 103 * Got rid of even further dependencies. In Particular OSCore 104 * 105 * Revision 1.4 2003/02/09 00:15:55 pelle 106 * Fixed things so they now compile with r_0.7 of XMLSig 107 * 108 * Revision 1.3 2002/10/06 00:39:26 pelle 109 * I have now expanded support for different types of Signers. 110 * There is now a JCESigner which uses a JCE KeyStore for signing. 111 * I have refactored the SigningServlet a bit, eliminating most of the demo code. 112 * This has been moved into DemoSigningServlet. 113 * I have expanded the CommandLineSigner, so it now also has an option for specifying a default signing service. 114 * The default web application now contains two signers. 115 * - The Demo one is still at /Signer 116 * - There is a new one at /personal/Signer this uses the testkeys.ks for 117 * signing anything under neu://test 118 * Note neu://test now has a default interactive signer running on localhost. 119 * So to play with this you must install the webapp on your own local machine. 120 * 121 * Revision 1.2 2002/09/23 15:09:11 pelle 122 * Got the SimpleSigner working properly. 123 * I couldn't get SealedObjects working with BouncyCastle's Symmetric keys. 124 * Don't know what I was doing, so I reimplemented it. Encrypting 125 * and decrypting it my self. 126 * 127 * Revision 1.1 2002/09/21 23:11:16 pelle 128 * A bunch of clean ups. Got rid of as many hard coded URL's as I could. 129 * 130 * User: pelleb 131 * Date: Sep 20, 2002 132 * Time: 12:37:32 PM 133 */ 134 package org.neuclear.commons.crypto.signers; 135 136 import org.neuclear.commons.LowLevelException; 137 import org.neuclear.commons.crypto.CryptoException; 138 import org.neuclear.commons.crypto.CryptoTools; 139 import org.neuclear.commons.crypto.passphraseagents.PassPhraseAgent; 140 import org.neuclear.commons.crypto.passphraseagents.UserCancellationException; 141 142 import javax.crypto.Cipher; 143 import javax.crypto.CipherInputStream; 144 import javax.crypto.CipherOutputStream; 145 import java.io.*; 146 import java.security.*; 147 import java.security.spec.KeySpec; 148 import java.security.spec.PKCS8EncodedKeySpec; 149 import java.util.HashMap; 150 import java.util.Map; 151 152 /*** 153 * Simple memory based implementation of Signer. 154 * Currently it doesnt even use the passphrase. However it does do a SHA1 digest on the name first. 155 */ 156 public final class SimpleSigner implements Signer { 157 158 public SimpleSigner(final String file, final PassPhraseAgent agent) { 159 this.agent = agent; 160 try { 161 signerFile = new File(file); 162 if (signerFile.exists()) { 163 System.out.println("NeuClear: Loading KeyStore"); 164 final FileInputStream in = new FileInputStream(signerFile); 165 final ObjectInputStream s = new ObjectInputStream(in); 166 ks = (HashMap) s.readObject(); 167 } else 168 ks = new HashMap(); 169 kf = KeyFactory.getInstance("RSA"); 170 kpg = KeyPairGenerator.getInstance("RSA"); 171 kpg.initialize(1024, SecureRandom.getInstance("SHA1PRNG")); 172 173 } catch (IOException e) { 174 throw new LowLevelException(e); 175 } catch (ClassNotFoundException e) { 176 throw new LowLevelException(e); 177 } catch (NoSuchAlgorithmException e) { 178 throw new LowLevelException(e); 179 } 180 } 181 182 private PrivateKey getKey(final String name, final char[] passphrase) throws InvalidPassphraseException, NonExistingSignerException { 183 System.out.println("NEUDIST: UnSealing key " + name + " ..."); 184 final byte[] encrypted = (byte[]) ks.get(getDigestedName(name)); 185 if (encrypted == null) 186 throw new NonExistingSignerException("Signer " + name + "doesnt exist in this Store"); 187 final ByteArrayInputStream bis = new ByteArrayInputStream(encrypted); 188 byte keyBytes[] = new byte[0]; 189 try { 190 final Cipher c = CryptoTools.makePBECipher(Cipher.DECRYPT_MODE, passphrase); 191 final CipherInputStream cin = new CipherInputStream(bis, c); 192 final DataInputStream din = new DataInputStream(cin); 193 //byte keyBytes[]=new byte[c.getOutputSize(encrypted.length)]; 194 if (din.readInt() != 11870) //This is just a quick check to see if the passphrase worked 195 throw new InvalidPassphraseException("Passphrase Didnt Match"); 196 197 final int i = din.readInt(); 198 // Sanity Check 199 if (i > 5000) 200 throw new InvalidPassphraseException("Returned key is too big"); 201 keyBytes = new byte[i]; 202 din.readFully(keyBytes, 0, keyBytes.length); 203 din.close(); 204 final KeySpec spec = new PKCS8EncodedKeySpec(keyBytes); 205 return kf.generatePrivate(spec); 206 } catch (GeneralSecurityException e) { 207 throw new InvalidPassphraseException(e.getLocalizedMessage()); 208 } catch (IOException e) { 209 throw new LowLevelException(e); 210 } 211 } 212 213 /*** 214 * Adds the given key to the store. Uses the PassPhrase 215 * agent to ask for PassPhrase. 216 * 217 * @param name The name to store it as 218 * @param key The PrivateKey itself. 219 */ 220 221 public final void addKey(final String name, final PrivateKey key) throws UserCancellationException { 222 addKey(name, agent.getPassPhrase(name), key); 223 } 224 225 /*** 226 * Adds the given key to the store. 227 * 228 * @param name The name to store it as 229 * @param passphrase The passphrase to encrypt the key 230 * @param key The PrivateKey itself. 231 */ 232 233 public final void addKey(final String name, final char[] passphrase, final PrivateKey key) { 234 System.out.println("NeuClear: Sealing key: " + name + " in format " + key.getFormat()); 235 try { 236 final ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 237 DataOutputStream dOut = new DataOutputStream(bOut); 238 final Cipher c = CryptoTools.makePBECipher(Cipher.ENCRYPT_MODE, passphrase); 239 final CipherOutputStream cOut = new CipherOutputStream(dOut, c); 240 dOut = new DataOutputStream(cOut); 241 dOut.writeInt(11870);//This is just a quick check to see if the passphrase worked 242 final byte[] keyBytes = key.getEncoded(); //I'm assuming this is PKCS8, If not tough dooda 243 dOut.writeInt(keyBytes.length); 244 dOut.write(keyBytes); 245 dOut.close(); 246 final byte[] encrypted = bOut.toByteArray(); 247 ks.put(getDigestedName(name), encrypted); 248 } catch (GeneralSecurityException e) { 249 throw new LowLevelException(e); 250 } catch (IOException e) { 251 throw new LowLevelException(e); 252 } 253 } 254 255 public final boolean canSignFor(final String name) { 256 return ks.containsKey(getDigestedName(name)); 257 } 258 259 /*** 260 * Checks the key type of the given alias 261 * 262 * @param name 263 * @return KEY_NONE,KEY_RSA,KEY_DSA 264 */ 265 public final int getKeyType(final String name) { 266 return (canSignFor(name)) ? KEY_RSA : KEY_NONE; // We always use RSA here 267 } 268 269 static final protected String getDigestedName(final String name) { 270 return new String(CryptoTools.digest(name.getBytes())); 271 } 272 273 public final void save() { 274 if (signerFile.getParent() != null) 275 signerFile.getParentFile().mkdirs(); 276 277 try { 278 final FileOutputStream f = new FileOutputStream(signerFile); 279 final ObjectOutput s = new ObjectOutputStream(f); 280 s.writeObject(ks); 281 s.flush(); 282 } catch (IOException e) { 283 throw new LowLevelException(e); 284 } 285 286 } 287 288 /*** 289 * Signs the data with the privatekey of the given name 290 * 291 * @param name Alias of private key to be used within KeyStore 292 * @param data Data to be signed 293 * @return The signature 294 * @throws UserCancellationException 295 */ 296 public final byte[] sign(final String name, final byte[] data) throws UserCancellationException { 297 return sign(name, data, false); 298 } 299 300 private final byte[] sign(final String name, final byte[] data, boolean incorrect) throws UserCancellationException { 301 try { 302 return CryptoTools.sign(getKey(name, agent.getPassPhrase(name, incorrect)), data); 303 } catch (CryptoException e) { 304 return sign(name, data, true); 305 } 306 } 307 308 public final PublicKey generateKey(final String alias) throws UserCancellationException { 309 final KeyPair kp = kpg.generateKeyPair(); 310 addKey(alias, agent.getPassPhrase(alias), kp.getPrivate()); 311 return kp.getPublic(); 312 } 313 314 public PublicKey generateKey() throws UserCancellationException { 315 final KeyPair kp = kpg.generateKeyPair(); 316 String alias = CryptoTools.encodeBase32(CryptoTools.digest(kp.getPublic().getEncoded())); 317 addKey(alias, agent.getPassPhrase(alias), kp.getPrivate()); 318 return kp.getPublic(); 319 } 320 321 private KeyFactory kf; 322 private Map ks; 323 324 private final File signerFile; 325 private final PassPhraseAgent agent; 326 private final KeyPairGenerator kpg; 327 }

This page was automatically generated by Maven