Advertisement
Guest User

Untitled

a guest
Jun 25th, 2019
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 32.46 KB | None | 0 0
  1. import Control.Monad
  2. import System.Exit
  3. import System.IO
  4. import MyUtils
  5. import Ciphers.Caesar
  6. import Ciphers.Vigenere
  7. import Ciphers.ADFGVX
  8. import Codebreaking.Cryptanalysis
  9. import Codebreaking.VigenereCrack
  10.  
  11. caesarEncryption = do
  12. clearAll
  13. putStrLn ""
  14. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  15. putStrLn "Enter the shift number:"
  16. shift <- getLine
  17. putStrLn "Enter the message:"
  18. message <- getLine
  19. let shift_int = (read shift :: Int) --convert input to int
  20. let ciphertext = caesarShift shift_int message
  21. clearAll
  22. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  23. putStrLn "Ciphertext:"
  24. print (ciphertext)
  25. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  26. putStrLn "Press any key to return to the main menu."
  27. input <- getLine
  28. main
  29.  
  30. vigenereEncryption = do
  31. clearAll
  32. putStrLn ""
  33. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  34. putStrLn "Enter the desired keyword:"
  35. key <- getLine
  36. putStrLn "Enter the message:"
  37. message <- getLine
  38. let ciphertext = vigenereEncrypt key message
  39. clearAll
  40. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  41. putStrLn ("Ciphertext:")
  42. print (ciphertext)
  43. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  44. putStrLn "Press any key to return to the main menu."
  45. input <- getLine
  46. main
  47.  
  48. adfgvxEncryption = do
  49. clearAll
  50. putStrLn ""
  51. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  52. putStrLn "The program will now read the substitution key from my_grid.txt."
  53. putStrLn "Do you want to change it (y/n)?"
  54. input1 <- getLine
  55. when (input1 == "y") (do createSubstitutionKey; putStrLn "Substitution key created.")
  56. handle <- openFile "my_grid.txt" ReadMode
  57. substitution_key <- hGetContents handle
  58. putStrLn "Enter the desired keyword:"
  59. key <- getLine
  60. putStrLn "Enter the message:"
  61. message <- getLine
  62. let ciphertext = adfgvxEncrypt substitution_key key message
  63. clearAll
  64. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  65. putStrLn ("Ciphertext:")
  66. print (ciphertext)
  67. putStrLn "nDon't forget to share the substitution key with the recipient"
  68. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  69. putStrLn "Press any key to return to the main menu."
  70. input2 <- getLine
  71. main
  72.  
  73. caesar_decryption = do
  74. clearAll
  75. putStrLn ""
  76. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  77. putStrLn "Enter the shift number:"
  78. shift <- getLine
  79. putStrLn "Enter the message:"
  80. message <- getLine
  81. let shift_int = (read shift :: Int) --convert input to int
  82. let plaintext = caesarShift (-shift_int) message
  83. clearAll
  84. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  85. putStrLn "Plaintext:"
  86. print (plaintext)
  87. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  88. putStrLn "Press any key to return to the main menu."
  89. input <- getLine
  90. main
  91.  
  92. vigenereDecryption = do
  93. clearAll
  94. putStrLn ""
  95. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  96. putStrLn "Enter the keyword:"
  97. key <- getLine
  98. putStrLn "Enter the message:"
  99. message <- getLine
  100. let plaintext = vigenereDecrypt key message
  101. clearAll
  102. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  103. putStrLn ("Plaintext:")
  104. print (plaintext)
  105. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  106. putStrLn "Press any key to return to the main menu."
  107. input <- getLine
  108. main
  109.  
  110. adfgvxDecryption = do
  111. clearAll
  112. putStrLn ""
  113. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  114. putStrLn "The program will now read the substitution key from my_grid.txt."
  115. handle <- openFile "my_grid.txt" ReadMode
  116. substitution_key <- hGetContents handle
  117. putStrLn "Enter the keyword:"
  118. key <- getLine
  119. putStrLn "Enter the message:"
  120. message <- getLine
  121. let plaintext = adfgvxDecrypt substitution_key key message
  122. clearAll
  123. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  124. putStrLn ("Plaintext:")
  125. print (plaintext)
  126. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  127. putStrLn "Press any key to return to the main menu."
  128. input <- getLine
  129. main
  130.  
  131. decryption = do
  132. clearAll
  133. putStrLn ""
  134. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  135. putStrLn "::1 - Caesar's cipher ::"
  136. putStrLn "::2 - Vigenere's cipher ::"
  137. putStrLn "::3 - ADFGVX ::"
  138. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  139. putStrLn "::r - Return e - Exit ::"
  140. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  141. input <- getLine
  142. case input of
  143. "1" -> caesar_decryption
  144. "2" -> vigenereDecryption
  145. "3" -> adfgvxDecryption
  146. "r" -> main
  147. "e" -> exitSuccess
  148. otherwise -> do
  149. putStrLn ""
  150. putStrLn ("Please enter a valid option")
  151. encryption
  152.  
  153. encryption = do
  154. clearAll
  155. putStrLn ""
  156. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  157. putStrLn "::1 - Caesar's cipher ::"
  158. putStrLn "::2 - Vigenere's cipher ::"
  159. putStrLn "::3 - ADFGVX ::"
  160. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  161. putStrLn "::r - Return e - Exit ::"
  162. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  163. input <- getLine
  164. case input of
  165. "1" -> caesarEncryption
  166. "2" -> vigenereEncryption
  167. "3" -> adfgvxEncryption
  168. "r" -> main
  169. "e" -> exitSuccess
  170. otherwise -> do
  171. putStrLn ""
  172. putStrLn ("Please enter a valid option")
  173. encryption
  174.  
  175. tools :: String -> String -> IO()
  176. tools ciphertext guess = forever $ do
  177. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  178. putStrLn "Ciphertext:"
  179. print (ciphertext)
  180. putStrLn ""
  181. putStrLn "My guess:"
  182. print (guess)
  183. putStrLn ""
  184. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  185. putStrLn "::0 - Display the letter frequency in descending order ::"
  186. putStrLn "::1 - Break Caesar's cipher ::"
  187. putStrLn "::2 - Break Vigenere's cipher (Babbage/Kasiski Algorithm) ::"
  188. putStrLn "::3 - Get repeated substrings ::"
  189. putStrLn "::4 - Count the occurrences of a substring ::"
  190. putStrLn "::5 - Count the occurrences of a letter immediately before/after other letters ::"
  191. putStrLn "::6 - Count the occurrences of a letter immediately before other letters ::"
  192. putStrLn "::7 - Count the occurrences of a letter immediately after other letters ::"
  193. putStrLn "::8 - Substitute a letter by another in the ciphertext ::"
  194. putStrLn "::r - Return ::"
  195. putStrLn "::e - Exit ::"
  196. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  197. input <- getLine
  198. case input of
  199. "0" -> do
  200. putStrLn ""
  201. putStrLn "Letter frequency:"
  202. print (sortAlphabetCount ciphertext)
  203. putStrLn ""
  204. "1" -> do
  205. putStrLn ""
  206. print(breakCaesar ciphertext)
  207. putStrLn ""
  208. "2" -> do
  209. putStrLn ""
  210. putStrLn "For this tool to work it is necessary to find some substrings that have multiple occurrences along the ciphertext."
  211. crackVigenere ciphertext
  212. "3" -> do
  213. putStrLn ""
  214. putStrLn "Enter the minimum size of the substrings to be searched for:"
  215. min_size <- getLine
  216. putStrLn "Enter the maximum size of the substrings to be searched for:"
  217. max_size <- getLine
  218. let min_size_int = (read min_size :: Int)
  219. max_size_int = (read max_size :: Int)
  220. putStrLn "Repeated substrings:"
  221. print (repeatedSubs min_size_int max_size_int ciphertext)
  222. "4" -> do
  223. putStrLn ""
  224. putStrLn "Enter the substring:"
  225. substring <- getLine
  226. putStrLn "Occurrences:"
  227. print(countSubstring substring ciphertext)
  228. putStrLn ""
  229. "5" -> do
  230. putStrLn ""
  231. putStrLn "Enter the letter(between ''):"
  232. letter <- getLine
  233. let letter_char = (read letter :: Char)
  234. putStrLn "Occurrences:"
  235. print(countAllNeighbours letter_char ciphertext)
  236. putStrLn ""
  237. "6" -> do
  238. putStrLn ""
  239. putStrLn "Enter the letter(between ''):"
  240. letter <- getLine
  241. let letter_char = (read letter :: Char)
  242. putStrLn "Occurrences:"
  243. print(countAllBefore letter_char ciphertext)
  244. putStrLn ""
  245. "7" -> do
  246. putStrLn ""
  247. putStrLn "Enter the letter(between ''):"
  248. letter <- getLine
  249. let letter_char = (read letter :: Char)
  250. putStrLn "Occurrences:"
  251. print(countAllAfter letter_char ciphertext)
  252. putStrLn ""
  253. "8" -> do
  254. putStrLn ""
  255. putStrLn "Enter the letter(between '') you wish to substitute:"
  256. letter1 <- getLine
  257. let letter1_char = (read letter1 :: Char)
  258. putStrLn "Enter the letter(beween '') to substitute by:"
  259. letter2 <- getLine
  260. let letter2_char = (read letter2 :: Char)
  261. new_ciphertext = substitute letter1_char letter2_char guess
  262. putStrLn "New ciphertext:"
  263. print(new_ciphertext)
  264. tools ciphertext new_ciphertext
  265. "r" -> main
  266. "e" -> exitSuccess
  267. otherwise -> do
  268. putStrLn ""
  269. putStrLn ("Please enter a valid option")
  270. tools ciphertext guess
  271.  
  272. crack = do
  273. clearAll
  274. putStrLn ""
  275. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  276. putStrLn "Enter the message:"
  277. ciphertext <- getLine
  278. tools ciphertext ciphertext
  279.  
  280. main = forever $ do
  281. clearAll
  282. putStrLn ""
  283. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  284. putStrLn ":: /$$$$$$ /$$$$$$ /$$$$$$$$ ::"
  285. putStrLn ":: /$$__ $$ /$$__ $$ |__ $$__/ ::"
  286. putStrLn "::| $$ __/ /$$ /$$ | $$ __/ /$$ /$$| $$ ::"
  287. putStrLn "::| $$ |__/|__/| $$ |__/|__/| $$ ::"
  288. putStrLn "::| $$ | $$ | $$ ::"
  289. putStrLn "::| $$ $$ /$$ /$$| $$ $$ /$$ /$$| $$ ::"
  290. putStrLn "::| $$$$$$/|__/|__/| $$$$$$/|__/|__/| $$ ::"
  291. putStrLn ":: |______/ |______/ |__/ ::"
  292. putStrLn "::::::::Classic Cryptography Toolbox:::::::::::::::::::::::::::::::::::::::::::::"
  293. putStrLn ":: ::"
  294. putStrLn "::What would you like to do? ::"
  295. putStrLn ":: ::"
  296. putStrLn "::1 - Encrypt a message ::"
  297. putStrLn "::2 - Decrypt a message ::"
  298. putStrLn "::3 - Cryptanalyse an encrypted message ::"
  299. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  300. putStrLn "::e - Exit ::"
  301. putStrLn ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
  302. input <- getLine
  303. case input of
  304. "1" -> encryption
  305. "2" -> decryption
  306. "3" -> crack
  307. "e" -> exitSuccess
  308. otherwise -> do
  309. putStrLn ""
  310. putStrLn ("Please enter a valid option")
  311. main
  312.  
  313. module MyUtils where
  314.  
  315. import Data.Char
  316. import Data.List
  317. import System.Console.ANSI
  318. import System.Random
  319.  
  320. --lowercase letter to int conversion
  321. let2int :: Char -> Int
  322. let2int c = ord c - ord 'a'
  323.  
  324. --int to lowercase letter conversion
  325. int2let :: Int -> Char
  326. int2let n = chr(ord 'a' + n)
  327.  
  328. --converts an entire string an array of ints (each char -> int)
  329. text2ints :: String -> [Int]
  330. text2ints xs = map (let2int) xs
  331.  
  332. --convrets an array of ints into a string (each int -> char)
  333. ints2text :: [Int] -> String
  334. ints2text xs = map (int2let) xs
  335.  
  336. --shifts the given lowercase letter n positions
  337. shift :: Int -> Char -> Char
  338. shift n c |isLower c = int2let((let2int c + n) `mod` 26)
  339. |otherwise = c
  340.  
  341. --gets the factors of n
  342. factors :: Int -> [Int]
  343. factors n = [x |x<-[2..n], n`mod`x == 0]
  344.  
  345. --deletes all occurrences of an element within a list
  346. deleteAll :: Eq a => a -> [a] -> [a]
  347. deleteAll x s = filter (/=x) s
  348.  
  349. --gives a list of all the elements that have multiple occurrences within a list
  350. equals :: Eq a => [a] -> [a]
  351. equals [] = []
  352. equals (x:xs)
  353. |elem x xs = x : equals (deleteAll x xs)
  354. |otherwise = equals xs
  355.  
  356. --gives a list of all the elements that are common to all the lists within a list of lists
  357. commonElems :: Eq a => [[a]] -> [a]
  358. commonElems l = equals [x | y<-l, x<-y, length (filter (elem x) l) == length l]
  359.  
  360. --gives a list of all the factors in common to all the integers in a list
  361. commonFactors :: [Int] -> [Int]
  362. commonFactors xs
  363. |length xs == 1 = factors (head (xs))
  364. |otherwise = commonElems [factors x | x<-xs]
  365.  
  366. --gives a list of the indexes of each occurrence of a substring within a string
  367. matchIndices :: (Eq a, Num b, Enum b) => [a] -> [a] -> [b]
  368. matchIndices needle = map fst . filter (isPrefixOf needle . snd) . zip [0..] . tails
  369.  
  370. --gives a list of the lengths between each consecutive occurrences of a substring within a string
  371. spaceBetween :: String -> String -> [Int]
  372. spaceBetween needle = diffs . matchIndices needle -- calculates the difference between each consecutive index
  373. where diffs xs = zipWith (flip(-)) xs (tail xs)
  374.  
  375. --count the space between the first occurrence of a subtring and the next occurrence within a string
  376. repeatSpacing :: String -> String -> Int
  377. repeatSpacing substring ciphertext
  378. |spaceBetween substring ciphertext == [] = 0
  379. |otherwise = head (spaceBetween (substring) (ciphertext))
  380.  
  381. --gives a list of the lengths between the first occurrence of multiple substrings and the next respective occurrence
  382. multRepeatSpacing :: [String] -> String -> [Int]
  383. multRepeatSpacing substrings ciphertext = [y | x<-substrings, y<-[repeatSpacing x ciphertext]]
  384.  
  385. --gets all chars n chars away from each other
  386. getSpacedLetters :: Int -> String -> String
  387. getSpacedLetters n (x:xs)
  388. |n > length xs = [x]
  389. |otherwise = x : getSpacedLetters n (drop (n-1) xs)
  390.  
  391. --gets all chars "size" chars away from each other starting from the nth position
  392. getNthSpacedLetters :: Int -> Int -> String -> String
  393. getNthSpacedLetters size n s
  394. |n > length s = ""
  395. |otherwise = getSpacedLetters size (drop (n-1) s)
  396.  
  397. --removes all tuples with x as fst
  398. removeAllTuplesByInt :: Int -> [(a,Int)] -> [(a,Int)]
  399. removeAllTuplesByInt x [] = []
  400. removeAllTuplesByInt x list
  401. |snd (head list) /= x = head list : removeAllTuplesByInt x (tail list)
  402. |otherwise = removeAllTuplesByInt x (tail list)
  403.  
  404. --gets the index of a char in a dictionary of type [(Char,Integer)]
  405. getDictIndex :: Eq a => a -> [(a,Integer)] -> Integer
  406. getDictIndex c [key]
  407. |c == fst key = snd key
  408. |otherwise = error "no such element"
  409. getDictIndex c dict
  410. |c == fst (head dict) = snd (head dict)
  411. |otherwise = getDictIndex c (tail dict)
  412.  
  413. --gives a list of the elements in a list withou repeating them
  414. delRepeated :: Eq a => [a] -> [a]
  415. delRepeated [] = []
  416. delRepeated list = x : delRepeated (deleteAll x (tail list))
  417. where x = head list
  418.  
  419. --clears the terminal and sets the cursor position to 0 0
  420. clearAll :: IO()
  421. clearAll = do
  422. clearScreen
  423. setCursorPosition 0 0
  424.  
  425. --converts something of type a into the corresponding value of type b in a dictionary of the type [(b,a)]
  426. convertTo :: Eq a => a -> [(b,a)]-> b
  427. convertTo x [] = error ("int not found in the dict")
  428. convertTo x dict
  429. |x == (snd (head dict)) = fst (head dict)
  430. |otherwise = convertTo x (tail dict)
  431.  
  432. convertFrom :: Eq a => a -> [(a,b)] -> b
  433. convertFrom x [] = error ("not found in the dict")
  434. convertFrom x dict
  435. |x == (fst (head dict)) = snd (head dict)
  436. |otherwise = convertFrom x (tail dict)
  437.  
  438. --converts an entire list into the corresponding dictionary values
  439. toDictValue :: Eq a => [a] -> [(b,a)] -> [b]
  440. toDictValue ns dict = map (x -> convertTo x dict) ns
  441.  
  442. --generates a list of different random integers from n1 to n2 of size n2
  443. genRandNrs :: Integer -> Integer -> IO([Integer])
  444. genRandNrs n1 n2 = do
  445. g <- newStdGen
  446. return (take (fromIntegral n2) (nub (randomRs (n1,n2) g :: [Integer])))
  447.  
  448. --groups the given list in a list of lists in, n by n
  449. groupN:: Int -> [a] -> [[a]]
  450. groupN 0 _ = []
  451. groupN size [] = []
  452. groupN size s = (take (size) s) : groupN size (drop size s)
  453.  
  454. module Codebreaking.Cryptanalysis where
  455.  
  456. import Data.Char
  457. import Data.List
  458. import Data.Function
  459. import MyUtils
  460.  
  461. alphabet = "abcdefghijklmnopqrstuvwxyz"
  462.  
  463. --most to least frequent letters in english with respective index
  464. etaoin = zip "etaoinshrdlcumwfgypbvkjxqz" [1..]
  465.  
  466. en_letter_most_freq = "etaoin" --most frequent english letters
  467. en_letter_least_freq = "vkjxqz" --least frequent english letters
  468.  
  469. --counts the number of ocurrences of a char in a string
  470. count :: Char -> String -> Int
  471. count a [x]
  472. |a == x = 1
  473. |otherwise = 0
  474. count a (x:xs)
  475. |a == x = 1 + count a xs
  476. |otherwise = count a xs
  477.  
  478. --counts the numbers of ocurrences of a string in another string
  479. countSubstring :: String -> String -> Int
  480. countSubstring s1 s2
  481. |length s1 > length s2 = 0
  482. |take (length s1) s2 == s1 = 1 + countSubstring s1 (drop 1 s2)
  483. |otherwise = countSubstring s1 (drop 1 s2)
  484.  
  485. --given a number m and a string, finds all the substrings with size n that have multiple occurrences on the given string
  486. repeatedSubsBySize :: Int -> String -> [String]
  487. repeatedSubsBySize n [] = []
  488. repeatedSubsBySize n s
  489. |countSubstring (take n s) s > 1 = (take n s) : repeatedSubsBySize n (drop 1 s)
  490. |otherwise = repeatedSubsBySize n (drop 1 s)
  491.  
  492. --finds all the substrings with sizes between n1 and n2 that have multiple occurrences on the given string
  493. repeatedSubs :: Int -> Int -> String -> [String]
  494. repeatedSubs n1 n2 [] = []
  495. repeatedSubs n1 n2 s = [sub | n<-[n1..n2], sub<-repeatedSubsBySize n s]
  496.  
  497. --counts the number of ocurrences of each letter of the alphabet in a string
  498. countAlphabet :: String -> [(Char, Int)]
  499. countAlphabet s = [(letter,occurs) | letter<-alphabet, occurs<-[count letter s]]
  500.  
  501. --outputs the result of count alphabet from the most frequent letter to the least
  502. sortAlphabetCount :: String -> [(Char, Int)]
  503. sortAlphabetCount s = reverse (sortOn (snd) (countAlphabet s))
  504.  
  505. --substitutes all occurrences of c1 by c2 on the given string
  506. substitute :: Char -> Char -> String -> String
  507. substitute c1 c2 [] = []
  508. substitute c1 c2 (x:xs)
  509. |c1 == x = toUpper c2 : substitute c1 c2 xs
  510. |otherwise = x : substitute c1 c2 xs
  511.  
  512. --counts the occurrences of c1 immediately before c2
  513. countBefore :: Char -> Char -> String -> Int
  514. countBefore c1 c2 [x] = 0
  515. countBefore c1 c2 (x:xs)
  516. |head xs == c2 && x == c1 = 1 + countBefore c1 c2 xs
  517. |otherwise = 0 + countBefore c1 c2 xs
  518.  
  519. --counts the occurrences of c1 immediately after c2
  520. countAfter :: Char -> Char -> String -> Int
  521. countAfter c1 c2 [x] = 0
  522. countAfter c1 c2 (x:xs)
  523. |x == c2 && head xs == c1 = 1 + countAfter c1 c2 xs
  524. |otherwise = 0 + countAfter c1 c2 xs
  525.  
  526. -- counts the ocurrences of c1 immediately before or after c2
  527. countNeighbours :: Char -> Char -> String -> Int
  528. countNeighbours c1 c2 s = (countBefore c1 c2 s) + (countAfter c1 c2 s)
  529.  
  530. --counts the occurrences of c immediately before or after every letter of the alphabet
  531. countAllNeighbours :: Char -> String -> [(Char, Int)]
  532. countAllNeighbours c s = [(letter, occurs) | letter<-alphabet, occurs<-[countNeighbours c letter s]]
  533.  
  534. --counts the occurrences of c immediately before every letter of the alphabet
  535. countAllBefore :: Char -> String -> [(Char, Int)]
  536. countAllBefore c s = [(letter, occurs) | letter<-alphabet, occurs<-[countBefore c letter s]]
  537.  
  538. --counts the occurrences of c immediately after every letter of the alphabet
  539. countAllAfter :: Char -> String -> [(Char, Int)]
  540. countAllAfter c s = [(letter, occurs) | letter<-alphabet, occurs<-[countAfter c letter s]]
  541.  
  542. --attributes a letter frequency score to the first 6 letters in a string
  543. matchFreqScoreFirst :: String -> Int
  544. matchFreqScoreFirst [] = 0
  545. matchFreqScoreFirst s
  546. |elem (head sorted_first) en_letter_most_freq = 1 + matchFreqScoreFirst (drop 1 sorted_first)
  547. |otherwise = 0 + matchFreqScoreFirst (drop 1 sorted_first)
  548. where sorted_first = take 6 s
  549.  
  550. --attributes a letter frequency score to the last 6 letters in a string
  551. matchFreqScoreLast :: String -> Int
  552. matchFreqScoreLast [] = 0
  553. matchFreqScoreLast s
  554. |elem (head sorted_last) en_letter_least_freq = 1 + matchFreqScoreLast (drop 1 sorted_last)
  555. |otherwise = 0 + matchFreqScoreLast (drop 1 sorted_last)
  556. where sorted_last = take 6 (reverse s)
  557.  
  558. --sorts the strings in the tuple in reverse ETAOIN order
  559. reverseEtaoinSortFreqs :: [(Int, String)] -> [(Int, String)]
  560. reverseEtaoinSortFreqs [] = []
  561. reverseEtaoinSortFreqs [x]
  562. |length (snd x) > 1 = [(fst x, reverseEtaoinSort (snd x))]
  563. |otherwise = [x]
  564. reverseEtaoinSortFreqs (x:xs)
  565. |length (snd x) > 1 = (fst x, reverseEtaoinSort (snd x)) : reverseEtaoinSortFreqs xs
  566. |otherwise = x : reverseEtaoinSortFreqs xs
  567.  
  568. --gives a list of frequencies and the respective group of letters
  569. sortFreqToLetters :: String -> [(Int, String)]
  570. sortFreqToLetters s = reverseEtaoinSortFreqs [(snd (head gr), map fst gr) | gr <- groupBy ((==) `on` snd) (sorted_freqs)]
  571. where
  572. sorted_freqs = (sortAlphabetCount s)
  573.  
  574. --inserts a letter in a "reverse_etaoin" ordered string keeping its order
  575. reverseEtaoinInsert :: Char -> String -> String
  576. reverseEtaoinInsert c [] = [c]
  577. reverseEtaoinInsert c (x:xs)
  578. |(getDictIndex c etaoin) > (getDictIndex x etaoin) = c : x : xs
  579. |otherwise = x : reverseEtaoinInsert c xs
  580.  
  581. --sorts a string in reverse ETAOIN order
  582. reverseEtaoinSort :: String -> String
  583. reverseEtaoinSort [] = []
  584. reverseEtaoinSort (x:xs) = reverseEtaoinInsert x (reverseEtaoinSort xs)
  585.  
  586. --gives the 2 highest ints in lust of (Char,Int)
  587. getHighestFreqScores :: [(Char,Int)] -> [Int]
  588. getHighestFreqScores scores = [maximum (map (snd) scores),maximum (map (snd) rest)]
  589. where rest = removeAllTuplesByInt (maximum (map (snd) scores)) scores
  590.  
  591. --outputs the letters corresponding to the given highest freq scores
  592. getHighestLetters :: [Int] -> [(Char,Int)] -> String
  593. getHighestLetters highest_scores [] = []
  594. getHighestLetters highest_scores scores
  595. |elem (snd (head scores)) highest_scores = fst (head scores) : getHighestLetters highest_scores (tail scores)
  596. |otherwise = getHighestLetters highest_scores (tail scores)
  597.  
  598. --given a reverse_etaoin sorted string, attributes a frequency match score
  599. matchFreqScore :: String -> Int
  600. matchFreqScore s = matchFreqScoreFirst s + matchFreqScoreLast s
  601.  
  602. --gets the reverse etaoin sorted string of a string
  603. sortedEtaoinString :: String -> String
  604. sortedEtaoinString x = concat (map (snd) (init (sortFreqToLetters x)))
  605.  
  606. module Ciphers.Caesar where
  607.  
  608. import MyUtils
  609. import Data.Char
  610.  
  611. --encrypts(n) or decrypts(-n)
  612. caesarShift :: Int -> String -> String
  613. caesarShift n xs = [shift n x | x <- map (toLower) xs]
  614.  
  615. --given a string, shifts it 26 times and generates a list with all of the shifted strings
  616. --one of the elements might mean something
  617. breakCaesar :: String -> [String]
  618. breakCaesar xs = [s | n<-[(0)..(25)], s<- [caesarShift (-n) (map (toLower) xs)]]
  619.  
  620. module Ciphers.Vigenere where
  621.  
  622. import MyUtils
  623. import Data.Char
  624.  
  625. --encrypts the plaintext with the given key
  626. vigenereEncrypt :: String -> String -> String
  627. vigenereEncrypt key plaintext = ints2text result
  628. where result = map (`mod` 26) (zipWith (+) keyCycle intPlainText)
  629. keyCycle = (cycle(text2ints key))
  630. intPlainText = text2ints (map (toLower) (filter (isAlphaNum) plaintext))
  631.  
  632. --decrypts the ciphertext with the given key
  633. vigenereDecrypt :: String -> String -> String
  634. vigenereDecrypt key ciphertext = ints2text result
  635. where result = map (`mod` 26) (zipWith (-) intciphertext keyCycle)
  636. keyCycle = (cycle(text2ints key))
  637. intciphertext = text2ints (map (toLower)(filter (isAlphaNum) ciphertext))
  638.  
  639. module Ciphers.ADFGVX where
  640.  
  641. import Control.Monad
  642. import System.Directory
  643. import Data.List
  644. import Data.Char
  645. import Data.Maybe
  646. import MyUtils
  647.  
  648. grid = sequence ["adfgvx","adfgvx"]
  649. alpha_nums = zip ['a'..'z'] [1..] ++ zip ['0'..'9'] [27..]
  650.  
  651. --creates a file with a random substitution key
  652. createSubstitutionKey :: IO()
  653. createSubstitutionKey = do
  654. let filename = "my_grid.txt"
  655. fileExists <- doesFileExist (filename)
  656. when fileExists (removeFile filename)
  657. rands <- genRandNrs 1 36--random list of alpha_nums indexes
  658. writeFile filename (toDictValue rands alpha_nums)
  659.  
  660. --fills the ADFGVX grid with the given string
  661. fillGrid :: String -> [(String,Char)]
  662. fillGrid s = zip grid s
  663.  
  664. --substitutes all chars in a string for their respecive value in the ADFGVX grid
  665. substitutionStep :: String -> [(String,Char)] -> String
  666. substitutionStep plaintext filled_grid = concat (toDictValue plaintext filled_grid)
  667.  
  668. --attributes each letter in the ciphertext to each letter of the key in a cyclic fashion
  669. --if the the ciphertext leaves blank spaces on the gird, fills it with encrypted 'a's
  670. createKeyGrid :: String -> String -> [(Char,Char)]
  671. createKeyGrid key ciphertext = zip (cycle key) fit_ciphertext
  672. where fit_ciphertext = if length (ciphertext) `mod` length (key) == 0 then ciphertext else ciphertext ++ replicate (rest) 'a'
  673. rest = length key - length (ciphertext) `mod` length (key)
  674.  
  675. --sorts the key grid columns in alphabetical order
  676. sortKeyGrid :: String -> [(Char,Char)] -> [(Char,Char)]
  677. sortKeyGrid key [] = []
  678. sortKeyGrid key keygrid = sortOn (fst) (take (length key) keygrid) ++ (sortKeyGrid key (drop (length key) keygrid))
  679.  
  680. --ouputs the key grid with the columns as lines
  681. groupByCols :: Eq a => [(a,b)] -> [(a,b)]
  682. groupByCols [] = []
  683. groupByCols [x] = [x]
  684. groupByCols (x:xs) = [x] ++ (filter (t -> fst(t) == fst(x)) xs) ++ groupByCols (filter (t2 -> fst(t2) /= fst(x)) xs)
  685.  
  686. --gives the elements of the key grid as a string
  687. transpositionStep :: String -> [(Char,Char)] -> String
  688. transpositionStep key keygrid = map (snd) (groupByCols sorted_keygrid)
  689. where sorted_keygrid = sortKeyGrid key keygrid
  690.  
  691. --given a key, sorts the key and fills the grid the same way it was on the encryption process
  692. recreateKeyGrid :: String -> String -> [(Char,String)]
  693. recreateKeyGrid key ciphertext = zip (sorted_key) (groupN nrows ciphertext)
  694. where nrows = cipher_text_size `div` key_size
  695. sorted_key = sort key
  696. cipher_text_size = length ciphertext
  697. key_size = length key
  698.  
  699. --sorts the columns of the grid by the order of the password
  700. unSortKeyGrid :: String -> [(Char,String)] -> [(Char,String)]
  701. unSortKeyGrid key [] = []
  702. unSortKeyGrid key keygrid = found : unSortKeyGrid (drop 1 key) (delete found keygrid)
  703. where found = fromJust (find (x -> fst(x) == head key) keygrid)
  704.  
  705. --get the untransposed text from the unsorted grid
  706. getPreCipherText :: [(Char,String)] -> [String]
  707. getPreCipherText keygrid = groupN 2 [s | n<-[1..nrows], s<-getNthSpacedLetters (nrows) n gridstring]--(map (head) (map (snd) keygrid)) ++ getPreCipherText (map (tail) (map (snd) keygrid))
  708. where gridstring = concat (map (snd) keygrid)
  709. nrows = length (snd (head keygrid))
  710.  
  711. --converts the untransposed text into plaintext
  712. getPlainText :: [String] -> [(String,Char)] -> String
  713. getPlainText preciphertext adfgvxgrid = map (x -> convertFrom x adfgvxgrid) preciphertext
  714.  
  715. --encryption algorithm
  716. adfgvxEncrypt :: String -> String -> String -> String
  717. adfgvxEncrypt substitution_key key plaintext = transpositionStep key keygrid
  718. where keygrid = createKeyGrid key ciphertext1
  719. ciphertext1 = substitutionStep (filter (isAlphaNum) (map (toLower) plaintext)) my_grid
  720. my_grid = fillGrid substitution_key
  721.  
  722. --decryption algorithm
  723. adfgvxDecrypt :: String -> String -> String -> String
  724. adfgvxDecrypt substitution_key key ciphertext = getPlainText preciphertext my_grid
  725. where my_grid = fillGrid substitution_key
  726. preciphertext = getPreCipherText (unSortKeyGrid key keygrid)
  727. keygrid = recreateKeyGrid key ciphertext
  728.  
  729. module Codebreaking.VigenereCrack where
  730.  
  731. import Ciphers.Caesar
  732. import Ciphers.Vigenere
  733. import Codebreaking.Cryptanalysis
  734. import MyUtils
  735. import Control.Monad
  736. import System.Exit
  737. import System.Console.ANSI
  738. import Control.Concurrent
  739. import Data.Function
  740.  
  741. --given two numbers representing the min and max size of the substrings that may repeat along the ciphertext and the ciphertext gives a list of all the possible lengths of the vigenere key
  742. guessKeyLength :: Int -> Int -> String -> [Int]
  743. guessKeyLength n1 n2 ciphertext = commonFactors (multRepeatSpacing (repeatedSubs n1 n2 ciphertext) ciphertext)
  744.  
  745. --given a list of possible keysizes and the ciphertext, splits the ciphertext into subkey parts for each possible keysize
  746. groupBySubkeys :: [Int] -> String -> [(Int,String)]
  747. groupBySubkeys sizes ciphertext = [(keysize,x) | keysize<-sizes, n<-[1..keysize], x<-[getNthSpacedLetters keysize n ciphertext]]
  748.  
  749. --attributes a frequency score to each caesar shift of the string
  750. subkeyScores :: String -> [(Char,Int)]
  751. subkeyScores s = zip alphabet [matchFreqScore shifted | shifted <- map (sortedEtaoinString) (breakCaesar s)]
  752.  
  753. --filters the most likely subkeys out of the string
  754. filterSubkey :: (Int,String) -> (Int,String)
  755. filterSubkey subkey_group = (keysize, candidates)
  756. where keysize = fst subkey_group
  757. string = snd subkey_group
  758. candidates = getHighestLetters (getHighestFreqScores (subkeyScores (string))) (subkeyScores (string))
  759.  
  760. --outputs the possible subkeys for each position of each possible key size
  761. possibleSubkeys :: [(Int,String)] -> [(Int,String)]
  762. possibleSubkeys subkey_groups = map (filterSubkey) subkey_groups
  763.  
  764. --given a keysize, ouputs the components of the key
  765. getKeysizeGroup :: Int -> [(Int,String)] -> [(Int,String)]
  766. getKeysizeGroup x group = filter (i -> fst i == x) group
  767.  
  768. --given a list of possible subkeys and the respective keysize, gives a list of all the keys for all the possible keysizes
  769. possibleKeys :: [(Int,String)] -> [String]
  770. possibleKeys subkeys = [ key | keysize <- keysizes, key<-keys keysize]
  771. where keysizes = delRepeated (map (fst) subkeys)
  772. keys x = sequence (map (snd) (getKeysizeGroup x subkeys))
  773.  
  774. --tries all the keys
  775. bruteForceKeys :: [String] -> String -> IO()
  776. bruteForceKeys [] ciphertext = putStrLn "nDone"
  777. bruteForceKeys keys ciphertext = do
  778. let key = head keys
  779. putStrLn ""
  780. putStrLn ("Attempting with key: " ++ key ++ " :")
  781. threadDelay 500000
  782. print(vigenereDecrypt key ciphertext)
  783. bruteForceKeys (drop 1 keys) ciphertext
  784.  
  785. --kasiski Algorithm
  786. --user interaction
  787. crackVigenere :: String -> IO()
  788. crackVigenere ciphertext = do
  789. putStrLn "Enter min size of repeated words:"
  790. readMin <- getLine
  791. putStrLn "Enter max size of repeated words:"
  792. readMax <- getLine
  793. let minsize = (read readMin :: Int)
  794. maxsize = (read readMax :: Int)
  795. let key_lengths = guessKeyLength minsize maxsize ciphertext
  796. --putStrLn "Possible key lengths:"
  797. clearAll
  798. putStrLn "Possible keys:"
  799. putStrLn "Calculating possible key lengths..."
  800. --print (key_lengths)
  801. let subkey_groups = groupBySubkeys key_lengths ciphertext
  802. --putStrLn "Subkey groups for each possible key size:"
  803. --print (subkey_groups)
  804. let subkeys = possibleSubkeys subkey_groups
  805. --putStrLn "Possible subkeys:"
  806. --print (subkeys)
  807. let keys = possibleKeys subkeys
  808. print (keys)
  809. forever $ do
  810. putStrLn "1 - Try a key"
  811. putStrLn "2 - Brute-force attack"
  812. putStrLn "r - Retry"
  813. putStrLn "e - Exit"
  814. input <- getLine
  815. case input of
  816. "1" -> do
  817. key <- getLine
  818. let plaintext = vigenereDecrypt key ciphertext
  819. print (plaintext)
  820. "2" -> bruteForceKeys keys ciphertext
  821. "r" -> crackVigenere ciphertext
  822. "e" -> exitSuccess
  823. otherwise -> do
  824. putStrLn "Please enter a valid option."
  825. exitFailure
  826. ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement