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