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.UnsupportedEncodingException;
23  import java.security.MessageDigest;
24  import java.security.NoSuchAlgorithmException;
25  
26  /**
27   * The implementation supplies a default password in the case that
28   * the programmer don't want to have additional hassles. It is easy to
29   * reengineer the password being used but much better than a hard-coded
30   * password in the application.
31   *
32   * The code uses parts from Markus Hahn's Blowfish library found at
33   * http://blowfishj.sourceforge.net/
34   *
35   * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl </a>
36   * @author <a href="mailto:maakus@earthlink.net">Markus Hahn</a>
37   */
38  
39  public class PasswordFactory implements PasswordParameters
40  {
41      /**
42       * @return a default password using "xxxx-xxxx-xxxx-xxxxx"
43       */
44      public static final char[] create()
45          throws NoSuchAlgorithmException, UnsupportedEncodingException
46      {
47          return create(
48              PasswordParameters.DEFAULTPASSWORD,
49              PasswordParameters.SALT,
50              PasswordParameters.COUNT
51              );
52      }
53  
54      /**
55       * @param seed the default password supplied by the caller
56       * @return a password using "xxxx-xxxx-xxxx-xxxxx"
57       */
58      public static final char[] create( String seed )
59          throws NoSuchAlgorithmException, UnsupportedEncodingException
60      {
61          return create(
62              seed.toCharArray()
63              );
64      }
65  
66      /**
67       * @param seed the default password supplied by the caller
68       * @return a password using "xxxx-xxxx-xxxx-xxxxx"
69       */
70      public static final char[] create( char[] seed )
71          throws NoSuchAlgorithmException, UnsupportedEncodingException
72      {
73          return create(
74              seed,
75              PasswordParameters.SALT,
76              PasswordParameters.COUNT
77              );
78      }
79  
80      /**
81       * Creates a default password using "xxxx-xxxx-xxxx-xxxxx".
82       *
83       * @param salt the password salt
84       * @param password the default password
85       * @param count number of MessageDigest iterations
86       * @return the default password
87       * @throws NoSuchAlgorithmException the encryption algorithm is not supported
88       * @throws UnsupportedEncodingException the requested encoding is not supported
89       */
90      public static final char [] create( char[] password, byte[] salt, int count )
91          throws NoSuchAlgorithmException, UnsupportedEncodingException
92      {
93          char [] result = null;
94          MessageDigest sha1 = MessageDigest.getInstance( "SHA1" );
95          byte [] passwordMask = new String( password ).getBytes( "UTF-8" );
96          byte [] temp = new byte[salt.length + passwordMask.length];
97          byte [] digest = null;
98  
99          StringBuffer stringBuffer = new StringBuffer();
100 
101         // combine the password with the salt string into a byte[9
102 
103         System.arraycopy( passwordMask, 0, temp, 0, passwordMask.length );
104         System.arraycopy( salt, 0, temp, passwordMask.length, salt.length );
105 
106         // create a hash over and over to make it a bit random
107 
108         digest = temp;
109 
110         for (int i = 0; i < count; i++)
111         {
112             sha1.update( digest );
113             digest = sha1.digest();
114         }
115 
116         // build a well-formed password string to be usable
117         // by a human
118 
119         long long1 = createLong( digest, 0 );
120         long long2 = createLong( digest, 4 );
121         long long3 = createLong( digest, 8 );
122         long long4 = createLong( digest, 12 );
123 
124         stringBuffer.append( Long.toHexString( long1 ).substring( 0, 4 ) );
125         stringBuffer.append( '-' );
126         stringBuffer.append( Long.toHexString( long2 ).substring( 0, 4 ) );
127         stringBuffer.append( '-' );
128         stringBuffer.append( Long.toHexString( long3 ).substring( 0, 4 ) );
129         stringBuffer.append( '-' );
130         stringBuffer.append( Long.toHexString( long4 ).substring( 0, 5 ) );
131 
132         // copy the password
133 
134         result = new char[stringBuffer.length()];
135 
136         for (int i = 0; i < stringBuffer.length(); i++)
137         {
138             result[i] = stringBuffer.charAt( i );
139         }
140 
141         // wipe out the StringBuffer
142 
143         for (int i = 0; i < stringBuffer.length(); i++)
144         {
145             stringBuffer.setCharAt( i, ' ' );
146         }
147 
148         return result;
149     }
150 
151     /**
152      * Gets bytes from an array into a long.
153      *
154      * @param buf where to get the bytes
155      * @param nOfs index from where to read the data
156      * @return the 64bit integer
157      */
158     private static final long createLong(byte [] buf, int nOfs)
159     {
160         return
161             ((long)(( buf[nOfs    ]          << 24) |
162                     ((buf[nOfs + 1] & 0x0ff) << 16) |
163                     ((buf[nOfs + 2] & 0x0ff) <<  8) |
164                     ( buf[nOfs + 3] & 0x0ff       )) << 32) |
165             ((long)(( buf[nOfs + 4]          << 24) |
166                     ((buf[nOfs + 5] & 0x0ff) << 16) |
167                     ((buf[nOfs + 6] & 0x0ff) <<  8) |
168                     ( buf[nOfs + 7] & 0x0ff       )) & 0x0ffffffffL);
169     }
170 }