001 /* 002 * JBoss DNA (http://www.jboss.org/dna) 003 * See the COPYRIGHT.txt file distributed with this work for information 004 * regarding copyright ownership. Some portions may be licensed 005 * to Red Hat, Inc. under one or more contributor license agreements. 006 * See the AUTHORS.txt file in the distribution for a full listing of 007 * individual contributors. 008 * 009 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA 010 * is licensed to you under the terms of the GNU Lesser General Public License as 011 * published by the Free Software Foundation; either version 2.1 of 012 * the License, or (at your option) any later version. 013 * 014 * JBoss DNA is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 017 * Lesser General Public License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this software; if not, write to the Free 021 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 022 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 023 */ 024 package org.jboss.dna.common.util; 025 026 import java.io.BufferedInputStream; 027 import java.io.File; 028 import java.io.FileInputStream; 029 import java.io.IOException; 030 import java.io.InputStream; 031 import java.security.MessageDigest; 032 import java.security.NoSuchAlgorithmException; 033 034 /** 035 * @author Randall Hauch 036 */ 037 public class SecureHash { 038 039 /** 040 * Commonly-used hashing algorithms. 041 */ 042 public enum Algorithm { 043 MD2("MD2", "The MD2 message digest algorithm as defined in RFC 1319"), 044 MD5("MD5", "The MD5 message digest algorithm as defined in RFC 1321"), 045 SHA_1("SHA-1", "The Secure Hash Algorithm, as defined in Secure Hash Standard, NIST FIPS 180-1"), 046 SHA_256( 047 "SHA-256", 048 "New hash algorithms for which the draft Federal Information Processing Standard 180-2, " 049 + "Secure Hash Standard (SHS) is now available. SHA-256 is a 256-bit hash function intended to provide 128 bits of " 050 + "security against collision attacks."), 051 SHA_384( 052 "SHA-384", 053 "New hash algorithms for which the draft Federal Information Processing Standard 180-2, " 054 + "Secure Hash Standard (SHS) is now available. A 384-bit hash may be obtained by truncating the SHA-512 output."), 055 SHA_512( 056 "SHA-512", 057 "New hash algorithms for which the draft Federal Information Processing Standard 180-2, " 058 + "Secure Hash Standard (SHS) is now available. SHA-512 is a 512-bit hash function intended to provide 256 bits of security."); 059 private String name; 060 private String description; 061 062 private Algorithm( String name, 063 String description ) { 064 this.name = name; 065 this.description = description; 066 } 067 068 public String digestName() { 069 return this.name; 070 } 071 072 public String description() { 073 return this.description; 074 } 075 076 @Override 077 public String toString() { 078 return digestName(); 079 } 080 } 081 082 /** 083 * Get the hash of the supplied content, using the supplied digest algorithm. 084 * 085 * @param algorithm the hashing function algorithm that should be used 086 * @param content the content to be hashed; may not be null 087 * @return the hash of the contents as a byte array 088 * @throws NoSuchAlgorithmException if the supplied algorithm could not be found 089 * @throws IllegalArgumentException if the algorithm is null 090 */ 091 public static byte[] getHash( Algorithm algorithm, 092 byte[] content ) throws NoSuchAlgorithmException { 093 CheckArg.isNotNull(algorithm, "algorithm"); 094 return getHash(algorithm.digestName(), content); 095 } 096 097 /** 098 * Get the hash of the supplied content, using the supplied digest algorithm. 099 * 100 * @param algorithm the hashing function algorithm that should be used 101 * @param file the file containing the content to be hashed; may not be null 102 * @return the hash of the contents as a byte array 103 * @throws NoSuchAlgorithmException if the supplied algorithm could not be found 104 * @throws IllegalArgumentException if the algorithm is null 105 * @throws IOException if there is an error reading the file 106 */ 107 public static byte[] getHash( Algorithm algorithm, 108 File file ) throws NoSuchAlgorithmException, IOException { 109 CheckArg.isNotNull(algorithm, "algorithm"); 110 return getHash(algorithm.digestName(), file); 111 } 112 113 /** 114 * Get the hash of the supplied content, using the supplied digest algorithm. 115 * 116 * @param algorithm the hashing function algorithm that should be used 117 * @param stream the stream containing the content to be hashed; may not be null 118 * @return the hash of the contents as a byte array 119 * @throws NoSuchAlgorithmException if the supplied algorithm could not be found 120 * @throws IllegalArgumentException if the algorithm is null 121 * @throws IOException if there is an error reading the stream 122 */ 123 public static byte[] getHash( Algorithm algorithm, 124 InputStream stream ) throws NoSuchAlgorithmException, IOException { 125 CheckArg.isNotNull(algorithm, "algorithm"); 126 return getHash(algorithm.digestName(), stream); 127 } 128 129 /** 130 * Get the hash of the supplied content, using the digest identified by the supplied name. 131 * 132 * @param digestName the name of the hashing function (or {@link MessageDigest message digest}) that should be used 133 * @param content the content to be hashed; may not be null 134 * @return the hash of the contents as a byte array 135 * @throws NoSuchAlgorithmException if the supplied algorithm could not be found 136 */ 137 public static byte[] getHash( String digestName, 138 byte[] content ) throws NoSuchAlgorithmException { 139 MessageDigest digest = MessageDigest.getInstance(digestName); 140 assert digest != null; 141 return digest.digest(content); 142 } 143 144 /** 145 * Get the hash of the supplied content, using the digest identified by the supplied name. 146 * 147 * @param digestName the name of the hashing function (or {@link MessageDigest message digest}) that should be used 148 * @param file the file whose content is to be hashed; may not be null 149 * @return the hash of the contents as a byte array 150 * @throws NoSuchAlgorithmException if the supplied algorithm could not be found 151 * @throws IOException if there is an error reading the file 152 */ 153 public static byte[] getHash( String digestName, 154 File file ) throws NoSuchAlgorithmException, IOException { 155 CheckArg.isNotNull(file, "file"); 156 MessageDigest digest = MessageDigest.getInstance(digestName); 157 assert digest != null; 158 InputStream in = new BufferedInputStream(new FileInputStream(file)); 159 boolean error = false; 160 try { 161 int bufSize = 1024; 162 byte[] buffer = new byte[bufSize]; 163 int n = in.read(buffer, 0, bufSize); 164 int count = 0; 165 while (n != -1) { 166 count += n; 167 digest.update(buffer, 0, n); 168 n = in.read(buffer, 0, bufSize); 169 } 170 } catch (IOException e) { 171 error = true; 172 throw e; 173 } finally { 174 try { 175 in.close(); 176 } catch (IOException e) { 177 if (!error) throw e; 178 } 179 } 180 return digest.digest(); 181 } 182 183 /** 184 * Get the hash of the supplied content, using the digest identified by the supplied name. Note that this method never closes 185 * the supplied stream. 186 * 187 * @param digestName the name of the hashing function (or {@link MessageDigest message digest}) that should be used 188 * @param stream the stream containing the content to be hashed; may not be null 189 * @return the hash of the contents as a byte array 190 * @throws NoSuchAlgorithmException if the supplied algorithm could not be found 191 * @throws IOException if there is an error reading the stream 192 */ 193 public static byte[] getHash( String digestName, 194 InputStream stream ) throws NoSuchAlgorithmException, IOException { 195 CheckArg.isNotNull(stream, "stream"); 196 MessageDigest digest = MessageDigest.getInstance(digestName); 197 assert digest != null; 198 int bufSize = 1024; 199 byte[] buffer = new byte[bufSize]; 200 int n = stream.read(buffer, 0, bufSize); 201 int count = 0; 202 while (n != -1) { 203 count += n; 204 digest.update(buffer, 0, n); 205 n = stream.read(buffer, 0, bufSize); 206 } 207 return digest.digest(); 208 } 209 }