* get get better later on
*/
String magic = "$1$";
byte finalState[];
MD5Digest ctx, ctx1;
long l;
/* -- */
/* 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);
}
ctx = new MD5Digest();
write(ctx, password.getBytes()); // The password first, since that is
// what is most unknown
write(ctx, magic.getBytes()); // Then our magic string
write(ctx, salt.getBytes()); // Then the raw salt
/* Then just as many characters of the MD5(pw,salt,pw) */
ctx1 = new MD5Digest();
write(ctx1, password.getBytes());
write(ctx1, salt.getBytes());
write(ctx1, password.getBytes());
finalState = new byte[ctx1.getDigestSize()];
ctx1.doFinal(finalState, 0);
for (int pl = password.length(); pl > 0; pl -= 16) {
for (int i = 0; i < (pl > 16 ? 16 : pl); i++)
ctx.update(finalState[i]);
}
/*
* 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]);
} else {
ctx.update(password.getBytes()[0]);
}
}
finalState = new byte[ctx.getDigestSize()];
ctx.doFinal(finalState, 0);
/*
* 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++) {
ctx1 = new MD5Digest();
if ((i & 1) != 0) {
write(ctx1, password.getBytes());
} else {
for (int c = 0; c < 16; c++)
ctx1.update(finalState[c]);
}
if ((i % 3) != 0) {
write(ctx1, salt.getBytes());
}
if ((i % 7) != 0) {
write(ctx1, password.getBytes());
}
if ((i & 1) != 0) {
for (int c = 0; c < 16; c++)
ctx1.update(finalState[c]);
} else {
write(ctx1, password.getBytes());
}
finalState = new byte[ctx.getDigestSize()];
ctx1.doFinal(finalState, 0);
}
/* Now make the output string */