1 /**
2 This file is part of GoldenGate Project (named also GoldenGate or GG).
3
4 Copyright 2009, Frederic Bregier, and individual contributors by the @author
5 tags. See the COPYRIGHT.txt in the distribution for a full listing of
6 individual contributors.
7
8 All GoldenGate Project is free software: you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as published
10 by the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 GoldenGate is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GoldenGate . If not, see <http://www.gnu.org/licenses/>.
20 */
21 package goldengate.common.crypto;
22
23 import goldengate.common.digest.FilesystemBasedDigest;
24 import goldengate.common.exception.CryptoException;
25 import goldengate.common.logging.GgInternalLogger;
26 import goldengate.common.logging.GgInternalLoggerFactory;
27
28 import java.io.DataInputStream;
29 import java.io.File;
30 import java.io.FileInputStream;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.security.Key;
34
35 import javax.crypto.Cipher;
36 import javax.crypto.KeyGenerator;
37 import javax.crypto.spec.SecretKeySpec;
38
39
40 /**
41 * This class handles method to crypt and decrypt using the chosen algorithm.<br>
42 *
43 * <br>
44 * Usage:<br>
45 * <ul>
46 * <li>Create a Key object: KeyObject key = new KeyObject();</li>
47 * <li>Create a key:
48 * <ul>
49 * <li>Generate: key.generateKey();<br>
50 * The method key.getSecretKeyInBytes() allow getting the key in Bytes.</li>
51 * <li>From an external source: key.setSecretKey(arrayOfBytes);</li>
52 * </ul></li>
53 * <li>To crypt a String in a Hex format: String myStringCrypt = key.cryptToHex(myString);</li>
54 * <li>To decrypt one string from Hex format to the original String: String myStringDecrypt = key.decryptHexInString(myStringCrypte);</li>
55 * </ul>
56 *
57 * @author frederic bregier
58 *
59 */
60 public abstract class KeyObject {
61 /**
62 * Internal Logger
63 */
64 private static final GgInternalLogger logger = GgInternalLoggerFactory
65 .getLogger(KeyObject.class);
66
67 /**
68 * The True Key associated with this object
69 */
70 Key secretKey = null;
71
72 /**
73 * Empty constructor
74 */
75 public KeyObject() {
76 }
77
78 /**
79 *
80 * @return the algorithm used (Java name)
81 */
82 public abstract String getAlgorithm();
83 /**
84 *
85 * @return the instance used (Java name)
86 */
87 public abstract String getInstance();
88 /**
89 *
90 * @return the size for the algorithm key
91 */
92 public abstract int getKeySize();
93 /**
94 * @return the key associated with this object
95 */
96 public Key getSecretKey() {
97 return secretKey;
98 }
99
100 /**
101 *
102 * @return True if this key is ready to be used
103 */
104 public boolean keyReady() {
105 return secretKey != null;
106 }
107 /**
108 * Returns the key as an array of bytes in order to be stored somewhere else
109 * and retrieved using the setSecretKey(byte[] keyData) method.
110 * @return the key as an array of bytes (or null if not ready)
111 */
112 public byte[] getSecretKeyInBytes() {
113 if (keyReady()) {
114 return secretKey.getEncoded();
115 } else {
116 return null;
117 }
118 }
119
120 /**
121 * Set the secretKey
122 *
123 * @param secretKey
124 */
125 public void setSecretKey(Key secretKey) {
126 this.secretKey = secretKey;
127 }
128
129 /**
130 * Reconstruct a key from an array of bytes
131 */
132 public void setSecretKey(byte[] keyData) {
133 secretKey = new SecretKeySpec(keyData, getAlgorithm());
134 }
135
136 /**
137 * Create a Key from a File
138 * @param file
139 * @throws CryptoException
140 * @throws IOException
141 */
142 public void setSecretKey(File file) throws CryptoException, IOException {
143 if (file.canRead()) {
144 int len = (int)file.length();
145 byte []key = new byte[len];
146 FileInputStream inputStream = null;
147 inputStream = new FileInputStream(file);
148 DataInputStream dis = new DataInputStream(inputStream);
149 try {
150 dis.readFully(key);
151 } finally {
152 dis.close();
153 }
154 this.setSecretKey(key);
155 } else {
156 throw new CryptoException("Cannot read crypto file");
157 }
158 }
159 /**
160 * Save a Key to a File
161 * @param file
162 * @throws CryptoException
163 * @throws IOException
164 */
165 public void saveSecretKey(File file) throws CryptoException, IOException {
166 if (keyReady() && ((!file.exists()) || file.canWrite())) {
167 byte []key = getSecretKeyInBytes();
168 FileOutputStream outputStream = new FileOutputStream(file);
169 try {
170 outputStream.write(key);
171 outputStream.flush();
172 } finally {
173 outputStream.close();
174 }
175 } else {
176 throw new CryptoException("Cannot read crypto file");
177 }
178 }
179
180 /**
181 * Generate a key from nothing
182 * @throws Exception
183 */
184 public void generateKey() throws Exception {
185 try {
186 KeyGenerator keyGen = KeyGenerator.getInstance(getAlgorithm());
187 keyGen.init(getKeySize());
188 secretKey = keyGen.generateKey();
189 } catch (Exception e) {
190 logger.warn("GenerateKey Error", e);
191 throw e;
192 }
193 }
194 /**
195 * Returns a cipher for encryption associated with the key
196 *
197 * @return the cipher for encryption or null if it fails
198 * in case Encryption method or key is incorrect
199 */
200 public Cipher toCrypt() {
201 Cipher cipher;
202 try {
203 cipher = Cipher.getInstance(getInstance());
204 cipher.init(Cipher.ENCRYPT_MODE, secretKey);
205 } catch (Exception e) {
206 return null;
207 }
208 return cipher;
209 }
210 /**
211 * Crypt one array of bytes and returns the crypted array of bytes
212 *
213 * @param plaintext
214 * @return the crypted array of bytes
215 * @throws Exception
216 */
217 public byte[] crypt(byte[] plaintext) throws Exception {
218 if (! keyReady()) {
219 throw new CryptoException("Key not Ready");
220 }
221 try {
222 Cipher cipher = Cipher.getInstance(getInstance());
223 cipher.init(Cipher.ENCRYPT_MODE, secretKey);
224 return cipher.doFinal(plaintext);
225 } catch (Exception e) {
226 logger.warn("Crypt Error", e);
227 throw e;
228 }
229 }
230
231 /**
232 * Crypt one array of bytes and returns the crypted String as HEX format
233 *
234 * @param plaintext
235 * @return the crypted String as HEX format
236 * @throws Exception
237 */
238 public String cryptToHex(byte[] plaintext) throws Exception {
239 byte []result = crypt(plaintext);
240 return encodeHex(result);
241 }
242
243 /**
244 * Crypt one String and returns the crypted array of bytes
245 *
246 * @param plaintext
247 * @return the crypted array of bytes
248 * @throws Exception
249 */
250 public byte[] crypt(String plaintext) throws Exception {
251 return crypt(plaintext.getBytes());
252 }
253
254 /**
255 * Crypt one String and returns the crypted String as HEX format
256 *
257 * @param plaintext
258 * @return the crypted String as HEX format
259 * @throws Exception
260 */
261 public String cryptToHex(String plaintext) throws Exception {
262 return cryptToHex(plaintext.getBytes());
263 }
264 /**
265 * Returns a cipher for decryption associated with the key
266 *
267 * @return the cipher for decryption or null if it fails
268 * in case Encryption method or key is incorrect
269 */
270 public Cipher toDecrypt() {
271 Cipher cipher;
272 try {
273 cipher = Cipher.getInstance(getAlgorithm());
274 cipher.init(Cipher.DECRYPT_MODE, secretKey);
275 } catch (Exception e) {
276 return null;
277 }
278 return cipher;
279 }
280 /**
281 * Decrypt an array of bytes and returns the uncrypted array of bytes
282 *
283 * @param ciphertext
284 * @return the uncrypted array of bytes
285 * @throws Exception
286 */
287 public byte[] decrypt(byte[] ciphertext) throws Exception {
288 if (! keyReady()) {
289 throw new CryptoException("Key not Ready");
290 }
291 try {
292 Cipher cipher = Cipher.getInstance(getAlgorithm());
293 cipher.init(Cipher.DECRYPT_MODE, secretKey);
294 return cipher.doFinal(ciphertext);
295 } catch (Exception e) {
296 logger.warn("Decrypt Error", e);
297 throw e;
298 }
299 }
300
301 /**
302 * Decrypt an array of bytes and returns the uncrypted String
303 *
304 * @param ciphertext
305 * @return the uncrypted array of bytes
306 * @throws Exception
307 */
308 public String decryptInString(byte[] ciphertext) throws Exception {
309 return new String(decrypt(ciphertext));
310 }
311
312 /**
313 * Decrypt a String as HEX format representing a crypted array of bytes and
314 * returns the uncrypted array of bytes
315 *
316 * @param ciphertext
317 * @return the uncrypted array of bytes
318 * @throws Exception
319 */
320 public byte[] decryptHexInBytes(String ciphertext) throws Exception {
321 byte[] arrayBytes = decodeHex(ciphertext);
322 return decrypt(arrayBytes);
323 }
324 /**
325 * Decrypt an array of bytes as HEX format representing a crypted array of bytes and
326 * returns the uncrypted array of bytes
327 *
328 * @param ciphertext
329 * @return the uncrypted array of bytes
330 * @throws Exception
331 */
332 public byte[] decryptHexInBytes(byte[] ciphertext) throws Exception {
333 byte[] arrayBytes = decodeHex(new String(ciphertext));
334 return decrypt(arrayBytes);
335 }
336 /**
337 * Decrypt a String as HEX format representing a crypted array of bytes and
338 * returns the uncrypted String
339 *
340 * @param ciphertext
341 * @return the uncrypted String
342 * @throws Exception
343 */
344 public String decryptHexInString(String ciphertext) throws Exception {
345 return new String(decryptHexInBytes(ciphertext));
346 }
347
348 /**
349 * Decode from a file containing a HEX crypted string
350 * @param file
351 * @return the decoded uncrypted content of the file
352 * @throws Exception
353 */
354 public byte[] decryptHexFile(File file) throws Exception {
355 byte [] byteKeys = new byte[(int) file.length()];
356 FileInputStream inputStream = null;
357 DataInputStream dis = null;
358 try {
359 inputStream = new FileInputStream(file);
360 dis = new DataInputStream(inputStream);
361 dis.readFully(byteKeys);
362 dis.close();
363 String skey = new String(byteKeys);
364 // decrypt it
365 byteKeys = decryptHexInBytes(skey);
366 return byteKeys;
367 } catch (IOException e) {
368 try {
369 if (dis != null) {
370 dis.close();
371 } else if (inputStream != null)
372 inputStream.close();
373 } catch (IOException e1) {
374 }
375 throw e;
376 }
377 }
378
379 /**
380 *
381 * @param encoded
382 * @return the array of bytes from encoded String (HEX)
383 */
384 public byte[] decodeHex(String encoded) {
385 return FilesystemBasedDigest.getFromHex(encoded);
386 }
387
388 /**
389 *
390 * @param bytes
391 * @return The encoded array of bytes in HEX
392 */
393 public String encodeHex(byte[] bytes) {
394 return FilesystemBasedDigest.getHex(bytes);
395 }
396 }