Task

Find, through brute force, the five-letter passwords corresponding with the following SHA-256 hashes:

1. 1115dd800feaacefdf481f1f9070374a2a81e27880f187396db67958b207cbad
2. 3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b
3. 74e1bb62f8dabb8125a58852b63bdf6eaef667cb56ac7f7cdba6d7305c50a22f

Your program should naively iterate through all possible passwords consisting only of five lower-case ASCII English letters. It should use concurrent or parallel processing, if your language supports that feature. You may calculate SHA-256 hashes by calling a library or through a custom implementation. Print each matching password, along with its SHA-256 hash.

Related task: SHA-256

#lang racket/base
(require racket/place
         racket/list
         racket/match
         ;; requires sha package. install it in DrRacket's "File/Install Package..."
         ;; or with raco:
         ;; % raco pkg install sha
         sha
         (only-in openssl/sha1 hex-string->bytes))
 
(define (brute css targs)
  (define (sub-work i) (let ((cs (list-ref css i))) (in-range (car cs) (cdr cs))))
  (define-values (as bs cs ds es) (apply values (map sub-work (range 5))))
  (define s (make-bytes 5))
  (for*/list ((a as) #:when (bytes-set! s 0 a)
                     (b bs) #:when (bytes-set! s 1 b)
                     (c cs) #:when (bytes-set! s 2 c)
                     (d ds) #:when (bytes-set! s 3 d)
                     (e es) #:when (bytes-set! s 4 e)
                     (h (in-value (sha256 s)))
                     (t (in-list targs))
                     #:when (bytes=? t h))
    (eprintf "found ~s -> ~s~%" t s)
    (cons (bytes-copy s) t)))
 
;; ---------------------------------------------------------------------------------------------------
(unless (place-enabled?) (error "We're using places... they're not enabled!"))
 
(define target-list
  (map hex-string->bytes
       (list "1115dd800feaacefdf481f1f9070374a2a81e27880f187396db67958b207cbad"
             "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b"
             "74e1bb62f8dabb8125a58852b63bdf6eaef667cb56ac7f7cdba6d7305c50a22f")))
 
(define (run-place/assign-task sub-task)
  (define there (place here
                       (match-define (cons work targs) (place-channel-get here))
                       (place-channel-put here (brute work targs))))
  (place-channel-put there (cons sub-task target-list))
  there)
 
(define (task->subtasks css n-tasks)
  (match css
    [(list (and initial-range (cons A Z+)) common-tail ...)
     (define step (quotient (+ n-tasks (- Z+ A)) n-tasks))
     (for/list ((a (in-range A Z+ step)))
       ;; replace the head with a sub-task head
       (cons (cons a (min (+ a step) Z+)) common-tail))]))
 
(define readable-pair (match-lambda [(cons x (app bytes->hex-string s)) (cons x s)]))
 
(define (parallel-brute css (n-tasks (processor-count)))
  (define the-places (map run-place/assign-task (task->subtasks css n-tasks)))
  (define collected-results (append* (map place-channel-get the-places)))
  (map readable-pair collected-results))
 
(define 5-char-lowercase-work
  (make-list 5 (cons (char->integer #\a) (add1 (char->integer #\z)))))
 
;; ---------------------------------------------------------------------------------------------------
(module+ main
  (time (parallel-brute 5-char-lowercase-work)))
 
;; ---------------------------------------------------------------------------------------------------
(module+ test
  (require rackunit)
  (check-equal?
   (bytes->hex-string (sha256 #"mmmmm"))
   "74e1bb62f8dabb8125a58852b63bdf6eaef667cb56ac7f7cdba6d7305c50a22f"
   "SHA-256 works as expected")
 
  (check-equal?
   (hex-string->bytes "74e1bb62f8dabb8125a58852b63bdf6eaef667cb56ac7f7cdba6d7305c50a22f")
   #"t\341\273b\370\332\273\201%\245\210R\266;\337n\256\366g\313V\254\177|\333\246\3270\\P\242/"
   "This is the raw value we'll be hashing to")
 
  (define m-idx (char->integer #\m))
  (define m-idx+ (add1 m-idx))
  (check-equal?
   (brute (make-list 5 (cons m-idx m-idx+)) target-list)
   (list
    (cons
     #"mmmmm"
     #"t\341\273b\370\332\273\201%\245\210R\266;\337n\256\366g\313V\254\177|\333\246\3270\\P\242/")))
 
  ;; Brute works without parallelism
  ;; check when you have the time... it takes a minute (literally)
  (check-equal?
   (time
    (brute 5-char-lowercase-work target-list))
   '((#"apple"
      . #":{\323\3426\n=)\356\2446\374\373~D\3075\321\27\304-\34\0305B\vk\231B\335O\e")
     (#"mmmmm"
      .
      #"t\341\273b\370\332\273\201%\245\210R\266;\337n\256\366g\313V\254\177|\333\246\3270\\P\242/")
     (#"zyzzx"
      .
      #"\21\25\335\200\17\352\254\357\337H\37\37\220p7J*\201\342x\200\361\2079m\266yX\262\a\313\255"))
   "without parallelism, it works"))