1 /***
2 *
3 */
4 package de.cohesion.bssh.impl;
5
6 import java.io.File;
7 import java.io.FileInputStream;
8 import java.io.FileOutputStream;
9 import java.io.IOException;
10 import java.io.ObjectInputStream;
11 import java.io.ObjectOutputStream;
12 import java.security.Provider;
13 import java.security.Security;
14 import java.util.Iterator;
15
16 import javax.crypto.Cipher;
17 import javax.crypto.SealedObject;
18 import javax.crypto.SecretKey;
19 import javax.crypto.SecretKeyFactory;
20 import javax.crypto.spec.PBEKeySpec;
21 import javax.crypto.spec.PBEParameterSpec;
22
23 import de.cohesion.bssh.Member;
24 import de.cohesion.bssh.PasswordStore;
25
26 /***
27 * @author schulzs
28 */
29 public class PBEPasswordStore implements PasswordStore {
30
31 private enum Ciphers {
32 ENCRYPT(Cipher.ENCRYPT_MODE), DECRYPT(Cipher.DECRYPT_MODE);
33
34 private static final String CIPHER_ALGORITHM_NAME = "PBEWithMD5AndDES";
35
36 private static final byte[] SALT = { (byte) 0xc7, (byte) 0x73,
37 (byte) 0x21, (byte) 0x8c, (byte) 0x7e, (byte) 0xc8,
38 (byte) 0xee, (byte) 0x99 };
39
40 private static final int ITERATIONS = 20;
41
42 private static final PBEParameterSpec PARAM_SPEC = new PBEParameterSpec(
43 SALT, ITERATIONS);
44
45 private int opMode;
46
47 Ciphers(int opMode) {
48 this.opMode = opMode;
49 }
50
51 public Cipher get(final char[] passphrase) throws Exception {
52 Cipher c = Cipher.getInstance(CIPHER_ALGORITHM_NAME, "SunJCE");
53 c.init(opMode, this.getKey(passphrase), PARAM_SPEC);
54 return c;
55 }
56
57 private SecretKey getKey(final char[] passphrase) throws Exception {
58 SecretKeyFactory factory = SecretKeyFactory
59 .getInstance(CIPHER_ALGORITHM_NAME);
60 return factory.generateSecret(new PBEKeySpec(passphrase));
61 }
62
63 }
64
65 private static void dumpProviders() {
66 try {
67 Provider[] providers = Security.getProviders();
68 for (Provider p : providers) {
69 System.out.println("Provider: " + p.getName() + ", "
70 + p.getInfo());
71 for (Iterator itr = p.keySet().iterator(); itr.hasNext();) {
72 String key = (String) itr.next();
73 String value = (String) p.get(key);
74 System.out.println("\t" + key + " = " + value);
75 }
76 }
77 } catch (Exception e) {
78 e.printStackTrace();
79 }
80 }
81
82 private final File root;
83
84 private final char[] passphrase;
85
86 public PBEPasswordStore(final File root, final char[] passphrase)
87 throws IOException {
88 this.root = root;
89 this.passphrase = passphrase;
90 }
91
92 private File getPasswordFile(final Member member) throws IOException {
93 File f = new File(root.getAbsolutePath() + File.separator
94 + member.getUserName() + File.separator
95 + member.getHost().toString().replace('/', '-') + "-"
96 + member.getPort());
97 if (!f.exists()) {
98 boolean success = f.mkdirs();
99 if (!success) {
100 throw new IOException("could not create directory structure");
101 }
102 }
103 return f;
104 }
105
106 public char[] getPassword(final Member member) throws IOException {
107 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(this
108 .getPasswordFile(member)));
109 String result = null;
110 try {
111 SealedObject so = (SealedObject) ois.readObject();
112 result = (String) so.getObject(Ciphers.DECRYPT.get(passphrase));
113 } catch (Exception e) {
114 IOException ioe = new IOException(
115 "opening sealed password file failed");
116 ioe.initCause(e);
117 throw ioe;
118 } finally {
119 ois.close();
120 }
121
122 return result.toCharArray();
123 }
124
125 public void store(final Member member, char[] password) throws IOException {
126 File f = this.getPasswordFile(member);
127 if (f.exists()) {
128 boolean success = f.delete();
129 if (!success) {
130 throw new IOException(
131 "file already exists and could not be deleted");
132 }
133 }
134 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
135 try {
136 SealedObject so = new SealedObject(new String(password),
137 Ciphers.ENCRYPT.get(passphrase));
138 oos.writeObject(so);
139 } catch (Exception e) {
140 IOException ioe = new IOException(
141 "storing sealed password file failed");
142 ioe.initCause(e);
143 throw ioe;
144 } finally {
145 oos.close();
146 }
147 }
148
149 }