001package co.codewizards.cloudstore.core.util; 002 003import java.io.ByteArrayInputStream; 004import java.io.IOException; 005import java.io.InputStream; 006import java.security.MessageDigest; 007import java.security.NoSuchAlgorithmException; 008import java.util.Locale; 009 010import co.codewizards.cloudstore.core.progress.NullProgressMonitor; 011import co.codewizards.cloudstore.core.progress.ProgressMonitor; 012 013public final class HashUtil { 014 015 /** 016 * Specifies usage of the MD5 algorithm in {@link #hash(String, InputStream)}. 017 */ 018 public static final String HASH_ALGORITHM_MD5 = "MD5"; 019 /** 020 * Specifies usage of the SHA algorithm in {@link #hash(String, InputStream)}. 021 */ 022 public static final String HASH_ALGORITHM_SHA = "SHA"; 023 024 private HashUtil() { } 025 026 public static String encodeHexStr(byte[] buf) 027 { 028 return encodeHexStr(buf, 0, buf.length); 029 } 030 031 /** 032 * Encode a byte array into a human readable hex string. For each byte, 033 * two hex digits are produced. They are concatenated without any separators. 034 * 035 * @param buf The byte array to translate into human readable text. 036 * @param pos The start position (0-based). 037 * @param len The number of bytes that shall be processed beginning at the position specified by <code>pos</code>. 038 * @return a human readable string like "fa3d70" for a byte array with 3 bytes and these values. 039 * @see #encodeHexStr(byte[]) 040 * @see #decodeHexStr(String) 041 */ 042 public static String encodeHexStr(byte[] buf, int pos, int len) 043 { 044 StringBuilder hex = new StringBuilder(); 045 while (len-- > 0) { 046 byte ch = buf[pos++]; 047 int d = (ch >> 4) & 0xf; 048 hex.append((char)(d >= 10 ? 'a' - 10 + d : '0' + d)); 049 d = ch & 0xf; 050 hex.append((char)(d >= 10 ? 'a' - 10 + d : '0' + d)); 051 } 052 return hex.toString(); 053 } 054 055 /** 056 * Decode a string containing two hex digits for each byte. 057 * @param hex The hex encoded string 058 * @return The byte array represented by the given hex string 059 * @see #encodeHexStr(byte[]) 060 * @see #encodeHexStr(byte[], int, int) 061 */ 062 public static byte[] decodeHexStr(String hex) 063 { 064 if (hex.length() % 2 != 0) 065 throw new IllegalArgumentException("The hex string must have an even number of characters!"); 066 067 byte[] res = new byte[hex.length() / 2]; 068 069 int m = 0; 070 for (int i = 0; i < hex.length(); i += 2) { 071 res[m++] = (byte) Integer.parseInt(hex.substring(i, i + 2), 16); 072 } 073 074 return res; 075 } 076 077 public static byte[] hash(String algorithm, InputStream in) throws NoSuchAlgorithmException, IOException { 078 return hash(algorithm, in, new NullProgressMonitor()); 079 } 080 081 public static byte[] hash(String algorithm, InputStream in, ProgressMonitor monitor) throws NoSuchAlgorithmException, IOException { 082 monitor.beginTask(algorithm, Math.max(1, in.available())); 083 try { 084 MessageDigest md = MessageDigest.getInstance(algorithm); 085 byte[] data = new byte[10240]; 086 while (true) { 087 int bytesRead = in.read(data, 0, data.length); 088 if (bytesRead < 0) { 089 break; 090 } 091 if (bytesRead > 0) { 092 md.update(data, 0, bytesRead); 093 monitor.worked(bytesRead); 094 } 095 } 096 return md.digest(); 097 } finally { 098 monitor.done(); 099 } 100 } 101 102 public static String formatEncodedHexStrForHuman(String hex) { 103 if (hex.length() % 2 != 0) 104 throw new IllegalArgumentException("The hex string must have an even number of characters!"); 105 106 hex = hex.toUpperCase(Locale.UK); 107 108 StringBuilder sb = new StringBuilder(hex.length() * 3 / 2); 109 for (int i = 0; i < hex.length(); i += 2) { 110 if (sb.length() > 0) 111 sb.append(':'); 112 113 sb.append(hex.substring(i, i + 2)); 114 } 115 return sb.toString(); 116 } 117 118 public static String sha1ForHuman(byte[] in) { 119 try { 120 return sha1ForHuman(new ByteArrayInputStream(in)); 121 } catch (IOException x) { 122 throw new RuntimeException(x); 123 } 124 } 125 126 public static String sha1ForHuman(InputStream in) throws IOException { 127 return formatEncodedHexStrForHuman(sha1(in)); 128 } 129 130 public static String sha1(String in) { 131 return sha1(in.getBytes(IOUtil.CHARSET_UTF_8)); 132 } 133 134 public static String sha1(byte[] in) { 135 try { 136 return sha1(new ByteArrayInputStream(in)); 137 } catch (IOException x) { 138 throw new RuntimeException(x); 139 } 140 } 141 142 public static String sha1(InputStream in) throws IOException { 143 byte[] hash; 144 try { 145 hash = hash(HASH_ALGORITHM_SHA, in); 146 } catch (NoSuchAlgorithmException e) { 147 throw new RuntimeException(e); 148 } 149 return encodeHexStr(hash); 150 } 151 152}