download MD5Crypt.java
Language: Java
LOC: 111
Project Info
CB reloaded(cbreloaded)
Server: Spider_20090121_inc
Type: filesystem
...rc.tgz\Jap\src\anon\crypto\
   AbstractPrivateKey.java
   AbstractPublicKey.java
   ...509AlternativeName.java
   AbstractX509Extension.java
   AesDecryption.java
   AesEncryption.java
   ...etricCryptoKeyPair.java
   ByteSignature.java
   CertificateContainer.java
   ...icateInfoStructure.java
   CertificateStore.java
   CertificationRequest.java
   ...icationRequestInfo.java
   CertPath.java
   DESCrypt.java
   DSAKeyPair.java
   ICertificate.java
   ICrypt.java
   IMyPrivateKey.java
   IMyPublicKey.java
   IMySignature.java
   ...eCreationAlgorithm.java
   ...ificationAlgorithm.java
   JAPCertificate.java
   MD5Crypt.java
   MyAES.java
   MyDSAParams.java
   MyDSAPrivateKey.java
   MyDSAPublicKey.java
   MyDSASignature.java
   MyRandom.java
   MyRSA.java
   MyRSAPrivateKey.java
   MyRSAPublicKey.java
   MyRSASignature.java
   ...rtificationRequest.java
   PKCS12.java
   PKCS7SignedData.java
   RSAKeyPair.java
   SignatureCreator.java
   SignatureVerifier.java
   Validity.java
   X509CertGenerator.java
   X509DistinguishedName.java
   X509Extensions.java
   ...uerAlternativeName.java
   ...ectAlternativeName.java
   ...bjectKeyIdentifier.java
   X509UnknownExtension.java
   XMLEncryption.java
   XMLSignature.java

/**
 * FreeBSD-compatible md5-style password crypt,
 * based on crypt-md5.c by Poul-Henning Kamp, which was distributed
 * with the following notice:
 *
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
 * ----------------------------------------------------------------------------
 *
 * @author Nick Johnson <freebsd@spatula.net>
 * @version 1.0
 */

package anon.crypto;
import java.security.MessageDigest;
import java.security.SecureRandom;

/**
 * Class containing static methods for encrypting passwords
 * in FreeBSD md5 style.
 *
 * @author Nick Johnson <freebsd@spatula.net>
 * @version 1.0
 */

public class MD5Crypt implements ICrypt {

    private static final String magic = "$1$";
    private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    private static String cryptTo64(int value, int length) {
	StringBuffer output = new StringBuffer();

	while (--length >= 0) {
	    output.append(itoa64.substring(value & 0x3f, (value & 0x3f)+1));
	    value >>=6;
	}

	return (output.toString());
    }

	/**
	 * Encrypts a password using FreeBSD-style md5-based encryption
	 * @param password The cleartext password to be encrypted
	 * @throws java.security.NoSuchAlgorithmException if java.security
	 *        does not support MD5
	 * @return The encrypted password, or an empty string on error
	 */
	public final String crypt(String password) throws java.security.NoSuchAlgorithmException
	{
		StringBuffer salt = new StringBuffer();
		SecureRandom randgen = new SecureRandom();
		while (salt.length() < 8)
		{
			int index = (int) (randgen.nextFloat() * itoa64.length());
			salt.append(itoa64.substring(index, index+1));
		}
		return crypt(password, salt.toString());
	}

