KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > filesys > server > auth > PasswordEncryptor


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.filesys.server.auth;
18
19 import java.io.UnsupportedEncodingException JavaDoc;
20 import java.security.InvalidKeyException JavaDoc;
21 import java.security.MessageDigest JavaDoc;
22 import java.security.NoSuchAlgorithmException JavaDoc;
23
24 import javax.crypto.BadPaddingException;
25 import javax.crypto.Cipher;
26 import javax.crypto.IllegalBlockSizeException;
27 import javax.crypto.NoSuchPaddingException;
28 import javax.crypto.spec.SecretKeySpec;
29
30 /**
31  * Password Encryptor Class
32  *
33  * <p>Generates LanMan and NTLMv1 encrypted passwords from the plain text password and challenge key.
34  *
35  * @author GKSpencer
36  */

37 public class PasswordEncryptor
38 {
39
40     // Encryption algorithm types
41

42     public static final int LANMAN = 0;
43     public static final int NTLM1 = 1;
44     public static final int NTLM2 = 2;
45     public static final int MD4 = 3;
46
47     // Encrpytion algorithm names
48

49     private final static String JavaDoc[] _algNames = { "LanMan", "NTLMv1", "NTLMv2", "MD4" };
50
51     /**
52      * Default constructor
53      */

54     public PasswordEncryptor()
55     {
56     }
57
58     /**
59      * Check if the required algorithms are available
60      *
61      * @return boolean
62      */

63     public static final boolean checkEncryptionAlgorithms()
64     {
65
66         boolean algOK = false;
67
68         try
69         {
70
71             // Check if MD4 is available
72

73             MessageDigest.getInstance("MD4");
74
75             // Check if DES is available
76

77             Cipher.getInstance("DES");
78         }
79         catch (NoSuchAlgorithmException JavaDoc ex)
80         {
81         }
82         catch (NoSuchPaddingException ex)
83         {
84         }
85
86         // Return the encryption algorithm status
87

88         return algOK;
89     }
90
91     /**
92      * Encrypt the plain text password with the specified encryption key using the specified
93      * encryption algorithm.
94      *
95      * @param plainPwd Plaintext password string
96      * @param encryptKey byte[] Encryption key
97      * @param alg int Encryption algorithm
98      * @return byte[] Encrypted password
99      * @exception NoSuchAlgorithmException If a required encryption algorithm is not available
100      */

101     public byte[] generateEncryptedPassword(String JavaDoc plainPwd, byte[] encryptKey, int alg)
102             throws NoSuchAlgorithmException JavaDoc
103     {
104
105         // Get the password
106

107         String JavaDoc pwd = plainPwd;
108         if (pwd == null)
109             pwd = "";
110
111         // Determine the encryption algorithm
112

113         byte[] encPwd = null;
114         MessageDigest JavaDoc md4 = null;
115         int len = 0;
116         byte[] pwdBytes = null;
117
118         switch (alg)
119         {
120
121         // LanMan DES encryption
122

123         case LANMAN:
124             encPwd = P24(pwd, encryptKey);
125             break;
126
127         // NTLM v1 encryption
128

129         case NTLM1:
130
131             // Create the MD4 hash
132

133             md4 = MessageDigest.getInstance("MD4");
134     
135             try {
136               pwdBytes = pwd.getBytes("UnicodeLittleUnmarked");
137             }
138             catch (UnsupportedEncodingException JavaDoc ex) {
139             }
140         
141             md4.update(pwdBytes);
142             byte[] p21 = new byte[21];
143             System.arraycopy(md4.digest(), 0, p21, 0, 16);
144
145             // Now use the LM encryption
146

147             encPwd = P24(p21,encryptKey);
148             break;
149
150         // NTLM v2 encryption
151

152         case NTLM2:
153             break;
154
155         // MD4 encryption
156

157         case MD4:
158
159             // Create the MD4 hash
160

161             md4 = MessageDigest.getInstance("MD4");
162             len = pwd.length();
163             pwdBytes = new byte[len * 2];
164
165             for (int i = 0; i < len; i++)
166             {
167                 char ch = pwd.charAt(i);
168                 pwdBytes[i * 2] = (byte) ch;
169                 pwdBytes[i * 2 + 1] = (byte) ((ch >> 8) & 0xFF);
170             }
171
172             md4.update(pwdBytes);
173             encPwd = new byte[16];
174             System.arraycopy(md4.digest(), 0, encPwd, 0, 16);
175             break;
176         }
177
178         // Return the encrypted password
179

180         return encPwd;
181     }
182
183     /**
184      * P16 encryption
185      *
186      * @param pwd java.lang.String
187      * @param s8 byte[]
188      * @return byte[]
189      * @exception NoSuchAlgorithmException If a required encryption algorithm is not available
190      */

191     public final byte[] P16(String JavaDoc pwd, byte[] s8) throws NoSuchAlgorithmException JavaDoc
192     {
193
194         // Make a 14 byte string using the password string. Truncate the
195
// password or pad with nulls to 14 characters.
196

197         StringBuffer JavaDoc p14str = new StringBuffer JavaDoc();
198         p14str.append(pwd.toUpperCase());
199         if (p14str.length() > 14)
200             p14str.setLength(14);
201
202         while (p14str.length() < 14)
203             p14str.append((char) 0x00);
204
205         // Convert the P14 string to an array of bytes. Allocate a 21 byte buffer as the result is usually passed
206
// through the P24() method
207

208         byte[] p14 = p14str.toString().getBytes();
209         byte[] p16 = new byte[21];
210
211         try
212         {
213
214             // DES encrypt the password bytes using the challenge key
215

216             Cipher des = Cipher.getInstance("DES");
217
218             // Set the encryption seed using the first 7 bytes of the password string.
219
// Generate the first 8 bytes of the return value.
220

221             byte[] key = generateKey(p14, 0);
222
223             SecretKeySpec chKey = new SecretKeySpec(key, 0, key.length, "DES");
224             des.init(Cipher.ENCRYPT_MODE, chKey);
225             byte[] res = des.doFinal(s8);
226             System.arraycopy(res, 0, p16, 0, 8);
227
228             // Encrypt the second block
229

230             key = generateKey(p14, 7);
231
232             chKey = new SecretKeySpec(key, 0, key.length, "DES");
233             des.init(Cipher.ENCRYPT_MODE, chKey);
234             res = des.doFinal(s8);
235             System.arraycopy(res, 0, p16, 8, 8);
236         }
237         catch (NoSuchPaddingException ex)
238         {
239             p16 = null;
240         }
241         catch (IllegalBlockSizeException ex)
242         {
243             p16 = null;
244         }
245         catch (BadPaddingException ex)
246         {
247             p16 = null;
248         }
249         catch (InvalidKeyException JavaDoc ex)
250         {
251             p16 = null;
252         }
253
254         // Return the 16 byte encrypted value
255

256         return p16;
257     }
258
259     /**
260      * P24 DES encryption
261      *
262      * @param pwd java.lang.String
263      * @param c8 byte[]
264      * @return byte[]
265      * @exception NoSuchAlgorithmException If a required encryption algorithm is not available
266      */

267     private final byte[] P24(String JavaDoc pwd, byte[] c8) throws NoSuchAlgorithmException JavaDoc
268     {
269
270         // Generate the 16 byte encrypted value using the password string and well
271
// known value.
272

273         byte[] s8 = new String JavaDoc("KGS!@#$%").getBytes();
274         byte[] p16 = P16(pwd, s8);
275
276         // Generate the 24 byte encrypted value
277

278         return P24(p16, c8);
279     }
280
281     /**
282      * P24 DES encryption
283      *
284      * @param p21 Plain password or hashed password bytes
285      * @param ch Challenge bytes
286      * @return Encrypted password
287      * @exception NoSuchAlgorithmException If a required encryption algorithm is not available
288      */

289     private final byte[] P24(byte[] p21, byte[] ch) throws NoSuchAlgorithmException JavaDoc
290     {
291
292         byte[] enc = null;
293
294         try
295         {
296
297             // DES encrypt the password bytes using the challenge key
298

299             Cipher des = Cipher.getInstance("DES");
300
301             // Allocate the output bytes
302

303             enc = new byte[24];
304
305             // Encrypt the first block
306

307             byte[] key = generateKey(p21, 0);
308
309             SecretKeySpec chKey = new SecretKeySpec(key, 0, key.length, "DES");
310             des.init(Cipher.ENCRYPT_MODE, chKey);
311             byte[] res = des.doFinal(ch);
312             System.arraycopy(res, 0, enc, 0, 8);
313
314             // Encrypt the second block
315

316             key = generateKey(p21, 7);
317
318             chKey = new SecretKeySpec(key, 0, key.length, "DES");
319             des.init(Cipher.ENCRYPT_MODE, chKey);
320             res = des.doFinal(ch);
321             System.arraycopy(res, 0, enc, 8, 8);
322
323             // Encrypt the last block
324

325             key = generateKey(p21, 14);
326
327             chKey = new SecretKeySpec(key, 0, key.length, "DES");
328             des.init(Cipher.ENCRYPT_MODE, chKey);
329             res = des.doFinal(ch);
330             System.arraycopy(res, 0, enc, 16, 8);
331         }
332         catch (NoSuchPaddingException ex)
333         {
334             ex.printStackTrace();
335             enc = null;
336         }
337         catch (IllegalBlockSizeException ex)
338         {
339             ex.printStackTrace();
340             enc = null;
341         }
342         catch (BadPaddingException ex)
343         {
344             ex.printStackTrace();
345             enc = null;
346         }
347         catch (InvalidKeyException JavaDoc ex)
348         {
349             ex.printStackTrace();
350             enc = null;
351         }
352
353         // Return the encrypted password, or null if an error occurred
354

355         return enc;
356     }
357
358     /**
359      * Return the encryption algorithm as a string
360      *
361      * @param alg int
362      * @return String
363      */

364     public static String JavaDoc getAlgorithmName(int alg)
365     {
366         if (alg >= 0 && alg < _algNames.length)
367             return _algNames[alg];
368         return "Unknown";
369     }
370
371     /**
372      * Make a 7-byte string into a 64 bit/8 byte/longword key.
373      *
374      * @param byt byte[]
375      * @param off int
376      * @return byte[]
377      */

378     private byte[] generateKey(byte[] byt, int off)
379     {
380
381         // Allocate the key
382

383         byte[] key = new byte[8];
384
385         // Make a key from the input string
386

387         key[0] = (byte) (byt[off + 0] >> 1);
388         key[1] = (byte) (((byt[off + 0] & 0x01) << 6) | ((byt[off + 1] & 0xFF) >> 2));
389         key[2] = (byte) (((byt[off + 1] & 0x03) << 5) | ((byt[off + 2] & 0xFF) >> 3));
390         key[3] = (byte) (((byt[off + 2] & 0x07) << 4) | ((byt[off + 3] & 0xFF) >> 4));
391         key[4] = (byte) (((byt[off + 3] & 0x0F) << 3) | ((byt[off + 4] & 0xFF) >> 5));
392         key[5] = (byte) (((byt[off + 4] & 0x1F) << 2) | ((byt[off + 5] & 0xFF) >> 6));
393         key[6] = (byte) (((byt[off + 5] & 0x3F) << 1) | ((byt[off + 6] & 0xFF) >> 7));
394         key[7] = (byte) (byt[off + 6] & 0x7F);
395
396         for (int i = 0; i < 8; i++)
397         {
398             key[i] = (byte) (key[i] << 1);
399         }
400
401         return key;
402     }
403     
404     /**
405      * NTLM1 encryption of the MD4 hashed password
406      *
407      * @param p21 byte[]
408      * @param c8 byte[]
409      * @return byte[]
410      * @exception NoSuchAlgorithmException
411      */

412     public final byte[] doNTLM1Encryption(byte[] p21, byte[] c8)
413         throws NoSuchAlgorithmException JavaDoc
414     {
415         return P24(p21, c8);
416     }
417 }
418
Popular Tags