Commit | Line | Data |
---|---|---|
52e0732e NR |
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 | } |