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      public static byte[] getChecksum(String algorithm, File file) throws NoSuchAlgorithmException, IOException {
61          final MessageDigest digest = MessageDigest.getInstance(algorithm);
62          FileInputStream fis = null;
63          try {
64              fis = new FileInputStream(file);
65              final FileChannel ch = fis.getChannel();
66              long remainingToRead = file.length();
67              long start = 0;
68              while (remainingToRead > 0) {
69                  long amountToRead;
70                  if (remainingToRead > Integer.MAX_VALUE) {
71                      remainingToRead -= Integer.MAX_VALUE;
72                      amountToRead = Integer.MAX_VALUE;
73                  } else {
74                      amountToRead = remainingToRead;
75                      remainingToRead = 0;
76                  }
77                  final MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, start, amountToRead);
78                  digest.update(byteBuffer);
79                  start += amountToRead;
80              }
81          } finally {
82              if (fis != null) {
83                  try {
84                      fis.close();
85                  } catch (IOException ex) {
86                      LOGGER.trace("Error closing file '{}'.", file.getName(), ex);
87                  }
88              }
89          }
90          return digest.digest();
91      }
92  
93      /**
94       * Calculates the MD5 checksum of a specified file.
95       *
96       * @param file the file to generate the MD5 checksum
97       * @return the hex representation of the MD5 hash
98       * @throws IOException when the file passed in does not exist
99       * @throws NoSuchAlgorithmException when the MD5 algorithm is not available
100      */
101     public static String getMD5Checksum(File file) throws IOException, NoSuchAlgorithmException {
102         final byte[] b = getChecksum("MD5", file);
103         return getHex(b);
104     }
105 
106     /**
107      * Calculates the SHA1 checksum of a specified file.
108      *
109      * @param file the file to generate the MD5 checksum
110      * @return the hex representation of the SHA1 hash
111      * @throws IOException when the file passed in does not exist
112      * @throws NoSuchAlgorithmException when the SHA1 algorithm is not available
113      */
114     public static String getSHA1Checksum(File file) throws IOException, NoSuchAlgorithmException {
115         final byte[] b = getChecksum("SHA1", file);
116         return getHex(b);
117     }
118     /**
119      * Hex code characters used in getHex.
120      */
121     private static final String HEXES = "0123456789abcdef";
122 
123     /**
124      * <p>
125      * Converts a byte array into a hex string.</p>
126      *
127      * <p>
128      * This method was copied from <a
129      * href="http://www.rgagnon.com/javadetails/java-0596.html">http://www.rgagnon.com/javadetails/java-0596.html</a></p>
130      *
131      * @param raw a byte array
132      * @return the hex representation of the byte array
133      */
134     public static String getHex(byte[] raw) {
135         if (raw == null) {
136             return null;
137         }
138         final StringBuilder hex = new StringBuilder(2 * raw.length);
139         for (final byte b : raw) {
140             hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt(b & 0x0F));
141         }
142         return hex.toString();
143     }
144 }