]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/util/PasswordEncryption.java
Adapt CMS Web to new assembly approach.
[lgpl/argeo-commons.git] / org.argeo.util / src / org / argeo / util / PasswordEncryption.java
1 /*
2 * Copyright (C) 2007-2012 Argeo GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.argeo.util;
17
18 import java.io.ByteArrayInputStream;
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.security.GeneralSecurityException;
24 import java.security.InvalidKeyException;
25 import java.security.Key;
26
27 import javax.crypto.Cipher;
28 import javax.crypto.CipherInputStream;
29 import javax.crypto.CipherOutputStream;
30 import javax.crypto.SecretKey;
31 import javax.crypto.SecretKeyFactory;
32 import javax.crypto.spec.IvParameterSpec;
33 import javax.crypto.spec.PBEKeySpec;
34 import javax.crypto.spec.SecretKeySpec;
35
36 public class PasswordEncryption {
37 public final static Integer DEFAULT_ITERATION_COUNT = 1024;
38 /** Stronger with 256, but causes problem with Oracle JVM */
39 public final static Integer DEFAULT_SECRETE_KEY_LENGTH = 256;
40 public final static Integer DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED = 128;
41 public final static String DEFAULT_SECRETE_KEY_FACTORY = "PBKDF2WithHmacSHA1";
42 public final static String DEFAULT_SECRETE_KEY_ENCRYPTION = "AES";
43 public final static String DEFAULT_CIPHER_NAME = "AES/CBC/PKCS5Padding";
44 public final static String DEFAULT_CHARSET = "UTF-8";
45
46 private Integer iterationCount = DEFAULT_ITERATION_COUNT;
47 private Integer secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH;
48 private String secreteKeyFactoryName = DEFAULT_SECRETE_KEY_FACTORY;
49 private String secreteKeyEncryption = DEFAULT_SECRETE_KEY_ENCRYPTION;
50 private String cipherName = DEFAULT_CIPHER_NAME;
51
52 private static byte[] DEFAULT_SALT_8 = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
53 (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
54 private static byte[] DEFAULT_IV_16 = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
55 (byte) 0x35, (byte) 0xE3, (byte) 0x03, (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
56 (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
57
58 private Key key;
59 private Cipher ecipher;
60 private Cipher dcipher;
61
62 private String securityProviderName = null;
63
64 /**
65 * This is up to the caller to clear the passed array. Neither copy of nor
66 * reference to the passed array is kept
67 */
68 public PasswordEncryption(char[] password) {
69 this(password, DEFAULT_SALT_8, DEFAULT_IV_16);
70 }
71
72 /**
73 * This is up to the caller to clear the passed array. Neither copies of nor
74 * references to the passed arrays are kept
75 */
76 public PasswordEncryption(char[] password, byte[] passwordSalt, byte[] initializationVector) {
77 try {
78 initKeyAndCiphers(password, passwordSalt, initializationVector);
79 } catch (InvalidKeyException e) {
80 Integer previousSecreteKeyLength = secreteKeyLength;
81 secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED;
82 System.err.println("'" + e.getMessage() + "', will use " + secreteKeyLength
83 + " secrete key length instead of " + previousSecreteKeyLength);
84 try {
85 initKeyAndCiphers(password, passwordSalt, initializationVector);
86 } catch (Exception e1) {
87 throw new UtilsException("Cannot get secret key (with restricted length)", e1);
88 }
89 } catch (Exception e) {
90 throw new UtilsException("Cannot get secret key", e);
91 }
92 }
93
94 protected void initKeyAndCiphers(char[] password, byte[] passwordSalt, byte[] initializationVector)
95 throws GeneralSecurityException {
96 byte[] salt = new byte[8];
97 System.arraycopy(passwordSalt, 0, salt, 0, salt.length);
98 // for (int i = 0; i < password.length && i < salt.length; i++)
99 // salt[i] = (byte) password[i];
100 byte[] iv = new byte[16];
101 System.arraycopy(initializationVector, 0, iv, 0, iv.length);
102
103 SecretKeyFactory keyFac = SecretKeyFactory.getInstance(getSecretKeyFactoryName());
104 PBEKeySpec keySpec = new PBEKeySpec(password, salt, getIterationCount(), getKeyLength());
105 String secKeyEncryption = getSecretKeyEncryption();
106 if (secKeyEncryption != null) {
107 SecretKey tmp = keyFac.generateSecret(keySpec);
108 key = new SecretKeySpec(tmp.getEncoded(), getSecretKeyEncryption());
109 } else {
110 key = keyFac.generateSecret(keySpec);
111 }
112 if (securityProviderName != null)
113 ecipher = Cipher.getInstance(getCipherName(), securityProviderName);
114 else
115 ecipher = Cipher.getInstance(getCipherName());
116 ecipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
117 dcipher = Cipher.getInstance(getCipherName());
118 dcipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
119 }
120
121 public void encrypt(InputStream decryptedIn, OutputStream encryptedOut) throws IOException {
122 try {
123 CipherOutputStream out = new CipherOutputStream(encryptedOut, ecipher);
124 StreamUtils.copy(decryptedIn, out);
125 StreamUtils.closeQuietly(out);
126 } catch (IOException e) {
127 throw e;
128 } catch (Exception e) {
129 throw new UtilsException("Cannot encrypt", e);
130 } finally {
131 StreamUtils.closeQuietly(decryptedIn);
132 }
133 }
134
135 public void decrypt(InputStream encryptedIn, OutputStream decryptedOut) throws IOException {
136 try {
137 CipherInputStream decryptedIn = new CipherInputStream(encryptedIn, dcipher);
138 StreamUtils.copy(decryptedIn, decryptedOut);
139 } catch (IOException e) {
140 throw e;
141 } catch (Exception e) {
142 throw new UtilsException("Cannot decrypt", e);
143 } finally {
144 StreamUtils.closeQuietly(encryptedIn);
145 }
146 }
147
148 public byte[] encryptString(String str) {
149 ByteArrayOutputStream out = null;
150 ByteArrayInputStream in = null;
151 try {
152 out = new ByteArrayOutputStream();
153 in = new ByteArrayInputStream(str.getBytes(DEFAULT_CHARSET));
154 encrypt(in, out);
155 return out.toByteArray();
156 } catch (Exception e) {
157 throw new UtilsException("Cannot encrypt", e);
158 } finally {
159 StreamUtils.closeQuietly(out);
160 }
161 }
162
163 /** Closes the input stream */
164 public String decryptAsString(InputStream in) {
165 ByteArrayOutputStream out = null;
166 try {
167 out = new ByteArrayOutputStream();
168 decrypt(in, out);
169 return new String(out.toByteArray(), DEFAULT_CHARSET);
170 } catch (Exception e) {
171 throw new UtilsException("Cannot decrypt", e);
172 } finally {
173 StreamUtils.closeQuietly(out);
174 }
175 }
176
177 protected Key getKey() {
178 return key;
179 }
180
181 protected Cipher getEcipher() {
182 return ecipher;
183 }
184
185 protected Cipher getDcipher() {
186 return dcipher;
187 }
188
189 protected Integer getIterationCount() {
190 return iterationCount;
191 }
192
193 protected Integer getKeyLength() {
194 return secreteKeyLength;
195 }
196
197 protected String getSecretKeyFactoryName() {
198 return secreteKeyFactoryName;
199 }
200
201 protected String getSecretKeyEncryption() {
202 return secreteKeyEncryption;
203 }
204
205 protected String getCipherName() {
206 return cipherName;
207 }
208
209 public void setIterationCount(Integer iterationCount) {
210 this.iterationCount = iterationCount;
211 }
212
213 public void setSecreteKeyLength(Integer keyLength) {
214 this.secreteKeyLength = keyLength;
215 }
216
217 public void setSecreteKeyFactoryName(String secreteKeyFactoryName) {
218 this.secreteKeyFactoryName = secreteKeyFactoryName;
219 }
220
221 public void setSecreteKeyEncryption(String secreteKeyEncryption) {
222 this.secreteKeyEncryption = secreteKeyEncryption;
223 }
224
225 public void setCipherName(String cipherName) {
226 this.cipherName = cipherName;
227 }
228
229 public void setSecurityProviderName(String securityProviderName) {
230 this.securityProviderName = securityProviderName;
231 }
232 }