1 package be
.nikiroo
.utils
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
5 import java
.io
.OutputStream
;
6 import java
.io
.UnsupportedEncodingException
;
7 import java
.security
.InvalidKeyException
;
8 import java
.security
.NoSuchAlgorithmException
;
10 import javax
.crypto
.BadPaddingException
;
11 import javax
.crypto
.Cipher
;
12 import javax
.crypto
.CipherInputStream
;
13 import javax
.crypto
.CipherOutputStream
;
14 import javax
.crypto
.IllegalBlockSizeException
;
15 import javax
.crypto
.NoSuchPaddingException
;
16 import javax
.crypto
.SecretKey
;
17 import javax
.crypto
.spec
.SecretKeySpec
;
18 import javax
.net
.ssl
.SSLException
;
21 * Small utility class to do AES encryption/decryption.
23 * Do not assume it is actually secure until you checked the code...
27 public class CryptUtils
{
28 private Cipher ecipher
;
29 private Cipher dcipher
;
32 * Small and leazy way to initialize a 128 bits key with {@link CryptUtils}.
34 * <b>Some</b> part of the key will be used to generate a 128 bits key and
35 * initialize the {@link CryptUtils}; even NULL will generate something.
37 * <b>This is most probably not secure. Do not use if you actually care
41 * the {@link String} to use as a base for the key, can be NULL
43 public CryptUtils(String key
) {
46 } catch (InvalidKeyException e
) {
47 // We made sure that the key is correct, so nothing here
53 * Create a new instance of {@link CryptUtils} with the given 128 bytes key.
55 * The key <b>must</b> be exactly 128 bytes long.
58 * the 128 bits (32 bytes) of the key
60 * @throws InvalidKeyException
61 * if the key is not an array of 128 bytes
63 public CryptUtils(byte[] bytes32
) throws InvalidKeyException
{
68 * Wrap the given {@link InputStream} so it is transparently encrypted by
69 * the current {@link CryptUtils}.
72 * the {@link InputStream} to wrap
73 * @return the auto-encode {@link InputStream}
75 public InputStream
encryptInputStream(InputStream in
) {
76 return new CipherInputStream(in
, ecipher
);
80 * Wrap the given {@link OutputStream} so it is transparently encrypted by
81 * the current {@link CryptUtils}.
84 * the {@link OutputStream} to wrap
85 * @return the auto-encode {@link OutputStream}
87 public OutputStream
encryptOutpuStream(OutputStream out
) {
88 return new CipherOutputStream(out
, ecipher
);
92 * Wrap the given {@link OutStream} so it is transparently decoded by the
93 * current {@link CryptUtils}.
96 * the {@link InputStream} to wrap
97 * @return the auto-decode {@link InputStream}
99 public InputStream
decryptInputStream(InputStream in
) {
100 return new CipherInputStream(in
, dcipher
);
104 * Wrap the given {@link OutStream} so it is transparently decoded by the
105 * current {@link CryptUtils}.
108 * the {@link OutputStream} to wrap
109 * @return the auto-decode {@link OutputStream}
111 public OutputStream
decryptOutputStream(OutputStream out
) {
112 return new CipherOutputStream(out
, dcipher
);
116 * This method required an array of 128 bytes.
119 * the array, which <b>must</b> be of 128 bits (32 bytes)
121 * @throws InvalidKeyException
122 * if the key is not an array of 128 bits (32 bytes)
124 private void init(byte[] bytes32
) throws InvalidKeyException
{
125 if (bytes32
== null || bytes32
.length
!= 32) {
126 throw new InvalidKeyException(
127 "The size of the key must be of 128 bits (32 bytes), it is: "
128 + (bytes32
== null ?
"null" : "" + bytes32
.length
)
132 SecretKey key
= new SecretKeySpec(bytes32
, "AES");
134 ecipher
= Cipher
.getInstance("AES/ECB/PKCS5Padding");
135 dcipher
= Cipher
.getInstance("AES/ECB/PKCS5Padding");
136 ecipher
.init(Cipher
.ENCRYPT_MODE
, key
);
137 dcipher
.init(Cipher
.DECRYPT_MODE
, key
);
138 } catch (NoSuchAlgorithmException e
) {
139 // Every implementation of the Java platform is required to support
140 // this standard Cipher transformation with 128 bits keys
142 } catch (NoSuchPaddingException e
) {
143 // Every implementation of the Java platform is required to support
144 // this standard Cipher transformation with 128 bits keys
146 } catch (InvalidKeyException e
) {
147 // Every implementation of the Java platform is required to support
148 // this standard Cipher transformation with 128 bits keys
157 * the data to encrypt
159 * @return the encrypted data
161 * @throws SSLException
162 * in case of I/O error (i.e., the data is not what you assumed
165 public byte[] encrypt(byte[] data
) throws SSLException
{
167 return ecipher
.doFinal(data
);
168 } catch (IllegalBlockSizeException e
) {
169 throw new SSLException(e
);
170 } catch (BadPaddingException e
) {
171 throw new SSLException(e
);
179 * the data to encrypt
181 * @return the encrypted data
183 * @throws SSLException
184 * in case of I/O error (i.e., the data is not what you assumed
187 public byte[] encrypt(String data
) throws SSLException
{
189 return encrypt(data
.getBytes("UTF8"));
190 } catch (UnsupportedEncodingException e
) {
191 // UTF-8 is required in all confirm JVMs
198 * Encrypt the data, then encode it into Base64.
201 * the data to encrypt
203 * TRUE to also compress the data in GZIP format; remember that
204 * compressed and not-compressed content are different; you need
205 * to know which is which when decoding
207 * @return the encrypted data, encoded in Base64
209 * @throws SSLException
210 * in case of I/O error (i.e., the data is not what you assumed
213 public String
encrypt64(String data
, boolean zip
) throws SSLException
{
215 return encrypt64(data
.getBytes("UTF8"), zip
);
216 } catch (UnsupportedEncodingException e
) {
217 // UTF-8 is required in all confirm JVMs
224 * Encrypt the data, then encode it into Base64.
227 * the data to encrypt
229 * TRUE to also compress the data in GZIP format; remember that
230 * compressed and not-compressed content are different; you need
231 * to know which is which when decoding
233 * @return the encrypted data, encoded in Base64
235 * @throws SSLException
236 * in case of I/O error (i.e., the data is not what you assumed
239 public String
encrypt64(byte[] data
, boolean zip
) throws SSLException
{
241 return StringUtils
.base64(encrypt(data
), zip
);
242 } catch (IOException e
) {
243 // not exactly true, but we consider here that this error is a crypt
244 // error, not a normal I/O error
245 throw new SSLException(e
);
250 * Decode the data which is assumed to be encrypted with the same utilities.
253 * the encrypted data to decode
255 * @return the original, decoded data
257 * @throws SSLException
258 * in case of I/O error
260 public byte[] decrypt(byte[] data
) throws SSLException
{
262 return dcipher
.doFinal(data
);
263 } catch (IllegalBlockSizeException e
) {
264 throw new SSLException(e
);
265 } catch (BadPaddingException e
) {
266 throw new SSLException(e
);
271 * Decode the data which is assumed to be encrypted with the same utilities
272 * and is a Base64 encoded value.
275 * the encrypted data to decode in Base64 format
277 * TRUE to also uncompress the data from a GZIP format
278 * automatically; if set to FALSE, zipped data can be returned
280 * @return the original, decoded data
282 * @throws SSLException
283 * in case of I/O error
285 public byte[] decrypt64(String data
, boolean zip
) throws SSLException
{
287 return decrypt(StringUtils
.unbase64(data
, zip
));
288 } catch (IOException e
) {
289 // not exactly true, but we consider here that this error is a crypt
290 // error, not a normal I/O error
291 throw new SSLException(e
);
296 * Decode the data which is assumed to be encrypted with the same utilities
297 * and is a Base64 encoded value, then convert it into a String (this method
298 * assumes the data <b>was</b> indeed a UTF-8 encoded {@link String}).
301 * the encrypted data to decode in Base64 format
303 * TRUE to also uncompress the data from a GZIP format
304 * automatically; if set to FALSE, zipped data can be returned
306 * @return the original, decoded data
308 * @throws SSLException
309 * in case of I/O error
311 public String
decrypt64s(String data
, boolean zip
) throws SSLException
{
313 return new String(decrypt(StringUtils
.unbase64(data
, zip
)), "UTF-8");
314 } catch (UnsupportedEncodingException e
) {
315 // UTF-8 is required in all confirm JVMs
318 } catch (IOException e
) {
319 // not exactly true, but we consider here that this error is a crypt
320 // error, not a normal I/O error
321 throw new SSLException(e
);
326 * This is probably <b>NOT</b> secure!
329 * some {@link String} input
331 * @return a 128 bits key computed from the given input
333 static private byte[] key2key(String input
) {
334 return StringUtils
.getMd5Hash("" + input
).getBytes();