// Copyright 2009 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.enterprise.connector.util; import com.google.common.base.Charsets; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.logging.Level; import java.util.logging.Logger; /** * An implementation of {@link ChecksumGenerator} that return * hexadecimal-encoded checksums using algorithms from * {@code java.security.MessageDigest}. * * @see java.security.MessageDigest * @since 2.8 */ public class BasicChecksumGenerator implements ChecksumGenerator { private static final Logger LOGGER = Logger.getLogger(BasicChecksumGenerator.class.getName()); /* Algorithms supported for MessageDigest. */ /** The MD2 message digest algorithm as defined in RFC 1319. */ public static final String MD2 = "MD2"; /** The MD5 message digest algorithm as defined in RFC 1321. */ public static final String MD5 = "MD5"; /** The Secure Hash Algorithm, as defined in NIST FIPS 180-1. */ public static final String SHA1 = "SHA-1"; /** * The Secure Hash Algorithm, as defined in NIST FIPS 180-2. * SHA-256 is a 256-bit hash function intended to provide 128 bits of * security against collision attacks. */ public static final String SHA256 = "SHA-256"; /** * The Secure Hash Algorithm, as defined in NIST FIPS 180-2. * A 384-bit hash may be obtained by truncating the SHA-512 output. */ public static final String SHA384 = "SHA-384"; /** * The Secure Hash Algorithm, as defined in NIST FIPS 180-2. * SHA-512 is a 512-bit hash function intended to provide 256 bits of * security. */ public static final String SHA512 = "SHA-512"; private static final int BUF_SIZE = 32768; private final String algorithm; /** * Constructs a {@code BasicChecksumGenerator} that uses the specified * message digest algorithm. The supported algorithms are: * {@link BasicChecksumGenerator#MD2 "MD2"}, * {@link BasicChecksumGenerator#MD5 "MD5"}, * {@link BasicChecksumGenerator#SHA1 "SHA-1"}, * {@link BasicChecksumGenerator#SHA256 "SHA-256"}, * {@link BasicChecksumGenerator#SHA384 "SHA-384"}, and * {@link BasicChecksumGenerator#SHA512 "SHA-512"} * * @param algorithm message digest algorithm */ public BasicChecksumGenerator(String algorithm) { this.algorithm = algorithm; } /** * Returns the message digest checksum as an unecoded array of bytes. * * @param in input stream to create a checksum for * @return a checksum for the bytes of {@code in} * @throws IOException */ byte[] getDigest(InputStream in) throws IOException { MessageDigest digest; try { digest = MessageDigest.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Failed to get a message digest for " + algorithm); } try { byte[] buf = new byte[BUF_SIZE]; int count = in.read(buf); while (count != -1) { digest.update(buf, 0, count); count = in.read(buf); } return digest.digest(); } finally { try { in.close(); } catch (Exception e) { LOGGER.log(Level.WARNING, "Failed to close InputStream", e); } } } /** * Returns a hexadecimal string representation of the message digest * checksum of the input stream. * * @param in input stream to create a checksum for * @return a checksum for the bytes of {@code in} * @throws IOException */ @Override public String getChecksum(InputStream in) throws IOException { return Base16.lowerCase().encode(getDigest(in)); } /** * Returns a hexadecimal string representation of the message digest * checksum of the input string. * * @param input a String to create a checksum for * @return a checksum for the bytes of {@code input} */ @Override public String getChecksum(String input) { try { return getChecksum( new ByteArrayInputStream(input.getBytes(Charsets.UTF_8))); } catch (IOException e) { throw new RuntimeException("IO exception reading a string!?", e); } } }