Skip to content

Instantly share code, notes, and snippets.

@ikkentim
Last active December 29, 2015 16:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ikkentim/9892256 to your computer and use it in GitHub Desktop.
Save ikkentim/9892256 to your computer and use it in GitHub Desktop.
MD5 brute forcer
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