import scala.util.Random
import scala.actors.Actor
import scala.actors.Actor._
import java.security.MessageDigest
class HaystackActor extends Actor {
val rand = new Random
val sha1 = MessageDigest.getInstance("SHA1")
// Generates the SHA1 hash of a byte array.
def hash(source: Array[Byte]): Array[Byte] = {
sha1.reset()
sha1.update(source, 0, source.length)
sha1.digest
}
// Returns a random word from a list of words.
def randomWord: String = {
Haystack.dictionary.apply(rand.nextInt(1000))
}
// Generates a random string from a list of words.
def generateGuess: String = {
var i = 0
var guess = new String
while (i < 13) {
guess += randomWord
i += 1
}
// Returns the guess with a trailing space stripped off.
guess.substring(0, guess.length - 1)
}
// Returns a hex string representation of a byte array (Alex Payne)
def printHex(digestBytes: Array[Byte]): String = {
var hex = new StringBuffer()
for (byte <- digestBytes) {
val hexByte = byte & 0xFF
if (hexByte < 0x10) hex.append("0")
hex.append(Integer.toHexString(hexByte))
}
hex.toString
}
// Returns a binary string representation of a byte array (Alex Payne)
def bytesToBinary(digestBytes: Array[Byte]): String = {
var binary = new String()
for (byte <- digestBytes) {
var binaryByte = byte & 0xFF
var binaryString = Integer.toBinaryString(binaryByte)
var size = binaryString.length
while (size < 9) {
binary += "0"
size += 1
}
binary += binaryString
}
binary
}
def ham(guessHash: Array[Byte]): Int = {
var i = 0
var differences = 0
val guessBinary = bytesToBinary(guessHash)
while (i < 160) {
if (Haystack.sourceBinary.apply(i) != guessBinary.apply(i)) differences += 1
i += 1
}
differences
}
def act() {
loop {
var guess = generateGuess
var guessHash = hash(guess.getBytes)
var result = ham(guessHash)
if (result < Haystack.bestScore) {
Haystack.bestScore = result
println(result + " (" + printHex(guessHash) + "): " + guess)
}
}
}
}
object Haystack {
var bestScore = 100
val setup = new HaystackActor
val sourceGuess = "string fetch closures reaper pages win32 grove rfc959 standard marking qalqashandi load sccs"
val sourceHash = setup.hash(sourceGuess.getBytes)
val sourceBinary = setup.bytesToBinary(sourceHash)
val dictionary = List("solo ", "flex ", "scalable ", "rubyonrails ", "rails ", "cloud ", "web ", "hosting ", "ec2 ", "aws ", "git ", "3des ", "abbrev ", "accessor ", "actionpack ", "active ", "activereload ", "addon ", "adjoin ", "aes ", "agile ", "ajax ", "alberti ", "algol ", "alias ", "allen ", "allman ", "aloha ", "amazon ", "AMI ", "amp ", "andreessen ", "android ", "apache ", "apple ", "applet ", "apricot ", "ar ", "arcade ", "array ", "assert ", "assoc ", "atbash ", "atkinson ", "awk ", "awsm ", "awstats ", "babbage ", "backus ", "balancers ", "bartle ", "base64 ", "based ", "bash ", "bazeries ", "bdd ", "beck ", "becker ", "behavior ", "behlendorf ", "bell ", "benchmark ", "benchmarks ", "berkeleydb ", "berners ", "beta ", "betas ", "bford ", "bigdecimal ", "bignum ", "bigtable ", "biham ", "bin ", "bina ", "binaries ", "binary ", "bitsweat ", "bizstone ", "blank ", "bletchley ", "block ", "blocks ", "blog ", "blogs ", "boole ", "boolean ", "bot ", "box ", "bricklin ", "bridge ", "brin ", "browser ", "browsers ", "bsd ", "bug ", "bugs ", "build ", "builder ", "builders ", "builds ", "bytesize ", "c10k ", "cache ", "caches ", "caching ", "caesar ", "call ", "camp ", "capistrano ", "cardelli ", "carmack ", "carribault ", "case ", "catalyst ", "center ", "cerf ", "cgi ", "chabaud ", "chain ", "channel ", "chars ", "cheezburger ", "chef ", "chen ", "child ", "chomp ", "chop ", "chore ", "church ", "ci ", "city ", "class ", "classes ", "cleanup ", "clear ", "client ", "clients ", "clone ", "closures ", "cluster ", "clusters ", "cmd ", "cochran ", "code ", "coder ", "codes ", "codex ", "collect ", "collossus ", "colocated ", "colocation ", "combine ", "combines ", "command ", "commands ", "commit ", "commits ", "complex ", "computer ", "computes ", "computing ", "concat ", "config ", "configs ", "console ", "contest ", "controller ", "converge ", "cook ", "cooley ", "core ", "cores ", "count ", "counter ", "counters ", "cows ", "cpu ", "cpus ", "cray ", "creation ", "creator ", "crispin ", "cryptanalysis ", "css ", "csshsh ", "csv ", "cucumber ", "cunningham ", "cvs ", "daemon ", "daemons ", "damgard ", "dastels ", "data ", "db ", "dbfile ", "dbm ", "dclone ", "debug ", "decode ", "decode64 ", "dedicated ", "defect ", "deicaza ", "delayedjob ", "delegate ", "delete ", "demos ", "denmark ", "dependency ", "deploy ", "deployment ", "deprecate ", "des ", "development ", "dhh ", "diffie ", "digest ", "dijkstra ", "dirty ", "disk ", "display ", "div ", "dix ", "django ", "dll ", "dom ", "dongarra ", "driver ", "dry ", "dst ", "ducktype ", "dup ", "dupe ", "dynamic ", "dystopia ", "eager ", "edge ", "editor ", "eff ", "eich ", "eiffel ", "eight ", "eighty ", "elastic ", "element ", "emacs ", "encode ", "encode64 ", "end ", "enebo ", "engine ", "engineyard ", "eniac ", "enigma ", "enum ", "enumerator ", "environment ", "equal ", "erb ", "error ", "escape ", "etc ", "eval ", "event ", "events ", "exception ", "exceptions ", "excerpt ", "excerpts ", "exist ", "exists ", "expert ", "experts ", "expire ", "expo ", "extend ", "ezmobius ", "facets ", "fairchild ", "fastcgi ", "fastxs ", "fcgi ", "fcntl ", "feature ", "fedora ", "feigenbaum ", "ferret ", "fetch ", "file ", "filesystem ", "fileutils ", "filo ", "filter ", "finish ", "fips ", "first ", "fix ", "fixnum ", "fixture ", "flowers ", "floyd ", "flush ", "footer ", "foreign ", "form ", "format ", "formt ", "formula ", "formulas ", "fowler ", "fragment ", "fragments ", "fraser ", "free ", "freebsd ", "freeware ", "freeze ", "friedman ", "front ", "frozen ", "ftools ", "ftp ", "function ", "functional ", "gadget ", "gate ", "gem ", "gems ", "generator ", "generators ", "generic ", "gentoo ", "gets ", "gfs ", "ginsburg ", "github ", "gitignore ", "glob ", "global ", "globals ", "glue ", "godel ", "goldberg ", "golden ", "golub ", "gosling ", "gray ", "greater ", "greenblatt ", "grep ", "grok ", "group ", "groups ", "grove ", "gsub ", "gutmans ", "h1 ", "h2 ", "h3 ", "habtm ", "hack ", "hacker ", "hackers ", "hacks ", "haml ", "hamming ", "handler ", "handlers ", "handling ", "hansson ", "haproxy ", "hash ", "hashing ", "hawkes ", "headers ", "headius ", "heinemeier ", "hejlsberg ", "hellman ", "hello ", "helper ", "hex ", "hexadecimal ", "hibernate ", "hillis ", "hoedown ", "hopper ", "host ", "hosted ", "hosts ", "howcast ", "hpricot ", "href ", "html ", "htonl ", "http ", "https ", "i10n ", "i18n ", "icanhaz ", "icann ", "ichbiah ", "icon ", "iconv ", "id ", "ietf ", "imap ", "include ", "index ", "ingalls ", "inject ", "injection ", "inline ", "inode ", "insert ", "inspect ", "install ", "instance ", "integer ", "integration ", "intern ", "internet ", "internets ", "interpreter ", "interpreters ", "invalid ", "io ", "iphone ", "iphones ", "ipsec ", "irb ", "irbrc ", "is ", "iterators ", "ivarsoy ", "iverson ", "iwatani ", "jacobson ", "jakarta ", "jalby ", "javascript ", "join ", "joshp ", "joux ", "joy ", "jquery ", "jruby ", "json ", "kahan ", "kahn ", "kaigi ", "kapor ", "karpinski ", "kasiski ", "katz ", "kay ", "kconv ", "kemeny ", "kemper ", "kerckhoff ", "kernighan ", "key ", "keyboard ", "kindi ", "king ", "kit ", "knuth ", "koenig ", "koichi ", "korn ", "koster ", "koz ", "kri ", "kurtz ", "label ", "lacida ", "lamport ", "lampson ", "landing ", "last ", "layer ", "layout ", "legacy ", "lehey ", "lemuet ", "length ", "lesk ", "less ", "lib ", "libcrypt ", "library ", "lifo ", "lift ", "lighttpd ", "limit ", "line ", "lines ", "link ", "linus ", "linux ", "lisp ", "load ", "locale ", "locales ", "localize ", "lock ", "locks ", "logger ", "lolcode ", "love ", "lovelace ", "lua ", "macro ", "macromates ", "mailer ", "mailers ", "managed ", "many ", "map ", "maps ", "marking ", "mash ", "master ", "masters ", "match ", "matsumoto ", "matz ", "mccarthy ", "mcdonald ", "mcilroy ", "mckusick ", "md5 ", "memcached ", "memory ", "merb ", "merkle ", "mesh ", "meta ", "metaclass ", "metaprogramming ", "metcalfe ", "method ", "methods ", "mime ", "minam ", "miner ", "minsky ", "mixmax ", "miyamoto ", "mock ", "mocks ", "mod ", "module ", "modules ", "moler ", "mongrel ", "monitor ", "monitoring ", "montulli ", "moolenaar ", "moore ", "moravec ", "morhaime ", "mozilla ", "mri ", "multicore ", "mysql ", "naik ", "named ", "nested ", "netbeans ", "network ", "new ", "newman ", "next ", "nginx ", "nil ", "nine ", "nist ", "nitems ", "node ", "nodes ", "nodoc ", "noradio ", "norton ", "notift ", "nsa ", "nzkoz ", "object ", "objects ", "observer ", "offline ", "oikarinen ", "olson ", "one ", "online ", "open ", "opera ", "opscode ", "optimize ", "optimizes ", "option ", "options ", "order ", "orders ", "oriented ", "oscon ", "oss ", "oswald ", "ousterhout ", "outer ", "output ", "outputs ", "package ", "page ", "pages ", "pair ", "pajitnov ", "papert ", "parameter ", "parameters ", "params ", "parent ", "parents ", "parse ", "parser ", "partition ", "passenger ", "path ", "paths ", "pattern ", "patterns ", "peek ", "peeks ", "penny ", "perform ", "performs ", "perl ", "pgp ", "phoenix ", "php ", "phusion ", "pica ", "pieprzyk ", "pivot ", "pixel ", "plugin ", "poe ", "polybius ", "pop3 ", "pops ", "portable ", "portage ", "postel ", "postgres ", "postgressql ", "private ", "proc ", "process ", "processes ", "procs ", "program ", "programmer ", "programming ", "programs ", "properties ", "proxy ", "pstore ", "puppet ", "puts ", "python ", "qalqashandi ", "quantity ", "query ", "queue ", "rack ", "railsconf ", "railties ", "raise ", "rake ", "rakefile ", "ram ",