View Javadoc

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.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 }