001: package org.bouncycastle.crypto.examples;
002:
003: import java.io.BufferedInputStream;
004: import java.io.BufferedOutputStream;
005: import java.io.BufferedReader;
006: import java.io.FileInputStream;
007: import java.io.FileNotFoundException;
008: import java.io.FileOutputStream;
009: import java.io.IOException;
010: import java.io.InputStreamReader;
011: import java.security.SecureRandom;
012:
013: import org.bouncycastle.crypto.CryptoException;
014: import org.bouncycastle.crypto.KeyGenerationParameters;
015: import org.bouncycastle.crypto.engines.DESedeEngine;
016: import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
017: import org.bouncycastle.crypto.modes.CBCBlockCipher;
018: import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
019: import org.bouncycastle.crypto.params.DESedeParameters;
020: import org.bouncycastle.crypto.params.KeyParameter;
021: import org.bouncycastle.util.encoders.Hex;
022:
023: /**
024: * DESExample is a simple DES based encryptor/decryptor.
025: * <p>
026: * The program is command line driven, with the input
027: * and output files specified on the command line.
028: * <pre>
029: * java org.bouncycastle.crypto.examples.DESExample infile outfile [keyfile]
030: * </pre>
031: * A new key is generated for each encryption, if key is not specified,
032: * then the example will assume encryption is required, and as output
033: * create deskey.dat in the current directory. This key is a hex
034: * encoded byte-stream that is used for the decryption. The output
035: * file is Hex encoded, 60 characters wide text file.
036: * <p>
037: * When encrypting;
038: * <ul>
039: * <li>the infile is expected to be a byte stream (text or binary)
040: * <li>there is no keyfile specified on the input line
041: * </ul>
042: * <p>
043: * When decrypting;
044: * <li>the infile is expected to be the 60 character wide base64
045: * encoded file
046: * <li>the keyfile is expected to be a base64 encoded file
047: * <p>
048: * This example shows how to use the light-weight API, DES and
049: * the filesystem for message encryption and decryption.
050: *
051: */
052: public class DESExample extends Object {
053: // Encrypting or decrypting ?
054: private boolean encrypt = true;
055:
056: // To hold the initialised DESede cipher
057: private PaddedBufferedBlockCipher cipher = null;
058:
059: // The input stream of bytes to be processed for encryption
060: private BufferedInputStream in = null;
061:
062: // The output stream of bytes to be procssed
063: private BufferedOutputStream out = null;
064:
065: // The key
066: private byte[] key = null;
067:
068: /*
069: * start the application
070: */
071: public static void main(String[] args) {
072: boolean encrypt = true;
073: String infile = null;
074: String outfile = null;
075: String keyfile = null;
076:
077: if (args.length < 2) {
078: DESExample de = new DESExample();
079: System.err.println("Usage: java " + de.getClass().getName()
080: + " infile outfile [keyfile]");
081: System.exit(1);
082: }
083:
084: keyfile = "deskey.dat";
085: infile = args[0];
086: outfile = args[1];
087:
088: if (args.length > 2) {
089: encrypt = false;
090: keyfile = args[2];
091: }
092:
093: DESExample de = new DESExample(infile, outfile, keyfile,
094: encrypt);
095: de.process();
096: }
097:
098: // Default constructor, used for the usage message
099: public DESExample() {
100: }
101:
102: /*
103: * Constructor, that takes the arguments appropriate for
104: * processing the command line directives.
105: */
106: public DESExample(String infile, String outfile, String keyfile,
107: boolean encrypt) {
108: /*
109: * First, determine that infile & keyfile exist as appropriate.
110: *
111: * This will also create the BufferedInputStream as required
112: * for reading the input file. All input files are treated
113: * as if they are binary, even if they contain text, it's the
114: * bytes that are encrypted.
115: */
116: this .encrypt = encrypt;
117: try {
118: in = new BufferedInputStream(new FileInputStream(infile));
119: } catch (FileNotFoundException fnf) {
120: System.err.println("Input file not found [" + infile + "]");
121: System.exit(1);
122: }
123:
124: try {
125: out = new BufferedOutputStream(
126: new FileOutputStream(outfile));
127: } catch (IOException fnf) {
128: System.err.println("Output file not created [" + outfile
129: + "]");
130: System.exit(1);
131: }
132:
133: if (encrypt) {
134: try {
135: /*
136: * The process of creating a new key requires a
137: * number of steps.
138: *
139: * First, create the parameters for the key generator
140: * which are a secure random number generator, and
141: * the length of the key (in bits).
142: */
143: SecureRandom sr = null;
144: try {
145: sr = new SecureRandom();
146: /*
147: * This following call to setSeed() makes the
148: * initialisation of the SecureRandom object
149: * _very_ fast, but not secure AT ALL.
150: *
151: * Remove the line, recreate the class file and
152: * then run DESExample again to see the difference.
153: *
154: * The initialisation of a SecureRandom object
155: * can take 5 or more seconds depending on the
156: * CPU that the program is running on. That can
157: * be annoying during unit testing.
158: * -- jon
159: */
160: sr.setSeed("www.bouncycastle.org".getBytes());
161: } catch (Exception nsa) {
162: System.err
163: .println("Hmmm, no SHA1PRNG, you need the "
164: + "Sun implementation");
165: System.exit(1);
166: }
167: KeyGenerationParameters kgp = new KeyGenerationParameters(
168: sr, DESedeParameters.DES_EDE_KEY_LENGTH * 8);
169:
170: /*
171: * Second, initialise the key generator with the parameters
172: */
173: DESedeKeyGenerator kg = new DESedeKeyGenerator();
174: kg.init(kgp);
175:
176: /*
177: * Third, and finally, generate the key
178: */
179: key = kg.generateKey();
180:
181: /*
182: * We can now output the key to the file, but first
183: * hex encode the key so that we can have a look
184: * at it with a text editor if we so desire
185: */
186: BufferedOutputStream keystream = new BufferedOutputStream(
187: new FileOutputStream(keyfile));
188: byte[] keyhex = Hex.encode(key);
189: keystream.write(keyhex, 0, keyhex.length);
190: keystream.flush();
191: keystream.close();
192: } catch (IOException createKey) {
193: System.err
194: .println("Could not decryption create key file "
195: + "[" + keyfile + "]");
196: System.exit(1);
197: }
198: } else {
199: try {
200: // read the key, and decode from hex encoding
201: BufferedInputStream keystream = new BufferedInputStream(
202: new FileInputStream(keyfile));
203: int len = keystream.available();
204: byte[] keyhex = new byte[len];
205: keystream.read(keyhex, 0, len);
206: key = Hex.decode(keyhex);
207: } catch (IOException ioe) {
208: System.err.println("Decryption key file not found, "
209: + "or not valid [" + keyfile + "]");
210: System.exit(1);
211: }
212: }
213: }
214:
215: private final void process() {
216: /*
217: * Setup the DESede cipher engine, create a PaddedBufferedBlockCipher
218: * in CBC mode.
219: */
220: cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(
221: new DESedeEngine()));
222:
223: /*
224: * The input and output streams are currently set up
225: * appropriately, and the key bytes are ready to be
226: * used.
227: *
228: */
229:
230: if (encrypt) {
231: performEncrypt(key);
232: } else {
233: performDecrypt(key);
234: }
235:
236: // after processing clean up the files
237: try {
238: in.close();
239: out.flush();
240: out.close();
241: } catch (IOException closing) {
242:
243: }
244: }
245:
246: /*
247: * This method performs all the encryption and writes
248: * the cipher text to the buffered output stream created
249: * previously.
250: */
251: private final void performEncrypt(byte[] key) {
252: // initialise the cipher with the key bytes, for encryption
253: cipher.init(true, new KeyParameter(key));
254:
255: /*
256: * Create some temporary byte arrays for use in
257: * encryption, make them a reasonable size so that
258: * we don't spend forever reading small chunks from
259: * a file.
260: *
261: * There is no particular reason for using getBlockSize()
262: * to determine the size of the input chunk. It just
263: * was a convenient number for the example.
264: */
265: // int inBlockSize = cipher.getBlockSize() * 5;
266: int inBlockSize = 47;
267: int outBlockSize = cipher.getOutputSize(inBlockSize);
268:
269: byte[] inblock = new byte[inBlockSize];
270: byte[] outblock = new byte[outBlockSize];
271:
272: /*
273: * now, read the file, and output the chunks
274: */
275: try {
276: int inL;
277: int outL;
278: byte[] rv = null;
279: while ((inL = in.read(inblock, 0, inBlockSize)) > 0) {
280: outL = cipher
281: .processBytes(inblock, 0, inL, outblock, 0);
282: /*
283: * Before we write anything out, we need to make sure
284: * that we've got something to write out.
285: */
286: if (outL > 0) {
287: rv = Hex.encode(outblock, 0, outL);
288: out.write(rv, 0, rv.length);
289: out.write('\n');
290: }
291: }
292:
293: try {
294: /*
295: * Now, process the bytes that are still buffered
296: * within the cipher.
297: */
298: outL = cipher.doFinal(outblock, 0);
299: if (outL > 0) {
300: rv = Hex.encode(outblock, 0, outL);
301: out.write(rv, 0, rv.length);
302: out.write('\n');
303: }
304: } catch (CryptoException ce) {
305:
306: }
307: } catch (IOException ioeread) {
308: ioeread.printStackTrace();
309: }
310: }
311:
312: /*
313: * This method performs all the decryption and writes
314: * the plain text to the buffered output stream created
315: * previously.
316: */
317: private final void performDecrypt(byte[] key) {
318: // initialise the cipher for decryption
319: cipher.init(false, new KeyParameter(key));
320:
321: /*
322: * As the decryption is from our preformatted file,
323: * and we know that it's a hex encoded format, then
324: * we wrap the InputStream with a BufferedReader
325: * so that we can read it easily.
326: */
327: BufferedReader br = new BufferedReader(
328: new InputStreamReader(in));
329:
330: /*
331: * now, read the file, and output the chunks
332: */
333: try {
334: int outL;
335: byte[] inblock = null;
336: byte[] outblock = null;
337: String rv = null;
338: while ((rv = br.readLine()) != null) {
339: inblock = Hex.decode(rv);
340: outblock = new byte[cipher
341: .getOutputSize(inblock.length)];
342:
343: outL = cipher.processBytes(inblock, 0, inblock.length,
344: outblock, 0);
345: /*
346: * Before we write anything out, we need to make sure
347: * that we've got something to write out.
348: */
349: if (outL > 0) {
350: out.write(outblock, 0, outL);
351: }
352: }
353:
354: try {
355: /*
356: * Now, process the bytes that are still buffered
357: * within the cipher.
358: */
359: outL = cipher.doFinal(outblock, 0);
360: if (outL > 0) {
361: out.write(outblock, 0, outL);
362: }
363: } catch (CryptoException ce) {
364:
365: }
366: } catch (IOException ioeread) {
367: ioeread.printStackTrace();
368: }
369: }
370:
371: }
|