View Javadoc

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.digest;
22  
23  import java.io.File;
24  import java.io.FileInputStream;
25  import java.io.FileNotFoundException;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.nio.ByteBuffer;
29  import java.nio.channels.FileChannel;
30  import java.security.MessageDigest;
31  import java.security.NoSuchAlgorithmException;
32  import java.util.Arrays;
33  import java.util.zip.Adler32;
34  import java.util.zip.CRC32;
35  import java.util.zip.Checksum;
36  
37  import org.jboss.netty.buffer.ChannelBuffer;
38  
39  /**
40   * Class implementing digest like MD5, SHA1. MD5 is based on the Fast MD5
41   * implementation, without C library support, but can be revert to JVM native
42   * digest.<br><br>
43   * 
44   * Some performance reports: (done using java -server option)
45   * <ul>
46   * <li>File based only:</li>
47   * <ul><li>FastMD5 in C is almost the fastest (+20%), while FastMD5 in Java is the slowest (-20%) and JVM version is in the middle.</li>
48   * <li>If ADLER32 is the referenced time ADLER32=1, CRC32=2.5, MD5=4, SHA1=7, SHA256=11, SHA512=25</li>
49   * </ul>
50   * <li>Buffer based only:</li>
51   * <ul><li>JVM version is the fastest (+20%), while FastMD5 in C or in Java are the same (-20% than JVM).</li>
52   * <li>If ADLER32 is the referenced time ADLER32=1, CRC32=2.5, MD5=4, SHA1=8, SHA256=13, SHA384=29, SHA512=31</li>
53   * </ul></ul>
54   * 
55   * @author Frederic Bregier
56   *
57   */
58  public class FilesystemBasedDigest {
59      
60      protected MD5 md5 = null;
61      protected Checksum checksum = null;
62      protected MessageDigest digest = null;
63      protected DigestAlgo algo = null;
64      /**
65       * Constructor of an independent Digest
66       * @param algo
67       * @throws NoSuchAlgorithmException
68       */
69      public FilesystemBasedDigest(DigestAlgo algo) throws NoSuchAlgorithmException {
70          initialize(algo);
71      }
72      /**
73       * (Re)Initialize the digest
74       * @throws NoSuchAlgorithmException
75       */
76      public void initialize() throws NoSuchAlgorithmException {
77          if (algo == DigestAlgo.MD5 && useFastMd5) {
78              md5 = new MD5();
79              return;
80          }
81          switch (algo) {
82              case ADLER32:
83                  checksum = new Adler32();
84                  return;
85              case CRC32:
86                  checksum = new CRC32();
87                  return;
88              case MD5:
89              case MD2:
90              case SHA1:
91              case SHA256:
92              case SHA384:
93              case SHA512:
94                  String algoname = algo.name;
95                  try {
96                      digest = MessageDigest.getInstance(algoname);
97                  } catch (NoSuchAlgorithmException e) {
98                      throw new NoSuchAlgorithmException(algo +
99                              " Algorithm not supported by this JVM", e);
100                 }
101                 return;
102             default:
103                 throw new NoSuchAlgorithmException(algo.name +
104                         " Algorithm not supported by this JVM");
105         }
106     }
107     /**
108      * (Re)Initialize the digest
109      * @param algo
110      * @throws NoSuchAlgorithmException
111      */
112     public void initialize(DigestAlgo algo) throws NoSuchAlgorithmException {
113         this.algo = algo;
114         initialize();
115     }
116     
117     /**
118      * Update the digest with new bytes
119      * @param bytes
120      * @param offset
121      * @param length
122      */
123     public void Update(byte [] bytes, int offset, int length) {
124         if (md5 != null) {
125             md5.Update(bytes, offset, length);
126             return;
127         }
128         switch (algo) {
129             case ADLER32:
130             case CRC32:
131                 checksum.update(bytes, offset, length);
132                 return;
133             case MD5:
134             case MD2:
135             case SHA1:
136             case SHA256:
137             case SHA384:
138             case SHA512:
139                 digest.update(bytes, offset, length);
140                 return;
141         }
142     }
143     /**
144      * 
145      * @return the digest in array of bytes
146      */
147     public byte[] Final() {
148         if (md5 != null) {
149             return md5.Final();
150         }
151         switch (algo) {
152             case ADLER32:
153             case CRC32:
154                 return Long.toOctalString(checksum.getValue()).getBytes();
155             case MD5:
156             case MD2:
157             case SHA1:
158             case SHA256:
159             case SHA384:
160             case SHA512:
161                 return digest.digest();
162         }
163         return null;
164     }
165     /**
166      * Initialize the MD5 support
167      * @param mustUseFastMd5 True will use FastMD5 support, False will use JVM native MD5
168      * @param path If useFastMD5 is True, if path is not null, specify the C Library (optional), 
169      *          else if null will use the Java implementation
170      * @return True if the native library is loaded
171      */
172     public static boolean initializeMd5(boolean mustUseFastMd5, String path) {
173         useFastMd5 = mustUseFastMd5;
174         fastMd5Path = path;
175         if (fastMd5Path == null) {
176             return MD5.initNativeLibrary(true);
177         } else {
178             // If useFastMd5 is false, ignore fastMd5Path later on
179             if (useFastMd5) {
180                 return MD5.initNativeLibrary(fastMd5Path);
181             } else {
182                 return MD5.initNativeLibrary(true);
183             }
184         }
185     }
186     /**
187      * All Algo that Digest Class could handle
188      * @author Frederic Bregier
189      *
190      */
191     public static enum DigestAlgo {
192         CRC32("CRC32",11), ADLER32("ADLER32",9), 
193         MD5("MD5",16), MD2("MD2",16), SHA1("SHA-1", 20), 
194         SHA256("SHA-256",32), SHA384("SHA-384",48), SHA512("SHA-512",64);
195 
196         public String name;
197         public int byteSize;
198         /**
199          * 
200          * @return the length in bytes of one Digest
201          */
202         public int getByteSize() {
203             return byteSize;
204         }
205         /**
206          * 
207          * @return the length in Hex form of one Digest
208          */
209         public int getHexSize() {
210             return byteSize*2;
211         }
212         private DigestAlgo(String name, int byteSize) {
213             this.name=name;
214             this.byteSize=byteSize;
215         }
216     }
217     /**
218      * Should a file MD5 be computed using FastMD5
219      */
220     public static boolean useFastMd5 = false;
221 
222     /**
223      * If using Fast MD5, should we used the binary JNI library, empty meaning
224      * no. FastMD5 is up to 50% fastest than JVM, but JNI library might be not better
225      * than java FastMD5.
226      */
227     public static String fastMd5Path = null;
228 
229     /**
230      *
231      * @param dig1
232      * @param dig2
233      * @return True if the two digest are equals
234      */
235     public static final boolean digestEquals(byte[] dig1, byte[] dig2) {
236         return MessageDigest.isEqual(dig1, dig2);
237     }
238 
239     /**
240      *
241      * @param dig1
242      * @param dig2
243      * @return True if the two digest are equals
244      */
245     public static final boolean digestEquals(String dig1, byte[] dig2) {
246         byte[] bdig1 = getFromHex(dig1);
247         return MessageDigest.isEqual(bdig1, dig2);
248     }
249 
250 
251     /**
252      * get the byte array of the MD5 for the given FileInterface using Nio
253      * access
254      *
255      * @param f
256      * @return the byte array representing the MD5
257      * @throws IOException
258      */
259     public static byte[] getHashMd5Nio(File f) throws IOException {
260         if (useFastMd5) {
261             return MD5.getHashNio(f);
262         }
263         return getHash(f, true, DigestAlgo.MD5);
264     }
265 
266     /**
267      * get the byte array of the MD5 for the given FileInterface using standard
268      * access
269      *
270      * @param f
271      * @return the byte array representing the MD5
272      * @throws IOException
273      */
274     public static byte[] getHashMd5(File f) throws IOException {
275         if (useFastMd5) {
276             return MD5.getHash(f);
277         }
278         return getHash(f, false, DigestAlgo.MD5);
279     }
280 
281     /**
282      * get the byte array of the SHA-1 for the given FileInterface using Nio
283      * access
284      *
285      * @param f
286      * @return the byte array representing the SHA-1
287      * @throws IOException
288      */
289     public static byte[] getHashSha1Nio(File f) throws IOException {
290         return getHash(f, true, DigestAlgo.SHA1);
291     }
292 
293     /**
294      * get the byte array of the SHA-1 for the given FileInterface using
295      * standard access
296      *
297      * @param f
298      * @return the byte array representing the SHA-1
299      * @throws IOException
300      */
301     public static byte[] getHashSha1(File f) throws IOException {
302         return getHash(f, false, DigestAlgo.SHA1);
303     }
304     
305     /**
306      * Internal function for No NIO InputStream support
307      * @param in
308      * @param algo
309      * @param buf
310      * @return the digest
311      * @throws IOException
312      */
313     private static byte[] getHashNoNio(InputStream in, DigestAlgo algo, byte[] buf) throws IOException {
314      // Not NIO
315         Checksum checksum = null;
316         int size = 0;
317         switch (algo) {
318             case ADLER32:
319                 checksum = new Adler32();
320             case CRC32:
321                 if (checksum == null) { // not ADLER32
322                     checksum = new CRC32();
323                 }
324                 while ((size = in.read(buf)) >= 0) {
325                     checksum.update(buf, 0, size);
326                 }
327                 in.close();
328                 buf = null;
329                 buf = Long.toOctalString(checksum.getValue()).getBytes();
330                 checksum = null;                        
331                 break;
332             case MD5:
333             case MD2:
334             case SHA1:
335             case SHA256:
336             case SHA384:
337             case SHA512:
338                 String algoname = algo.name;
339                 MessageDigest digest = null;
340                 try {
341                     digest = MessageDigest.getInstance(algoname);
342                 } catch (NoSuchAlgorithmException e) {
343                     throw new IOException(algo +
344                             " Algorithm not supported by this JVM", e);
345                 }
346                 while ((size = in.read(buf)) >= 0) {
347                     digest.update(buf, 0, size);
348                 }
349                 in.close();
350                 buf = null;
351                 buf = digest.digest();
352                 digest = null;                
353                 break;
354             default:
355                 throw new IOException(algo.name +
356                         " Algorithm not supported by this JVM");
357         }
358         return buf;
359     }
360     
361     /**
362      * Get the Digest for the file using the specified algorithm using access through NIO or not 
363      * @param f
364      * @param nio
365      * @param algo
366      * @return the digest
367      * @throws IOException
368      */
369     public static byte[] getHash(File f, boolean nio, DigestAlgo algo) throws IOException {
370         if (!f.exists()) {
371             throw new FileNotFoundException(f.toString());
372         }
373         if (algo == DigestAlgo.MD5 && useFastMd5) {
374             if (nio) {
375                 return MD5.getHashNio(f);
376             } else {
377                 return MD5.getHash(f);
378             }
379         }
380         InputStream close_me = null;
381         try {
382             long buf_size = f.length();
383             if (buf_size < 512) {
384                 buf_size = 512;
385             }
386             if (buf_size > 65536) {
387                 buf_size = 65536;
388             }
389             byte[] buf = new byte[(int) buf_size];
390             FileInputStream in = new FileInputStream(f);
391             close_me = in;
392             if (nio) { // NIO
393                 FileChannel fileChannel = in.getChannel();
394                 ByteBuffer bb = ByteBuffer.wrap(buf);
395                 Checksum checksum = null;
396                 int size = 0;
397                 switch (algo) {
398                     case ADLER32:
399                         checksum = new Adler32();
400                     case CRC32:
401                         if (checksum == null) { // Not ADLER32
402                             checksum = new CRC32();
403                         }
404                         while ((size = fileChannel.read(bb)) >= 0) {
405                             checksum.update(buf, 0, size);
406                             bb.clear();
407                         }
408                         fileChannel.close();
409                         fileChannel = null;
410                         bb = null;
411                         buf = Long.toOctalString(checksum.getValue()).getBytes();
412                         checksum = null;                        
413                         break;
414                     case MD5:
415                     case MD2:
416                     case SHA1:
417                     case SHA256:
418                     case SHA384:
419                     case SHA512:
420                         String algoname = algo.name;
421                         MessageDigest digest = null;
422                         try {
423                             digest = MessageDigest.getInstance(algoname);
424                         } catch (NoSuchAlgorithmException e) {
425                             throw new IOException(algo +
426                                     " Algorithm not supported by this JVM", e);
427                         }
428                         while ((size = fileChannel.read(bb)) >= 0) {
429                             digest.update(buf, 0, size);
430                             bb.clear();
431                         }
432                         fileChannel.close();
433                         fileChannel = null;
434                         bb = null;
435                         buf = digest.digest();
436                         digest = null;                        
437                         break;
438                     default:
439                         throw new IOException(algo.name +
440                                 " Algorithm not supported by this JVM");
441                 }
442             } else { // Not NIO
443                 buf = getHashNoNio(in, algo, buf);
444                 in = null;
445                 close_me = null;
446                 return buf;
447             }
448             in = null;
449             close_me = null;
450             return buf;
451         } catch (IOException e) {
452             if (close_me != null) {
453                 try {
454                     close_me.close();
455                 } catch (Exception e2) {
456                 }
457             }
458             throw e;
459         }        
460     }
461     /**
462      * Get the Digest for the file using the specified algorithm using access through NIO or not 
463      * @param stream
464      * @param algo
465      * @return the digest
466      * @throws IOException
467      */
468     public static byte[] getHash(InputStream stream, DigestAlgo algo) throws IOException {
469         if (stream == null) {
470             throw new FileNotFoundException();
471         }
472         if (algo == DigestAlgo.MD5 && useFastMd5) {
473             return MD5.getHash(stream);
474         }
475         try {
476             long buf_size = 65536;
477             byte[] buf = new byte[(int) buf_size];
478             // Not NIO
479             buf = getHashNoNio(stream, algo, buf);
480             return buf;
481         } catch (IOException e) {
482             if (stream != null) {
483                 try {
484                     stream.close();
485                 } catch (Exception e2) {
486                 }
487             }
488             throw e;
489         }        
490     }
491 
492     /**
493      * Get hash with given {@link ChannelBuffer} (from Netty)
494      * 
495      * @param buffer this buffer will not be changed
496      * @param algo
497      * @return the hash
498      * @throws IOException 
499      */
500     public static byte[] getHash(ChannelBuffer buffer, DigestAlgo algo) throws IOException {
501         Checksum checksum = null;
502         byte[] bytes = null;
503         int start = 0;
504         int length = buffer.readableBytes();
505         if (buffer.hasArray()) {
506             start = buffer.arrayOffset();
507             bytes = buffer.array();
508             if (bytes.length > start+length) {
509                 byte[] temp = new byte[length];
510                 System.arraycopy(bytes, start, temp, 0, length);
511                 start = 0;
512                 bytes = temp;
513             }
514         } else {
515             bytes = new byte[length];
516             buffer.getBytes(buffer.readerIndex(), bytes);
517         }
518         switch (algo) {
519             case ADLER32:
520                 checksum = new Adler32();
521             case CRC32:
522                 if (checksum == null) { // not ADLER32
523                     checksum = new CRC32();
524                 }
525                 checksum.update(bytes, start, length);
526                 bytes = null;
527                 bytes = Long.toOctalString(checksum.getValue()).getBytes();
528                 checksum = null;
529                 return bytes;
530             case MD5:
531                 if (useFastMd5) {
532                     MD5 md5 = new MD5();
533                     md5.Update(bytes, start, length);
534                     bytes = md5.Final();
535                     md5 = null;
536                     return bytes;
537                 }
538             case MD2:
539             case SHA1:
540             case SHA256:
541             case SHA384:
542             case SHA512:
543                 String algoname = algo.name;
544                 MessageDigest digest = null;
545                 try {
546                     digest = MessageDigest.getInstance(algoname);
547                 } catch (NoSuchAlgorithmException e) {
548                     throw new IOException(algoname +
549                             " Algorithm not supported by this JVM", e);
550                 }
551                 digest.update(bytes, start, length);
552                 bytes = digest.digest();
553                 digest = null;
554                 return bytes;
555             default:
556                 throw new IOException(algo.name +
557                         " Algorithm not supported by this JVM");            
558         }
559     }
560     /**
561      * Get hash with given {@link ChannelBuffer} (from Netty)
562      *
563      * @param buffer
564      *            ChannelBuffer to use to get the hash and 
565      *            this buffer will not be changed
566      * @return the hash
567      */
568     public static byte[] getHashMd5(ChannelBuffer buffer) {
569         try {
570             return getHash(buffer, DigestAlgo.MD5);
571         } catch (IOException e) {
572             MD5 md5 = new MD5();
573             md5.Update(buffer);
574             byte [] bytes = md5.Final();
575             md5 = null;
576             return bytes;
577         }
578     }
579 
580     /**
581      * Internal representation of Hexadecimal Code
582      */
583     private static final char[] HEX_CHARS = {
584             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c',
585             'd', 'e', 'f', };
586 
587     /**
588      * Get the hexadecimal representation as a String of the array of bytes
589      *
590      * @param hash
591      * @return the hexadecimal representation as a String of the array of bytes
592      */
593     public static final String getHex(byte[] hash) {
594         char buf[] = new char[hash.length * 2];
595         for (int i = 0, x = 0; i < hash.length; i ++) {
596             buf[x ++] = HEX_CHARS[hash[i] >>> 4 & 0xf];
597             buf[x ++] = HEX_CHARS[hash[i] & 0xf];
598         }
599         return new String(buf);
600     }
601 
602     /**
603      * Get the array of bytes representation of the hexadecimal String
604      *
605      * @param hex
606      * @return the array of bytes representation of the hexadecimal String
607      */
608     public static final byte[] getFromHex(String hex) {
609         byte from[] = hex.getBytes();
610         byte hash[] = new byte[from.length / 2];
611         for (int i = 0, x = 0; i < hash.length; i ++) {
612             byte code1 = from[x ++];
613             byte code2 = from[x ++];
614             if (code1 >= HEX_CHARS[10]) {
615                 code1 -= HEX_CHARS[10] - 10;
616             } else {
617                 code1 -= HEX_CHARS[0];
618             }
619             if (code2 >= HEX_CHARS[10]) {
620                 code2 -= HEX_CHARS[10] - 10;
621             } else {
622                 code2 -= HEX_CHARS[0];
623             }
624             hash[i] = (byte) ((code1 << 4) + code2);
625         }
626         return hash;
627     }
628 
629     private static byte[] salt = {'G','o','l','d','e','n','G','a','t','e'};
630     /**
631      * Crypt a password
632      * @param pwd to crypt
633      * @return the crypted password
634      * @throws IOException 
635      */
636     public static final String passwdCrypt(String pwd) {
637         if (useFastMd5) {
638             return MD5.passwdCrypt(pwd);
639         }
640         MessageDigest digest = null;
641         try {
642             digest = MessageDigest.getInstance(DigestAlgo.MD5.name);
643         } catch (NoSuchAlgorithmException e) {
644             return MD5.passwdCrypt(pwd);
645         }
646         byte [] bpwd = pwd.getBytes();
647         for (int i = 0; i < 16; i++) {
648             digest.update(bpwd, 0, bpwd.length);
649             digest.update(salt, 0, salt.length);
650         }
651         byte []buf = digest.digest();
652         digest = null;
653         return getHex(buf);
654     }
655     /**
656      * Crypt a password 
657      * @param pwd to crypt
658      * @return the crypted password
659      * @throws IOException 
660      */
661     public static final byte[] passwdCrypt(byte[] pwd) {
662         if (useFastMd5) {
663             return MD5.passwdCrypt(pwd);
664         }
665         MessageDigest digest = null;
666         try {
667             digest = MessageDigest.getInstance(DigestAlgo.MD5.name);
668         } catch (NoSuchAlgorithmException e) {
669             return MD5.passwdCrypt(pwd);
670         }
671         for (int i = 0; i < 16; i++) {
672             digest.update(pwd, 0, pwd.length);
673             digest.update(salt, 0, salt.length);
674         }
675         byte []buf = digest.digest();
676         digest = null;
677         return buf;
678     }
679     /**
680      * 
681      * @param pwd
682      * @param cryptPwd
683      * @return True if the pwd is comparable with the cryptPwd
684      * @throws IOException 
685      */
686     public static final boolean equalPasswd(String pwd, String cryptPwd) {
687         String asHex;
688         asHex = passwdCrypt(pwd);
689         return cryptPwd.equals(asHex);
690     }
691     /**
692      * 
693      * @param pwd
694      * @param cryptPwd
695      * @return True if the pwd is comparable with the cryptPwd
696      */
697     public static final boolean equalPasswd(byte[] pwd, byte[] cryptPwd) {
698         byte[] bytes;
699         bytes = passwdCrypt(pwd);
700         return Arrays.equals(cryptPwd, bytes);
701     }
702     /**
703      * Test function
704      *
705      * @param argv
706      *            with 2 arguments as filename to hash and full path to the
707      *            Native Library
708      * @throws IOException 
709      */
710     public static void main(String argv[]) throws IOException {
711         if (argv.length < 1) {
712             useFastMd5 = false;
713             initializeMd5(false, null);
714             long start = System.currentTimeMillis();
715             for (int i = 0; i < 1000000; i++) {
716                 passwdCrypt("Ceci est mon password!");
717             }
718             System.err.println("Final passwd crypted in "+(System.currentTimeMillis() - start)+"ms is: "+passwdCrypt("Ceci est mon password!"));
719             System.err
720                     .println("Not enough argument: <full path to the filename to hash> ");
721             return;
722         }
723         //initializeMd5(true, "D:/NEWJARS/goldengate/lib/arch/win32_x86/MD5.dll");
724         initializeMd5(true, null);
725         File file = new File(argv[0]);
726         System.out.println("FileInterface: " + file.getAbsolutePath());
727         byte[] bmd5;
728         // one time for nothing
729         useFastMd5 = false;
730         long start = System.currentTimeMillis();
731         try {
732             bmd5 = getHashMd5Nio(file);
733         } catch (IOException e1) {
734             System.err
735                     .println("Cannot compute " + DigestAlgo.MD5.name + " for " + argv[1]);
736             return;
737         }
738         long end = System.currentTimeMillis();
739         try {
740             Thread.sleep(6000);
741         } catch (InterruptedException e) {
742         }
743         System.out.println("Start testing");
744 
745         // JVM Nio MD5
746         start = System.currentTimeMillis();
747         for (int i = 0; i < 100; i ++) {
748             try {
749                 bmd5 = getHashMd5Nio(file);
750             } catch (IOException e1) {
751                 System.err.println("Cannot compute " + DigestAlgo.MD5.name + " for " +
752                         argv[1]);
753                 return;
754             }
755         }
756         end = System.currentTimeMillis();
757         System.out.println("Algo Nio JVM " + DigestAlgo.MD5.name + " is " + getHex(bmd5) +
758                 "("+bmd5.length+")"+
759                 " in " + (end - start) + " ms");
760         // Fast Nio MD5
761         useFastMd5 = true;
762         start = System.currentTimeMillis();
763         for (int i = 0; i < 100; i ++) {
764             try {
765                 bmd5 = getHashMd5Nio(file);
766             } catch (IOException e1) {
767                 System.err.println("Cannot compute " + DigestAlgo.MD5.name + " for " +
768                         argv[1]);
769                 return;
770             }
771         }
772         end = System.currentTimeMillis();
773         System.out.println("Algo Nio Fast " + DigestAlgo.MD5.name + " is " + getHex(bmd5) +
774                 "("+bmd5.length+")"+
775                 " in " + (end - start) + " ms");
776 
777         // JVM MD5
778         useFastMd5 = false;
779         start = System.currentTimeMillis();
780         for (int i = 0; i < 100; i ++) {
781             try {
782                 bmd5 = getHashMd5(file);
783             } catch (IOException e1) {
784                 System.err.println("Cannot compute " + DigestAlgo.MD5.name + " for " +
785                         argv[1]);
786                 return;
787             }
788         }
789         end = System.currentTimeMillis();
790         System.out.println("Algo JVM " + DigestAlgo.MD5.name + " is " + getHex(bmd5) +
791                 "("+bmd5.length+")"+
792                 " in " + (end - start) + " ms");
793         // Fast MD5
794         useFastMd5 = true;
795         start = System.currentTimeMillis();
796         for (int i = 0; i < 100; i ++) {
797             try {
798                 bmd5 = getHashMd5(file);
799             } catch (IOException e1) {
800                 System.err.println("Cannot compute " + DigestAlgo.MD5.name + " for " +
801                         argv[1]);
802                 return;
803             }
804         }
805         end = System.currentTimeMillis();
806         System.out.println("Algo Fast " + DigestAlgo.MD5.name + " is " + getHex(bmd5) +
807                 "("+bmd5.length+")"+
808                 " in " + (end - start) + " ms");
809 
810         // JVM Nio SHA1
811         start = System.currentTimeMillis();
812         for (int i = 0; i < 100; i ++) {
813             try {
814                 bmd5 = getHashSha1Nio(file);
815             } catch (IOException e1) {
816                 System.err.println("Cannot compute " + DigestAlgo.SHA1.name + " for " +
817                         argv[1]);
818                 return;
819             }
820         }
821         end = System.currentTimeMillis();
822         System.out.println("Algo Nio JVM " + DigestAlgo.SHA1.name + " is " + getHex(bmd5) +
823                 "("+bmd5.length+")"+
824                 " in " + (end - start) + " ms");
825         // JVM SHA1
826         start = System.currentTimeMillis();
827         for (int i = 0; i < 100; i ++) {
828             try {
829                 bmd5 = getHashSha1(file);
830             } catch (IOException e1) {
831                 System.err.println("Cannot compute " + DigestAlgo.SHA1.name + " for " +
832                         argv[1]);
833                 return;
834             }
835         }
836         end = System.currentTimeMillis();
837         System.out.println("Algo JVM " + DigestAlgo.SHA1.name + " is " + getHex(bmd5) +
838                 "("+bmd5.length+")"+
839                 " in " + (end - start) + " ms");
840         // JVM Nio SHA256
841         start = System.currentTimeMillis();
842         for (int i = 0; i < 100; i ++) {
843             try {
844                 bmd5 = getHash(file,true,DigestAlgo.SHA256);
845             } catch (IOException e1) {
846                 System.err.println("Cannot compute " + DigestAlgo.SHA256.name + " for " +
847                         argv[1]);
848                 return;
849             }
850         }
851         end = System.currentTimeMillis();
852         System.out.println("Algo Nio JVM " + DigestAlgo.SHA256.name + " is " + getHex(bmd5) +
853                 "("+bmd5.length+")"+
854                 " in " + (end - start) + " ms");
855         // JVM SHA256
856         start = System.currentTimeMillis();
857         for (int i = 0; i < 100; i ++) {
858             try {
859                 bmd5 = getHash(file,false,DigestAlgo.SHA256);
860             } catch (IOException e1) {
861                 System.err.println("Cannot compute " + DigestAlgo.SHA256.name + " for " +
862                         argv[1]);
863                 return;
864             }
865         }
866         end = System.currentTimeMillis();
867         System.out.println("Algo JVM " + DigestAlgo.SHA256.name + " is " + getHex(bmd5) +
868                 "("+bmd5.length+")"+
869                 " in " + (end - start) + " ms");
870         // JVM Nio SHA512
871         start = System.currentTimeMillis();
872         for (int i = 0; i < 100; i ++) {
873             try {
874                 bmd5 = getHash(file,true,DigestAlgo.SHA512);
875             } catch (IOException e1) {
876                 System.err.println("Cannot compute " + DigestAlgo.SHA512.name + " for " +
877                         argv[1]);
878                 return;
879             }
880         }
881         end = System.currentTimeMillis();
882         System.out.println("Algo Nio JVM " + DigestAlgo.SHA512.name + " is " + getHex(bmd5) +
883                 "("+bmd5.length+")"+
884                 " in " + (end - start) + " ms");
885         // JVM SHA512
886         start = System.currentTimeMillis();
887         for (int i = 0; i < 100; i ++) {
888             try {
889                 bmd5 = getHash(file,false,DigestAlgo.SHA512);
890             } catch (IOException e1) {
891                 System.err.println("Cannot compute " + DigestAlgo.SHA512.name + " for " +
892                         argv[1]);
893                 return;
894             }
895         }
896         end = System.currentTimeMillis();
897         System.out.println("Algo JVM " + DigestAlgo.SHA512.name + " is " + getHex(bmd5) +
898                 "("+bmd5.length+")"+
899                 " in " + (end - start) + " ms");
900         // JVM Nio CRC32
901         start = System.currentTimeMillis();
902         for (int i = 0; i < 100; i ++) {
903             try {
904                 bmd5 = getHash(file,true,DigestAlgo.CRC32);
905             } catch (IOException e1) {
906                 System.err.println("Cannot compute " + DigestAlgo.CRC32.name + " for " +
907                         argv[1]);
908                 return;
909             }
910         }
911         end = System.currentTimeMillis();
912         System.out.println("Algo Nio JVM " + DigestAlgo.CRC32.name + " is " + getHex(bmd5) +
913                 "("+bmd5.length+")"+
914                 " in " + (end - start) + " ms");
915         // JVM CRC32
916         start = System.currentTimeMillis();
917         for (int i = 0; i < 100; i ++) {
918             try {
919                 bmd5 = getHash(file,false,DigestAlgo.CRC32);
920             } catch (IOException e1) {
921                 System.err.println("Cannot compute " + DigestAlgo.CRC32.name + " for " +
922                         argv[1]);
923                 return;
924             }
925         }
926         end = System.currentTimeMillis();
927         System.out.println("Algo JVM " + DigestAlgo.CRC32.name + " is " + getHex(bmd5) +
928                 "("+bmd5.length+")"+
929                 " in " + (end - start) + " ms");
930         // JVM Nio ADLER
931         start = System.currentTimeMillis();
932         for (int i = 0; i < 100; i ++) {
933             try {
934                 bmd5 = getHash(file,true,DigestAlgo.ADLER32);
935             } catch (IOException e1) {
936                 System.err.println("Cannot compute " + DigestAlgo.ADLER32.name + " for " +
937                         argv[1]);
938                 return;
939             }
940         }
941         end = System.currentTimeMillis();
942         System.out.println("Algo Nio JVM " + DigestAlgo.ADLER32.name + " is " + getHex(bmd5) +
943                 "("+bmd5.length+")"+
944                 " in " + (end - start) + " ms");
945         // JVM ADLER
946         start = System.currentTimeMillis();
947         for (int i = 0; i < 100; i ++) {
948             try {
949                 bmd5 = getHash(file,false,DigestAlgo.ADLER32);
950             } catch (IOException e1) {
951                 System.err.println("Cannot compute " + DigestAlgo.ADLER32.name + " for " +
952                         argv[1]);
953                 return;
954             }
955         }
956         end = System.currentTimeMillis();
957         System.out.println("Algo JVM " + DigestAlgo.ADLER32.name + " is " + getHex(bmd5) +
958                 "("+bmd5.length+")"+
959                 " in " + (end - start) + " ms");
960         // JVM MD2
961         start = System.currentTimeMillis();
962         for (int i = 0; i < 100; i ++) {
963             try {
964                 bmd5 = getHash(file,false,DigestAlgo.MD2);
965             } catch (IOException e1) {
966                 System.err.println("Cannot compute " + DigestAlgo.MD2.name + " for " +
967                         argv[1]);
968                 return;
969             }
970         }
971         end = System.currentTimeMillis();
972         System.out.println("Algo JVM " + DigestAlgo.MD2.name + " is " + getHex(bmd5) +
973                 "("+bmd5.length+")"+
974                 " in " + (end - start) + " ms");
975         // JVM SHA-384
976         start = System.currentTimeMillis();
977         for (int i = 0; i < 100; i ++) {
978             try {
979                 bmd5 = getHash(file,false,DigestAlgo.SHA384);
980             } catch (IOException e1) {
981                 System.err.println("Cannot compute " + DigestAlgo.SHA384.name + " for " +
982                         argv[1]);
983                 return;
984             }
985         }
986         end = System.currentTimeMillis();
987         System.out.println("Algo JVM " + DigestAlgo.SHA384.name + " is " + getHex(bmd5) +
988                 "("+bmd5.length+")"+
989                 " in " + (end - start) + " ms");
990     }
991 
992 }