cryptopals

Matasano's cryptopals challenges (cryptopals.com).
git clone git://git.jtobin.io/cryptopals.git
Log | Files | Refs | README | LICENSE

OfflineDictionaryAttack.hs (2018B)


      1 {-# LANGUAGE OverloadedStrings #-}
      2 {-# LANGUAGE RecordWildCards #-}
      3 
      4 module Main where
      5 
      6 import Cryptopals.SRP.Simple (Env(..), defaultEnv)
      7 import qualified Cryptopals.Digest.Pure.SHA as CS
      8 import qualified Cryptopals.DH as DH
      9 import qualified Data.Binary as DB
     10 import qualified Data.ByteString.Base16 as B16
     11 import qualified Data.ByteString.Char8 as B8
     12 import qualified Data.ByteString.Lazy as BL
     13 import qualified Data.ByteString.Lazy.Char8 as BL8
     14 import qualified Data.HashMap.Lazy as HML
     15 import qualified Data.Text as T
     16 import qualified Data.Text.Encoding as TE
     17 import qualified Data.Text.IO as TIO
     18 import Numeric.Natural
     19 import qualified Options.Applicative as O
     20 
     21 populate :: Natural -> IO (HML.HashMap BL.ByteString BL.ByteString)
     22 populate herpub = do
     23   let Env {..} = defaultEnv
     24   dict <- BL8.readFile "/usr/share/dict/words"
     25   let derive x = ((herpub `mod` en) * (DH.modexp eg x en)) `mod` en
     26 
     27   let ls = BL8.lines dict
     28       ns = fmap (fromIntegral . CS.integerDigest . CS.sha256) ls :: [Natural]
     29       ss = fmap derive ns
     30       hs = fmap (CS.bytestringDigest . CS.sha256 . DB.encode) ss
     31       ms = fmap (\s -> CS.bytestringDigest (CS.hmacSha256 s mempty)) hs
     32 
     33   pure . HML.fromList $ zip ms ls
     34 
     35 data Args = Args {
     36     argsNat :: Natural
     37   , argsMAC :: T.Text
     38   }
     39 
     40 ops :: O.Parser Args
     41 ops = Args
     42   <$> O.argument O.auto (O.metavar "PUBLICKEY")
     43   <*> O.argument O.str (O.metavar "MAC")
     44 
     45 crack :: Args -> IO ()
     46 crack Args {..} = do
     47   let mac = BL.fromStrict . B16.decodeBase16Lenient $ TE.encodeUtf8 argsMAC
     48   dict <- populate argsNat
     49   case HML.lookup mac dict of
     50     Nothing -> TIO.putStrLn "(cryptopals) couldn't crack password"
     51     Just pw -> do
     52       let s = BL.toStrict pw
     53       B8.putStrLn "(cryptopals) success"
     54       B8.putStrLn $ "(cryptopals) password: " <> s
     55 
     56 main :: IO ()
     57 main = do
     58   let pars = O.info (O.helper <*> ops) $
     59            O.fullDesc
     60         <> O.progDesc "perform an offline dictionary attack"
     61         <> O.header "offline-dictionary-attack"
     62 
     63   args <- O.execParser pars
     64 
     65   crack args
     66