2 * Copyright (C) 2007-2012 Mathieu Baudier
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.util
.crypto
;
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
.Key
;
25 import javax
.crypto
.Cipher
;
26 import javax
.crypto
.CipherInputStream
;
27 import javax
.crypto
.CipherOutputStream
;
28 import javax
.crypto
.SecretKey
;
29 import javax
.crypto
.SecretKeyFactory
;
30 import javax
.crypto
.spec
.IvParameterSpec
;
31 import javax
.crypto
.spec
.PBEKeySpec
;
32 import javax
.crypto
.spec
.SecretKeySpec
;
34 import org
.argeo
.ArgeoException
;
35 import org
.argeo
.StreamUtils
;
37 /** Simple password based encryption / decryption */
38 public class PasswordBasedEncryption
{
39 public final static Integer DEFAULT_ITERATION_COUNT
= 1024;
40 public final static Integer DEFAULT_KEY_LENGTH
= 256;
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
= "AES/CBC/PKCS5Padding";
44 public final static String DEFAULT_CHARSET
= "UTF-8";
46 private static byte[] DEFAULT_SALT_8
= { (byte) 0xA9, (byte) 0x9B,
47 (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3,
49 private static byte[] DEFAULT_IV_16
= { (byte) 0xA9, (byte) 0x9B,
50 (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3,
51 (byte) 0x03, (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32,
52 (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
54 private final Key key
;
55 private final Cipher ecipher
;
56 private final Cipher dcipher
;
59 * This is up to the caller to clear the passed array. Neither copy of nor
60 * reference to the passed array is kept
62 public PasswordBasedEncryption(char[] password
) {
63 this(password
, DEFAULT_SALT_8
, DEFAULT_IV_16
);
67 * This is up to the caller to clear the passed array. Neither copies of nor
68 * references to the passed arrays are kept
70 public PasswordBasedEncryption(char[] password
, byte[] passwordSalt
,
71 byte[] initializationVector
) {
73 byte[] salt
= new byte[8];
74 System
.arraycopy(passwordSalt
, 0, salt
, 0, salt
.length
);
75 // for (int i = 0; i < password.length && i < salt.length; i++)
76 // salt[i] = (byte) password[i];
77 byte[] iv
= new byte[16];
78 System
.arraycopy(initializationVector
, 0, iv
, 0, iv
.length
);
79 // for (int i = 0; i < password.length && i < iv.length; i++)
80 // iv[i] = (byte) password[i];
82 SecretKeyFactory keyFac
= SecretKeyFactory
83 .getInstance(getSecretKeyFactoryName());
84 PBEKeySpec keySpec
= new PBEKeySpec(password
, salt
,
85 getIterationCount(), getKeyLength());
86 String secKeyEncryption
= getSecretKeyEncryption();
87 if (secKeyEncryption
!= null) {
88 SecretKey tmp
= keyFac
.generateSecret(keySpec
);
89 key
= new SecretKeySpec(tmp
.getEncoded(),
90 getSecretKeyEncryption());
92 key
= keyFac
.generateSecret(keySpec
);
94 ecipher
= Cipher
.getInstance(getCipherName());
95 ecipher
.init(Cipher
.ENCRYPT_MODE
, key
, new IvParameterSpec(iv
));
96 // AlgorithmParameters params = ecipher.getParameters();
98 // params.getParameterSpec(IvParameterSpec.class).getIV();
99 dcipher
= Cipher
.getInstance(getCipherName());
100 dcipher
.init(Cipher
.DECRYPT_MODE
, key
, new IvParameterSpec(iv
));
101 } catch (Exception e
) {
102 throw new ArgeoException("Cannot get secret key", e
);
106 public void encrypt(InputStream decryptedIn
, OutputStream encryptedOut
)
109 CipherOutputStream out
= new CipherOutputStream(encryptedOut
,
111 StreamUtils
.copy(decryptedIn
, out
);
112 StreamUtils
.closeQuietly(out
);
113 } catch (IOException e
) {
115 } catch (Exception e
) {
116 throw new ArgeoException("Cannot encrypt", e
);
118 StreamUtils
.closeQuietly(decryptedIn
);
122 public void decrypt(InputStream encryptedIn
, OutputStream decryptedOut
)
125 CipherInputStream decryptedIn
= new CipherInputStream(encryptedIn
,
127 StreamUtils
.copy(decryptedIn
, decryptedOut
);
128 } catch (IOException e
) {
130 } catch (Exception e
) {
131 throw new ArgeoException("Cannot decrypt", e
);
133 StreamUtils
.closeQuietly(encryptedIn
);
137 public byte[] encryptString(String str
) {
138 ByteArrayOutputStream out
= null;
139 ByteArrayInputStream in
= null;
141 out
= new ByteArrayOutputStream();
142 in
= new ByteArrayInputStream(str
.getBytes(DEFAULT_CHARSET
));
144 return out
.toByteArray();
145 } catch (Exception e
) {
146 throw new ArgeoException("Cannot encrypt", e
);
148 StreamUtils
.closeQuietly(out
);
152 /** Closes the input stream */
153 public String
decryptAsString(InputStream in
) {
154 ByteArrayOutputStream out
= null;
156 out
= new ByteArrayOutputStream();
158 return new String(out
.toByteArray(), DEFAULT_CHARSET
);
159 } catch (Exception e
) {
160 throw new ArgeoException("Cannot decrypt", e
);
162 StreamUtils
.closeQuietly(out
);
166 protected Key
getKey() {
170 protected Cipher
getEcipher() {
174 protected Cipher
getDcipher() {
178 protected Integer
getIterationCount() {
179 return DEFAULT_ITERATION_COUNT
;
182 protected Integer
getKeyLength() {
183 return DEFAULT_KEY_LENGTH
;
186 protected String
getSecretKeyFactoryName() {
187 return DEFAULT_SECRETE_KEY_FACTORY
;
190 protected String
getSecretKeyEncryption() {
191 return DEFAULT_SECRETE_KEY_ENCRYPTION
;
194 protected String
getCipherName() {
195 return DEFAULT_CIPHER
;