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
) {
45 byte[] bytes32
= key2key(key
);
47 for (int i
= 0 ; i
< bytes32
.length
; i
++) {
50 } catch (InvalidKeyException e
) {
51 // We made sure that the key is correct, so nothing here
57 * Create a new instance of {@link CryptUtils} with the given 128 bytes key.
59 * The key <b>must</b> be exactly 128 bytes long.
62 * the 128 bits (32 bytes) of the key
64 * @throws InvalidKeyException
65 * if the key is not an array of 128 bytes
67 public CryptUtils(byte[] bytes32
) throws InvalidKeyException
{
69 for (int i
= 0 ; i
< bytes32
.length
; i
++) {
75 * Wrap the given {@link InputStream} so it is transparently encrypted by
76 * the current {@link CryptUtils}.
79 * the {@link InputStream} to wrap
80 * @return the auto-encode {@link InputStream}
82 public InputStream
encryptInputStream(InputStream in
) {
83 return new CipherInputStream(in
, ecipher
);
87 * Wrap the given {@link OutputStream} so it is transparently encrypted by
88 * the current {@link CryptUtils}.
91 * the {@link OutputStream} to wrap
92 * @return the auto-encode {@link OutputStream}
94 public OutputStream
encryptOutpuStream(OutputStream out
) {
95 return new CipherOutputStream(out
, ecipher
);
99 * Wrap the given {@link OutStream} so it is transparently decoded by the
100 * current {@link CryptUtils}.
103 * the {@link InputStream} to wrap
104 * @return the auto-decode {@link InputStream}
106 public InputStream
decryptInputStream(InputStream in
) {
107 return new CipherInputStream(in
, dcipher
);
111 * Wrap the given {@link OutStream} so it is transparently decoded by the
112 * current {@link CryptUtils}.
115 * the {@link OutputStream} to wrap
116 * @return the auto-decode {@link OutputStream}
118 public OutputStream
decryptOutputStream(OutputStream out
) {
119 return new CipherOutputStream(out
, dcipher
);
123 * This method required an array of 128 bytes.
126 * the array, which <b>must</b> be of 128 bits (32 bytes)
128 * @throws InvalidKeyException
129 * if the key is not an array of 128 bits (32 bytes)
131 private void init(byte[] bytes32
) throws InvalidKeyException
{
132 if (bytes32
== null || bytes32
.length
!= 32) {
133 throw new InvalidKeyException(
134 "The size of the key must be of 128 bits (32 bytes), it is: "
135 + (bytes32
== null ?
"null" : "" + bytes32
.length
)
139 SecretKey key
= new SecretKeySpec(bytes32
, "AES");
141 ecipher
= Cipher
.getInstance("AES/ECB/PKCS5Padding");
142 dcipher
= Cipher
.getInstance("AES/ECB/PKCS5Padding");
143 ecipher
.init(Cipher
.ENCRYPT_MODE
, key
);
144 dcipher
.init(Cipher
.DECRYPT_MODE
, key
);
145 } catch (NoSuchAlgorithmException e
) {
146 // Every implementation of the Java platform is required to support
147 // this standard Cipher transformation with 128 bits keys
149 } catch (NoSuchPaddingException e
) {
150 // Every implementation of the Java platform is required to support
151 // this standard Cipher transformation with 128 bits keys
153 } catch (InvalidKeyException e
) {
154 // Every implementation of the Java platform is required to support
155 // this standard Cipher transformation with 128 bits keys
164 * the data to encrypt
166 * @return the encrypted data
168 * @throws SSLException
169 * in case of I/O error (i.e., the data is not what you assumed
172 public byte[] encrypt(byte[] data
) throws SSLException
{
174 return ecipher
.doFinal(data
);
175 } catch (IllegalBlockSizeException e
) {
176 throw new SSLException(e
);
177 } catch (BadPaddingException e
) {
178 throw new SSLException(e
);
186 * the data to encrypt
188 * @return the encrypted data
190 * @throws SSLException
191 * in case of I/O error (i.e., the data is not what you assumed
194 public byte[] encrypt(String data
) throws SSLException
{
196 return encrypt(data
.getBytes("UTF8"));
197 } catch (UnsupportedEncodingException e
) {
198 // UTF-8 is required in all confirm JVMs
205 * Encrypt the data, then encode it into Base64.
208 * the data to encrypt
210 * TRUE to also compress the data in GZIP format; remember that
211 * compressed and not-compressed content are different; you need
212 * to know which is which when decoding
214 * @return the encrypted data, encoded in Base64
216 * @throws SSLException
217 * in case of I/O error (i.e., the data is not what you assumed
220 public String
encrypt64(String data
, boolean zip
) throws SSLException
{
222 return encrypt64(data
.getBytes("UTF8"), zip
);
223 } catch (UnsupportedEncodingException e
) {
224 // UTF-8 is required in all confirm JVMs
231 * Encrypt the data, then encode it into Base64.
234 * the data to encrypt
236 * TRUE to also compress the data in GZIP format; remember that
237 * compressed and not-compressed content are different; you need
238 * to know which is which when decoding
240 * @return the encrypted data, encoded in Base64
242 * @throws SSLException
243 * in case of I/O error (i.e., the data is not what you assumed
246 public String
encrypt64(byte[] data
, boolean zip
) throws SSLException
{
248 return StringUtils
.base64(encrypt(data
), zip
);
249 } catch (IOException e
) {
250 // not exactly true, but we consider here that this error is a crypt
251 // error, not a normal I/O error
252 throw new SSLException(e
);
257 * Decode the data which is assumed to be encrypted with the same utilities.
260 * the encrypted data to decode
262 * @return the original, decoded data
264 * @throws SSLException
265 * in case of I/O error
267 public byte[] decrypt(byte[] data
) throws SSLException
{
269 return dcipher
.doFinal(data
);
270 } catch (IllegalBlockSizeException e
) {
271 throw new SSLException(e
);
272 } catch (BadPaddingException e
) {
273 throw new SSLException(e
);
278 * Decode the data which is assumed to be encrypted with the same utilities
279 * and to be a {@link String}.
282 * the encrypted data to decode
284 * @return the original, decoded data,as a {@link String}
286 * @throws SSLException
287 * in case of I/O error
289 public String
decrypts(byte[] data
) throws SSLException
{
291 return new String(decrypt(data
), "UTF-8");
292 } catch (UnsupportedEncodingException e
) {
293 // UTF-8 is required in all confirm JVMs
300 * Decode the data which is assumed to be encrypted with the same utilities
301 * and is a Base64 encoded value.
304 * the encrypted data to decode in Base64 format
306 * TRUE to also uncompress the data from a GZIP format
307 * automatically; if set to FALSE, zipped data can be returned
309 * @return the original, decoded data
311 * @throws SSLException
312 * in case of I/O error
314 public byte[] decrypt64(String data
, boolean zip
) throws SSLException
{
316 return decrypt(StringUtils
.unbase64(data
, zip
));
317 } catch (IOException e
) {
318 // not exactly true, but we consider here that this error is a crypt
319 // error, not a normal I/O error
320 throw new SSLException(e
);
325 * Decode the data which is assumed to be encrypted with the same utilities
326 * and is a Base64 encoded value, then convert it into a String (this method
327 * assumes the data <b>was</b> indeed a UTF-8 encoded {@link String}).
330 * the encrypted data to decode in Base64 format
332 * TRUE to also uncompress the data from a GZIP format
333 * automatically; if set to FALSE, zipped data can be returned
335 * @return the original, decoded data
337 * @throws SSLException
338 * in case of I/O error
340 public String
decrypt64s(String data
, boolean zip
) throws SSLException
{
342 return new String(decrypt(StringUtils
.unbase64(data
, zip
)), "UTF-8");
343 } catch (UnsupportedEncodingException e
) {
344 // UTF-8 is required in all confirm JVMs
347 } catch (IOException e
) {
348 // not exactly true, but we consider here that this error is a crypt
349 // error, not a normal I/O error
350 throw new SSLException(e
);
355 * This is probably <b>NOT</b> secure!
358 * some {@link String} input
360 * @return a 128 bits key computed from the given input
362 static private byte[] key2key(String input
) {
363 return StringUtils
.getMd5Hash("" + input
).getBytes();