Last active
December 29, 2015 16:01
-
-
Save ikkentim/9892256 to your computer and use it in GitHub Desktop.
MD5 brute forcer
This file contains 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
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Security.Cryptography; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace ConsoleApplication2 | |
{ | |
internal class Program | |
{ | |
private static void Main(string[] args) | |
{ | |
// Set the priority of this process to the highest available. | |
Console.Title = "BFCrypto"; | |
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime; | |
// Configuration: Set the hash we're brute forcing and | |
// the char set we assume the unhashed string consists of. | |
const string hashstring = "a34feb63bb51d48ce8992cf0361f8121"; | |
const string chars = "qwertyuiopasdfghjklzxcvbnm1234567890"; | |
// Convert the hash string and char set to byte arrays. | |
var input = Enumerable.Range(0, hashstring.Length / 2) | |
.Select(i => Convert.ToByte(hashstring.Substring(i * 2, 2), 16)) | |
.ToArray(); | |
var charSet = chars.ToCharArray() | |
.Select(c => (byte)c) | |
.ToArray(); | |
// Run the MD5 brute force. | |
Console.WriteLine($"Starting on {Environment.ProcessorCount} threads..."); | |
var result = BruteForceMD5(input, charSet).Result; | |
Console.WriteLine($"Result: {string.Join("", result.Select(b => (char)b))}"); | |
Console.ReadLine(); | |
} | |
private static async Task<byte[]> BruteForceMD5(byte[] hash, byte[] charSet) => await Task.Run(() => | |
{ | |
var enumerator = new BruteForceSetEnumerator(charSet); | |
var cancellationTokenSource = new CancellationTokenSource(); | |
// Spawn a few tasks based on the processor count. | |
var tasks = Enumerable.Range(0, Environment.ProcessorCount).Select(i => | |
{ | |
return Task.Run(() => | |
{ | |
// Create an instance of MD5 for this task. | |
var md5 = MD5.Create(); | |
// Loop indefinetely until a result was found or the task was canceled. | |
for (;;) | |
{ | |
// If the task has been canceled, return null. | |
if (cancellationTokenSource.Token.IsCancellationRequested) | |
return null; | |
// Have a crash at the next hash in the enumerator. | |
// If the attempt was successful, return the value. | |
var r = Attempt(md5, hash, enumerator); | |
if (r != null) | |
return r; | |
} | |
}, cancellationTokenSource.Token); | |
}).ToArray(); | |
// Wait for any of the spawned tasks to complete. | |
Task.WaitAny(tasks); | |
// Cancel running tasks. | |
cancellationTokenSource.Cancel(); | |
// Return the result value of the task which found the result. | |
return tasks.FirstOrDefault(t => t.IsCompleted & t.Result != null).Result; | |
}); | |
private static byte[] Attempt(MD5 md5, IEnumerable<byte> hash, BruteForceSetEnumerator enumerator) | |
{ | |
// Lock the enumerator, move it to the next value and store the value as `current`. | |
byte[] current; | |
lock (enumerator) | |
{ | |
enumerator.MoveNext(); | |
current = enumerator.Current; | |
} | |
// Compute a hash for the current enumerator value. If the computed hash sequence equals the hash | |
// we're brute forcing, return the current enumerator value. | |
return md5.ComputeHash(current).SequenceEqual(hash) ? current : null; | |
} | |
/// <summary> | |
/// Represents an infinite set generator based on a specified char set. | |
/// </summary> | |
private class BruteForceSetEnumerator : IEnumerator<byte[]> | |
{ | |
private readonly byte[] _charSet; | |
private List<byte> _currentIndices = new List<byte>(); | |
private bool _isDisposed; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="T:System.Object" /> class. | |
/// </summary> | |
/// <param name="charSet">The char set to use.</param> | |
public BruteForceSetEnumerator(byte[] charSet) | |
{ | |
if (charSet == null) throw new ArgumentNullException(nameof(charSet)); | |
if (charSet.Length < 1) throw new ArgumentOutOfRangeException("must contain values", nameof(charSet)); | |
_charSet = charSet; | |
} | |
#region Implementation of IDisposable | |
/// <summary> | |
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. | |
/// </summary> | |
public void Dispose() | |
{ | |
_isDisposed = true; | |
_currentIndices = null; | |
} | |
#endregion | |
private void AssertNotDisposed() | |
{ | |
if (_isDisposed) | |
throw new ObjectDisposedException(GetType().ToString()); | |
} | |
private void Increase(int indexIndex) | |
{ | |
// If the indexIndex is out of bounds of the indices list, add a index to the list. | |
if (indexIndex >= _currentIndices.Count) | |
{ | |
_currentIndices.Add(0); | |
} | |
// If an increment of the index at the indexIndex would overflow the index, | |
// reset the index to 0 and increase the index at the next indexIndex. | |
else if (_currentIndices[indexIndex] + 1 >= _charSet.Length) | |
{ | |
_currentIndices[indexIndex] = 0; | |
Increase(indexIndex + 1); | |
} | |
// Increase the index at the indexIndex. | |
else | |
{ | |
_currentIndices[indexIndex]++; | |
} | |
} | |
#region Implementation of IEnumerator | |
/// <summary> | |
/// Advances the enumerator to the next element of the collection. | |
/// </summary> | |
/// <returns> | |
/// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of | |
/// the collection. | |
/// </returns> | |
/// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception> | |
public bool MoveNext() | |
{ | |
AssertNotDisposed(); | |
// Increase the index of the first character | |
Increase(0); | |
// Is infinite; The move is always successful. | |
return true; | |
} | |
/// <summary> | |
/// Sets the enumerator to its initial position, which is before the first element in the collection. | |
/// </summary> | |
/// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception> | |
public void Reset() | |
{ | |
AssertNotDisposed(); | |
// Simply clear the indices and we're reset | |
_currentIndices.Clear(); | |
} | |
/// <summary> | |
/// Gets the element in the collection at the current position of the enumerator. | |
/// </summary> | |
/// <returns> | |
/// The element in the collection at the current position of the enumerator. | |
/// </returns> | |
public byte[] Current => | |
// Cast the list to an array, and convert the indices to bytes based on the char set. | |
_currentIndices.Select(i => _charSet[i]).ToArray(); | |
/// <summary> | |
/// Gets the current element in the collection. | |
/// </summary> | |
/// <returns> | |
/// The current element in the collection. | |
/// </returns> | |
object IEnumerator.Current => Current; | |
#endregion | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment