1 package org
.argeo
.util
;
3 import java
.io
.ByteArrayInputStream
;
4 import java
.io
.ByteArrayOutputStream
;
5 import java
.io
.IOException
;
6 import java
.io
.InputStream
;
7 import java
.io
.OutputStream
;
8 import java
.security
.GeneralSecurityException
;
9 import java
.security
.InvalidKeyException
;
10 import java
.security
.Key
;
12 import javax
.crypto
.Cipher
;
13 import javax
.crypto
.CipherInputStream
;
14 import javax
.crypto
.CipherOutputStream
;
15 import javax
.crypto
.SecretKey
;
16 import javax
.crypto
.SecretKeyFactory
;
17 import javax
.crypto
.spec
.IvParameterSpec
;
18 import javax
.crypto
.spec
.PBEKeySpec
;
19 import javax
.crypto
.spec
.SecretKeySpec
;
21 public class PasswordEncryption
{
22 public final static Integer DEFAULT_ITERATION_COUNT
= 1024;
23 /** Stronger with 256, but causes problem with Oracle JVM */
24 public final static Integer DEFAULT_SECRETE_KEY_LENGTH
= 256;
25 public final static Integer DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED
= 128;
26 public final static String DEFAULT_SECRETE_KEY_FACTORY
= "PBKDF2WithHmacSHA1";
27 public final static String DEFAULT_SECRETE_KEY_ENCRYPTION
= "AES";
28 public final static String DEFAULT_CIPHER_NAME
= "AES/CBC/PKCS5Padding";
29 public final static String DEFAULT_CHARSET
= "UTF-8";
31 private Integer iterationCount
= DEFAULT_ITERATION_COUNT
;
32 private Integer secreteKeyLength
= DEFAULT_SECRETE_KEY_LENGTH
;
33 private String secreteKeyFactoryName
= DEFAULT_SECRETE_KEY_FACTORY
;
34 private String secreteKeyEncryption
= DEFAULT_SECRETE_KEY_ENCRYPTION
;
35 private String cipherName
= DEFAULT_CIPHER_NAME
;
37 private static byte[] DEFAULT_SALT_8
= { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
38 (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
39 private static byte[] DEFAULT_IV_16
= { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
40 (byte) 0x35, (byte) 0xE3, (byte) 0x03, (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
41 (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
44 private Cipher ecipher
;
45 private Cipher dcipher
;
47 private String securityProviderName
= null;
50 * This is up to the caller to clear the passed array. Neither copy of nor
51 * reference to the passed array is kept
53 public PasswordEncryption(char[] password
) {
54 this(password
, DEFAULT_SALT_8
, DEFAULT_IV_16
);
58 * This is up to the caller to clear the passed array. Neither copies of nor
59 * references to the passed arrays are kept
61 public PasswordEncryption(char[] password
, byte[] passwordSalt
, byte[] initializationVector
) {
63 initKeyAndCiphers(password
, passwordSalt
, initializationVector
);
64 } catch (InvalidKeyException e
) {
65 Integer previousSecreteKeyLength
= secreteKeyLength
;
66 secreteKeyLength
= DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED
;
67 System
.err
.println("'" + e
.getMessage() + "', will use " + secreteKeyLength
68 + " secrete key length instead of " + previousSecreteKeyLength
);
70 initKeyAndCiphers(password
, passwordSalt
, initializationVector
);
71 } catch (Exception e1
) {
72 throw new UtilsException("Cannot get secret key (with restricted length)", e1
);
74 } catch (Exception e
) {
75 throw new UtilsException("Cannot get secret key", e
);
79 protected void initKeyAndCiphers(char[] password
, byte[] passwordSalt
, byte[] initializationVector
)
80 throws GeneralSecurityException
{
81 byte[] salt
= new byte[8];
82 System
.arraycopy(passwordSalt
, 0, salt
, 0, salt
.length
);
83 // for (int i = 0; i < password.length && i < salt.length; i++)
84 // salt[i] = (byte) password[i];
85 byte[] iv
= new byte[16];
86 System
.arraycopy(initializationVector
, 0, iv
, 0, iv
.length
);
88 SecretKeyFactory keyFac
= SecretKeyFactory
.getInstance(getSecretKeyFactoryName());
89 PBEKeySpec keySpec
= new PBEKeySpec(password
, salt
, getIterationCount(), getKeyLength());
90 String secKeyEncryption
= getSecretKeyEncryption();
91 if (secKeyEncryption
!= null) {
92 SecretKey tmp
= keyFac
.generateSecret(keySpec
);
93 key
= new SecretKeySpec(tmp
.getEncoded(), getSecretKeyEncryption());
95 key
= keyFac
.generateSecret(keySpec
);
97 if (securityProviderName
!= null)
98 ecipher
= Cipher
.getInstance(getCipherName(), securityProviderName
);
100 ecipher
= Cipher
.getInstance(getCipherName());
101 ecipher
.init(Cipher
.ENCRYPT_MODE
, key
, new IvParameterSpec(iv
));
102 dcipher
= Cipher
.getInstance(getCipherName());
103 dcipher
.init(Cipher
.DECRYPT_MODE
, key
, new IvParameterSpec(iv
));
106 public void encrypt(InputStream decryptedIn
, OutputStream encryptedOut
) throws IOException
{
108 CipherOutputStream out
= new CipherOutputStream(encryptedOut
, ecipher
);
109 StreamUtils
.copy(decryptedIn
, out
);
110 StreamUtils
.closeQuietly(out
);
111 } catch (IOException e
) {
113 } catch (Exception e
) {
114 throw new UtilsException("Cannot encrypt", e
);
116 StreamUtils
.closeQuietly(decryptedIn
);
120 public void decrypt(InputStream encryptedIn
, OutputStream decryptedOut
) throws IOException
{
122 CipherInputStream decryptedIn
= new CipherInputStream(encryptedIn
, dcipher
);
123 StreamUtils
.copy(decryptedIn
, decryptedOut
);
124 } catch (IOException e
) {
126 } catch (Exception e
) {
127 throw new UtilsException("Cannot decrypt", e
);
129 StreamUtils
.closeQuietly(encryptedIn
);
133 public byte[] encryptString(String str
) {
134 ByteArrayOutputStream out
= null;
135 ByteArrayInputStream in
= null;
137 out
= new ByteArrayOutputStream();
138 in
= new ByteArrayInputStream(str
.getBytes(DEFAULT_CHARSET
));
140 return out
.toByteArray();
141 } catch (Exception e
) {
142 throw new UtilsException("Cannot encrypt", e
);
144 StreamUtils
.closeQuietly(out
);
148 /** Closes the input stream */
149 public String
decryptAsString(InputStream in
) {
150 ByteArrayOutputStream out
= null;
152 out
= new ByteArrayOutputStream();
154 return new String(out
.toByteArray(), DEFAULT_CHARSET
);
155 } catch (Exception e
) {
156 throw new UtilsException("Cannot decrypt", e
);
158 StreamUtils
.closeQuietly(out
);
162 protected Key
getKey() {
166 protected Cipher
getEcipher() {
170 protected Cipher
getDcipher() {
174 protected Integer
getIterationCount() {
175 return iterationCount
;
178 protected Integer
getKeyLength() {
179 return secreteKeyLength
;
182 protected String
getSecretKeyFactoryName() {
183 return secreteKeyFactoryName
;
186 protected String
getSecretKeyEncryption() {
187 return secreteKeyEncryption
;
190 protected String
getCipherName() {
194 public void setIterationCount(Integer iterationCount
) {
195 this.iterationCount
= iterationCount
;
198 public void setSecreteKeyLength(Integer keyLength
) {
199 this.secreteKeyLength
= keyLength
;
202 public void setSecreteKeyFactoryName(String secreteKeyFactoryName
) {
203 this.secreteKeyFactoryName
= secreteKeyFactoryName
;
206 public void setSecreteKeyEncryption(String secreteKeyEncryption
) {
207 this.secreteKeyEncryption
= secreteKeyEncryption
;
210 public void setCipherName(String cipherName
) {
211 this.cipherName
= cipherName
;
214 public void setSecurityProviderName(String securityProviderName
) {
215 this.securityProviderName
= securityProviderName
;