1 package org.apache.fulcrum.jce.crypto;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.security.GeneralSecurityException;
25 import java.security.Key;
26
27 import javax.crypto.Cipher;
28 import javax.crypto.SecretKeyFactory;
29 import javax.crypto.spec.PBEKeySpec;
30 import javax.crypto.spec.PBEParameterSpec;
31
32 /**
33 * Concrete factory for creating encrypting/decrypting streams. The
34 * implementation uses the JCA (Java Crypto Extension) supplied
35 * by SUN (using SunJCE 1.42).
36 *
37 * The implementation uses as PBEWithMD5AndDES for encryption which
38 * should be sufficent for most applications.
39 *
40 * The implementation also supplies a default password in the case that
41 * the programmer don't want to have additional hassles. It is easy to
42 * reengineer the password being used but much better than a hard-coded
43 * password in the application.
44 *
45 * The code uses parts from Markus Hahn's Blowfish library found at
46 * http://blowfishj.sourceforge.net/
47 *
48 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl </a>
49 * @author <a href="mailto:maakus@earthlink.net">Markus Hahn</a>
50 */
51
52 public class CryptoStreamFactoryImpl extends CryptoStreamFactoryTemplate implements CryptoStreamFactory
53 {
54 /** the salt for the PBE algorithm */
55 protected final byte[] salt;
56
57 /** the count paramter for the PBE algorithm */
58 protected int count;
59
60 /** the name of the JCE provider */
61 protected String providerName;
62
63 /** the algorithm to use */
64 protected String algorithm;
65
66 /** the default instance */
67 private static CryptoStreamFactory instance;
68
69 /**
70 * The JCE provider name known to work. If the value
71 * is set to null an appropriate provider will be
72 * used.
73 */
74 protected static final String PROVIDERNAME = null;
75
76 /**
77 * Factory method to get a default instance
78 * @return an instance of the CryptoStreamFactory
79 */
80 public static CryptoStreamFactory getInstance()
81 {
82 synchronized(CryptoStreamFactoryImpl.class ) {
83 if( CryptoStreamFactoryImpl.instance == null )
84 {
85 CryptoStreamFactoryImpl.instance = new CryptoStreamFactoryImpl();
86 }
87
88 return CryptoStreamFactoryImpl.instance;
89 }
90 }
91
92 /**
93 * Set the default instance from an external application.
94 * @param instance the new default instance
95 */
96 public static void setInstance( CryptoStreamFactory instance )
97 {
98 CryptoStreamFactoryImpl.instance = instance;
99 }
100
101 /**
102 * Constructor
103 */
104 public CryptoStreamFactoryImpl()
105 {
106 this.salt = CryptoParameters.Salt();
107 this.count = CryptoParameters.COUNT;
108 this.providerName = PROVIDERNAME;
109 this.algorithm = CryptoParameters.ALGORITHM;
110 }
111
112 /**
113 * Constructor
114 *
115 * @param salt the salt for the PBE algorithm
116 * @param count the iteration for PBEParameterSpec
117 */
118 public CryptoStreamFactoryImpl( byte[] salt, int count)
119 {
120 this.salt = salt.clone();
121 this.count = count;
122 this.providerName = PROVIDERNAME;
123 this.algorithm = CryptoParameters.ALGORITHM;
124 }
125
126
127 /**
128 * Factory method to get a default instance
129 *
130 * @param salt the salt for the PBE algorithm
131 * @param count the iteration for PBEParameterSpec
132 * @return an instance of the CryptoStreamFactory
133 *
134 */
135 public static CryptoStreamFactory getInstance( byte[] salt, int count)
136 {
137 synchronized(CryptoStreamFactoryImpl.class ) {
138 if( CryptoStreamFactoryImpl.instance == null )
139 {
140 CryptoStreamFactoryImpl.instance = new CryptoStreamFactoryImpl(salt, count);
141 }
142
143 return CryptoStreamFactoryImpl.instance;
144 }
145 }
146
147 /**
148 * @see org.apache.fulcrum.jce.crypto.CryptoStreamFactory#getSmartInputStream(java.io.InputStream,char[])
149 *
150 *
151 */
152 public InputStream getSmartInputStream(InputStream is, char[] password )
153 throws GeneralSecurityException, IOException
154 {
155 SmartDecryptingInputStream result;
156
157 result = new SmartDecryptingInputStream(
158 getInstance(),
159 is,
160 password
161 );
162
163 return result;
164 }
165
166 /**
167 * @return Returns the algorithm.
168 */
169 @Override
170 public String getAlgorithm()
171 {
172 return algorithm;
173 }
174
175 /**
176 * @return Returns the count.
177 */
178 protected int getCount()
179 {
180 return count;
181 }
182
183 /**
184 * @return Returns the providerName.
185 */
186 protected String getProviderName()
187 {
188 return providerName;
189 }
190
191 /**
192 * @return Returns the salt.
193 */
194 protected byte [] getSalt()
195 {
196 return salt;
197 }
198
199 /**
200 * Create a PBE key.
201 *
202 * @param password the password to use.
203 * @return the key
204 * @throws GeneralSecurityException creating the key failed
205 */
206 protected Key createKey( char[] password )
207 throws GeneralSecurityException
208 {
209 SecretKeyFactory keyFactory;
210 String algorithm = this.getAlgorithm();
211 PBEKeySpec keySpec = new PBEKeySpec(password);
212
213 if( this.getProviderName() == null )
214 {
215 keyFactory = SecretKeyFactory.getInstance( algorithm );
216 }
217 else
218 {
219 keyFactory = SecretKeyFactory.getInstance( algorithm, this.getProviderName() );
220 }
221
222 return keyFactory.generateSecret(keySpec);
223 }
224
225 /**
226 * Create a Cipher.
227 *
228 * @param mode the cipher mode
229 * @param password the password
230 * @return an instance of a cipher
231 * @throws GeneralSecurityException creating a cipher failed
232 * @throws IOException creating a cipher failed
233 */
234 protected Cipher createCipher( int mode, char[] password )
235 throws GeneralSecurityException, IOException
236 {
237 Cipher cipher;
238 PBEParameterSpec paramSpec = new PBEParameterSpec( this.getSalt(), this.getCount() );
239 Key key = this.createKey( password );
240
241 if( this.getProviderName() == null )
242 {
243 cipher = Cipher.getInstance( this.getAlgorithm() );
244 }
245 else
246 {
247 cipher = Cipher.getInstance( this.getAlgorithm(), this.getProviderName() );
248 }
249
250 cipher.init( mode, key, paramSpec );
251 return cipher;
252 }
253 }