diff options
| author | Gregor Kleen <gkleen@yggdrasil.li> | 2017-05-02 14:39:57 +0200 |
|---|---|---|
| committer | Gregor Kleen <gkleen@yggdrasil.li> | 2017-05-02 14:39:57 +0200 |
| commit | 47706c9239192b1298eef8b2cc0ead7a60262751 (patch) | |
| tree | f763a163666631666e528027d0d579ab9fe57a8d /ss2017/cryptography | |
| parent | 3073ee25e150388a660a352d4ab67dc583009604 (diff) | |
| download | uni-47706c9239192b1298eef8b2cc0ead7a60262751.tar uni-47706c9239192b1298eef8b2cc0ead7a60262751.tar.gz uni-47706c9239192b1298eef8b2cc0ead7a60262751.tar.bz2 uni-47706c9239192b1298eef8b2cc0ead7a60262751.tar.xz uni-47706c9239192b1298eef8b2cc0ead7a60262751.zip | |
crypto sheet01
Diffstat (limited to 'ss2017/cryptography')
| -rw-r--r-- | ss2017/cryptography/Sheet01/Sheet01.hs | 128 | ||||
| -rw-r--r-- | ss2017/cryptography/Sheet01/Sheet01.xoj | bin | 0 -> 273762 bytes | |||
| -rw-r--r-- | ss2017/cryptography/Sheet01/manifest | 6 | ||||
| -rw-r--r-- | ss2017/cryptography/Sheet01/math.pdf | bin | 0 -> 616760 bytes | |||
| -rw-r--r-- | ss2017/cryptography/Sheet01/shell.nix | 13 | ||||
| -rw-r--r-- | ss2017/cryptography/Sheet01/substitution.txt (renamed from ss2017/cryptography/substitution.txt) | 0 | ||||
| -rw-r--r-- | ss2017/cryptography/Sheet01/vigenere.txt (renamed from ss2017/cryptography/vigenere.txt) | 0 |
7 files changed, 147 insertions, 0 deletions
diff --git a/ss2017/cryptography/Sheet01/Sheet01.hs b/ss2017/cryptography/Sheet01/Sheet01.hs new file mode 100644 index 0000000..80c162d --- /dev/null +++ b/ss2017/cryptography/Sheet01/Sheet01.hs | |||
| @@ -0,0 +1,128 @@ | |||
| 1 | {-# LANGUAGE ViewPatterns, BangPatterns, TupleSections #-} | ||
| 2 | |||
| 3 | import Data.List | ||
| 4 | import Data.Set (Set) | ||
| 5 | import qualified Data.Set as Set | ||
| 6 | import Data.Map.Strict (Map) | ||
| 7 | import qualified Data.Map.Strict as Map | ||
| 8 | import Data.Char | ||
| 9 | import Data.Maybe | ||
| 10 | import Data.Ord | ||
| 11 | import Data.Tuple | ||
| 12 | import Data.Function | ||
| 13 | |||
| 14 | import Data.Monoid | ||
| 15 | |||
| 16 | import Debug.Trace | ||
| 17 | |||
| 18 | import Control.Monad | ||
| 19 | |||
| 20 | type Attack key = [Char] -> (key, String) | ||
| 21 | type Distribution = Char -> Rational | ||
| 22 | |||
| 23 | isLatin :: Char -> Bool | ||
| 24 | isLatin c = 'a' <= c && c <= 'z' | ||
| 25 | |||
| 26 | shift, unshift :: Integral n => Char -> n -> Char | ||
| 27 | shift c (fromIntegral -> n) = toEnum $ (fromEnum c - fromEnum 'a') + (n `mod` 26) | ||
| 28 | unshift c (fromIntegral -> n) = shift c (-n) | ||
| 29 | |||
| 30 | shift', unshift' :: Char -> Char -> Char | ||
| 31 | shift' c k = shift c $ fromEnum k - fromEnum 'a' | ||
| 32 | unshift' c k = shift c $ fromEnum 'a' - fromEnum k | ||
| 33 | |||
| 34 | -- shift :: Integral n => Char -> n -> Char | ||
| 35 | -- shift c@(fromIntegral . fromEnum -> c') (toInteger -> by) | ||
| 36 | -- = toEnum . fromIntegral $ a' + ((c' - a' + by) `mod` 26) | ||
| 37 | -- where | ||
| 38 | -- a = 'a' | ||
| 39 | -- a' = fromIntegral $ fromEnum a | ||
| 40 | |||
| 41 | main :: IO () | ||
| 42 | main = do | ||
| 43 | let | ||
| 44 | attack :: Show key => [Char] -> ([Char] -> (key, String)) -> [Char] -> IO () | ||
| 45 | attack desc attack' cyphertext = do | ||
| 46 | putStrLn $ desc ++ "..." | ||
| 47 | let (k, plaintext) = attack' cyphertext | ||
| 48 | putStrLn $ "Key: " ++ show k | ||
| 49 | putStrLn plaintext | ||
| 50 | |||
| 51 | attack "Substitution" substitution =<< (filter isLatin <$> readFile "substitution.txt") | ||
| 52 | attack "Vigenere" vigenere =<< (filter isLatin <$> readFile "vigenere.txt") | ||
| 53 | |||
| 54 | |||
| 55 | vigenere :: Attack [Char] | ||
| 56 | vigenere cyphertext = (map key [0 .. keyLength - 1], zipWith unshift' [keyStream i | i <- [0..]] cyphertext) | ||
| 57 | where | ||
| 58 | statistic = multigraphs cyphertext | ||
| 59 | multigraphs' = map (\(k, v) -> (k, diff v)) . take 3 . sortOn (Down . length . snd) . filter (\(k, _) -> length k >= 3) $ Map.toDescList statistic | ||
| 60 | keyLengths = foldr count Map.empty . filter (not . null) . subsequences $ foldr (\(_, v) l -> v ++ l) [] multigraphs' | ||
| 61 | count occs | ||
| 62 | | gcd' == 1 = id | ||
| 63 | | otherwise = Map.alter (Just . succ . fromMaybe 0) gcd' | ||
| 64 | where | ||
| 65 | gcd' = foldl gcd 0 occs | ||
| 66 | keyLength = fst . head . sortOn (Down . snd) $ Map.assocs keyLengths | ||
| 67 | keyStream = key . (`mod` keyLength) | ||
| 68 | key n = fst . caesar $ do | ||
| 69 | i <- [0..(length cyphertext `div` keyLength)] | ||
| 70 | let i' = i * keyLength + n | ||
| 71 | guard $ i' < length cyphertext | ||
| 72 | return $ cyphertext !! i' | ||
| 73 | |||
| 74 | caesar :: Attack Char | ||
| 75 | caesar cyphertext = (closestKey, map (unshift' closestKey) cyphertext) | ||
| 76 | where | ||
| 77 | possibilities :: [(Char, Rational)] | ||
| 78 | possibilities = [(k, char $ (-) <$> english <*> findDist (map (unshift' k) cyphertext)) | k <- ['a' .. 'z']] | ||
| 79 | -- cDist = findDist cyphertext | ||
| 80 | -- possibilities = [(k, sum $ map (\c -> square $ english c - cDist c) mostCommon) | k <- ['a' .. 'z']] | ||
| 81 | -- mostCommon = take 3 . map fst $ sortOn (Down . snd) [(c, english c) | c <- ['a' .. 'z']] | ||
| 82 | closestKey = undefined -- head . map fst $ sortOn snd possibilities | ||
| 83 | |||
| 84 | substitution :: Attack [(Char, Char)] | ||
| 85 | substitution cyphertext = (key, map (\c -> fromMaybe ' ' . lookup c $ map swap key) cyphertext) | ||
| 86 | where | ||
| 87 | cDist = invert $ findDist cyphertext | ||
| 88 | english' = invert english | ||
| 89 | keyStream :: Int -> Char | ||
| 90 | keyStream i = (!! i) . map snd $ sortOn fst assoc | ||
| 91 | where | ||
| 92 | assoc = map (\((_, c1), (_, c2)) -> (c1, c2)) $ (zip `on` sortOn fst) english' cDist | ||
| 93 | key = [(toEnum $ fromEnum 'a' + i, keyStream i) | i <- [0..25]] | ||
| 94 | |||
| 95 | multigraphs :: Ord a => [a] -> Map [a] [Int] | ||
| 96 | multigraphs = multigraphs' Map.empty 0 | ||
| 97 | where | ||
| 98 | multigraphs' acc _ [] = acc | ||
| 99 | multigraphs' acc i xs = let | ||
| 100 | inits' = take 3 . filter (not . null) $ inits xs | ||
| 101 | acc' = foldr (Map.alter (Just . (i :) . fromMaybe [])) acc inits' | ||
| 102 | in multigraphs' acc' (succ i) $ tail xs | ||
| 103 | |||
| 104 | diff :: Num a => [a] -> [a] | ||
| 105 | diff [] = [] | ||
| 106 | diff xs@(x:_) = tail $ diff' x xs | ||
| 107 | where | ||
| 108 | diff' _ [] = [] | ||
| 109 | diff' r (x:xs) = (r - x) : diff' x xs | ||
| 110 | |||
| 111 | english :: Distribution | ||
| 112 | english = fromMaybe 0 . flip lookup dist | ||
| 113 | where | ||
| 114 | dist = [('a', 8.2 / 100), ('b', 1.5 / 100),('c', 2.8 / 100), ('d', 4.2 / 100), ('e', 12.7 / 100), ('f', 2.2 / 100), ('g', 2 / 100), ('h', 6.1 / 100), ('i', 7 / 100), ('j', 0.1 / 100), ('k', 0.8 / 100), ('l', 4 / 100), ('m', 2.4 / 100), ('n', 6.7 / 100), ('o', 7.5 / 100), ('p', 1.9 / 100),('q', 0.1 / 100), ('r', 6 / 100), ('s', 6.3 / 100), ('t', 9 / 100), ('u', 2.8 / 100), ('v', 1 / 100), ('w', 2.4 / 100), ('x', 2 / 100), ('y', 0.1 / 100), ('z', 0.2 / 100)] | ||
| 115 | |||
| 116 | char :: Distribution -> Rational | ||
| 117 | char f = sum $ map (square . f) ['a'..'z'] | ||
| 118 | |||
| 119 | square :: Num n => n -> n | ||
| 120 | square = (*) <$> id <*> id | ||
| 121 | |||
| 122 | findDist :: [Char] -> Distribution | ||
| 123 | findDist text = (/ fromIntegral (length text)) . fromMaybe 0 . flip Map.lookup counts | ||
| 124 | where | ||
| 125 | counts = foldr (Map.alter $ Just . succ . fromMaybe 0) Map.empty text | ||
| 126 | |||
| 127 | invert :: Distribution -> [(Rational, Char)] | ||
| 128 | invert f = [(f c, c) | c <- ['a' .. 'z']] | ||
diff --git a/ss2017/cryptography/Sheet01/Sheet01.xoj b/ss2017/cryptography/Sheet01/Sheet01.xoj new file mode 100644 index 0000000..2878bd1 --- /dev/null +++ b/ss2017/cryptography/Sheet01/Sheet01.xoj | |||
| Binary files differ | |||
diff --git a/ss2017/cryptography/Sheet01/manifest b/ss2017/cryptography/Sheet01/manifest new file mode 100644 index 0000000..6ab37a3 --- /dev/null +++ b/ss2017/cryptography/Sheet01/manifest | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | substitution.txt | ||
| 2 | vigenere.txt | ||
| 3 | shell.nix | ||
| 4 | math.pdf | ||
| 5 | Sheet01.hs | ||
| 6 | manifest | ||
diff --git a/ss2017/cryptography/Sheet01/math.pdf b/ss2017/cryptography/Sheet01/math.pdf new file mode 100644 index 0000000..a85daa7 --- /dev/null +++ b/ss2017/cryptography/Sheet01/math.pdf | |||
| Binary files differ | |||
diff --git a/ss2017/cryptography/Sheet01/shell.nix b/ss2017/cryptography/Sheet01/shell.nix new file mode 100644 index 0000000..5f84e18 --- /dev/null +++ b/ss2017/cryptography/Sheet01/shell.nix | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | { pkgs ? (import <nixpkgs> {}) | ||
| 2 | }: | ||
| 3 | |||
| 4 | pkgs.stdenv.mkDerivation rec { | ||
| 5 | name = "substitution-env"; | ||
| 6 | buildInputs = [ (pkgs.haskellPackages.ghcWithPackages (p: | ||
| 7 | with p; [ case-insensitive containers | ||
| 8 | ])) | ||
| 9 | ]; | ||
| 10 | shellHook = '' | ||
| 11 | export PROMPT_INFO="${name}" | ||
| 12 | ''; | ||
| 13 | } | ||
diff --git a/ss2017/cryptography/substitution.txt b/ss2017/cryptography/Sheet01/substitution.txt index ccd7f58..ccd7f58 100644 --- a/ss2017/cryptography/substitution.txt +++ b/ss2017/cryptography/Sheet01/substitution.txt | |||
diff --git a/ss2017/cryptography/vigenere.txt b/ss2017/cryptography/Sheet01/vigenere.txt index 6ffbad3..6ffbad3 100644 --- a/ss2017/cryptography/vigenere.txt +++ b/ss2017/cryptography/Sheet01/vigenere.txt | |||
