Skip to content

Instantly share code, notes, and snippets.

@ilaotan
Last active August 29, 2015 14:08
Show Gist options
  • Save ilaotan/29abad3b5034af7bdc1b to your computer and use it in GitHub Desktop.
Save ilaotan/29abad3b5034af7bdc1b to your computer and use it in GitHub Desktop.
package testGetMapper;
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, jonabbey@arlut.utexas.edu
* Modified by: Vladimir Silva, vladimir_silva@yahoo.com
* 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./
* @return A string of size (size) from the set A-Za-z0-9./
* @param size Length of the string
* @param v value to be converted
*/
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
* @return The encrypted password as an MD5 hash
* @param password Password to be encrypted
*/
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
* @return The encrypted password as an MD5 hash
* @param salt Random string used to initialize the MD5 engine
* @param password Password to be encrypted
*/
static public final String crypt(String password, String salt)
{
return crypt(password, salt, "$1$");
}
/**
* Linux/BSD MD5Crypt function
* @throws java.lang.Exception
* @return The encrypted password as an MD5 hash
* @param magic $1$ for Linux/BSB, $apr1$ for Apache crypt
* @param salt 8 byte permutation string
* @param password user password
*/
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 <password> <salt>";
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("123456","r4QD4vG9"));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment