1   /* $RCSfile: CryptoTool.java,v $
2    * $Revision: 1.12 $
3    * $Date: 2002/11/23 11:07:03 $
4    * $Author: uwe_guenther $
5    * $State: Exp $
6    *
7    * Created on January 13, 2002 6:57 PM
8    *
9    * Copyright (C) 2001 Uwe Guenther <uwe@cscc.de>
10   *
11   * This file is part of the jhbci JCE-ServiceProvider. The jhbci JCE-
12   * ServiceProvider is a library, written in JavaTM, that should be 
13   * used in HBCI banking applications (clients and may be servers),
14   * to do cryptographic operations.
15   *
16   * The jhbci library is free software; you can redistribute it and/or
17   * modify it under the terms of the GNU Lesser General Public
18   * License as published by the Free Software Foundation; either
19   * version 2.1 of the License, or (at your option) any later version.
20   *
21   * The jhbci library is distributed in the hope that it will be useful,
22   * but WITHOUT ANY WARRANTY; without even the implied warranty of
23   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24   * Lesser General Public License for more details.
25   *
26   * You should have received a copy of the GNU Lesser General Public
27   * License along with this library; if not, write to the Free Software
28   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29   *
30   */
31  
32  package de.cscc.crypto.tools;
33  
34  import java.io.FileInputStream;
35  import java.io.FileOutputStream;
36  import java.io.IOException;
37  import java.io.InputStream;
38  import java.io.ObjectInputStream;
39  import java.io.ObjectOutputStream;
40  import java.io.OutputStream;
41  import java.io.PrintStream;
42  import java.io.PrintWriter;
43  import java.io.PushbackInputStream;
44  import java.math.BigInteger;
45  import java.security.KeyPair;
46  import java.security.KeyPairGenerator;
47  import java.security.MessageDigest;
48  import java.security.Security;
49  import java.security.Signature;
50  import java.security.interfaces.RSAPrivateCrtKey;
51  import java.security.interfaces.RSAPublicKey;
52  import java.util.Arrays;
53  import java.util.logging.Level;
54  
55  import javax.crypto.Cipher;
56  import javax.crypto.CipherInputStream;
57  import javax.crypto.CipherOutputStream;
58  import javax.crypto.KeyGenerator;
59  import javax.crypto.SecretKey;
60  import javax.crypto.SecretKeyFactory;
61  
62  import de.cscc.crypto.provider.JHBCI;
63  import de.cscc.crypto.provider.spec.DESOperationModeInitializationVectorSpec;
64  import de.cscc.crypto.provider.spec.DESede3KeySpec;
65  import de.cscc.crypto.util.BigIntegerUtil;
66  import de.cscc.crypto.util.LoggerUtil;
67  
68  /** 
69   * CryptoTool Class.
70   *
71   * @author  <a href=mailto:uwe@cscc.de>Uwe G&uuml;nther</a>
72   *
73   * @version $Revision: 1.12 $
74   */
75  public final class CryptoTool {
76      
77      private String version = "0.0.6";
78      
79      private String command = null;
80      private int keysize = 1024;
81      private String keyFile = null;
82      private char[] password = null;
83      private String pubKeyFile = null;
84      private String showKeyFormat = "hex";
85      private String inFile = null;
86      private String outFile = null;
87      private String algorithm = "DES1Key";
88      private String sigFile = null;
89      private String digestFile = null;
90      private boolean debug = false;
91      private boolean verbose = false;
92      private String logLevel = "off";
93      
94      private String lineSeparator = System.getProperty("line.separator");
95      private String fileSeparator = System.getProperty("file.separator");
96      private String userHome = System.getProperty("user.home");    
97      
98      private boolean headerPrinted = false;
99      
100     /**
101      * Don't instanciate this Object out of this class.
102      */
103     private CryptoTool() {
104     }
105 
106     /**
107      * String representation of this class. Useful for debugging.
108      *
109      * @return the String representation of this class.
110      */
111     public String toString() {
112         StringBuffer sb = new StringBuffer();
113         sb.append("version: ");
114         sb.append(version);
115         sb.append(lineSeparator);
116         sb.append("command: ");
117         sb.append(command);
118         sb.append(lineSeparator);
119         sb.append("keysize: ");
120         sb.append(keysize);
121         sb.append(lineSeparator);
122         sb.append("keyFile: ");
123         sb.append(keyFile);
124         sb.append(lineSeparator);    
125         sb.append("password: ");
126         sb.append(password);
127         sb.append(lineSeparator);            
128         sb.append("pubKeyFile: ");
129         sb.append(pubKeyFile);
130         sb.append(lineSeparator);         
131         sb.append("showKeyFormat: ");
132         sb.append(showKeyFormat);
133         sb.append(lineSeparator);            
134         sb.append("inFile: ");
135         sb.append(inFile);
136         sb.append(lineSeparator);    
137         sb.append("outFile: ");
138         sb.append(outFile);
139         sb.append(lineSeparator);
140         sb.append("algorithm: ");
141         sb.append(algorithm);
142         sb.append(lineSeparator);        
143         sb.append("sigFile: ");
144         sb.append(sigFile);
145         sb.append(lineSeparator);
146         sb.append("digestFile: ");
147         sb.append(digestFile);
148         sb.append(lineSeparator);        
149         sb.append("debug: ");
150         sb.append(debug);
151         sb.append(lineSeparator);    
152         sb.append("verbose: ");
153         sb.append(verbose);
154         sb.append(lineSeparator);
155         sb.append("logLevel: ");
156         sb.append(logLevel);
157         sb.append(lineSeparator);        
158         
159         sb.append(lineSeparator);        
160         
161         sb.append("userHome: ");
162         sb.append(userHome);
163         sb.append(lineSeparator);        
164         
165         return sb.toString();
166     }
167     
168     /**
169      * The main method.
170      *
171      * @param args the argument String array.
172      */
173     public static void main (String[] args) {
174         CryptoTool ct = new CryptoTool();
175         ct.run(args, System.out);
176     }
177     
178     /**
179      * The object starter.
180      *
181      * @param args the argument String array.
182      * @param out the PrintStream where the output should be go out.
183      */
184     public void run(String[] args, PrintStream out) {
185         try {
186             parseArgs(args);
187             doCommands(out);
188             if(debug) {
189                 System.err.println(this);
190             }            
191         } catch (Exception e) {
192             header();
193             System.err.println("CryptoTool Error: " + e.getMessage());
194             System.err.println();
195             if (debug) {
196                 e.printStackTrace();
197                 System.err.println(this);
198             }
199             System.exit(1);
200         } finally {
201             System.err.println();
202             System.err.println("Thanks for using CryptoTool.");
203         }
204     }
205     
206     /**
207      * Parse command line arguments.
208      *
209      * @args the argument String array.
210      * @throws Exception if there is an invalid commandline option.
211      */
212     private void parseArgs(String[] args) throws Exception {
213 
214         int i=0;
215 
216         for (i=0; (i < args.length) && args[i].startsWith("-"); i++) {
217 
218             String flags = args[i];
219             
220             /*
221              * command modes
222              */
223             if (flags.equalsIgnoreCase("-genkey")) {
224                 command = "genkey";
225             } else if (flags.equalsIgnoreCase("-showkey")) {
226                 command = "showkey";
227             } else if (flags.equalsIgnoreCase("-export")) {
228                 command = "export";           
229             } else if (flags.equalsIgnoreCase("-showpub")) {
230                 command = "showpub";                
231             } else if (flags.equalsIgnoreCase("-encrypt")) {
232                 command = "encrypt";
233             } else if (flags.equalsIgnoreCase("-decrypt")) {
234                 command = "decrypt";
235             } else if (flags.equalsIgnoreCase("-sign")) {
236                 command = "sign";
237             } else if (flags.equalsIgnoreCase("-verify")) {
238                 command = "verify";
239             } else if (flags.equalsIgnoreCase("-digest")) {
240                 command = "digest";
241             } else if (flags.equalsIgnoreCase("-help")) {
242                 usage();
243                 return;                
244             } 
245 
246             /*
247              * specifiers
248              */
249             else if (flags.equalsIgnoreCase("-keysize")) {
250                 if (++i == args.length) usage();
251                 keysize = Integer.parseInt(args[i]);
252             } else if (flags.equalsIgnoreCase("-keyfile")) {
253                 if (++i == args.length) usage();
254                 keyFile = args[i];
255             } else if (flags.equalsIgnoreCase("-keypass")) {
256                 if (++i == args.length) usage();
257                 password = args[i].toCharArray();                
258             } else if (flags.equalsIgnoreCase("-pubkey")) {
259                 if (++i == args.length) usage();
260                 pubKeyFile = args[i];                
261             } else if (flags.equalsIgnoreCase("-in")) {
262                 if (++i == args.length) usage();
263                 inFile = args[i];
264             } else if (flags.equalsIgnoreCase("-out")) {
265                 if (++i == args.length) usage();
266                 outFile = args[i];
267             } else if (flags.equalsIgnoreCase("-alg")) {
268                 if (++i == args.length) usage();
269                 algorithm = args[i];                
270             } else if (flags.equalsIgnoreCase("-sigfile")) {
271                 if (++i == args.length) usage();
272                 sigFile = args[i];
273             } else if (flags.equalsIgnoreCase("-digestfile")) {
274                 if (++i == args.length) usage();
275                 digestFile = args[i];
276             } else if (flags.equalsIgnoreCase("-logging")) {
277                 if (++i == args.length) usage();
278                 logLevel = args[i];
279             }
280 
281             /*
282              * options
283              */
284             else if (flags.equalsIgnoreCase("-v")) {
285                 verbose = true;
286             } else if (flags.equalsIgnoreCase("-debug")) {
287                 debug = true;
288             } else if (flags.equalsIgnoreCase("-hex")) {
289                 showKeyFormat = "hex";
290             } else if (flags.equalsIgnoreCase("-dec")) {
291                 showKeyFormat = "dec";
292             } else  {
293                 throw new Exception("Illegal option " + flags + ".");
294             }
295         }
296 
297         if (i<args.length || command==null) { 
298             usage();
299         }
300     }
301     
302     
303     /**
304      * Execute the commands.
305      *
306      * @out the PrintStream where the output should be go out.
307      * @throws Exception if some of the underlying commands goes wrong.
308      */    
309     private void doCommands(PrintStream out) throws Exception {
310         
311         if (command == null) {
312             return;
313         }
314         
315         //Add JHBCI Provider
316         Security.addProvider(new JHBCI());
317 
318         setStderrLogLevel();
319         
320         if (command.equals("genkey")) {
321             genKey();
322         } else if (command.equals("showkey")) {
323             showKey(out);
324         } else if (command.equals("export")) {
325             export();
326         } else if (command.equals("showpub")) {
327             showPub(out);            
328         } else if (command.equals("encrypt")) {
329             encrypt();
330         } else if (command.equals("decrypt")) {
331             decrypt();
332         } else if (command.equals("sign")) {
333             sign();
334         } else if (command.equals("verify")) {
335             verify();
336         } else if (command.equals("digest")) {
337             digest();  
338         }
339     }
340     
341     /**
342      * Sets a requested log level to the stderr.
343      *
344      * @throws Exception if a wrong log level has been requested.
345      */
346     private void setStderrLogLevel() throws Exception {
347         if (logLevel.equalsIgnoreCase("off")) { 
348             LoggerUtil.setConsoleLogging("", Level.OFF);        
349         } else if (logLevel.equalsIgnoreCase("severe")) { 
350             LoggerUtil.setConsoleLogging("", Level.SEVERE);
351         } else if (logLevel.equalsIgnoreCase("warning")) { 
352             LoggerUtil.setConsoleLogging("", Level.WARNING);
353         } else if (logLevel.equalsIgnoreCase("info")) { 
354             LoggerUtil.setConsoleLogging("", Level.INFO);
355         } else if (logLevel.equalsIgnoreCase("config")) { 
356             LoggerUtil.setConsoleLogging("", Level.CONFIG);
357         } else if (logLevel.equalsIgnoreCase("fine")) { 
358             LoggerUtil.setConsoleLogging("", Level.FINE);
359         } else if (logLevel.equalsIgnoreCase("finer")) { 
360             LoggerUtil.setConsoleLogging("", Level.FINER);
361         } else if (logLevel.equalsIgnoreCase("finest")) { 
362             LoggerUtil.setConsoleLogging("", Level.FINEST);
363         } else if(logLevel.equalsIgnoreCase("all")) { 
364             LoggerUtil.setConsoleLogging("", Level.ALL);
365         } else {
366             throw new Exception("Wrong logging level.");
367         }
368       
369     }
370     
371     /**
372      * Generate a RSA KeyPair and writes it to a DESede3Key encrypted
373      * "keyFile".
374      *
375      * @throws Exception if somthing goes wrong.
376      */
377     private void genKey() throws Exception {
378         if (keyFile == null) {
379             keyFile = userHome + fileSeparator + ".keyfile";
380         }
381         
382         header();
383         System.err.println("RSA Key File: " + keyFile);
384         System.err.println("RSA Key Length: " + keysize);
385         System.err.println();
386         
387         KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "JHBCI");
388         keyGen.initialize(keysize);
389         KeyPair keyPair = keyGen.generateKeyPair();
390         
391         SecretKey desede3Key = null;
392  
393         if (password == null) {
394             System.err.print("Enter keyfile password: ");
395             password = readPasswd(System.in);
396             if (password.length < 6) {
397                 throw new Exception("New password must be at least 6 characters.");
398             }
399         
400         
401             System.err.print("Enter keyfile password again: ");
402             char[] password2 = readPasswd(System.in);
403             if (Arrays.equals(password, password2)) {
404                     desede3Key = genDESede3Key(password);
405             } else {
406                 throw new Exception("Too many failures - try later.");
407             }
408             System.err.println();
409         } else {
410             if (password.length < 6) {
411                 throw new Exception("New password must be at least 6 characters.");
412             }            
413             desede3Key = genDESede3Key(password);
414         }
415 
416         byte[] rawIV = {
417             (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
418             (byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef
419         };
420         
421         DESOperationModeInitializationVectorSpec iv = 
422         new DESOperationModeInitializationVectorSpec(rawIV); 
423         
424         Cipher encrypt = Cipher.getInstance(
425         "DESede3Key/CBC/ISO10126OctetPadding", "JHBCI");
426         encrypt.init(Cipher.ENCRYPT_MODE, desede3Key, iv);
427         
428         OutputStream fos = null;
429         OutputStream cos = null;
430         ObjectOutputStream oos = null;
431         try {
432             fos = new FileOutputStream(keyFile);
433             cos = new CipherOutputStream(fos, encrypt);
434             oos = new ObjectOutputStream(cos);
435             
436             oos.writeObject(keyPair.getPublic());
437             oos.flush();
438             oos.writeObject(keyPair.getPrivate());
439             oos.flush();
440          } finally {
441             if (oos != null) {
442                 oos.close();
443             } else if (cos != null) {
444                 cos.close();
445             } else if (fos != null) {
446                 fos.close();
447             }
448         }
449         System.err.println("Key successfully generated.");
450     }
451     
452     /**
453      * Generates a DESede3Key from a given password.
454      *
455      * @param password the password that will be used for this PBE algorithm.
456      * @return the generated SecretKey.
457      * @throws Exception if something goes wrong with the SecretKeyFactory.
458      */
459     private SecretKey genDESede3Key(char[] password) throws Exception {
460         MessageDigest innerDigest = 
461         MessageDigest.getInstance("RIPEMD160", "JHBCI");
462         MessageDigest outerDigest = 
463         MessageDigest.getInstance("RIPEMD160", "JHBCI");
464         
465         char [] salt = {
466             'D', 'o', 'n', 't', ' ', 'h', 'a', 'r', 'm', ' ', 'm', 'e', '.'
467         };
468         
469         int iterationCount = 5;
470 
471         for (int i = 0; i < iterationCount; i++) {
472             for (int j = 0; j < password.length; j++) {
473                 innerDigest.update((byte) ((password[j] >>> 8) & 0xff));
474                 innerDigest.update((byte) (password[j] & 0xff));
475             }
476             for (int j = 0; j < salt.length; j++) {
477                 innerDigest.update((byte) ((salt[j] >>> 8) & 0xff));
478                 innerDigest.update((byte) (salt[j] & 0xff));
479             }
480             MessageDigest tempDigest = (MessageDigest) innerDigest.clone();
481             outerDigest.update(innerDigest.digest());
482             innerDigest = tempDigest;
483         }
484         
485         byte[] firstDigest = outerDigest.digest();
486         
487         innerDigest.reset();
488         outerDigest.reset();
489         iterationCount = 15;
490         for (int i = 0; i < iterationCount; i++) {
491             for (int j = 0; j < password.length; j++) {
492                 innerDigest.update((byte) ((password[j] >>> 8) & 0xff));
493                 innerDigest.update((byte) (password[j] & 0xff));
494             }
495             for (int j = 0; j < salt.length; j++) {
496                 innerDigest.update((byte) ((salt[j] >>> 8) & 0xff));
497                 innerDigest.update((byte) (salt[j] & 0xff));
498             }
499             MessageDigest tempDigest = (MessageDigest) innerDigest.clone();
500             outerDigest.update(innerDigest.digest());
501             innerDigest = tempDigest;
502         }        
503         
504         byte[] secondDigest = outerDigest.digest();
505        
506         byte[] rawDESede3Key = new byte[24];
507         System.arraycopy(firstDigest, 0, rawDESede3Key, 0, 12);
508         System.arraycopy(secondDigest, 8, rawDESede3Key, 12, 12);
509         
510         DESede3KeySpec keySpec = new DESede3KeySpec(rawDESede3Key);
511         SecretKeyFactory factory = 
512         SecretKeyFactory.getInstance("DESede3Key", "JHBCI");
513         return factory.generateSecret(keySpec);
514     }
515     
516     /**
517      * Reads user password from given input stream.
518      *
519      * @param in the InputStream frow which the password will be read.
520      * @return the password.
521      * @throws IOException if somthing goeas wrong with the InputStream.
522      */
523     private char[] readPasswd(InputStream in) throws IOException {
524         char[] lineBuffer;
525         char[] buf;
526 
527         buf = lineBuffer = new char[128];
528 
529         int room = buf.length;
530         int offset = 0;
531         int c;
532         
533         loop:        
534         while (true) {
535             switch (c = in.read()) {
536               case -1: 
537               case '\n':
538                 break loop;
539 
540               case '\r':
541                 int c2 = in.read();
542                 if ((c2 != '\n') && (c2 != -1)) {
543                     if (!(in instanceof PushbackInputStream)) {
544                         in = new PushbackInputStream(in);
545                     }
546                     ((PushbackInputStream)in).unread(c2);
547                 } else 
548                     break loop;
549 
550               default:
551                 if (--room < 0) {
552                     buf = new char[offset + 128];
553                     room = buf.length - offset - 1;
554                     System.arraycopy(lineBuffer, 0, buf, 0, offset);
555                     Arrays.fill(lineBuffer, ' ');
556                     lineBuffer = buf;
557                 }
558                 buf[offset++] = (char) c;
559                 break;
560             }
561         }
562 
563         if (offset == 0) {
564             return null;
565         }
566 
567         char[] ret = new char[offset];
568         System.arraycopy(buf, 0, ret, 0, offset);
569         Arrays.fill(buf, ' ');
570 
571         return ret;
572     }    
573     
574     /**
575      * List the key bytes as hex.
576      *
577      * @param out the PrintStream where the key will be shown.
578      * @throws Exception if the password cna't be read from readKeyPair()
579      */
580     private void showKey(PrintStream out) throws Exception {
581         header();
582         KeyPair keyPair = readKeyPair();
583         System.err.println();        
584         
585         if (showKeyFormat.equals("dec")) {
586             out.print(toDecString((RSAPrivateCrtKey) keyPair.getPrivate()));
587         } else if (showKeyFormat.equals("hex")) {
588             out.print(toHexString((RSAPrivateCrtKey) keyPair.getPrivate()));
589         }
590     }
591     
592     /**
593      * Reads a KeyPair form a "keyFile".
594      *
595      * @throws Exception if something goes wrong.
596      */
597     private KeyPair readKeyPair() throws Exception {
598         if (keyFile == null) {
599             keyFile = userHome + fileSeparator + ".keyfile";
600         }
601         if (password == null) {
602             System.err.print("Enter keyfile password: ");
603             password = readPasswd(System.in);
604             System.err.println();
605         }
606         SecretKey desede3Key = genDESede3Key(password);
607         
608         byte[] rawIV = {
609             (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
610             (byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef
611         };
612         
613         DESOperationModeInitializationVectorSpec iv = 
614         new DESOperationModeInitializationVectorSpec(rawIV);        
615         
616         Cipher decrypt = Cipher.getInstance(
617         "DESede3Key/CBC/ISO10126OctetPadding", "JHBCI");
618         decrypt.init(Cipher.DECRYPT_MODE, desede3Key, iv);
619 
620         RSAPublicKey publicKey = null;
621         RSAPrivateCrtKey privateCrtKey = null;
622         InputStream fis = null;
623         InputStream cis = null;
624         ObjectInputStream ois = null;        
625         try {
626             fis = new FileInputStream(keyFile);
627             cis = new CipherInputStream(fis, decrypt);
628             ois = new ObjectInputStream(cis);
629             publicKey = (RSAPublicKey) ois.readObject(); 
630             privateCrtKey = (RSAPrivateCrtKey) ois.readObject();            
631         } finally {
632             if (ois != null) {
633                 ois.close();
634             } else if (cis != null) {
635                 cis.close();
636             } else if (fis != null) {
637                 fis.close();
638             }
639         }
640 
641         System.err.println("RSA Key File: " + keyFile);
642         System.err.print("RSA Key Length: "); 
643         System.err.print(privateCrtKey.getModulus().bitLength() + " bit");
644         System.err.println();
645         
646         return new KeyPair(publicKey, privateCrtKey);
647     }
648     
649     /**
650      * Converts a RSAPrivateCrtKey in its decimal String representation.
651      *
652      * @param key that will be converted to a String.
653      * @return the converted key as String.
654      */
655     private String toDecString(RSAPrivateCrtKey key) {
656         BigInteger modulus = key.getModulus();
657         BigInteger publicExponent = key.getPublicExponent();
658         BigInteger privateExponent = key.getPrivateExponent();
659         BigInteger primeP = key.getPrimeP();
660         BigInteger primeQ = key.getPrimeQ();
661         BigInteger primeExponentP = key.getPrimeExponentP();
662         BigInteger primeExponentQ = key.getPrimeExponentQ();
663         BigInteger crtCoefficient = key.getCrtCoefficient();
664         
665         StringBuffer sb = new StringBuffer();
666         sb.append("Key length: ");
667         sb.append(key.getModulus().bitLength());
668         sb.append(lineSeparator);
669         sb.append(lineSeparator);
670         
671         sb.append("Modulus: ");
672         sb.append(lineSeparator);
673         sb.append(toDec(modulus));
674         sb.append(lineSeparator);
675         sb.append(lineSeparator);
676         
677         sb.append("Public Exponent: ");
678         sb.append(lineSeparator);
679         sb.append(toDec(publicExponent));
680         sb.append(lineSeparator);
681         sb.append(lineSeparator);
682         
683         sb.append("Private Exponent: ");
684         sb.append(lineSeparator);
685         sb.append(toDec(privateExponent));
686         sb.append(lineSeparator);
687         sb.append(lineSeparator); 
688         
689         sb.append("Prime P: ");
690         sb.append(lineSeparator);
691         sb.append(toDec(primeP));
692         sb.append(lineSeparator);
693         sb.append(lineSeparator);        
694         
695         sb.append("Prime Q: ");
696         sb.append(lineSeparator);
697         sb.append(toDec(primeQ));
698         sb.append(lineSeparator);
699         sb.append(lineSeparator);
700         
701         sb.append("Prime Exponent P: ");
702         sb.append(lineSeparator);
703         sb.append(toDec(primeExponentP));
704         sb.append(lineSeparator);
705         sb.append(lineSeparator);        
706         
707         sb.append("Prime Exponent Q: ");
708         sb.append(lineSeparator);
709         sb.append(toDec(primeExponentQ));
710         sb.append(lineSeparator);
711         sb.append(lineSeparator);
712         
713         sb.append("Chinese Remainder Coefficient: ");
714         sb.append(lineSeparator);
715         sb.append(toDec(crtCoefficient));
716         sb.append(lineSeparator);                 
717         
718         return sb.toString();        
719     }
720     
721     /**
722      * Converts a BigInteger to decimal block string.
723      *
724      * @param number that will be converted to a String.
725      * @return the converted number as String.
726      */
727     private String toDec(BigInteger number) {
728         char[] block = number.toString().toCharArray();
729         StringBuffer sb = new StringBuffer();
730         int len = block.length;
731         for (int i = 0; i < len; i++) {    
732              if ((i % 48 == 0) && (i != 0)) {
733                  sb.append(lineSeparator);
734              } 
735              sb.append(block[i]);
736         } 
737         return sb.toString();
738     }      
739     
740     /**
741      * Converts a RSAPrivateCrtKey in its hexadecimal String representation.
742      *
743      * @param key that will be converted to a String.
744      * @return the converted key as String.
745      */    
746     private String toHexString(RSAPrivateCrtKey key) {
747         BigInteger modulus = key.getModulus();
748         BigInteger publicExponent = key.getPublicExponent();
749         BigInteger privateExponent = key.getPrivateExponent();
750         BigInteger primeP = key.getPrimeP();
751         BigInteger primeQ = key.getPrimeQ();
752         BigInteger primeExponentP = key.getPrimeExponentP();
753         BigInteger primeExponentQ = key.getPrimeExponentQ();
754         BigInteger crtCoefficient = key.getCrtCoefficient();
755         
756         StringBuffer sb = new StringBuffer();
757         sb.append("Key length: ");
758         sb.append(key.getModulus().bitLength());
759         sb.append(lineSeparator);
760         sb.append(lineSeparator);
761         
762         sb.append("Modulus: ");
763         sb.append(lineSeparator);
764         sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(modulus)));
765         sb.append(lineSeparator);
766         sb.append(lineSeparator);
767         
768         sb.append("Public Exponent: ");
769         sb.append(lineSeparator);
770         sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(publicExponent)));
771         sb.append(lineSeparator);
772         sb.append(lineSeparator);
773         
774         sb.append("Private Exponent: ");
775         sb.append(lineSeparator);
776         sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(privateExponent)));
777         sb.append(lineSeparator);
778         sb.append(lineSeparator); 
779         
780         sb.append("Prime P: ");
781         sb.append(lineSeparator);
782         sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(primeP)));
783         sb.append(lineSeparator);
784         sb.append(lineSeparator);        
785         
786         sb.append("Prime Q: ");
787         sb.append(lineSeparator);
788         sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(primeQ)));
789         sb.append(lineSeparator);
790         sb.append(lineSeparator);
791         
792         sb.append("Prime Exponent P: ");
793         sb.append(lineSeparator);
794         sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(primeExponentP)));
795         sb.append(lineSeparator);
796         sb.append(lineSeparator);        
797         
798         sb.append("Prime Exponent Q: ");
799         sb.append(lineSeparator);
800         sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(primeExponentQ)));
801         sb.append(lineSeparator);
802         sb.append(lineSeparator);
803         
804         sb.append("Chinese Remainder Coefficient: ");
805         sb.append(lineSeparator);
806         sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(crtCoefficient)));
807         sb.append(lineSeparator);
808         
809         return sb.toString();
810     }
811 
812     /**
813      * Converts a byte array to hex string
814      *
815      * @param number that will be converted to a String.
816      * @return the converted number as String.
817      */
818     private String toHex(byte[] block) {
819         StringBuffer sb = new StringBuffer();
820         int len = block.length;
821         for (int i = 0; i < len; i++) {    
822              if ((i % 16 == 0) && (i != 0)) {
823                  sb.append(lineSeparator);
824              } 
825              if (i % 16 != 0){
826                 sb.append(' ');
827                 if (i % 8 == 0) {
828                     sb.append(' ');
829                 }
830              }
831              byte2hex(block[i], sb);             
832         } 
833         return sb.toString();
834     }  
835     
836     
837     /**
838      * Converts a byte to hex digit and writes to the supplied buffer
839      *
840      * @param b the byte that should be converted into the buf.
841      * @param buf the StringBuffer.
842      */
843     private void byte2hex(byte b, StringBuffer buf) {
844         char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
845                             '9', 'a', 'b', 'c', 'd', 'e', 'f' };
846         int high = ((b & 0xf0) >> 4);
847         int low = (b & 0x0f);
848         buf.append(hexChars[high]);
849         buf.append(hexChars[low]);
850     }   
851         
852     /**
853      * Exports a public Key out of the "keyFile" into the "pubKeyFile".
854      *
855      * @throws Exception if something goes wrong.
856      */
857     private void export() throws Exception {
858         if (pubKeyFile == null) {
859             throw new Exception("You have to specify a PublicKeyOutputFile.");
860         }
861         header();
862         RSAPublicKey publicKey = (RSAPublicKey) readKeyPair().getPublic();
863         System.err.println("RSA Public Key File: " + pubKeyFile);
864         
865         OutputStream fos = null;
866         ObjectOutputStream oos = null;
867         try {
868             fos = new FileOutputStream(pubKeyFile);
869             oos = new ObjectOutputStream(fos);
870             oos.writeObject(publicKey);
871         } finally {
872             if (oos != null) {
873                 oos.close();
874             } else if (fos != null) {
875                 fos.close();
876             }
877         }
878         System.err.println();
879         System.err.println("Public Key successfully exported.");
880     }
881     
882     /**
883      * Shows a previously exported public Key which is read from "pubKeyFile".
884      *
885      * @param out the PrintStream to which the public Key will be printed out.
886      * @throws Exception if key reading goes wrong.
887      */
888     private void showPub(PrintStream out) throws Exception {
889         if (pubKeyFile == null) {
890             throw new Exception("You have to specify a PublicKeyInputFile.");
891         }        
892         header();
893         
894         RSAPublicKey publicKey = readPublicKey();
895         System.err.println();
896         
897         if (showKeyFormat.equals("dec")) {
898             out.print(toDecString(publicKey));
899         } else if (showKeyFormat.equals("hex")) {
900             out.print(toHexString(publicKey));
901         }
902     }
903     
904     
905     /**
906      * Reads a previously exported public Key from "pubKeyFile".
907      *
908      * @throws Exception if key reading goes wrong.
909      */    
910     private RSAPublicKey readPublicKey() throws Exception {
911         if (pubKeyFile == null) {
912             throw new Exception("You have to specify a PublicKeyInputFile.");
913         }    
914         System.err.println("RSA Public Key File: " + pubKeyFile);     
915         
916         RSAPublicKey publicKey = null;
917         InputStream fis = null;
918         ObjectInputStream ois = null;
919         try {
920             fis = new FileInputStream(pubKeyFile);
921             ois = new ObjectInputStream(fis);            
922         
923             publicKey = (RSAPublicKey) ois.readObject(); 
924         } finally {
925             if (ois != null) {
926                 ois.close();
927             } else if (fis != null) {
928                 fis.close();
929             }
930         }
931         
932         System.err.print("RSA Key Length: "); 
933         System.err.print(publicKey.getModulus().bitLength() + " bit");
934         System.err.println();
935         
936         return publicKey;        
937     }
938     
939     /**
940      * Converts a RSAPublicKey in its decimal String representation.
941      *
942      * @param key that will be converted to a String.
943      * @return the converted key as String.
944      */
945     private String toDecString(RSAPublicKey key) {
946         BigInteger modulus = key.getModulus();
947         BigInteger publicExponent = key.getPublicExponent();
948         
949         StringBuffer sb = new StringBuffer();
950         sb.append("Key length: ");
951         sb.append(key.getModulus().bitLength());
952         sb.append(lineSeparator);
953         sb.append(lineSeparator);
954         
955         sb.append("Modulus: ");
956         sb.append(lineSeparator);
957         sb.append(toDec(modulus));
958         sb.append(lineSeparator);
959         sb.append(lineSeparator);
960         
961         sb.append("Public Exponent: ");
962         sb.append(lineSeparator);
963         sb.append(toDec(publicExponent));
964         sb.append(lineSeparator);
965         
966         return sb.toString();        
967     }    
968     
969     /**
970      * Converts a RSAPublicKey in its hexadecimal String representation.
971      *
972      * @param key that will be converted to a String.
973      * @return the converted key as String.
974      */    
975     private String toHexString(RSAPublicKey key) {
976         BigInteger modulus = key.getModulus();
977         BigInteger publicExponent = key.getPublicExponent();
978         
979         StringBuffer sb = new StringBuffer();
980         sb.append("Key length: ");
981         sb.append(key.getModulus().bitLength());
982         sb.append(lineSeparator);
983         sb.append(lineSeparator);
984         
985         sb.append("Modulus: ");
986         sb.append(lineSeparator);
987         sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(modulus)));
988         sb.append(lineSeparator);
989         sb.append(lineSeparator);
990         
991         sb.append("Public Exponent: ");
992         sb.append(lineSeparator);
993         sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(publicExponent)));
994         sb.append(lineSeparator);
995         
996         return sb.toString();
997     }    
998     
999     /**
1000     * Encrypts the "inFile" to the "outFile" with the "pubKeyFile".
1001     *
1002     * @throws Exception if something goes wrong.
1003     */    
1004    private void encrypt() throws Exception {
1005        if (inFile == null) {
1006            throw new Exception("You have to specify a PlainTextInputFile.");
1007        }
1008        if (outFile == null) {
1009            throw new Exception("You have to specify a CipherTextOutputFile.");
1010        }        
1011        
1012        header();
1013        System.err.println("Plain Text File: " + inFile);
1014        System.err.println("Cipher Text File: " + outFile);
1015
1016        RSAPublicKey publicKey = readPublicKey();
1017        
1018        KeyGenerator keyGen = KeyGenerator.getInstance(algorithm, "JHBCI");
1019        SecretKey desKey = keyGen.generateKey();
1020        
1021        System.err.println("DES Key Wrapper File: " + outFile + ".des");
1022        System.err.print("DES Key Length: ");
1023        System.err.print(desKey.getEncoded().length * 7);
1024        System.err.println(" bit without parity");
1025        System.err.println();
1026
1027        
1028        Cipher wrapper = Cipher.getInstance("RSA", "JHBCI");
1029        wrapper.init(Cipher.WRAP_MODE, publicKey);
1030        byte[] wrappedKey = wrapper.wrap(desKey);
1031        
1032        OutputStream kfos = new FileOutputStream(outFile + ".des");
1033        ObjectOutputStream oos = new ObjectOutputStream(kfos);
1034        oos.writeObject(algorithm);
1035        oos.writeObject(wrappedKey);
1036        kfos.close();
1037        
1038        Cipher encrypt = Cipher.getInstance(
1039        algorithm + "/CBC/ISO10126OctetPadding", "JHBCI");
1040        
1041        byte[] rawIV = {
1042            (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
1043            (byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef
1044        };
1045        
1046        DESOperationModeInitializationVectorSpec iv = 
1047        new DESOperationModeInitializationVectorSpec(rawIV);
1048        
1049        encrypt.init(Cipher.ENCRYPT_MODE, desKey, iv);
1050
1051
1052        InputStream fin = null;
1053        OutputStream fos = null;
1054        OutputStream cos = null;
1055        long before = System.currentTimeMillis();
1056        try {
1057            fin = new FileInputStream(inFile);
1058            fos = new FileOutputStream(outFile);
1059            cos = new CipherOutputStream(fos, encrypt);
1060            byte[] buffer = new byte[4096];
1061            loop:
1062            for(long read = 0, i = 0, j = 1024 * 100, k = 1; true;) {
1063                read = fin.read(buffer);
1064                if (read == -1) {
1065                    if (k != 1) {
1066                        System.err.print('.');
1067                        for (int l = 0; l < (60 - k); l++) {
1068                            System.err.print(' ');
1069                        }
1070                    }
1071                    System.err.println("[" + i + "]");
1072                    System.err.println();
1073                    break loop;
1074                }
1075                cos.write(buffer, 0, (int) read);
1076                i += read; 
1077                if (i > j) {
1078                    if (k == 60) {
1079                        System.err.println('.' + "[" + i  + "]");
1080                        k = 1;
1081                    } else {
1082                        System.err.print('.');
1083                        k++;
1084                    }
1085                    j += 1024 * 100;
1086                }
1087            }
1088        } finally {
1089            if (fin != null) {
1090                try {
1091                    fin.close();
1092                } finally {
1093                    if (fos != null) {
1094                        if (cos != null) {
1095                            cos.close();
1096                        } else {
1097                            fos.close();
1098                        }
1099                    }
1100                }
1101            }
1102        }
1103        long after = System.currentTimeMillis();
1104        System.err.print("Time to encrypt the whole file: ");
1105        System.err.println((after - before) + "ms");
1106        
1107    }
1108    
1109    /**
1110     * Decrypts the "inFile" to the "outFile" with the "keyFile".
1111     *
1112     * @throws Exception if something goes wrong.
1113     */    
1114    private void decrypt() throws Exception {
1115        if (inFile == null) {
1116            throw new Exception("You have to specify a PlainTextInputFile.");
1117        }
1118        if (outFile == null) {
1119            throw new Exception("You have to specify a CipherTextOutputFile.");
1120        }        
1121        
1122        header();
1123        System.err.println("Cipher Text File: " + inFile);
1124        System.err.println("Plain Text File: " + outFile);
1125        System.err.println();
1126        
1127        InputStream kfis = new FileInputStream(inFile + ".des");
1128        ObjectInputStream ois = new ObjectInputStream(kfis);
1129        
1130        algorithm = (String) ois.readObject();
1131        byte[] wrappedKey = (byte[]) ois.readObject();
1132        ois.close();
1133        
1134        RSAPrivateCrtKey privateCrtKey = 
1135        (RSAPrivateCrtKey) readKeyPair().getPrivate();     
1136        Cipher unwrapper = Cipher.getInstance("RSA", "JHBCI");
1137        unwrapper.init(Cipher.UNWRAP_MODE, privateCrtKey);
1138        SecretKey desKey = 
1139        (SecretKey) unwrapper.unwrap(wrappedKey, algorithm, Cipher.SECRET_KEY); 
1140
1141        System.err.println("DES Key Wrapper File: " + inFile + ".des");
1142        System.err.print("DES Key Length: ");
1143        System.err.print(desKey.getEncoded().length * 7);
1144        System.err.println(" bit without parity");
1145        System.err.println();        
1146        
1147        Cipher decrypt = Cipher.getInstance(
1148        algorithm + "/CBC/ISO10126OctetPadding", "JHBCI");
1149        
1150        byte[] rawIV = {
1151            (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
1152            (byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef
1153        };
1154        
1155        DESOperationModeInitializationVectorSpec iv = 
1156        new DESOperationModeInitializationVectorSpec(rawIV);
1157        
1158        decrypt.init(Cipher.DECRYPT_MODE, desKey, iv);
1159        
1160        InputStream fis = null;
1161        InputStream cis = null;
1162        OutputStream fos = null;
1163        long before = System.currentTimeMillis();                        
1164        try {
1165            fis = new FileInputStream(inFile);
1166            cis = new CipherInputStream(fis, decrypt);
1167            fos = new FileOutputStream(outFile);
1168            byte[] buffer = new byte[4096];
1169            loop:
1170            for(long read = 0, i = 0, j = 1024 * 100, k = 1; true;) {
1171                read = cis.read(buffer);
1172                if (read == -1) {
1173                    if (k != 1) {
1174                        System.err.print('.');
1175                        for (int l = 0; l < (60 - k); l++) {
1176                            System.err.print(' ');
1177                        }
1178                    }
1179                    System.err.println("[" + i + "]");
1180                    System.err.println();
1181                    break loop;
1182                }
1183                fos.write(buffer, 0, (int) read);
1184                i += read; 
1185                if (i > j) {
1186                    if (k == 60) {
1187                        System.err.println('.' + "[" + i  + "]");
1188                        k = 1;
1189                    } else {
1190                        System.err.print('.');
1191                        k++;
1192                    }
1193                    j += 1024 * 100;
1194                }
1195            }
1196            
1197        } finally {
1198            if (cis != null) {
1199                try {
1200                    cis.close();
1201                } finally {
1202                    if (fos != null) {
1203                        fos.close();
1204                    }
1205                }
1206            } else if (fis != null) {
1207                fis.close();
1208            }
1209        }
1210        long after = System.currentTimeMillis();
1211        System.err.print("Time to decrypt the whole file: ");
1212        System.err.println((after - before) + "ms");        
1213    }
1214    
1215    /**
1216     * Signs the "inFile" to the "sigFile" with the "keyFile".
1217     *
1218     * @throws Exception if something goes wrong.
1219     */    
1220    private void sign() throws Exception {
1221        if (inFile == null) {
1222            throw new Exception("You have to specify a MessageInputFile.");
1223        }
1224        if (sigFile == null) {
1225            throw new Exception("You have to specify a SignatureOutputFile.");
1226        }        
1227        
1228        header();
1229        System.err.println("Message File: " + inFile);
1230        System.err.println("Signature File: " + sigFile);
1231        System.err.println();
1232        
1233        RSAPrivateCrtKey privateCrtKey = 
1234        (RSAPrivateCrtKey) readKeyPair().getPrivate();
1235        System.err.println();
1236        Signature signer = 
1237        Signature.getInstance("RIPEMD160WithISO9796-1AndRSA", "JHBCI");
1238        signer.initSign(privateCrtKey);
1239        
1240        InputStream fin = null;
1241        long before = System.currentTimeMillis();
1242        try {
1243            fin = new FileInputStream(inFile);
1244            byte[] buffer = new byte[4096];
1245            loop:
1246            for(long read = 0, i = 0, j = 1024 * 100, k = 1; true;) {
1247                read = fin.read(buffer);
1248                if (read == -1) {
1249                    if (k != 1) {
1250                        System.err.print('.');
1251                        for (int l = 0; l < (60 - k); l++) {
1252                            System.err.print(' ');
1253                        }
1254                    }
1255                    System.err.println("[" + i + "]");
1256                    System.err.println();
1257                    break loop;
1258                }
1259                signer.update(buffer, 0, (int) read);
1260                i += read; 
1261                if (i > j) {
1262                    if (k == 60) {
1263                        System.err.println('.' + "[" + i  + "]");
1264                        k = 1;
1265                    } else {
1266                        System.err.print('.');
1267                        k++;
1268                    }
1269                    j += 1024 * 100;
1270                }
1271            }
1272        } finally {
1273            if (fin != null) {
1274                fin.close();
1275            }
1276        }
1277        
1278        byte[] signature = null;
1279        OutputStream fos = null;
1280        try {
1281            fos = new FileOutputStream(sigFile);
1282            signature = signer.sign();
1283            fos.write(signature);
1284        } finally {
1285            if (fos != null) {
1286                fos.close();
1287            }
1288        }
1289        
1290        System.err.println("Signature:");
1291        System.err.println("");
1292        System.err.println(toHex(signature));
1293        System.err.println();
1294        
1295        System.err.println("Signature successfully created.");
1296        System.err.println("");
1297
1298        long after = System.currentTimeMillis();
1299        System.err.print("Time to sign the whole file: ");
1300        System.err.println((after - before) + "ms");        
1301    }
1302    
1303    /**
1304     * Verifies the "inFile" to with the "sigFile" and the "pubKeyFile".
1305     *
1306     * @throws Exception if something goes wrong.
1307     */    
1308    private void verify() throws Exception {
1309        if (inFile == null) {
1310            throw new Exception("You have to specify a MessageInputFile.");
1311        }
1312        if (sigFile == null) {
1313            throw new Exception("You have to specify a SignatureInputFile.");
1314        } 
1315        
1316        header();
1317        System.err.println("Message File: " + inFile);
1318        System.err.println("Signature File: " + sigFile);
1319        
1320        RSAPublicKey publicKey = readPublicKey();
1321        System.err.println();
1322        Signature verifier = 
1323        Signature.getInstance("RIPEMD160WithISO9796-1AndRSA", "JHBCI");
1324        verifier.initVerify(publicKey); 
1325        
1326        InputStream fin = null;
1327        long before = System.currentTimeMillis();
1328        try {
1329            fin = new FileInputStream(inFile);
1330            byte[] buffer = new byte[4096];
1331            loop:
1332            for(long read = 0, i = 0, j = 1024 * 100, k = 1; true;) {
1333                read = fin.read(buffer);
1334                if (read == -1) {
1335                    if (k != 1) {
1336                        System.err.print('.');
1337                        for (int l = 0; l < (60 - k); l++) {
1338                            System.err.print(' ');
1339                        }
1340                    }
1341                    System.err.println("[" + i + "]");
1342                    System.err.println();
1343                    break loop;
1344                }
1345                verifier.update(buffer, 0, (int) read);
1346                i += read; 
1347                if (i > j) {
1348                    if (k == 60) {
1349                        System.err.println('.' + "[" + i  + "]");
1350                        k = 1;
1351                    } else {
1352                        System.err.print('.');
1353                        k++;
1354                    }
1355                    j += 1024 * 100;
1356                }
1357            }
1358        } finally {
1359            if (fin != null) {
1360                fin.close();
1361            }
1362        }        
1363        
1364        InputStream sfin = null;
1365        try {
1366            sfin = new FileInputStream(sigFile);
1367            byte[] buffer = null;
1368            byte[] signature = null;
1369            byte[] temp = null;
1370            loop2:
1371            for(int read = 0; true;) {
1372                buffer = new byte[4096];
1373                read = sfin.read(buffer);
1374                if (read == -1) {
1375                    break;
1376                }
1377                if (signature == null) {
1378                    signature = new byte[read];
1379                    System.arraycopy(buffer, 0, signature, 0, read);
1380                } else {
1381                    temp = signature;
1382                    signature = new byte[temp.length + read];
1383                    System.arraycopy(temp, 0, signature, 0, temp.length);
1384                    System.arraycopy(buffer, 0, signature, temp.length, read);
1385                    temp = null;
1386                }
1387            }
1388
1389            System.err.println("Signature:");
1390            System.err.println("");
1391            System.err.println(toHex(signature));
1392            System.err.println();        
1393                          
1394            boolean verified = verifier.verify(signature);
1395            if (verified) {
1396                System.err.println("Signature successfully verified.");
1397            } else {
1398                System.err.println("Signature rejected.");
1399            }
1400      
1401            long after = System.currentTimeMillis();
1402            System.err.println();
1403            System.err.print("Time to verify the whole file: ");
1404            System.err.println((after - before) + "ms");              
1405        } finally {
1406            if (sfin != null) {
1407                fin.close();
1408            }
1409        }
1410    }
1411    
1412    /**
1413     * Digest the "inFile" to "digestFile".
1414     *
1415     * @throws Exception if something goes wrong.
1416     */    
1417    private void digest() throws Exception {
1418        if (inFile == null) {
1419            throw new Exception("You have to specify a MessageInputFile.");
1420        }
1421        if (digestFile == null) {
1422            throw new Exception("You have to specify a DigestOutputFile.");
1423        }
1424        
1425        header();
1426        System.err.println("Message File: " + inFile);
1427        System.err.println("Digest File: " + digestFile);
1428        System.err.println();
1429        
1430        MessageDigest digest = MessageDigest.getInstance("RIPEMD160", "JHBCI");
1431        InputStream fin = null;
1432        try {
1433            fin = new FileInputStream(inFile);
1434            byte[] buffer = new byte[4096];
1435            loop:
1436            for(long read = 0, i = 0, j = 1024 * 100, k = 1; true;) {
1437                read = fin.read(buffer);
1438                if (read == -1) {
1439                    if (k != 1) {
1440                        System.err.print('.');
1441                        for (int l = 0; l < (60 - k); l++) {
1442                            System.err.print(' ');
1443                        }
1444                    }
1445                    System.err.println("[" + i + "]");
1446                    System.err.println();
1447                    break loop;
1448                }
1449                digest.update(buffer, 0, (int) read);
1450                i += read; 
1451                if (i > j) {
1452                    if (k == 60) {
1453                        System.err.println('.' + "[" + i  + "]");
1454                        k = 1;
1455                    } else {
1456                        System.err.print('.');
1457                        k++;
1458                    }
1459                    j += 1024 * 100;
1460                }
1461            }
1462        } finally {
1463            if (fin != null) {
1464                fin.close();
1465            }
1466        }        
1467        
1468        byte[] messageDigest = digest.digest();
1469        
1470        OutputStream fos = null;
1471        PrintWriter pw = null;
1472        try {
1473            fos = new FileOutputStream(digestFile);
1474            pw = new PrintWriter(fos);
1475            System.err.println("Signature RIPEMD160:");
1476            System.err.println();
1477            System.err.println(toHex(messageDigest));
1478            pw.println(toHex(messageDigest));
1479        } finally {
1480            if (pw != null) {
1481                pw.close();
1482            } else if( fos != null) {
1483                fos.close();
1484            }
1485        }        
1486    }
1487    
1488    /**
1489     * Prints the header info of this tool.
1490     */
1491    private void header() {
1492        if (headerPrinted) {
1493            return ;
1494        } else {
1495            headerPrinted = true;
1496        }
1497        
1498        //Header
1499        System.err.println();
1500        System.err.print("CryptoTool v" + version + " Copyright (C) ");
1501        System.err.print("2001, 2002 ");
1502        System.err.print("Uwe Guenther <uwe@cscc.de> ");
1503        System.err.println();
1504        System.err.print("All Rights Reserved. ");
1505        System.err.print("(build 0.0.6-b72, 10/04/2003 09:23 PM)");
1506        System.err.println();    
1507        System.err.println();
1508    }
1509    
1510    /**
1511     * Prints the usage of this tool.
1512     */
1513    private void usage() {
1514        //header
1515        header();
1516        System.err.print("CryptoTool Usage:");
1517        System.err.println();
1518        System.err.println();
1519
1520        //help
1521        System.err.print("-help     "); 
1522        System.err.print("Print out this usage message. ");
1523        System.err.println();
1524        System.err.println();        
1525        
1526        //genkey
1527        System.err.print("-genkey   "); 
1528        System.err.print("[-keysize <KeySize>] ");
1529        System.err.print("[-keyfile <KeyOutputFile>] ");
1530        System.err.println();
1531        System.err.print("          ");
1532        System.err.print("[-keypass <password>] ");
1533        System.err.println();
1534        System.err.print("          ");        
1535        System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1536        System.err.println();
1537        System.err.println();
1538
1539        //showkey
1540        System.err.print("-showkey  ");
1541        System.err.print("[-hex | -dec] ");
1542        System.err.print("[-keyfile <KeyInputFile>] ");
1543        System.err.println();
1544        System.err.print("          ");
1545        System.err.print("[-keypass <password>] ");
1546        System.err.println();
1547        System.err.print("          ");                
1548        System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1549        System.err.println();
1550        System.err.println();
1551        
1552        //exportkey
1553        System.err.print("-export   "); 
1554        System.err.print("[-keyfile <KeyInputFile>] [-pubkey <PublicKeyOutputFile]");
1555        System.err.println();
1556        System.err.print("          ");
1557        System.err.print("[-keypass <password>] ");
1558        System.err.println();
1559        System.err.print("          ");                
1560        System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1561        System.err.println();
1562        System.err.println();
1563        
1564        //showpubkey
1565        System.err.print("-showpub  ");
1566        System.err.print("[-hex | -dec] ");
1567        System.err.print("[-pubkey <PublicKeyInputFile>] ");
1568        System.err.println();
1569        System.err.print("          ");
1570        System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1571        System.err.println();
1572        System.err.println();        
1573                
1574        //encrypt
1575        System.err.print("-encrypt  ");
1576        System.err.print("[-in <PlainTextInputFile>] ");
1577        System.err.print("[-out <CipherTextOutputFile>] ");
1578        System.err.println();
1579        System.err.print("          ");
1580        System.err.print("[-pubkey <PublicKeyInputFile>] ");
1581        System.err.println();
1582        System.err.print("          ");        
1583        System.err.print("[-alg <DES1Key|DESede2Key|DESede3Key>] ");        
1584        System.err.println();
1585        System.err.print("          ");
1586        System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");
1587        System.err.println();
1588        System.err.println();
1589        
1590        //decrypt
1591        System.err.print("-decrypt  ");
1592        System.err.print("[-in <CipherTextInputFile>] ");
1593        System.err.print("[-out <PlainTextOutputFile>] ");
1594        System.err.println();
1595        System.err.print("          ");
1596        System.err.print("[-keyfile <KeyInputFile>] ");
1597        System.err.print("[-keypass <password>] ");
1598        System.err.println();
1599        System.err.print("          ");
1600        System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");
1601        System.err.println();
1602        System.err.println();
1603        
1604        //sign
1605        System.err.print("-sign     ");
1606        System.err.print("[-in <MessageInputFile>] ");
1607        System.err.print("[-sigfile <SignatureOutputFile>] ");
1608        System.err.println();
1609        System.err.print("          ");
1610        System.err.print("[-keyfile <KeyInputFile>] ");
1611        System.err.print("[-keypass <password>] ");        
1612        System.err.println();
1613        System.err.print("          ");
1614        System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1615        System.err.println();
1616        System.err.println();        
1617        
1618        //verify
1619        System.err.print("-verify   ");
1620        System.err.print("[-in <MessageInputFile>] ");
1621        System.err.print("[-sigfile <SignatureInputFile>] ");
1622        System.err.println();
1623        System.err.print("          ");
1624        System.err.print("[-pubkey <PublicKeyInputFile>] ");
1625        System.err.println();
1626        System.err.print("          ");
1627        System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1628        System.err.println();
1629        System.err.println();        
1630        
1631        //disgest
1632        System.err.print("-digest   ");
1633        System.err.print("[-in <MessageInputFile>] ");
1634        System.err.print("[-disgestfile <DigestOutputFile>] ");
1635        System.err.println();
1636        System.err.print("          ");
1637        System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1638        System.err.println();
1639        System.err.println();
1640        
1641        //Finish, we lose ;-)
1642        System.exit(1);
1643    }
1644}
1645