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
.nio
.charset
.Charset
;
9 import java
.nio
.charset
.StandardCharsets
;
10 import java
.security
.GeneralSecurityException
;
11 import java
.security
.InvalidKeyException
;
12 import java
.security
.Key
;
14 import javax
.crypto
.Cipher
;
15 import javax
.crypto
.CipherInputStream
;
16 import javax
.crypto
.CipherOutputStream
;
17 import javax
.crypto
.SecretKey
;
18 import javax
.crypto
.SecretKeyFactory
;
19 import javax
.crypto
.spec
.IvParameterSpec
;
20 import javax
.crypto
.spec
.PBEKeySpec
;
21 import javax
.crypto
.spec
.SecretKeySpec
;
23 public class PasswordEncryption
{
24 public final static Integer DEFAULT_ITERATION_COUNT
= 1024;
25 /** Stronger with 256, but causes problem with Oracle JVM */
26 public final static Integer DEFAULT_SECRETE_KEY_LENGTH
= 256;
27 public final static Integer DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED
= 128;
28 public final static String DEFAULT_SECRETE_KEY_FACTORY
= "PBKDF2WithHmacSHA1";
29 public final static String DEFAULT_SECRETE_KEY_ENCRYPTION
= "AES";
30 public final static String DEFAULT_CIPHER_NAME
= "AES/CBC/PKCS5Padding";
31 // public final static String DEFAULT_CHARSET = "UTF-8";
32 public final static Charset DEFAULT_CHARSET
= StandardCharsets
.UTF_8
;
34 private Integer iterationCount
= DEFAULT_ITERATION_COUNT
;
35 private Integer secreteKeyLength
= DEFAULT_SECRETE_KEY_LENGTH
;
36 private String secreteKeyFactoryName
= DEFAULT_SECRETE_KEY_FACTORY
;
37 private String secreteKeyEncryption
= DEFAULT_SECRETE_KEY_ENCRYPTION
;
38 private String cipherName
= DEFAULT_CIPHER_NAME
;
40 private static byte[] DEFAULT_SALT_8
= { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
41 (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
42 private static byte[] DEFAULT_IV_16
= { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
43 (byte) 0x35, (byte) 0xE3, (byte) 0x03, (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
44 (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
47 private Cipher ecipher
;
48 private Cipher dcipher
;
50 private String securityProviderName
= null;
53 * This is up to the caller to clear the passed array. Neither copy of nor
54 * reference to the passed array is kept
56 public PasswordEncryption(char[] password
) {
57 this(password
, DEFAULT_SALT_8
, DEFAULT_IV_16
);
61 * This is up to the caller to clear the passed array. Neither copies of nor
62 * references to the passed arrays are kept
64 public PasswordEncryption(char[] password
, byte[] passwordSalt
, byte[] initializationVector
) {
66 initKeyAndCiphers(password
, passwordSalt
, initializationVector
);
67 } catch (InvalidKeyException e
) {
68 Integer previousSecreteKeyLength
= secreteKeyLength
;
69 secreteKeyLength
= DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED
;
70 System
.err
.println("'" + e
.getMessage() + "', will use " + secreteKeyLength
71 + " secrete key length instead of " + previousSecreteKeyLength
);
73 initKeyAndCiphers(password
, passwordSalt
, initializationVector
);
74 } catch (GeneralSecurityException e1
) {
75 throw new IllegalStateException("Cannot get secret key (with restricted length)", e1
);
77 } catch (GeneralSecurityException e
) {
78 throw new IllegalStateException("Cannot get secret key", e
);
82 protected void initKeyAndCiphers(char[] password
, byte[] passwordSalt
, byte[] initializationVector
)
83 throws GeneralSecurityException
{
84 byte[] salt
= new byte[8];
85 System
.arraycopy(passwordSalt
, 0, salt
, 0, salt
.length
);
86 // for (int i = 0; i < password.length && i < salt.length; i++)
87 // salt[i] = (byte) password[i];
88 byte[] iv
= new byte[16];
89 System
.arraycopy(initializationVector
, 0, iv
, 0, iv
.length
);
91 SecretKeyFactory keyFac
= SecretKeyFactory
.getInstance(getSecretKeyFactoryName());
92 PBEKeySpec keySpec
= new PBEKeySpec(password
, salt
, getIterationCount(), getKeyLength());
93 String secKeyEncryption
= getSecretKeyEncryption();
94 if (secKeyEncryption
!= null) {
95 SecretKey tmp
= keyFac
.generateSecret(keySpec
);
96 key
= new SecretKeySpec(tmp
.getEncoded(), getSecretKeyEncryption());
98 key
= keyFac
.generateSecret(keySpec
);
100 if (securityProviderName
!= null)
101 ecipher
= Cipher
.getInstance(getCipherName(), securityProviderName
);
103 ecipher
= Cipher
.getInstance(getCipherName());
104 ecipher
.init(Cipher
.ENCRYPT_MODE
, key
, new IvParameterSpec(iv
));
105 dcipher
= Cipher
.getInstance(getCipherName());
106 dcipher
.init(Cipher
.DECRYPT_MODE
, key
, new IvParameterSpec(iv
));
109 public void encrypt(InputStream decryptedIn
, OutputStream encryptedOut
) throws IOException
{
111 CipherOutputStream out
= new CipherOutputStream(encryptedOut
, ecipher
);
112 StreamUtils
.copy(decryptedIn
, out
);
113 StreamUtils
.closeQuietly(out
);
114 } catch (IOException e
) {
117 StreamUtils
.closeQuietly(decryptedIn
);
121 public void decrypt(InputStream encryptedIn
, OutputStream decryptedOut
) throws IOException
{
123 CipherInputStream decryptedIn
= new CipherInputStream(encryptedIn
, dcipher
);
124 StreamUtils
.copy(decryptedIn
, decryptedOut
);
125 } catch (IOException e
) {
128 StreamUtils
.closeQuietly(encryptedIn
);
132 public byte[] encryptString(String str
) {
133 ByteArrayOutputStream out
= null;
134 ByteArrayInputStream in
= null;
136 out
= new ByteArrayOutputStream();
137 in
= new ByteArrayInputStream(str
.getBytes(DEFAULT_CHARSET
));
139 return out
.toByteArray();
140 } catch (IOException e
) {
141 throw new RuntimeException(e
);
143 StreamUtils
.closeQuietly(out
);
147 /** Closes the input stream */
148 public String
decryptAsString(InputStream in
) {
149 ByteArrayOutputStream out
= null;
151 out
= new ByteArrayOutputStream();
153 return new String(out
.toByteArray(), DEFAULT_CHARSET
);
154 } catch (IOException e
) {
155 throw new RuntimeException(e
);
157 StreamUtils
.closeQuietly(out
);
161 protected Key
getKey() {
165 protected Cipher
getEcipher() {
169 protected Cipher
getDcipher() {
173 protected Integer
getIterationCount() {
174 return iterationCount
;
177 protected Integer
getKeyLength() {
178 return secreteKeyLength
;
181 protected String
getSecretKeyFactoryName() {
182 return secreteKeyFactoryName
;
185 protected String
getSecretKeyEncryption() {
186 return secreteKeyEncryption
;
189 protected String
getCipherName() {
193 public void setIterationCount(Integer iterationCount
) {
194 this.iterationCount
= iterationCount
;
197 public void setSecreteKeyLength(Integer keyLength
) {
198 this.secreteKeyLength
= keyLength
;
201 public void setSecreteKeyFactoryName(String secreteKeyFactoryName
) {
202 this.secreteKeyFactoryName
= secreteKeyFactoryName
;
205 public void setSecreteKeyEncryption(String secreteKeyEncryption
) {
206 this.secreteKeyEncryption
= secreteKeyEncryption
;
209 public void setCipherName(String cipherName
) {
210 this.cipherName
= cipherName
;
213 public void setSecurityProviderName(String securityProviderName
) {
214 this.securityProviderName
= securityProviderName
;