1 | /*
|
---|
2 | Copyright (c) Dale Anson, 2004
|
---|
3 | Redistribution and use in source and binary forms, with or without
|
---|
4 | modification, are permitted provided that the following conditions are met:
|
---|
5 | 1. Redistributions of source code must retain the above copyright notice,
|
---|
6 | this list of conditions and the following disclaimer.
|
---|
7 | 2. Redistributions in binary form must reproduce the above copyright
|
---|
8 | notice, this list of conditions and the following disclaimer in the
|
---|
9 | documentation and/or other materials provided with the distribution.
|
---|
10 | 3. The name of the author may not be used to endorse or promote products
|
---|
11 | derived from this software without specific prior written permission.
|
---|
12 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
---|
13 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
---|
14 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
---|
15 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
---|
16 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
---|
17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
---|
18 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
---|
19 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
---|
20 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
---|
21 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
22 | */
|
---|
23 | package ise.antelope.tasks.password;
|
---|
24 |
|
---|
25 | import java.security.*;
|
---|
26 | import java.security.spec.*;
|
---|
27 | import javax.crypto.*;
|
---|
28 | import javax.crypto.spec.*;
|
---|
29 |
|
---|
30 | import ise.antelope.tasks.util.Base64;
|
---|
31 |
|
---|
32 | /**
|
---|
33 | * Simple class to encode and decode passwords. The encrypted password is a
|
---|
34 | * base-64 encoded string, so it's suitable for storage in a properties file or
|
---|
35 | * where ever a string might be stored. This class could be used for larger
|
---|
36 | * strings than passwords, but all I need is an easy way to store passwords in a
|
---|
37 | * file.
|
---|
38 | *
|
---|
39 | * @author Dale Anson, May 2002
|
---|
40 | * @version $Revision: 1.1 $
|
---|
41 | */
|
---|
42 | public class PasswordHandler {
|
---|
43 |
|
---|
44 | /** use Triple-DES as algorithm */
|
---|
45 | public final static String DESEDE = "DESede";
|
---|
46 | /** key to use if none given */
|
---|
47 | public final static String DEFAULT_KEY = "The quick brown fox jumped over the lazy dog.";
|
---|
48 | /** default character encoding */
|
---|
49 | private final static String ENCODING = "UTF8";
|
---|
50 |
|
---|
51 | private KeySpec keySpec;
|
---|
52 | private SecretKeyFactory keyFactory;
|
---|
53 | private Cipher cipher;
|
---|
54 |
|
---|
55 | /**
|
---|
56 | * Constructor for PasswordHandler, uses default key.
|
---|
57 | *
|
---|
58 | * @exception PasswordHandlerException Description of Exception
|
---|
59 | */
|
---|
60 | public PasswordHandler() throws PasswordHandlerException {
|
---|
61 | this(DEFAULT_KEY);
|
---|
62 | }
|
---|
63 |
|
---|
64 | /**
|
---|
65 | * Constructor for PasswordHandler
|
---|
66 | *
|
---|
67 | * @param encryptKey String to use for a key, must be at
|
---|
68 | * least 32 characters long.
|
---|
69 | * @exception PasswordHandlerException Description of Exception
|
---|
70 | */
|
---|
71 | public PasswordHandler(String encryptKey) throws PasswordHandlerException {
|
---|
72 | if (encryptKey == null) {
|
---|
73 | throw new IllegalArgumentException("Encrypt key cannot be null.");
|
---|
74 | }
|
---|
75 | if (encryptKey.trim().length() < 32) {
|
---|
76 | throw new IllegalArgumentException("Encrypt key cannot be less than 32 characters.");
|
---|
77 | }
|
---|
78 |
|
---|
79 | try {
|
---|
80 | byte[] bytes = encryptKey.getBytes(ENCODING);
|
---|
81 | keySpec = new DESedeKeySpec(bytes);
|
---|
82 | keyFactory = SecretKeyFactory.getInstance(DESEDE);
|
---|
83 | cipher = Cipher.getInstance(DESEDE);
|
---|
84 | }
|
---|
85 | catch (Exception e) {
|
---|
86 | throw new PasswordHandlerException(e);
|
---|
87 | }
|
---|
88 | }
|
---|
89 |
|
---|
90 | /**
|
---|
91 | * Encrypt a password.
|
---|
92 | *
|
---|
93 | * @param password the password to encrypt
|
---|
94 | * @return the encrypted password.
|
---|
95 | * @exception PasswordHandlerException Description of Exception
|
---|
96 | */
|
---|
97 | public String encrypt(String password) throws PasswordHandlerException {
|
---|
98 | if (password == null || password.trim().length() == 0)
|
---|
99 | throw new IllegalArgumentException("Password cannot be null or empty.");
|
---|
100 |
|
---|
101 | try {
|
---|
102 | SecretKey key = keyFactory.generateSecret(keySpec);
|
---|
103 | cipher.init(Cipher.ENCRYPT_MODE, key);
|
---|
104 | byte[] plain_bytes = password.getBytes(ENCODING);
|
---|
105 | byte[] cipher_bytes = cipher.doFinal(plain_bytes);
|
---|
106 | return Base64.encodeBytes(cipher_bytes);
|
---|
107 | }
|
---|
108 | catch (Exception e) {
|
---|
109 | throw new PasswordHandlerException(e);
|
---|
110 | }
|
---|
111 | }
|
---|
112 |
|
---|
113 | /**
|
---|
114 | * Decrypt a password.
|
---|
115 | *
|
---|
116 | * @param encryptedPassword the encrypted password, needing to
|
---|
117 | * be decrypted
|
---|
118 | * @return the original, plain text password
|
---|
119 | * @exception PasswordHandlerException Description of Exception
|
---|
120 | */
|
---|
121 | public String decrypt(String encryptedPassword) throws PasswordHandlerException {
|
---|
122 | if (encryptedPassword == null || encryptedPassword.trim().length() <= 0)
|
---|
123 | throw new IllegalArgumentException("Encrypted password cannot be null or empty.");
|
---|
124 |
|
---|
125 | try {
|
---|
126 | SecretKey key = keyFactory.generateSecret(keySpec);
|
---|
127 | cipher.init(Cipher.DECRYPT_MODE, key);
|
---|
128 | byte[] cipher_bytes = Base64.decode(encryptedPassword);
|
---|
129 | byte[] plain_bytes = cipher.doFinal(cipher_bytes);
|
---|
130 | //StringBuffer sb = new StringBuffer();
|
---|
131 | //for (int i = 0; i < plain_bytes.length; i++) {
|
---|
132 | // sb.append((char) plain_bytes[i]);
|
---|
133 | //}
|
---|
134 | return new String(plain_bytes);
|
---|
135 | }
|
---|
136 | catch (Exception e) {
|
---|
137 | throw new PasswordHandlerException(e);
|
---|
138 | }
|
---|
139 | }
|
---|
140 |
|
---|
141 | /**
|
---|
142 | * for testing only
|
---|
143 | *
|
---|
144 | * @param args The command line arguments
|
---|
145 | */
|
---|
146 | public static void main(String[] args) {
|
---|
147 | try {
|
---|
148 | //testPassword.append(String.valueOf(i % 10));
|
---|
149 | String testPassword = "abcdef1234567890";
|
---|
150 | System.out.println("original: " + testPassword.toString());
|
---|
151 | System.out.println("original length: " + testPassword.length());
|
---|
152 | PasswordHandler ph = new PasswordHandler();
|
---|
153 | String encrypted = ph.encrypt(testPassword.toString());
|
---|
154 | System.out.println("encrypted: " + encrypted);
|
---|
155 | System.out.println("encrypted length: " + encrypted.length());
|
---|
156 | if (encrypted.length() >= 32)
|
---|
157 | System.exit(0);
|
---|
158 | ph = new PasswordHandler();
|
---|
159 | String plain = ph.decrypt(encrypted);
|
---|
160 | System.out.println("decrypted: " + plain);
|
---|
161 | if (testPassword.toString().compareTo(plain) != 0) {
|
---|
162 | throw new Exception("test failed!");
|
---|
163 | }
|
---|
164 | }
|
---|
165 | catch (Exception e) {
|
---|
166 | e.printStackTrace();
|
---|
167 | }
|
---|
168 | }
|
---|
169 | }
|
---|
170 |
|
---|