View Javadoc
1   /*
2    * This file is part of dependency-check-core.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Copyright (c) 2014 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.utils;
19  
20  import org.slf4j.Logger;
21  import org.slf4j.LoggerFactory;
22  
23  import java.io.File;
24  import java.io.FileInputStream;
25  import java.io.IOException;
26  import java.nio.MappedByteBuffer;
27  import java.nio.channels.FileChannel;
28  import java.security.MessageDigest;
29  import java.security.NoSuchAlgorithmException;
30  
31  /**
32   * Includes methods to generate the MD5 and SHA1 checksum.
33   *
34   * @author Jeremy Long
35   *
36   */
37  public final class Checksum {
38  
39      /**
40       * The logger.
41       */
42      private static final Logger LOGGER = LoggerFactory.getLogger(Checksum.class);
43  
44      /**
45       * Private constructor for a utility class.
46       */
47      private Checksum() {
48      }
49  
50      /**
51       * <p>
52       * Creates the cryptographic checksum of a given file using the specified algorithm.</p>
53       *
54       * @param algorithm the algorithm to use to calculate the checksum
55       * @param file the file to calculate the checksum for
56       * @return the checksum
57       * @throws IOException when the file does not exist
58       * @throws NoSuchAlgorithmException when an algorithm is specified that does not exist
59       */
60      @SuppressWarnings("empty-statement")
61      public static byte[] getChecksum(String algorithm, File file) throws NoSuchAlgorithmException, IOException {
62          MessageDigest digest = MessageDigest.getInstance(algorithm);
63          FileInputStream fis = null;
64          try {
65              fis = new FileInputStream(file);
66              FileChannel ch = fis.getChannel();
67              long remainingToRead = file.length();
68              long start = 0;
69              while (remainingToRead > 0) {
70                  long amountToRead;
71                  if (remainingToRead > Integer.MAX_VALUE) {
72                      remainingToRead -= Integer.MAX_VALUE;
73                      amountToRead = Integer.MAX_VALUE;
74                  } else {
75                      amountToRead = remainingToRead;
76                      remainingToRead = 0;
77                  }
78                  MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, start, amountToRead);
79                  digest.update(byteBuffer);
80                  start += amountToRead;
81              }
82  
83  //            BufferedInputStream bis = new BufferedInputStream(fis);
84  //            DigestInputStream dis = new DigestInputStream(bis, digest);
85  //            //yes, we are reading in a buffer for performance reasons - 1 byte at a time is SLOW
86  //            byte[] buffer = new byte[8192];
87  //            while (dis.read(buffer) != -1);
88          } finally {
89              if (fis != null) {
90                  try {
91                      fis.close();
92                  } catch (IOException ex) {
93                      LOGGER.trace("Error closing file '{}'.", file.getName(), ex);
94                  }
95              }
96          }
97          return digest.digest();
98      }
99  
100     /**
101      * Calculates the MD5 checksum of a specified file.
102      *
103      * @param file the file to generate the MD5 checksum
104      * @return the hex representation of the MD5 hash
105      * @throws IOException when the file passed in does not exist
106      * @throws NoSuchAlgorithmException when the MD5 algorithm is not available
107      */
108     public static String getMD5Checksum(File file) throws IOException, NoSuchAlgorithmException {
109         byte[] b = getChecksum("MD5", file);
110         return getHex(b);
111     }
112 
113     /**
114      * Calculates the SHA1 checksum of a specified file.
115      *
116      * @param file the file to generate the MD5 checksum
117      * @return the hex representation of the SHA1 hash
118      * @throws IOException when the file passed in does not exist
119      * @throws NoSuchAlgorithmException when the SHA1 algorithm is not available
120      */
121     public static String getSHA1Checksum(File file) throws IOException, NoSuchAlgorithmException {
122         byte[] b = getChecksum("SHA1", file);
123         return getHex(b);
124     }
125     /**
126      * Hex code characters used in getHex.
127      */
128     private static final String HEXES = "0123456789abcdef";
129 
130     /**
131      * <p>
132      * Converts a byte array into a hex string.</p>
133      *
134      * <p>
135      * This method was copied from <a
136      * href="http://www.rgagnon.com/javadetails/java-0596.html">http://www.rgagnon.com/javadetails/java-0596.html</a></p>
137      *
138      * @param raw a byte array
139      * @return the hex representation of the byte array
140      */
141     public static String getHex(byte[] raw) {
142         if (raw == null) {
143             return null;
144         }
145         final StringBuilder hex = new StringBuilder(2 * raw.length);
146         for (final byte b : raw) {
147             hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt(b & 0x0F));
148         }
149         return hex.toString();
150     }
151 }