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