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