DetectSingleByteXor.hs (1553B)
1 {-# LANGUAGE OverloadedStrings #-} 2 {-# LANGUAGE RecordWildCards #-} 3 4 module Main where 5 6 import qualified Cryptopals.Util as CU 7 import qualified Data.ByteString.Base16 as B16 8 import qualified Data.ByteString.Char8 as B8 9 import qualified Data.Foldable as F 10 import Data.Function (on) 11 import qualified Data.List as L 12 import qualified Data.Text.IO as TIO 13 import qualified Data.Text.Encoding as TE 14 import qualified Options.Applicative as O 15 import qualified System.Exit as SE 16 import qualified System.IO as SIO 17 18 data Args = Args { argsFil :: SIO.FilePath } 19 20 ops :: O.Parser Args 21 ops = Args <$> O.argument O.str (O.metavar "FILE") 22 23 detect :: Args -> IO () 24 detect Args {..} = do 25 let err = TIO.hPutStrLn SIO.stderr 26 out = TIO.hPutStrLn SIO.stdout 27 28 contents <- B8.readFile argsFil 29 30 let ls = B8.lines contents 31 es = traverse B16.decodeBase16 ls 32 33 case es of 34 Left e -> do 35 err $ "cryptopals: " <> e 36 SE.exitFailure 37 38 Right bs -> do 39 let fs = concatMap (\s -> [(head . CU.often $ s, s)]) bs -- XX hack 40 sorted = L.sortBy (flip compare `on` (snd . fst)) fs 41 most = take 3 sorted 42 43 err "cryptopals: suspect inputs" 44 F.for_ most $ \((_, _), s) -> do 45 err $ "cryptopals: " <> (TE.decodeUtf8 . B16.encodeBase16' $ s) 46 out . TE.decodeUtf8 . B16.encodeBase16' $ s 47 48 main :: IO () 49 main = do 50 let pars = O.info (O.helper <*> ops) $ 51 O.fullDesc 52 <> O.progDesc "produce byte frequencies" 53 <> O.header "detect-single-byte-xor" 54 55 args <- O.execParser pars 56 57 detect args 58