1 package org.apache.fulcrum.jce.crypto;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.security.GeneralSecurityException;
26 import java.security.Key;
27
28 import javax.crypto.Cipher;
29 import javax.crypto.CipherInputStream;
30 import javax.crypto.CipherOutputStream;
31 import javax.crypto.SecretKeyFactory;
32 import javax.crypto.spec.PBEKeySpec;
33 import javax.crypto.spec.PBEParameterSpec;
34
35 /**
36 * Concrete factory for creating encrypting/decrypting streams. The
37 * implementation uses the JCE (Java Crypto Extension) either supplied
38 * by SUN (using SunJCE 1.42) or an custom provider such as BouncyCastle
39 * or the newer Cryptix libraries.
40 *
41 * The implementation uses as PBEWithMD5AndTripleDES for encryption which
42 * should be sufficent for most applications.
43 *
44 * The implementation also supplies a default password in the case that
45 * the programmer don't want to have additional hassles. It is easy to
46 * reengineer the password being used but much better than a hard-coded
47 * password in the application.
48 *
49 * The code uses parts from Markus Hahn's Blowfish library found at
50 * http://blowfishj.sourceforge.net/
51 *
52 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl </a>
53 * @author <a href="mailto:maakus@earthlink.net">Markus Hahn</a>
54 */
55
56 public final class CryptoStreamFactoryImpl implements CryptoStreamFactory
57 {
58 /** the salt for the PBE algorithm */
59 private byte[] salt;
60
61 /** the count paramter for the PBE algorithm */
62 private int count;
63
64 /** the name of the JCE provider */
65 private String providerName;
66
67 /** the algorithm to use */
68 private String algorithm;
69
70 /** the default instance */
71 private static CryptoStreamFactory instance;
72
73 /**
74 * Factory method to get a default instance
75 * @return an instance of the CryptoStreamFactory
76 */
77 public static CryptoStreamFactory getInstance()
78 {
79 if( CryptoStreamFactoryImpl.instance == null )
80 {
81 synchronized( CryptoStreamFactory.class )
82 {
83 if( CryptoStreamFactoryImpl.instance == null )
84 {
85 CryptoStreamFactoryImpl.instance = new CryptoStreamFactoryImpl();
86 }
87 }
88 }
89
90 return instance;
91 }
92
93 /**
94 * Set the default instance from an external application.
95 * @param instance the new default instance
96 */
97 public static void setInstance( CryptoStreamFactory instance )
98 {
99 CryptoStreamFactoryImpl.instance = instance;
100 }
101
102 /**
103 * Constructor
104 */
105 public CryptoStreamFactoryImpl()
106 {
107 this.salt = CryptoParameters.SALT;
108 this.count = CryptoParameters.COUNT;
109 this.providerName = CryptoParameters.PROVIDERNAME;
110 this.algorithm = CryptoParameters.ALGORITHM;
111 }
112
113 /**
114 * Constructor
115 *
116 * @param salt the salt for the PBE algorithm
117 * @param count the iteration for PBEParameterSpec
118 * @param algorithm the algorithm to be used
119 * @param providerName the name of the JCE provide to b used
120 */
121 public CryptoStreamFactoryImpl(
122 byte[] salt,
123 int count,
124 String algorithm,
125 String providerName )
126 {
127 this.salt = salt;
128 this.count = count;
129 this.algorithm = algorithm;
130 this.providerName = providerName;
131 }
132
133 /**
134 * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getInputStream(java.io.InputStream)
135 */
136 public InputStream getInputStream( InputStream is )
137 throws GeneralSecurityException, IOException
138 {
139 Cipher cipher = this.createCipher( Cipher.DECRYPT_MODE, PasswordFactory.create() );
140 CipherInputStream cis = new CipherInputStream( is, cipher );
141 return cis;
142 }
143
144 /**
145 * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getInputStream(java.io.InputStream,char[])
146 */
147 public InputStream getInputStream( InputStream is, char[] password )
148 throws GeneralSecurityException, IOException
149 {
150 Cipher cipher = this.createCipher( Cipher.DECRYPT_MODE, password );
151 CipherInputStream cis = new CipherInputStream( is, cipher );
152 return cis;
153 }
154
155 /**
156 * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getSmartInputStream(java.io.InputStream)
157 */
158 public InputStream getSmartInputStream(InputStream is)
159 throws GeneralSecurityException, IOException
160 {
161 return this.getSmartInputStream(
162 is,
163 PasswordFactory.create()
164 );
165 }
166
167 /**
168 * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getSmartInputStream(java.io.InputStream,char[])
169 */
170 public InputStream getSmartInputStream(InputStream is, char[] password )
171 throws GeneralSecurityException, IOException
172 {
173 SmartDecryptingInputStream result = null;
174
175 result = new SmartDecryptingInputStream(
176 getInstance(),
177 is,
178 password
179 );
180
181 return result;
182 }
183
184 /**
185 * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getOutputStream(java.io.OutputStream, char[])
186 */
187 public OutputStream getOutputStream( OutputStream os, char[] password )
188 throws GeneralSecurityException, IOException
189 {
190 Cipher cipher = this.createCipher( Cipher.ENCRYPT_MODE, password );
191 CipherOutputStream cos = new CipherOutputStream( os, cipher );
192 return cos;
193 }
194
195 /**
196 * @return Returns the algorithm.
197 */
198 private final String getAlgorithm()
199 {
200 return algorithm;
201 }
202
203 /**
204 * @return Returns the count.
205 */
206 private final int getCount()
207 {
208 return count;
209 }
210
211 /**
212 * @return Returns the providerName.
213 */
214 private final String getProviderName()
215 {
216 return providerName;
217 }
218
219 /**
220 * @return Returns the salt.
221 */
222 private final byte [] getSalt()
223 {
224 return salt;
225 }
226
227 /**
228 * Create a PBE key.
229 *
230 * @param password the password to use.
231 * @return the key
232 * @throws GeneralSecurityException creating the key failed
233 */
234 private final Key createKey( char[] password )
235 throws GeneralSecurityException
236 {
237 SecretKeyFactory keyFactory = null;
238 String algorithm = this.getAlgorithm();
239 PBEKeySpec keySpec = new PBEKeySpec(password);
240
241 if( this.getProviderName() == null )
242 {
243 keyFactory = SecretKeyFactory.getInstance( algorithm );
244 }
245 else
246 {
247 keyFactory = SecretKeyFactory.getInstance( algorithm, this.getProviderName() );
248 }
249
250 Key key = keyFactory.generateSecret(keySpec);
251 return key;
252 }
253
254 /**
255 * Create a Cipher.
256 *
257 * @param mode the cipher mode
258 * @param password the password
259 * @return an instance of a cipher
260 * @throws GeneralSecurityException creating a cipher failed
261 * @throws IOException creating a cipher failed
262 */
263 private final Cipher createCipher( int mode, char[] password )
264 throws GeneralSecurityException, IOException
265 {
266 Cipher cipher = null;
267 PBEParameterSpec paramSpec = new PBEParameterSpec( this.getSalt(), this.getCount() );
268 Key key = this.createKey( password );
269
270 if( this.getProviderName() == null )
271 {
272 cipher = Cipher.getInstance( this.getAlgorithm() );
273 }
274 else
275 {
276 cipher = Cipher.getInstance( this.getAlgorithm(), this.getProviderName() );
277 }
278
279 cipher.init( mode, key, paramSpec );
280 return cipher;
281 }
282 }