-- | -- Module : Crypto.Longshot.Internal -- License : MIT -- Maintainer : Francis Lim -- Stability : experimental -- Portability : unknown -- module Crypto.Longshot.Internal ( bruteforce , bruteforceDeep , bruteforcePar , (<%>) , image , byteChars , bytePrefixes ) where import Control.Monad ( replicateM ) import Control.Applicative ( (<|>) , empty ) import Control.Parallel ( par , pseq ) import Control.DeepSeq ( NFData , force ) import Data.Foldable ( foldl' ) import Data.ByteString ( ByteString ) import qualified Data.ByteString.Char8 as C import qualified Data.ByteString.Base16 as H import Crypto.Longshot.Hasher import Crypto.Longshot.TH import Crypto.Longshot.Const -- | Each bruteforceN declaration: generating code through splicing. -- Number of functions declared == 'maxNumBind' -- $( funcGenerator ) -- | Brute-force search only for a given exact length -- -- @ -- ------------------------------------------------------------------------------ -- size | Preimage length to search -- ------------------------------------------------------------------------------ -- chars | Given character set like "0123456789" -- ------------------------------------------------------------------------------ -- hex | Given hex-string like "17da1ae431f965d839ec8eb93087fb2b" -- ------------------------------------------------------------------------------ -- hasher | Hash functions in 'Hasher' module. Get it using 'getHasher' -- ------------------------------------------------------------------------------ -- numBind | Number of bound variables defined by search length and prefix size -- ------------------------------------------------------------------------------ -- runPar | A partially applied function for parallel execution -- ------------------------------------------------------------------------------ -- prefixes | All possible combinations of given prefix characters. -- | The search space is equally partitioned based on these prefixes. -- | length of prefixes == number of sparks -- ------------------------------------------------------------------------------ -- @ -- bruteforce :: Int -> String -> String -> Hasher -> Maybe String bruteforce size chars hex hasher = found where found = foldl' (<|>) empty (runPar <%> prefixes) runPar = bruteforcePar numBind (byteChars chars) (image hex) hasher numPrefix | size < defNumPrefix = 1 | otherwise = defNumPrefix numBind = size - numPrefix prefixes = bytePrefixes numPrefix chars -- | Pick up an appropriate search function -- -- Returns a partial application corresponding to the given numBind -- bruteforcePar :: Int -> [ByteString] -> ByteString -> Hasher -> ByteString -> Maybe String bruteforcePar numBind | numBind `elem` [0 .. maxNumBind] = $( funcList ) !! numBind | otherwise = errorWithoutStackTrace "Not available search length" -- | Deep Brute-force search including less than a given search size -- -- See the 'bruteforce' function for the arguments used -- bruteforceDeep :: String -> String -> Hasher -> Maybe String bruteforceDeep chars hex hasher = foldl' (<|>) empty found where found = deep chars hex hasher <$> [1 .. limitSearchLength] deep a b c d = bruteforce d a b c -- | Parallel map using deepseq, par and pseq -- -- Type of any argument in this map should be an instance of 'NFData'. -- (<%>) :: (NFData a, NFData b) => (a -> b) -> [a] -> [b] f <%> [] = [] f <%> (x : xs) = y `par` ys `pseq` (y : ys) where y = force $ f x ys = f <%> xs -- | Image bytestring: target hash value to find image :: String -> ByteString image = fst . H.decode . C.pack -- | Bytestring usable for preimage byteChars :: String -> [ByteString] byteChars chars = C.pack . (: []) <$> chars -- | Combination of prefixes possible: size of @(length of chars) ^ (numPrefix)@ bytePrefixes :: Int -> String -> [ByteString] bytePrefixes numPrefix chars = C.pack <$> replicateM numPrefix chars