]> git.argeo.org Git - lgpl/argeo-commons.git/blob - crypto/PasswordBasedEncryption.java
Prepare next development cycle
[lgpl/argeo-commons.git] / crypto / PasswordBasedEncryption.java
1 package org.argeo.util.crypto;
2
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.Key;
9
10 import javax.crypto.Cipher;
11 import javax.crypto.CipherInputStream;
12 import javax.crypto.CipherOutputStream;
13 import javax.crypto.SecretKey;
14 import javax.crypto.SecretKeyFactory;
15 import javax.crypto.spec.IvParameterSpec;
16 import javax.crypto.spec.PBEKeySpec;
17 import javax.crypto.spec.SecretKeySpec;
18
19 import org.argeo.ArgeoException;
20 import org.argeo.StreamUtils;
21
22 /** Simple password based encryption / decryption */
23 public class PasswordBasedEncryption {
24 public final static Integer DEFAULT_ITERATION_COUNT = 1024;
25 public final static Integer DEFAULT_KEY_LENGTH = 256;
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 = "AES/CBC/PKCS5Padding";
29 public final static String DEFAULT_CHARSET = "UTF-8";
30
31 private static byte[] DEFAULT_SALT_8 = { (byte) 0xA9, (byte) 0x9B,
32 (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3,
33 (byte) 0x03 };
34 private static byte[] DEFAULT_IV_16 = { (byte) 0xA9, (byte) 0x9B,
35 (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3,
36 (byte) 0x03, (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32,
37 (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
38
39 private final Key key;
40 private final Cipher ecipher;
41 private final Cipher dcipher;
42
43 /**
44 * This is up to the caller to clear the passed array. Neither copy of nor
45 * reference to the passed array is kept
46 */
47 public PasswordBasedEncryption(char[] password) {
48 this(password, DEFAULT_SALT_8, DEFAULT_IV_16);
49 }
50
51 /**
52 * This is up to the caller to clear the passed array. Neither copies of nor
53 * references to the passed arrays are kept
54 */
55 public PasswordBasedEncryption(char[] password, byte[] passwordSalt,
56 byte[] initializationVector) {
57 try {
58 byte[] salt = new byte[8];
59 System.arraycopy(passwordSalt, 0, salt, 0, salt.length);
60 // for (int i = 0; i < password.length && i < salt.length; i++)
61 // salt[i] = (byte) password[i];
62 byte[] iv = new byte[16];
63 System.arraycopy(initializationVector, 0, iv, 0, iv.length);
64 // for (int i = 0; i < password.length && i < iv.length; i++)
65 // iv[i] = (byte) password[i];
66
67 SecretKeyFactory keyFac = SecretKeyFactory
68 .getInstance(getSecretKeyFactoryName());
69 PBEKeySpec keySpec = new PBEKeySpec(password, salt,
70 getIterationCount(), getKeyLength());
71 String secKeyEncryption = getSecretKeyEncryption();
72 if (secKeyEncryption != null) {
73 SecretKey tmp = keyFac.generateSecret(keySpec);
74 key = new SecretKeySpec(tmp.getEncoded(),
75 getSecretKeyEncryption());
76 } else {
77 key = keyFac.generateSecret(keySpec);
78 }
79 ecipher = Cipher.getInstance(getCipherName());
80 ecipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
81 // AlgorithmParameters params = ecipher.getParameters();
82 // byte[] iv =
83 // params.getParameterSpec(IvParameterSpec.class).getIV();
84 dcipher = Cipher.getInstance(getCipherName());
85 dcipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
86 } catch (Exception e) {
87 throw new ArgeoException("Cannot get secret key", e);
88 }
89 }
90
91 public void encrypt(InputStream decryptedIn, OutputStream encryptedOut)
92 throws IOException {
93 try {
94 CipherOutputStream out = new CipherOutputStream(encryptedOut,
95 ecipher);
96 StreamUtils.copy(decryptedIn, out);
97 StreamUtils.closeQuietly(out);
98 } catch (IOException e) {
99 throw e;
100 } catch (Exception e) {
101 throw new ArgeoException("Cannot encrypt", e);
102 } finally {
103 StreamUtils.closeQuietly(decryptedIn);
104 }
105 }
106
107 public void decrypt(InputStream encryptedIn, OutputStream decryptedOut)
108 throws IOException {
109 try {
110 CipherInputStream decryptedIn = new CipherInputStream(encryptedIn,
111 dcipher);
112 StreamUtils.copy(decryptedIn, decryptedOut);
113 } catch (IOException e) {
114 throw e;
115 } catch (Exception e) {
116 throw new ArgeoException("Cannot decrypt", e);
117 } finally {
118 StreamUtils.closeQuietly(encryptedIn);
119 }
120 }
121
122 public byte[] encryptString(String str) {
123 ByteArrayOutputStream out = null;
124 ByteArrayInputStream in = null;
125 try {
126 out = new ByteArrayOutputStream();
127 in = new ByteArrayInputStream(str.getBytes(DEFAULT_CHARSET));
128 encrypt(in, out);
129 return out.toByteArray();
130 } catch (Exception e) {
131 throw new ArgeoException("Cannot encrypt", e);
132 } finally {
133 StreamUtils.closeQuietly(out);
134 }
135 }
136
137 /** Closes the input stream */
138 public String decryptAsString(InputStream in) {
139 ByteArrayOutputStream out = null;
140 try {
141 out = new ByteArrayOutputStream();
142 decrypt(in, out);
143 return new String(out.toByteArray(), DEFAULT_CHARSET);
144 } catch (Exception e) {
145 throw new ArgeoException("Cannot decrypt", e);
146 } finally {
147 StreamUtils.closeQuietly(out);
148 }
149 }
150
151 protected Key getKey() {
152 return key;
153 }
154
155 protected Cipher getEcipher() {
156 return ecipher;
157 }
158
159 protected Cipher getDcipher() {
160 return dcipher;
161 }
162
163 protected Integer getIterationCount() {
164 return DEFAULT_ITERATION_COUNT;
165 }
166
167 protected Integer getKeyLength() {
168 return DEFAULT_KEY_LENGTH;
169 }
170
171 protected String getSecretKeyFactoryName() {
172 return DEFAULT_SECRETE_KEY_FACTORY;
173 }
174
175 protected String getSecretKeyEncryption() {
176 return DEFAULT_SECRETE_KEY_ENCRYPTION;
177 }
178
179 protected String getCipherName() {
180 return DEFAULT_CIPHER;
181 }
182 }