    /**
     * Encrypts a password using FreeBSD-style md5-based encryption
     * @param password The cleartext password to be encrypted
     * @param salt The salt used to add some entropy to the encryption
     * @throws java.security.NoSuchAlgorithmException if java.security
     *        does not support MD5
     * @return The encrypted password, or an empty string on error
     */
    public final String crypt(String password, String salt)
	   throws java.security.NoSuchAlgorithmException {

	/* First get the salt into a proper format.  It can be no more than
         * 8 characters, and if it starts with the magic string, it should
         * be skipped.
	 */

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

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

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

	/* now we have a properly formatted salt */

	int saltLength = salt.length();

	MessageDigest md5_1, md5_2;

	md5_1 = MessageDigest.getInstance("MD5");

        /* First we update one MD5 with the password, magic string, and salt */
	md5_1.update(password.getBytes());
	md5_1.update(magic.getBytes());
	md5_1.update(salt.getBytes());

	md5_2 = MessageDigest.getInstance("MD5");

	/* Now start a second MD5 with the password, salt, and password again */
	md5_2.update(password.getBytes());
	md5_2.update(salt.getBytes());
	md5_2.update(password.getBytes());

	byte[] md5_2_digest = md5_2.digest();

	int md5Size = md5_2_digest.length; // XXX
	int pwLength = password.length();

	/* Update the first MD5 a few times starting at the first
         * character of the second MD5 digest using the smaller
   	 * of the MD5 length or password length as the number of
	 * bytes to use in the update.
	 */
	for (int i=pwLength; i>0; i-= md5Size) {
	    md5_1.update(md5_2_digest, 0, i > md5Size? md5Size : i);
	}

	/* the FreeBSD code does a memset to 0 on "final" (md5_2_digest) here
	 * which may be a bug, since it references "final" again if the
	 * conditional below is true, meaning it always is equal to 0
	 */

	md5_2.reset();

	/* Again, update the first MD5 a few times, this time
 	 * using either 0 (see above) or the first byte of the
 	 * password, depending on the lowest order bit's value
	 */
	byte[] pwBytes = password.getBytes();
	for (int i=pwLength; i>0; i >>= 1) {
	    if ((i & 1)== 1) {
		md5_1.update((byte)0);
	    } else {
		md5_1.update(pwBytes[0]);
	    }
	}

	/* Set up the output string. It'll look something like
	 * $1$salt$ to begin with
	 */
	StringBuffer output = new StringBuffer(magic);
	output.append(salt);
	output.append("$");

	byte[] md5_1_digest = md5_1.digest();

	/* According to the original source, this bit of madness
	 * is introduced to slow things down.  It also further
	 * mutates the result.
	 */
	byte[] saltBytes = salt.getBytes();
	for (int i=0; i<1000; i++) {
	    md5_2.reset();
	    if ((i & 1) == 1) {
		md5_2.update(pwBytes);
	    } else {
		md5_2.update(md5_1_digest);
	    }
	    if (i % 3 != 0) {
		md5_2.update(saltBytes);
	    }
	    if (i % 7 != 0) {
		md5_2.update(pwBytes);
	    }
	    if ((i & 1) != 0) {
		md5_2.update(md5_1_digest);
	    } else {
		md5_2.update(pwBytes);
	    }
	    md5_1_digest = md5_2.digest();
	}

	/* Reorder the bytes in the digest and convert them to base64 */
	int value;
	value = ((md5_1_digest[ 0] & 0xff) <<16) | ((md5_1_digest[ 6] &0xff) <<8) | (md5_1_digest[12] &0xff);
	output.append(cryptTo64(value,4));
	value = ((md5_1_digest[ 1] & 0xff) <<16) | ((md5_1_digest[ 7] &0xff) <<8) | (md5_1_digest[13] &0xff);
	output.append(cryptTo64(value,4));
	value = ((md5_1_digest[ 2] & 0xff) <<16) | ((md5_1_digest[ 8] &0xff) <<8) | (md5_1_digest[14] &0xff);
	output.append(cryptTo64(value,4));
	value = ((md5_1_digest[ 3] & 0xff) <<16) | ((md5_1_digest[ 9] &0xff) <<8) | (md5_1_digest[15] &0xff);
	output.append(cryptTo64(value,4));
	value = ((md5_1_digest[ 4] & 0xff) <<16) | ((md5_1_digest[10] &0xff) <<8) | (md5_1_digest[ 5] &0xff);
	output.append(cryptTo64(value,4));
	value = md5_1_digest[11] & 0xff;
	output.append(cryptTo64(value,2));

	/* Drop some hints to the GC */
	md5_1 = null;
	md5_2 = null;
	md5_1_digest = null;
	md5_2_digest = null;
	pwBytes = null;
	saltBytes = null;
	password = salt = "";
	saltLength = pwLength = 0;

	return output.toString();
    }

}

About Koders | Resources | Downloads | Support | Black Duck | Submit Project | Terms of Service | DMCA | Privacy Policy | Site Map| Contact Us