cryptopals

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

DetectRepeatingKeyXorKeysize.hs (1909B)


      1 {-# LANGUAGE BangPatterns #-}
      2 {-# LANGUAGE OverloadedStrings #-}
      3 {-# LANGUAGE RecordWildCards #-}
      4 
      5 module Main where
      6 
      7 import qualified Cryptopals.Util as CU
      8 import qualified Data.ByteString as BS
      9 import qualified Data.ByteString.Base64 as B64
     10 import qualified Data.Text as T
     11 import qualified Data.Text.IO as TIO
     12 import qualified Data.Text.Encoding as TE
     13 import qualified Options.Applicative as O
     14 import qualified System.Exit as SE
     15 import qualified System.IO as SIO
     16 
     17 data Args = Args { argsInp :: T.Text }
     18 
     19 ops :: O.Parser Args
     20 ops = Args <$> O.argument O.str (O.metavar "INPUT")
     21 
     22 score :: BS.ByteString -> Maybe (Double, Int)
     23 score b = loop Nothing 2 where
     24   loop acc siz
     25     | siz == 40 = acc
     26     | otherwise =
     27         let sc = CU.panhamming
     28                . filter (\s -> BS.length s == siz)
     29                . CU.chunks siz
     30                $ b
     31         in  case sc of
     32               Nothing -> loop acc (succ siz)
     33               Just s  ->
     34                 let nacc = case acc of
     35                       Nothing -> Just (s, siz)
     36                       Just (r, _)  -> if   s < r
     37                                       then Just (s, siz)
     38                                       else acc
     39                 in  loop nacc (succ siz)
     40 
     41 guess :: Args -> IO ()
     42 guess Args {..} = do
     43   let err = TIO.hPutStrLn SIO.stderr
     44 
     45       render :: Show a => a -> T.Text
     46       render = T.pack . show
     47 
     48       s = B64.decodeBase64Lenient $ TE.encodeUtf8 argsInp
     49 
     50   case score s of
     51     Nothing -> do
     52       err "cryptopals: couldn't guess keysize"
     53       SE.exitFailure
     54 
     55     Just (sc, siz) -> do
     56       err ("cryptopals: keysize of " <> render siz <>
     57            " yields minimum score of " <> render sc)
     58 
     59 main :: IO ()
     60 main = do
     61   let pars = O.info (O.helper <*> ops) $
     62            O.fullDesc
     63         <> O.progDesc "guess repeating-key-xor'd keysize"
     64         <> O.header "detect-repeating-key-xor-keysize"
     65 
     66   args <- O.execParser pars
     67 
     68   guess args
     69