commit 9b00748ce1fc78a38de6e8546200847a74b66463
parent 91d0db9973f11b6c292a2c9c99e67b68cb84d22a
Author: Jared Tobin <jared@jtobin.ca>
Date: Fri, 6 Jan 2017 23:56:09 +1300
Add misc utilities.
Diffstat:
9 files changed, 192 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -5,3 +5,4 @@ target
*.swp
*.o
*.hi
+etc/working
diff --git a/etc/data/3.txt b/etc/data/3.txt
@@ -0,0 +1 @@
+1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736
diff --git a/lib/b642hex/B642Hex.hs b/lib/b642hex/B642Hex.hs
@@ -0,0 +1,17 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as B8
+import qualified Data.ByteString.Base64 as B64
+import qualified Data.ByteString.Base16 as B16
+import System.IO
+
+main :: IO ()
+main = do
+ bs <- B.getContents
+
+ let decoded = B64.decodeLenient bs
+ encoded = B16.encode decoded
+
+ B8.hPutStrLn stdout encoded
+
diff --git a/lib/b642hex/b642hex b/lib/b642hex/b642hex
Binary files differ.
diff --git a/lib/chunks/Chunks.hs b/lib/chunks/Chunks.hs
@@ -0,0 +1,31 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+import Control.Error (readMay)
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as B8
+import System.Environment
+import System.IO
+
+-- | Split a bytestring into chunks.
+chunks :: Int -> B.ByteString -> [B.ByteString]
+chunks size = loop mempty where
+ loop !acc bs
+ | B.null bs = reverse acc
+ | otherwise = case B.splitAt size bs of
+ (chunk, rest) -> loop (chunk : acc) rest
+
+main :: IO ()
+main = do
+ args <- getArgs
+
+ case args of
+ (narg:_) -> case readMay narg :: Maybe Int of
+ Nothing -> hPutStrLn stderr "chunks: invalid keysize"
+ Just size -> do
+ bs <- B8.getContents
+ let chunked = chunks size (B8.filter (/= '\n') bs)
+ mapM_ B8.putStrLn chunked
+
+ _ -> putStrLn "USAGE: echo FOO | ./chunks KEYSIZE"
diff --git a/lib/hamming/Hamming.hs b/lib/hamming/Hamming.hs
@@ -0,0 +1,37 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Data.Bits
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as B8
+import System.Environment
+import System.Exit
+import System.IO
+
+-- | Hamming distance between bytestrings.
+--
+-- Returns Nothing if bytestrings are of unequal length.
+distance :: B.ByteString -> B.ByteString -> Maybe Int
+distance s0 s1
+ | B.length s0 /= B.length s1 = Nothing
+ | otherwise = Just (foldr alg 0 (B.zip s0 s1))
+ where
+ hamming a b = popCount (xor a b)
+ alg = (+) . uncurry hamming
+
+main :: IO ()
+main = do
+ args <- getArgs
+ case args of
+ (s0:s1:_) -> do
+ let b0 = B8.pack s0
+ b1 = B8.pack s1
+ mhamming = distance b0 b1
+ case mhamming of
+ Nothing -> do
+ hPutStrLn stderr "hamming: string lengths unequal"
+ exitFailure
+
+ Just hamming -> print hamming
+
+ _ -> hPutStrLn stderr "USAGE: ./hamming STRING STRING"
+
diff --git a/lib/rotate/Rotate.hs b/lib/rotate/Rotate.hs
@@ -0,0 +1,31 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+import Control.Error (readMay)
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as B8
+import System.Environment
+import System.IO
+
+-- | Split a bytestring into chunks.
+chunks :: Int -> B.ByteString -> [B.ByteString]
+chunks size = loop mempty where
+ loop !acc bs
+ | B.null bs = reverse acc
+ | otherwise = case B.splitAt size bs of
+ (chunk, rest) -> loop (chunk : acc) rest
+
+main :: IO ()
+main = do
+ args <- getArgs
+
+ case args of
+ (narg:_) -> case readMay narg :: Maybe Int of
+ Nothing -> hPutStrLn stderr "rotate: invalid keysize"
+ Just size -> do
+ bs <- B8.getContents
+ let flipped = B.transpose $ chunks size (B8.filter (/= '\n') bs)
+ mapM_ B8.putStrLn flipped
+
+ _ -> putStrLn "USAGE: echo FOO | ./rotate KEYSIZE"
diff --git a/lib/score_keysizes/Score.hs b/lib/score_keysizes/Score.hs
@@ -0,0 +1,74 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+import Control.Error (readMay)
+import Data.Bits
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as B8
+import qualified Data.ByteString.Base64 as B64
+import qualified Data.IntPSQ as PSQ
+import System.Environment
+
+-- | Hamming distance between bytestrings.
+--
+-- Returns Nothing if bytestrings are of unequal length.
+distance :: B.ByteString -> B.ByteString -> Maybe Int
+distance s0 s1
+ | B.length s0 /= B.length s1 = Nothing
+ | otherwise = Just (foldr alg 0 (B.zip s0 s1))
+ where
+ hamming a b = popCount (xor a b)
+ alg = (+) . uncurry hamming
+
+-- | Score a keysize applied to a bytestring.
+score :: Fractional a => B.ByteString -> Int -> Maybe a
+score text size = do
+ let (chunk0, rest) = B.splitAt size text
+ chunk1 = B.take size rest
+ hamming <- distance chunk0 chunk1
+ return $ fromIntegral hamming / fromIntegral size
+
+-- | Score keysizes 2-40 over a given bytestring.
+scoreKeysizes :: B.ByteString -> PSQ.IntPSQ Double ()
+scoreKeysizes text = loop PSQ.empty 2 where
+ plain = B64.decodeLenient text
+ loop !acc size
+ | size == 40 = acc
+ | otherwise = case score plain size of
+ Nothing -> acc
+ Just prio ->
+ let nacc = PSQ.insert size prio () acc
+ in loop nacc (succ size)
+
+-- | Return the best (smallest) n keys from a queue, by key..
+best :: Ord p => Int -> PSQ.IntPSQ p v -> [(Int, p)]
+best = loop mempty where
+ loop !acc idx queue
+ | idx <= 0 = reverse acc
+ | otherwise = case PSQ.minView queue of
+ Nothing -> reverse acc
+ Just (key, prio, _, rest) ->
+ let nacc = (key, prio) : acc
+ in loop nacc (pred idx) rest
+
+main :: IO ()
+main = do
+ bs <- B8.getContents
+ args <- getArgs
+
+ case args of
+ (narg:_) -> do
+ let n = case readMay narg :: Maybe Int of
+ Nothing -> PSQ.size scored
+ Just val -> val
+
+ scored = scoreKeysizes bs
+ top = best n scored
+
+ render (k, v) = show k ++ ": " ++ show v
+
+ putStrLn "keysize: score"
+ mapM_ (putStrLn . render) top
+
+ _ -> putStrLn "USAGE: echo BASE64 | ./score_keysizes NUM_RESULTS"
diff --git a/lib/score_keysizes/score_keysizes b/lib/score_keysizes/score_keysizes
Binary files differ.