All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xiongyingqi.util.MD5Crypt Maven / Gradle / Ivy

package com.xiongyingqi.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * A Java Implementation of the MD5Crypt function Modified from the GANYMEDE
 * network directory management system released under the GNU General Public
 * License by the University of Texas at Austin
 * http://tools.arlut.utexas.edu/gash2/ Original version from :Jonathan Abbey,
 * [email protected] Modified by: Vladimir Silva,
 * [email protected] Modification history: 9/2005 - Removed dependencies
 * on a MD5 private implementation - Added built-in java.security.MessageDigest
 * (MD5) support - Code cleanup
 */

public class MD5Crypt {
    // Character set allowed for the salt string
    static private final String SALTCHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

    // Character set of the encrypted password: A-Za-z0-9./
    static private final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    /**
     * Function to return a string from the set: A-Za-z0-9./
     *
     * @param size Length of the string
     * @param v    value to be converted
     * @return A string of size (size) from the set A-Za-z0-9./
     */
    static private final String to64(long v, int size) {
        StringBuffer result = new StringBuffer();

        while (--size >= 0) {
            result.append(itoa64.charAt((int) (v & 0x3f)));
            v >>>= 6;
        }

        return result.toString();
    }

    static private final void clearbits(byte bits[]) {
        for (int i = 0; i < bits.length; i++) {
            bits[i] = 0;
        }
    }

    /**
     * convert an encoded unsigned byte value into a int with the unsigned
     * value.
     */
    static private final int bytes2u(byte inp) {
        return (int) inp & 0xff;
    }

    /**
     * LINUX/BSD MD5Crypt function
     *
     * @param password Password to be encrypted
     * @return The encrypted password as an MD5 hash
     */
    static public final String crypt(String password) {
        StringBuffer salt = new StringBuffer();
        java.util.Random rnd = new java.util.Random();

        // build a random 8 chars salt
        while (salt.length() < 8) {
            int index = (int) (rnd.nextFloat() * SALTCHARS.length());
            salt.append(SALTCHARS.substring(index, index + 1));
        }

        // crypt
        return crypt(password, salt.toString(), "$1$");
    }

    /**
     * LINUX/BSD MD5Crypt function
     *
     * @param salt     Random string used to initialize the MD5 engine
     * @param password Password to be encrypted
     * @return The encrypted password as an MD5 hash
     */
    static public final String crypt(String password, String salt) {
        return crypt(password, salt, "$1$");
    }

    /**
     * Linux/BSD MD5Crypt function
     *
     * @param magic    $1$ for Linux/BSB, $apr1$ for Apache crypt
     * @param salt     8 byte permutation string
     * @param password user password
     * @return The encrypted password as an MD5 hash
     * @throws Exception
     */
    static public final String crypt(String password, String salt, String magic) {

        byte finalState[];
        long l;

        /**
         * Two MD5 hashes are used
         */
        MessageDigest ctx, ctx1;

        try {
            ctx = MessageDigest.getInstance("md5");
            ctx1 = MessageDigest.getInstance("md5");
        } catch (NoSuchAlgorithmException ex) {
            System.err.println(ex);
            return null;
        }

		/* Refine the Salt first */
        /* If it starts with the magic string, then skip that */

        if (salt.startsWith(magic)) {
            salt = salt.substring(magic.length());
        }

		/* It stops at the first '$', max 8 chars */

        if (salt.indexOf('$') != -1) {
            salt = salt.substring(0, salt.indexOf('$'));
        }

        if (salt.length() > 8) {
            salt = salt.substring(0, 8);
        }

        /**
         * Transformation set #1: The password first, since that is what is most
         * unknown Magic string Raw salt
         */
        ctx.update(password.getBytes());
        ctx.update(magic.getBytes());
        ctx.update(salt.getBytes());

		/* Then just as many characters of the MD5(pw,salt,pw) */

        ctx1.update(password.getBytes());
        ctx1.update(salt.getBytes());
        ctx1.update(password.getBytes());
        finalState = ctx1.digest(); // ctx1.Final();

        for (int pl = password.length(); pl > 0; pl -= 16) {
            ctx.update(finalState, 0, pl > 16 ? 16 : pl);
        }

        /**
         * the original code claimed that finalState was being cleared to keep
         * dangerous bits out of memory, but doing this is also required in
         * order to get the right output.
         */

        clearbits(finalState);

		/* Then something really weird... */

        for (int i = password.length(); i != 0; i >>>= 1) {
            if ((i & 1) != 0) {
                ctx.update(finalState, 0, 1);
            } else {
                ctx.update(password.getBytes(), 0, 1);
            }
        }

        finalState = ctx.digest();

        /**
         * and now, just to make sure things don't run too fast On a 60 Mhz
         * Pentium this takes 34 msec, so you would need 30 seconds to build a
         * 1000 entry dictionary... (The above timings from the C version)
         */

        for (int i = 0; i < 1000; i++) {
            try {
                ctx1 = MessageDigest.getInstance("md5");
            } catch (NoSuchAlgorithmException e0) {
                return null;
            }

            if ((i & 1) != 0) {
                ctx1.update(password.getBytes());
            } else {
                ctx1.update(finalState, 0, 16);
            }

            if ((i % 3) != 0) {
                ctx1.update(salt.getBytes());
            }

            if ((i % 7) != 0) {
                ctx1.update(password.getBytes());
            }

            if ((i & 1) != 0) {
                ctx1.update(finalState, 0, 16);
            } else {
                ctx1.update(password.getBytes());
            }

            finalState = ctx1.digest(); // Final();
        }

		/* Now make the output string */

        StringBuffer result = new StringBuffer();

        result.append(magic);
        result.append(salt);
        result.append("$");

        /**
         * Build a 22 byte output string from the set: A-Za-z0-9./
         */
        l = (bytes2u(finalState[0]) << 16) | (bytes2u(finalState[6]) << 8)
                | bytes2u(finalState[12]);
        result.append(to64(l, 4));

        l = (bytes2u(finalState[1]) << 16) | (bytes2u(finalState[7]) << 8)
                | bytes2u(finalState[13]);
        result.append(to64(l, 4));

        l = (bytes2u(finalState[2]) << 16) | (bytes2u(finalState[8]) << 8)
                | bytes2u(finalState[14]);
        result.append(to64(l, 4));

        l = (bytes2u(finalState[3]) << 16) | (bytes2u(finalState[9]) << 8)
                | bytes2u(finalState[15]);
        result.append(to64(l, 4));

        l = (bytes2u(finalState[4]) << 16) | (bytes2u(finalState[10]) << 8)
                | bytes2u(finalState[5]);
        result.append(to64(l, 4));

        l = bytes2u(finalState[11]);
        result.append(to64(l, 2));

		/* Don't leave anything around in vm they could use. */
        clearbits(finalState);

        return result.toString();
    }

    /**
     * Test subroutine
     *
     * @param args
     */
    static final String USAGE = "MD5Crypt  ";

    public static void main(String[] args) {
        //        try
        //        {
        //            if ( args.length != 2)
        //                System.err.println(USAGE);
        //            else
        //                System.out.println(MD5Crypt.crypt(args[0], args[1]));
        //
        //        } catch (Exception ex)
        //        {
        //            System.err.println(ex);
        //        }
        //		System.out.println(MD5Crypt.crypt("krkrkr1991", "$1$zc1.Aw0.$"));
        String a = MD5Crypt.crypt("krkrkr1991");
        System.out.println(a);
        System.out.println(MD5Crypt.crypt("krkrkr1991", a));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy