/*
 * Written by Dawid Kurzyniec and released to the public domain, as explained
 * at http://creativecommons.org/licenses/publicdomain
 */

package edu.emory.mathcs.util.security;

import java.io.*;
import java.security.*;
import edu.emory.mathcs.util.io.RedirectingInputStream;
import edu.emory.mathcs.util.io.NullOutputStream;


/**
 * Utility methods to manipulate message digests.
 *
 * @see MessageDigest
 *
 * @author Dawid Kurzyniec
 * @version 1.0
 */

public class DigestUtils {

    private DigestUtils() {}

    /**
     * Returns an instance of SHA digest.
     * @return an instance of SHA digest
     */
    public static MessageDigest getSHADigest() {
        try {
            return MessageDigest.getInstance("SHA");
        }
        catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("SHA not supported");
        }
    }

    /**
     * Returns an instance of MD5 digest.
     * @return an instance of MD5 digest
     */
    public static MessageDigest getMD5Digest() {
        try {
            return MessageDigest.getInstance("MD5");
        }
        catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 not supported");
        }
    }

    /**
     * Wraps specified input stream into an digest stream that calculates
     * the SHA digest as it reads.
     *
     * @param is the input stream to wrap
     * @return wrapping digest input stream
     */
    public static DigestInputStream getSHADigestInputStream(InputStream is) {
        return new DigestInputStream(is, getSHADigest());
    }

    /**
     * Wraps specified input stream into an digest stream that calculates
     * the MD5 digest as it reads.
     *
     * @param is the input stream to wrap
     * @return wrapping digest input stream
     */
    public static DigestInputStream getMD5DigestInputStream(InputStream is) {
        return new DigestInputStream(is, getMD5Digest());
    }

    /**
     * Wraps specified output stream into an digest stream that calculates
     * the SHA digest as it writes.
     *
     * @param os the output stream to wrap
     * @return wrapping digest output stream
     */
    public static DigestOutputStream getSHADigestOutputStream(OutputStream os) {
        return new DigestOutputStream(os, getSHADigest());
    }

    /**
     * Wraps specified output stream into an digest stream that calculates
     * the MD5 digest as it writes.
     *
     * @param os the output stream to wrap
     * @return wrapping digest output stream
     */
    public static DigestOutputStream getMD5DigestOutputStream(OutputStream os) {
        return new DigestOutputStream(os, getMD5Digest());
    }

    public static byte[] calculateDigest(InputStream in, MessageDigest digest)
        throws IOException
    {
        new RedirectingInputStream(new DigestInputStream(in, digest), false, true).
            redirectAll(new NullOutputStream());
        return digest.digest();
    }

    public static byte[] calculateSHADigest(InputStream in) throws IOException {
        return calculateDigest(in, getSHADigest());
    }

    public static byte[] calculateMD5Digest(InputStream in) throws IOException {
        return calculateDigest(in, getMD5Digest());
    }
}
