Skip to content

Instantly share code, notes, and snippets.

@limitedmage
Created November 28, 2010 06:01
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save limitedmage/718644 to your computer and use it in GitHub Desktop.
Save limitedmage/718644 to your computer and use it in GitHub Desktop.
MD5 Cracker in JavaScript (free under http://j.mp/ms-pl )
// Global variables
var word, count, time, status; // search status
var running; // should status be updated?
var showPause, showResume, showStop; // to show or hide buttons
var worker; // main WebWorker
$(document).ready(function () {
// Update DOM every 500 ms
setInterval("updateDom()", 500);
// Event en search button is clicked
$("#search").click(function () {
// If worker exists, stop it
if (worker && worker.terminate) {
worker.terminate();
}
// Initialize global variables
status = "Buscando...";
word = "";
time = "0:0:0:0";
count = "0";
running = true;
showPause = true;
showResume = false;
showStop = true;
// Get parameters from user input
var hash = $("#hash").val();
var charset = $("#charset").val();
var length = Number($("#length").val(), 10);
// Show results div
$("#results").css("background", "#fafafa");
$("#results").show('fast');
// Start new web worker to generate results in background thread
worker = new Worker("worker.js");
worker.addEventListener("message", handleWorkerMessage, false);
worker.postMessage({ command: "start", target: hash, charset: charset, length: length });
});
// Event when pause button is clicked
$("#pause").click(function () {
// Update global variables and DOM for paused state
status = "Paused";
showResume = true;
showPause = false;
updateDom();
running = false;
// Set background to yellow
$("#results").css("background", "#fff68f");
});
// Event when resume button is clicked
$("#resume").click(function () {
// Update global variables and DOME for running state
running = true;
showResume = false;
showPause = true;
updateDom();
// Set background to default
$("#results").css("background", "#fafafa");
});
// Event when stop button is clicked
$("#stop").click(function () {
// Kill the worker thread
worker.terminate();
// Update global variables and DOM for cancelled state
running = true;
status = "Cancelled";
showPause = false;
showResume = false;
showStop = false;
updateDom();
running = false;
// Set background to red
$("#results").css("background", "#ffc1c1");
});
});
// Handle messages sent by worker
function handleWorkerMessage(e) {
// The result was found
if (e.data.message == "success") {
// Update global variables and DOM for success state
status = "Found!";
showPause = false;
showResume = false;
showStop = false;
word = e.data.word;
count = e.data.count;
time = e.data.time;
updateDom();
$("#results").css("background", "#98fb98");
}
// A non-matching word was tried
if (e.data.message == "failure") {
// Update global variables for searching state
// Don't update DOM, because this will be called
// very fast. Let DOM update with its interval.
status = "Searching...";
word = e.data.word;
count = e.data.count;
time = e.data.time;
}
// All words were tried, no result was found
if (e.data.message == "end") {
// Update global variables and DOM for not found state
status = "No result found.";
word = "";
count = e.data.count;
time = e.data.time;
showPause = false;
showResume = false;
showStop = false;
$("#results").css("background", "#ffc1c1");
}
}
// Update DOM with latest values of global variables
function updateDom() {
if (running) {
$("#try").text(word);
$("#count").text(count);
$("#time").text(time);
$("#status").text(status);
}
if (showPause) $("#pause").show();
else $("#pause").hide();
if (showResume) $("#resume").show();
else $("#resume").hide();
if (showStop) $("#stop").show();
else $("#stop").hide();
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>MD5 Cracker</title>
<script type="text/javascript" src="jquery-1.4.1.js"></script>
<script type="text/javascript" src="cracker.js"></script>
<style type="text/css">
body { font-family: Segoe UI, Helvetica, Sans-Serif; }
#container { width: 500px; margin-left: auto; margin-right: auto; background: #eee; padding: 20px; border: 5px solid #6495ED; border-radius: 5px;}
#container > div { padding: 10px; background: #fafafa; margin-bottom: 20px; border-radius: 5px;}
#results { display: none; }
#resume { display: none; }
#hash { width: 400px; }
#length { width: 70px; }
</style>
</head>
<body>
<div id="container">
<h1>
MD5 Cracker
</h1>
<div>
<p><strong>Warning:</strong> Extremely slow</p>
<p>This is a brute force MD5 cracker implemented in JavaScript. If you know what those two terms mean, you know they shouldn't go together.</p>
</div>
<!-- Fields for user input -->
<div id="input">
<h4>Input</h4>
<p>
<label for="hash">Hash (<a href="http://www.miraclesalad.com/webtools/md5.php" target="_blank">generator</a>)</label>
<br />
<input type="text" name="hash" id="hash" />
</p>
<p>
<label for="charset">Characters</label>
<br />
<select name="charset" id="charset">
<option value="lower">Lower case (a-z)</option>
<option value="upper">Upper case (A-Z)</option>
<option value="digits">Digits (0-9)</option>
<option value="lowerdigits">Lower case and digits (a-z, 0-9)</option>
<option value="upperdigits">Upper case and digits (A-Z, 0-9)</option>
<option value="lettersdigits">Upper case, lower case and digits (a-z, A-Z, 0-9)</option>
<option value="lettersdigitsspecial">All letters and special characters</option>
</select>
</p>
<p>
<label for="length">Length</label>
<br />
<input type="number" value="0" name="length" id="length" />
</p>
<p>
<input type="button" id="search" value="Search" />
</p>
</div>
<!-- Computation results -->
<div id="results">
<h4>Results</h4>
<!-- Action buttons to pause, resume and stop a search -->
<p>
<input type="button" id="pause" value="Pause" />
<input type="button" id="resume" value="Resume" />
<input type="button" id="stop" value="Cancel" />
</p>
<!-- Current status (Searching, Found, etc) -->
<p id="status"></p>
<!-- Current test -->
<p id="try"></p>
<p id="timer">
<!-- Time taken till current try -->
Time passed: <span id="time"></span>
<br />
<!-- Tries until now -->
Tries: <span id="count">0</span>
</p>
</div>
<div id="notes">
<h4>Notes</h4>
<ul>
<li>
This page works correctly on Firefox 4 and Chrome. Other browsers that support web workers may work, but have not been tested.
</li>
<li>
Only time taken for calculations is counted. Time taken to update DOM is not counted.
</li>
</ul>
</div>
<div>
<h4>Credits</h4>
<p>
Developed by <a href="http://julianapena.com">Juliana Pe&ntilde;a</a>
<br />
Developed for <a href="http://homepage.cem.itesm.mx/rogomez/aplic-dist.html">TC2005.1 2010-13 ITESM CEM</a> <br />
Libraries used: <a href="http://jquery.com/">jQuery</a>, <a href="http://www.webtoolkit.info/javascript-md5.html">MD5</a>
</p>
</div>
</div>
</body>
</html>
// Possible character sets words can be generated from
var charsets = {
lower: "zyxwvutsrqponmlkjihgfedcba",
upper: "ZYXWVUTSRQPONMLKJIHGFEDCBA",
digits: "9876543210",
lowerdigits: "9876543210zyxwvutsrqponmlkjihgfedcba",
upperdigits: "9876543210ZYXWVUTSRQPONMLKJIHGFEDCBA",
lettersdigits: "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba",
lettersdigitsspecial: "!@#$%^&*()+=[]{};:,.<>?/\"'\\|~`9876543210ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba"
};
// Main worker function
// Generate all possible combinations of a charset of a certain length
// until a word that generates the targetHash with MD5 is found
//
// Parameters:
// charset: string of characters to work with
// length: length of the string we're looking for
// targetHash: MD5 hash generated by the word we're looking for
// onsuccess: function(word, count, time) called when matching word is found
// onfailure: function(word, count, time) called when non-matching word is tried
// onend: function(count, time) called when no matching words were found
function crackMd5(charset, length, targetHash, onsuccess, onfailure, onend) {
// Initialize local variables
var stack = [""];
var count = 0;
var started = (new Date()).getTime();
while (true) {
// Stack is empty, no matches were found
// Call onend and exit
if (stack.length == 0) {
var time = generateTimeString(started);
onend(count, time);
break;
}
// Pop the top of the stack
var curr = stack.pop();
// If popped item is the length we're looking for
if (curr.length >= length) {
// Increase count
count += 1;
// Calculate MD5 hash
var hash = MD5(curr);
// If hash is the one we're looking for
if (hash == targetHash) {
// Call onsuccess and exit
var time = generateTimeString(started);
onsuccess(curr, count, time);
break;
}
else {
// Call onfailure and let the loop run again
var time = generateTimeString(started);
onfailure(curr, count, time);
}
}
// Otherwise, push current item appended with every
// possible char in the charset back to the stack
else {
for (var i = 0; i < charset.length; i++) {
stack.push(curr.concat(charset.charAt(i)));
}
}
}
// Stop the worker
self.close();
}
// Helper to generated hours:mins:secs:ms string from milliseconds
function generateTimeString(started) {
var ms = (new Date()).getTime() - started;
var secs = Math.floor(ms / 1000);
var mins = Math.floor(secs / 60);
var hours = Math.floor(mins / 60);
ms = ms % 1000;
secs = secs % 60;
mins = mins % 60;
return hours + ":" + mins + ":" + secs + ":" + ms;
}
// Event listener for worker, start when the command "start" is received
self.addEventListener("message", function (e) {
if (e.data.command == "start") {
var charset = charsets[e.data.charset];
var length = Number(e.data.length, 10);
var target = e.data.target;
crackMd5(charset, length, target, success, failure, end);
}
}, false);
// Callback for success
function success(word, count, time) {
// Send server the appropriate message
postMessage({ message: "success", word: word, count: count, time: time });
}
// Callback for failure
function failure(word, count, time) {
// Send server the appropriate message
postMessage({ message: "failure", word: word, count: count, time: time });
}
// Callback for end
function end(count, time) {
// Send server the appropriate message
postMessage({ message: "end", count: count, time: time });
}
/**
*
* MD5 (Message-Digest Algorithm)
* http://www.webtoolkit.info/
*
**/
var MD5 = function (string) {
function RotateLeft(lValue, iShiftBits) {
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
}
function AddUnsigned(lX, lY) {
var lX4, lY4, lX8, lY8, lResult;
lX8 = (lX & 0x80000000);
lY8 = (lY & 0x80000000);
lX4 = (lX & 0x40000000);
lY4 = (lY & 0x40000000);
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
if (lX4 & lY4) {
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
}
if (lX4 | lY4) {
if (lResult & 0x40000000) {
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
} else {
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
}
} else {
return (lResult ^ lX8 ^ lY8);
}
}
function F(x, y, z) { return (x & y) | ((~x) & z); }
function G(x, y, z) { return (x & z) | (y & (~z)); }
function H(x, y, z) { return (x ^ y ^ z); }
function I(x, y, z) { return (y ^ (x | (~z))); }
function FF(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
function GG(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
function HH(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
function II(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
function ConvertToWordArray(string) {
var lWordCount;
var lMessageLength = string.length;
var lNumberOfWords_temp1 = lMessageLength + 8;
var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
var lWordArray = Array(lNumberOfWords - 1);
var lBytePosition = 0;
var lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
lByteCount++;
}
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
};
function WordToHex(lValue) {
var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
for (lCount = 0; lCount <= 3; lCount++) {
lByte = (lValue >>> (lCount * 8)) & 255;
WordToHexValue_temp = "0" + lByte.toString(16);
WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
}
return WordToHexValue;
};
function Utf8Encode(string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
};
var x = Array();
var k, AA, BB, CC, DD, a, b, c, d;
var S11 = 7, S12 = 12, S13 = 17, S14 = 22;
var S21 = 5, S22 = 9, S23 = 14, S24 = 20;
var S31 = 4, S32 = 11, S33 = 16, S34 = 23;
var S41 = 6, S42 = 10, S43 = 15, S44 = 21;
string = Utf8Encode(string);
x = ConvertToWordArray(string);
a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
for (k = 0; k < x.length; k += 16) {
AA = a; BB = b; CC = c; DD = d;
a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
a = AddUnsigned(a, AA);
b = AddUnsigned(b, BB);
c = AddUnsigned(c, CC);
d = AddUnsigned(d, DD);
}
var temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d);
return temp.toLowerCase();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment