Created
November 28, 2010 06:01
-
-
Save limitedmage/718644 to your computer and use it in GitHub Desktop.
MD5 Cracker in JavaScript (free under http://j.mp/ms-pl )
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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ñ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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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