new: crypt utils
[nikiroo-utils.git] / src / be / nikiroo / utils / CryptUtils.java
1 package be.nikiroo.utils;
2
3 import java.io.IOException;
4 import java.security.InvalidKeyException;
5 import java.security.NoSuchAlgorithmException;
6
7 import javax.crypto.BadPaddingException;
8 import javax.crypto.Cipher;
9 import javax.crypto.IllegalBlockSizeException;
10 import javax.crypto.NoSuchPaddingException;
11 import javax.crypto.SecretKey;
12 import javax.crypto.spec.SecretKeySpec;
13
14 /**
15 * Small utility class to do AES encryption/decryption.
16 * <p>
17 * Do not assume it is actually secure until you checked the code...
18 *
19 * @author niki
20 */
21 public class CryptUtils {
22 private Cipher ecipher;
23 private Cipher dcipher;
24
25 /**
26 * Small and leazy way to initialize a 128 bits key with {@link CryptUtils}.
27 * <p>
28 * <b>Some</b> part of the key will be used to generate a 128 bits key and
29 * initialize the {@link CryptUtils}; even NULL will generate something.
30 * <p>
31 * <b>This is most probably not secure. Do not use if you actually care
32 * about security.</b>
33 *
34 * @param key
35 * the {@link String} to use as a base for the key, can be NULL
36 */
37 public CryptUtils(String key) {
38 try {
39 init(key2key(key));
40 } catch (InvalidKeyException e) {
41 // We made sure that the key is correct, so nothing here
42 e.printStackTrace();
43 }
44 }
45
46 /**
47 * Create a new instance of {@link CryptUtils} with the given 128 bytes key.
48 * <p>
49 * The key <b>must</b> be exactly 128 bytes long.
50 *
51 * @param bytes32
52 * the 128 bits (32 bytes) of the key
53 *
54 * @throws InvalidKeyException
55 * if the key is not an array of 128 bytes
56 */
57 public CryptUtils(byte[] bytes32) throws InvalidKeyException {
58 init(bytes32);
59 }
60
61 /**
62 * This method required an array of 128 bytes.
63 *
64 * @param bytes32
65 * the array, which <b>must</b> be of 128 bits (32 bytes)
66 *
67 * @throws InvalidKeyException
68 * if the key is not an array of 128 bits (32 bytes)
69 */
70 private void init(byte[] bytes32) throws InvalidKeyException {
71 if (bytes32 == null || bytes32.length != 32) {
72 throw new InvalidKeyException(
73 "The size of the key must be of 128 bits (32 bytes), it is: "
74 + (bytes32 == null ? "null" : "" + bytes32.length)
75 + " bytes");
76 }
77
78 SecretKey key = new SecretKeySpec(bytes32, "AES");
79 try {
80 ecipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
81 dcipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
82 ecipher.init(Cipher.ENCRYPT_MODE, key);
83 dcipher.init(Cipher.DECRYPT_MODE, key);
84 } catch (NoSuchAlgorithmException e) {
85 // Every implementation of the Java platform is required to support
86 // this standard Cipher transformation with 128 bits keys
87 e.printStackTrace();
88 } catch (NoSuchPaddingException e) {
89 // Every implementation of the Java platform is required to support
90 // this standard Cipher transformation with 128 bits keys
91 e.printStackTrace();
92 } catch (InvalidKeyException e) {
93 // Every implementation of the Java platform is required to support
94 // this standard Cipher transformation with 128 bits keys
95 e.printStackTrace();
96 }
97 }
98
99 /**
100 * Encrypt the data.
101 *
102 * @param data
103 * the data to encrypt
104 *
105 * @return the encrypted data
106 *
107 * @throws IOException
108 * in case of I/O error (i.e., the data is not what you assumed
109 * it was)
110 */
111 public byte[] encrypt(byte[] data) throws IOException {
112 try {
113 return ecipher.doFinal(data);
114 } catch (IllegalBlockSizeException e) {
115 throw new IOException(e);
116 } catch (BadPaddingException e) {
117 throw new IOException(e);
118 }
119 }
120
121 /**
122 * Encrypt the data.
123 *
124 * @param data
125 * the data to encrypt
126 *
127 * @return the encrypted data
128 *
129 * @throws IOException
130 * in case of I/O error (i.e., the data is not what you assumed
131 * it was)
132 */
133 public byte[] encrypt(String data) throws IOException {
134 return encrypt(data.getBytes("UTF8"));
135 }
136
137 /**
138 * Encrypt the data, then encode it into Base64.
139 *
140 * @param data
141 * the data to encrypt
142 * @param zip
143 * TRUE to also compress the data in GZIP format; remember that
144 * compressed and not-compressed content are different; you need
145 * to know which is which when decoding
146 *
147 * @return the encrypted data, encoded in Base64
148 *
149 * @throws IOException
150 * in case of I/O error (i.e., the data is not what you assumed
151 * it was)
152 */
153 public String encrypt64(String data, boolean zip) throws IOException {
154 return encrypt64(data.getBytes("UTF8"), zip);
155 }
156
157 /**
158 * Encrypt the data, then encode it into Base64.
159 *
160 * @param data
161 * the data to encrypt
162 * @param zip
163 * TRUE to also compress the data in GZIP format; remember that
164 * compressed and not-compressed content are different; you need
165 * to know which is which when decoding
166 *
167 * @return the encrypted data, encoded in Base64
168 *
169 * @throws IOException
170 * in case of I/O error (i.e., the data is not what you assumed
171 * it was)
172 */
173 public String encrypt64(byte[] data, boolean zip) throws IOException {
174 return StringUtils.base64(encrypt(data), zip);
175 }
176
177 /**
178 * Decode the data which is assumed to be encrypted with the same utilities.
179 *
180 * @param data
181 * the encrypted data to decode
182 *
183 * @return the original, decoded data
184 *
185 * @throws IOException
186 * in case of I/O error
187 */
188 public byte[] decrypt(byte[] data) throws IOException {
189 try {
190 return dcipher.doFinal(data);
191 } catch (IllegalBlockSizeException e) {
192 throw new IOException(e);
193 } catch (BadPaddingException e) {
194 throw new IOException(e);
195 }
196 }
197
198 /**
199 * Decode the data which is assumed to be encrypted with the same utilities
200 * and is a Base64 encoded value.
201 *
202 * @param data
203 * the encrypted data to decode in Base64 format
204 * @param zip
205 * TRUE to also uncompress the data from a GZIP format
206 * automatically; if set to FALSE, zipped data can be returned
207 *
208 * @return the original, decoded data
209 *
210 * @throws IOException
211 * in case of I/O error
212 */
213 public byte[] decrypt64(String data, boolean zip) throws IOException {
214 return decrypt(StringUtils.unbase64(data, zip));
215 }
216
217 /**
218 * Decode the data which is assumed to be encrypted with the same utilities
219 * and is a Base64 encoded value, then convert it into a String (this method
220 * assumes the data <b>was</b> indeed a UTF-8 encoded {@link String}).
221 *
222 * @param data
223 * the encrypted data to decode in Base64 format
224 * @param zip
225 * TRUE to also uncompress the data from a GZIP format
226 * automatically; if set to FALSE, zipped data can be returned
227 *
228 * @return the original, decoded data
229 *
230 * @throws IOException
231 * in case of I/O error
232 */
233 public String decrypt64s(String data, boolean zip) throws IOException {
234 return new String(decrypt(StringUtils.unbase64(data, zip)), "UTF-8");
235 }
236
237 /**
238 * This is probably <b>NOT</b> secure!
239 *
240 * @param input
241 * some {@link String} input
242 *
243 * @return a 128 bits key computed from the given input
244 */
245 static private byte[] key2key(String input) {
246 return StringUtils.getMd5Hash(input).getBytes();
247 }
248 }