mangotiger.net.EncodedDigester.java Source code

Java tutorial

Introduction

Here is the source code for mangotiger.net.EncodedDigester.java

Source

package mangotiger.net;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * EncodedDigester is a thin wrapper around Sun Java's MessageDigest with particular convenience for those who want MD5
 * digests Base64Encoder encoded through US-ASCII string representation. These are the defaults and for those who want that, it
 * can be as simple as calling:
 *
 * public static String getEncodedDigest(String toDigest)
 *
 * Since we use defaults, the caller will not even need to worry about exception handling using this method.
 *
 * It is typical, however, to digest a pair of strings -- one known only to us and one known only to the outside party.
 * The former string is called "the secret" and this technique makes it very difficult for anyone to spoof the digested
 * strings. This is highly recommended for systems that store user passwords as digests, for example.
 *
 * In this case, it is recommended that you use:
 *
 * public static String getEncodedDigest(String[] toDigest)
 *
 * passing the secret and the outside party string as a String[]
 *
 * You can additionally select the encoding algorithm (for example, if you want "SHA") or the string byte encoding
 * (though, this will always return a Base64Encoder string anyway), but if you use these methods, exception handling becomes
 * your responsibility.
 */
public class EncodedDigester {
    private static final Log logger = LogFactory.getLog(EncodedDigester.class);

    /** Disallow instantiation -- it's all static */
    private EncodedDigester() {
        // Disallow instantiation -- it's all static
    }

    // default to MD5
    private static String algorithm = "MD5";
    // for xlating chars to bytes
    private static final String stringToBytesEncoding = "US-ASCII";

    /**
     * Utility Method for obtaining a BASE64 encoded MessageDigest while specifying the desired digest algorithm. Note
     * that the algorithm must be understood by Sun's MessageDigest -- we are but a conduit. <p>
     * @param toDigest           - string to digest
     * @param digestingAlgorithm - string of algorithm to use to digest
     * @return BASE64 encoded String of a MessageDigest digested by the specified algorithm
     * @throws java.security.NoSuchAlgorithmException
     *          - when the algorithm is unknown
     * @see MessageDigest
     */
    public static String getEncodedDigest(String toDigest, String digestingAlgorithm)
            throws java.security.NoSuchAlgorithmException {
        String[] toDigestArray = { toDigest };
        String digest = null;
        try {
            digest = getEncodedDigest(toDigestArray, digestingAlgorithm, stringToBytesEncoding);
        } catch (UnsupportedEncodingException e) {
            // we're using the defaults in this class, if we get exceptions, we should fix 'em in development
            logger.fatal("the default encoding is not supported: " + stringToBytesEncoding);
            throw new RuntimeException(e);
        }
        return digest;
    }

    /**
     * Utility Method for obtaining a BASE64 encoded MessageDigest via default algorithm (MD5).
     * @param toDigest - string to digest
     * @return BASE64 encoded String of a MessageDigest digested by the specified algorithm
     * @see MessageDigest
     */
    public static String getEncodedDigest(String toDigest) {
        String[] toDigestArray = { toDigest };
        String digest = null;
        try {
            digest = getEncodedDigest(toDigestArray, algorithm, stringToBytesEncoding);
        } catch (Exception e) {
            // we're using the defaults in this class, if we get exceptions, we should fix 'em in development
            logger.fatal("if the defaults don't work, it's really darned broken");
            throw new RuntimeException(e);
        }
        return digest;
    }

    /**
     * Utility Method for obtaining a BASE64 encoded MessageDigest via default algorithm (MD5).
     * @param toDigest - array of strings to digest together
     * @return BASE64 encoded String of a MessageDigest digested by the "MD5" algorithm
     * @see MessageDigest
     */
    public static String getEncodedDigest(String[] toDigest) {
        String digest = null;
        try {
            digest = getEncodedDigest(toDigest, algorithm, stringToBytesEncoding);
        } catch (Exception e) {
            // we're using the defaults in this class, if we get exceptions, we should fix 'em in development
            logger.fatal("if the defaults don't work, it's really darned broken");
            throw new RuntimeException(e);
        }
        return digest;
    }

    /**
     * Utility Method for obtaining a BASE64 encoded MessageDigest via specified algorithm.
     *
     * Added a check for null here.
     * @param toDigest    - array of strings to digest
     * @param anAlgorithm - digesting algorithm to use to perform the digest
     * @return BASE64 encoded String of a MessageDigest digested by the specified algorithm
     * @throws java.security.NoSuchAlgorithmException
     *                                      - when the algorithm is unknown
     * @throws UnsupportedEncodingException - when the string-to-byte encoding is not supported
     * @see MessageDigest
     */
    public static String getEncodedDigest(String[] toDigest, String anAlgorithm, String stringEncoding)
            throws java.security.NoSuchAlgorithmException, java.io.UnsupportedEncodingException {
        String digest = null;
        if (toDigest != null && toDigest.length > 0) {
            try {
                MessageDigest messageDigest = MessageDigest.getInstance(anAlgorithm);
                for (int i = 0; i < toDigest.length && toDigest[i] != null; i++) {
                    messageDigest.update(toDigest[i].getBytes(stringEncoding));
                }
                digest = encode(messageDigest.digest());
            } catch (java.security.NoSuchAlgorithmException e) {
                logger.error("SecurityManager.getLicenseKey(): can't get a digest instance", e);
                throw e;
            } catch (java.io.UnsupportedEncodingException e) {
                logger.error("SecurityManager.getLicenseKey(): can't get a digest instance", e);
                throw e;
            }
        }
        return digest;
    }

    //*********************************************************************
    //* Base64Encoder - a simple base64 encoder and decoder.
    //*
    //*     Copyright (c) 1999, Bob Withers - bwit@pobox.com
    //*
    //* This code may be freely used for any purpose, either personal
    //* or commercial, provided the authors copyright notice remains
    //* intact.
    //*********************************************************************

    /**
     * Encodes data via the BASE64 encoding scheme. This is taken from Base64Encoder by Bob Withers (freely used for any purpose)
     * <p> Copyright (c) 1999, Bob Withers - bwit@pobox.com
     * @param data - bytes to BASE64 encode
     * @return String representing BASE64 encoding of argument
     */
    private static String encode(byte[] data) {
        int fillchar = '=';
        String cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/";
        int c;
        int len = data.length;
        StringBuffer ret = new StringBuffer(((len / 3) + 1) * 4);
        for (int i = 0; i < len; ++i) {
            c = (data[i] >> 2) & 0x3f;
            ret.append(cvt.charAt(c));
            c = (data[i] << 4) & 0x3f;
            if (++i < len)
                c |= (data[i] >> 4) & 0x0f;
            ret.append(cvt.charAt(c));
            if (i < len) {
                c = (data[i] << 2) & 0x3f;
                if (++i < len)
                    c |= (data[i] >> 6) & 0x03;
                ret.append(cvt.charAt(c));
            } else {
                ++i;
                ret.append((char) fillchar);
            }
            if (i < len) {
                c = data[i] & 0x3f;
                ret.append(cvt.charAt(c));
            } else {
                ret.append((char) fillchar);
            }
        }
        return (ret.toString());
    }
}