haskell – Classic Cryptography Toolkit

I've written a program in haskell that aims to allow the user to encrypt, decrypt, and decrypt / encrypt pre-electromechanical code analysis at Haskell. I want to know your opinion on this because it is my first project Haskell and my approach is slightly different from the one I would choose for other languages.
It currently supports Caesar, Vigenere and ADFGVX ciphers and allows the user to decipher the first two. It also allows the user to perform certain methods of cryptographic analysis such as counting letter / substring frequencies and substituting letters until the following occurs. user is satisfied with the result.
My code has a lot of functions set at the top level, so I'm getting a little worried if I should have defined some of them locally. I am also a little concerned about the type of my duties because some of them might be more generalized.
Keep in mind that vigenere cracking and adfgvx implementations still have work to do. For vigenere cracking, the user must manually enter the minimum and maximum size of repeated words along the ciphertext to be searched (Kasiski algorithm) and adfgvx encryption and decryption still do not work at 100% because i & # 39; m by filling in the ciphertext with the letter 'a & # 39; until it is fully inserted into the grid.

I will show you all the modules from the CLI (since it acts as the main method).

cct.hs

import Control.Monad
to import System.Exit
import System.IO
import MyUtils
import Ciphers.Cesar
import Ciphers.Vigenere
to import ciphers.ADFGVX
import Codebreaking.Cryptanalysis
import Codebreaking.VigenereCrack

caesarEncryption = do
erase everything
putStrLn ""
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Enter the team number:"
offset <- getLine
putStrLn "Enter the message:"
message <- getLine
let shift_int = (read shift :: Int) --convert the entire entry
let ciphertext = message caesarShift shift_int
erase everything
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Encrypted text:"
print (ciphertext)
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Press any key to return to the main menu."
input <- getLine
primary

vigenereEncryption = do
erase everything
putStrLn ""
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Enter the desired keyword:"
key <- getLine
putStrLn "Enter the message:"
message <- getLine
leave ciphertext = vigenereEncrypt key message
erase everything
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn ("Ciphertext:")
print (ciphertext)
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Press any key to return to the main menu."
input <- getLine
primary

adfgvxEncryption = do
erase everything
putStrLn ""
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "The program will now read the substitution key of my_grid.txt."
putStrLn "Do you want to change it (y / n)?"
input1 <- getLine
when (input1 == "y") (do createSubstitutionKey; putStrLn "Substitution key created.")
handle <- openFile "my_grid.txt" ReadMode
substitution_key <- hGetContents handle
putStrLn "Enter the desired keyword:"
key <- getLine
putStrLn "Enter the message:"
message <- getLine
let ciphertext = adfgvxEncrypt substitution_key key message
erase everything
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn ("Ciphertext:")
print (ciphertext)
putStrLn " nDo not forget to share the substitution key with the recipient"
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Press any key to return to the main menu."
input2 <- getLine
primary

caesar_decryption = do
erase everything
putStrLn ""
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Enter the team number:"
offset <- getLine
putStrLn "Enter the message:"
message <- getLine
let shift_int = (read shift :: Int) --convert the entire entry
leave the text unencrypted = message caesarShift (-shift_int)
erase everything
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Plaintext:"
print (plain text)
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Press any key to return to the main menu."
input <- getLine
primary

vigenereDecryption = do
erase everything
putStrLn ""
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Enter the keyword:"
key <- getLine
putStrLn "Enter the message:"
message <- getLine
leave the text unencrypted = the message of the key vigenereDecrypt
erase everything
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn ("Plaintext:")
print (plain text)
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Press any key to return to the main menu."
input <- getLine
primary

adfgvxDecryption = do
erase everything
putStrLn ""
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "The program will now read the substitution key of my_grid.txt."
handle <- openFile "my_grid.txt" ReadMode
substitution_key <- hGetContents handle
putStrLn "Enter the keyword:"
key <- getLine
putStrLn "Enter the message:"
message <- getLine
let textxt = adfgvxDecrypt replace_key key message
erase everything
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn ("Plaintext:")
print (plain text)
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Press any key to return to the main menu."
input <- getLine
primary

decryption = do
erase everything
putStrLn ""
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn ":: 1 - César Number ::"
putStrLn ":: 2 - Vigenere Number ::"
putStrLn ":: 3 - ADFGVX ::"
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn ":: r - Return e - Output ::"
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
contribution <- getLine
  case input of
    "1" -> caesar_decryption
"2" -> vigenereDecryption
"3" -> adfgvxDecryption
"r" -> main
"e" -> exitSuccess
otherwise -> do
putStrLn ""
putStrLn ("Please enter a valid option")
encryption

encryption = do
erase everything
putStrLn ""
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn ":: 1 - César Number ::"
putStrLn ":: 2 - Vigenere Number ::"
putStrLn ":: 3 - ADFGVX ::"
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn ":: r - Return e - Output ::"
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
contribution <- getLine
  case input of
    "1" -> caesarEncryption
"2" -> vigenereEncryption
"3" -> adfgvxEncryption
"r" -> main
"e" -> exitSuccess
otherwise -> do
putStrLn ""
putStrLn ("Please enter a valid option")
encryption

tools :: String -> String -> IO ()
tools ciphertext guess = forever $ do
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Encrypted text:"
print (ciphertext)
putStrLn ""
putStrLn "My hypothesis:"
print (guess)
putStrLn ""
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn ":: 0 - Display the frequency of the letters in descending order ::"
putStrLn ":: 1 - Break the Caesar figure ::"
putStrLn ":: 2 - Interrupting Vigenere Encryption (Babbage / Kasiski algorithm) ::"
putStrLn ":: 3 - Get repeated substrings ::"
putStrLn ":: 4 - Count occurrences of a substring ::"
putStrLn ":: 5 - Count the occurrences of a letter immediately before / after other letters ::"
putStrLn ":: 6 - Count the occurrences of a letter immediately before the other letters ::"
putStrLn ":: 7 - Count the occurrences of a letter immediately after other letters ::"
putStrLn ":: 8 - Replaces one letter with another in the encrypted text ::"
putStrLn ":: r - Back ::"
putStrLn ":: e - Exit ::"
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
contribution <- getLine
  case input of
    "0" -> make
putStrLn ""
putStrLn "Letter frequency:"
print (sortAlphabetCount encrypted text)
putStrLn ""
"1" -> do
putStrLn ""
print (breakCaesar ciphertext)
putStrLn ""
"2" -> do
putStrLn ""
putStrLn "For this tool to work, it is necessary to find substrings with multiple occurrences along the ciphertext."
crackVigenere ciphertext
"3" -> do
putStrLn ""
putStrLn "Enter the minimum size of substrings to search for:"
min_size <- getLine
putStrLn "Enter the maximum size of substrings to look for:"
max size <- getLine
      let min_size_int = (read min_size :: Int)
          max_size_int = (read max_size :: Int)
      putStrLn "Repeated substrings:"
      print (repeatedSubs min_size_int max_size_int ciphertext)
    "4" -> make
putStrLn ""
putStrLn "Enter the substring:"
substring <- getLine
      putStrLn "Occurrences:"
      print(countSubstring substring ciphertext)
      putStrLn ""
    "5" -> make
putStrLn ""
putStrLn "Enter the letter (between '& # 39; & # 39;):"
letter <- getLine
      let letter_char = (read letter :: Char)
      putStrLn "Occurrences:"
      print(countAllNeighbours letter_char ciphertext)
      putStrLn ""
    "6" -> make
putStrLn ""
putStrLn "Enter the letter (between '& # 39; & # 39;):"
letter <- getLine
      let letter_char = (read letter :: Char)
      putStrLn "Occurrences:"
      print(countAllBefore letter_char ciphertext)
      putStrLn ""
    "7" -> make
putStrLn ""
putStrLn "Enter the letter (between '& # 39; & # 39;):"
letter <- getLine
      let letter_char = (read letter :: Char)
      putStrLn "Occurrences:"
      print(countAllAfter letter_char ciphertext)
      putStrLn ""
    "8" -> make
putStrLn ""
putStrLn "Enter the letter (between") you want to replace: "
letter1 <- getLine
let letter1_char = (read letter1 :: Char)
putStrLn "Enter the letter (beween ') to be substituted with:"
letter2 <- getLine
      let letter2_char = (read letter2 :: Char)
          new_ciphertext = substitute letter1_char letter2_char guess
      putStrLn "New ciphertext:"
      print(new_ciphertext)
      tools ciphertext new_ciphertext
    "r" -> primary
"e" -> exitSuccess
otherwise -> do
putStrLn ""
putStrLn ("Please enter a valid option")
guess ciphertext tools

crack = do
erase everything
putStrLn ""
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn "Enter the message:"
encrypted text <- getLine
ciphertext ciphertext tools

main = forever $ do
erase everything
putStrLn ""
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn ":: /$$$$$$ / $$$$$$       /$$$$$$$$                                  :: "
putStrLn ":: /$$ __ $$         /$$ __ $$     | __  $$ __ / :: "
putStrLn ":: | $$  __ / /$$ / $$ | $$ __ / / $$ /$$ | $$                                     :: "
putStrLn ":: | $$ | __ / | __ / | $$      | __ / | __ / | $$ :: "
putStrLn ":: | $$              | $$ | $$                                     :: "
putStrLn ":: | $$ $$ /$$ / $$| $$ $$ /$$ / $$| $$ :: "
putStrLn ":: | $$$$$$/ | __ / | __ / |  $$$$$$ / | __ / | __ / | $$                                     :: "
putStrLn ":: | ______ / | ______ / | __ / ::"
putStrLn ":::::::: Classic Cryptography Toolbox :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: : :::::::: "
putStrLn ":: ::"
putStrLn ":: What would you like to do? ::"
putStrLn ":: ::"
putStrLn ":: 1 - Crypt a message ::"
putStrLn ":: 2 - Decrypt a message ::"
putStrLn ":: 3 - Cryptanalysis an encrypted message ::"
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
putStrLn ":: e - Exit ::"
putStr ::::::::::::::::::::::::::::::::::::::::::::::::: ::: ::::::::::::::::::::::::::::::::::::::::::::::: ::::::
contribution <- getLine
  case input of
    "1" -> encryption
"2" -> decryption
"3" -> crack
"e" -> exitSuccess
otherwise -> do
putStrLn ""
putStrLn ("Please enter a valid option")
primary

MyUtils.hs

MyUtils module where

import Data.Char
import Data.List
import System.Console.ANSI
import System.Random

- Tiny letter in int conversion
let2int :: Char -> Int
let2int c = ord c - ord & # 39; a & # 39;

--int in lowercase letter conversion
int2let :: Int -> Char
int2let n = chr (ord 'a' + n)

--converts an entire string into an array of ints (each character -> int)
text2ints :: String -> [Int]
text2ints xs = card (let2int) xs

--convrets an array of ints into a string (each integer -> char)
ints2text :: [Int] -> String
ints2text xs = map (int2let) xs

- shifts the letters n tiny data
shift :: Int -> Char -> Char
offset n c | isLower c = int2let ((let2int c + n) `model` 26)
| otherwise = c

--get the factors of n
factors :: Int -> [Int]
factors n =[X|x[X|x[x|x[x|x<-[2..n], n`mod`x == 0]

--deletes all occurrences of an element within a list
deleteAll :: Eq a => a -> [a] -> [a]
deleteAll x s = filter (/ = x) s

- gives a list of all items that have multiple occurrences in a list
is equal to :: Eq a => [a] -> [a]
equals [] = []
is equal to (x: xs)
| elem x xs = x: equal to (deleteAll x xs)
| otherwise = equal to xs

- gives a list of all elements common to all lists in a list of lists
commonElems :: Eq a =>[[[[[a]]-> [a]
commonElems l = equals[X|y<-lx[X|y<-lx[x|y<-lx[x|y<-lx<-y, length (filter (elem x) l) == length l]

--gives a list of all the factors in common to all the integers in a list
commonFactors :: [Int] -> [Int]



commonFactors xs
| length xs == 1 = factors (head (xs))
otherwise = commonElems[Facteursx|X[Factorsx|x[facteursx|X[factorsx|x<-xs]

--gives a list of the indexes of each occurrence of a substring within a string
matchIndices :: (Eq a, Num b, Enum b) => [a]    -> [a] -> [b]
needle matchIndices = fst card. filter (isPrefixOf needle .snd). Zip *: French [0..] . tails

- gives a list of the lengths between each consecutive occurrence of a substring in a string
spaceBetween :: String -> String -> [Int]
spaceBetween needle = diffs. MatchIndices Needle - calculates the difference between each consecutive index
where diffs xs = zipWith (flip (-)) xs (tail xs)

--count the space between the first occurrence of a subtring and the next one in a string
repeatSpacing :: String -> String -> Int
repeatSpacing substring ciphertext
| spaceBetween substring ciphertext == [] = 0
otherwise = header (spaceBetween (substring) (ciphertext))

- gives a list of the lengths between the first occurrence of several substrings and the next respective occurrence
multRepeatSpacing :: [String] -> String -> [Int]
multRepeatSpacing substrings ciphertext =[Y|x<-substringsy[Y|x<-substringsy[y|x<-substringsy[y|x<-substringsy<-[repeatSpacing x ciphertext]]

--gets all chars n chars away from each other
getSpacedLetters :: Int -> String -> String
getSpacedLetters n (x: xs)
| n> length xs = [x]
  otherwise = x: getSpacedLetters n (drop (n-1) xs)

- eliminates all "size" characters from each other from the nth position
getNthSpacedLetters :: Int -> Int -> String -> String
getNthSpacedLetters size n s
| n> length s = ""
otherwise = getSpacedLetters size (drop (n-1) s)

- delete all tuples with x as fst
removeAllTuplesByInt :: Int -> [(a,Int)] -> [(a,Int)]
removeAllThePlusByInt x [] = []
removeAllTuplesByInt x list
| snd (list of header) / = x = list of header: removeAllTuplesByInt x (end list)
otherwise = removeAllTuplesByInt x (checklist)

--get the index of a character in a type dictionary [(Char,Integer)]
getDictIndex :: Eq a => a -> [(a,Integer)] -> Whole
getDictIndex c [key]
  | c == key fst = key snd
otherwise = error "none of these elements"
getDictIndex c dict
| c == fst (head dict) = snd (head dict)
| otherwise = getDictIndex c (queue dict)

- gives a list of elements of a list without repeating them
delRepeated :: Eq a => [a] -> [a]
delRepeated [] = []
delRepeated list = x: delRepeated (deleteAll x (final list))
where x = list of heads

- clears the terminal and sets the cursor to 0 0
clearAll :: IO ()
clearAll = do
clean screen
setCursorPosition 0 0

--converts something of type a to the corresponding value of type b in a dictionary of the type [(b,a)]
convertTo :: Eq a => a -> [(b,a)]-> b
convertTo x [] = error ("int not found in the dict")
convertTo x dict
| x == (snd (head dict)) = fst (head dict)
otherwise = convertTo x (final dictation)

convertFrom :: Eq a => a -> [(a,b)] -> b
convertFrom x [] = error ("not found in the dict")
convertFrom x dict
| x == (fst (head dict)) = snd (head dict)
otherwise = convertFrom x (queue dictation)

--converts a complete list into the corresponding dictionary values
toDictValue :: Eq a => [a] -> [(b,a)] -> [b]
toDictValue ns dict = map ( x -> convertTo x dict) ns

--generates a list of different random integers from n1 to n2 of size n2
genRandNrs :: Integer -> Integer -> IO ([Integer])
genRandNrs n1 n2 = do
g <- newStdGen
  return (take (fromIntegral n2) (nub (randomRs (n1,n2) g :: [Integer])))

--groups the given list in a list of lists in, n by n
groupN:: Int -> [a]    ->[[[[[a]]groupN 0 _ = []
group size [] = []
size groupN s = (take (size) s): size groupN (size of the drop s)

Cryptanalyse.hs

Codebreaking.Cryptanalysis module where

import Data.Char
import Data.List
import Data.Function
import MyUtils

alphabet = "abcdefghijklmnopqrstuvwxyz"

- most frequent at least frequent letters in English with respective index
etaoin = zip "etaoinshrdlcumwfgypbvvkjxqz" [1..]

en_letter_most_freq = "etaoin" - most English letters
en_letter_least_freq = "vkjxqz" - less English letters

--count the number of occurrences of a character in a string
count :: Char -> String -> Int
count one [x]
  | a == x = 1
| otherwise = 0
count one (x: xs)
| a == x = 1 + count at xs
if not = count an xs

--count the number of occurrences of a string in another string
countSubstring :: String -> String -> Int
countSubstring s1 s2
| length s1> length s2 = 0
| take (length s1) s2 == s1 = 1 + countSubstring s1 (drop 1 s2)
| otherwise = countSubstring s1 (drop 1 s2)

--given a number m and a string, look for all substrings of size n having multiple occurrences on the given string
repeatSubsBySize :: Int -> String -> [String]
RepeatedUnderBy Size n [] = []
RepeatedUnParSize ns
| countSubstring (take n s) s> 1 = (take n s): RepeatSubsBySize n (drop 1 s)
otherwise = repeatSubsBySize n (drop 1 s)

- Finds all substrings of size between n1 and n2 having multiple occurrences on the given string.
ReplySubs :: Int -> Int -> String -> [String]
RepeatedSubs n1 n2 [] = []
RepeatedSubs n1 n2 s = [sub | n<-[n1..n2]under<-repeatedSubsBySize n s]

--counts the number of ocurrences of each letter of the alphabet in a string
countAlphabet :: String -> [(Char, Int)]



countAlphabet s =[(Lettreseproduit)|letter<-alphabetseproduit[(Letteroccurs)|letter<-alphabetoccurs[(lettreseproduit)|lettre<-alphabetseproduit[(letteroccurs)|letter<-alphabetoccurs<-[count letter s]]

--outputs the result of count alphabet from the most frequent letter to the least
sortAlphabetCount :: String -> [(Char, Int)]



sortAlphabetCount s = reverse (sortOn (snd) (countAlphabet s))

--substitutes all occurrences of c1 by c2 on the given string
Substitute :: Char -> Char -> String -> String
substitute c1 c2 [] = []
substitute c1 c2 (x: xs)
| c1 == x = toUpper c2: substitute c1 c2 xs
otherwise = x: substitute c1 c2 xs

--count the occurrences of c1 immediately before c2
countBefore :: Char -> Char -> String -> Int
accountBefore c1 c2 [x] = 0
countAvant c1 c2 (x: xs)
| head xs == c2 && x == c1 = 1 + countBefore c1 c2 xs
| otherwise = 0 + countBefore c1 c2 xs

--count the occurrences of c1 immediately after c2
countAfter :: Char -> Char -> String -> Int
countAfter c1 c2 [x] = 0
countAfter c1 c2 (x: xs)
| x == c2 && head xs == c1 = 1 + countAfter c1 c2 xs
otherwise = 0 + numberAfter c1 c2 xs

- count occurrences of c1 immediately before or after c2
countNeighbors :: Char -> Char -> String -> Int
countNeighbors c1 c2 s = (countAvant c1 c2 s) + (countAfter c1 c2 s)

--count occurrences of c immediately before or after each letter of the alphabet
countAllNeighbors :: Char -> String -> [(Char, Int)]
countAllNeighbours c s =[(Lettreseproduit)|letter<-alphabetseproduit[(Letteroccurs)|letter<-alphabetoccurs[(lettreseproduit)|lettre<-alphabetseproduit[(letteroccurs)|letter<-alphabetoccurs<-[countNeighbours c letter s]]

--counts the occurrences of c immediately before every letter of the alphabet
countAllBefore :: Char -> String -> [(Char, Int)]
countAllBefore c s =[(Lettreseproduit)|letter<-alphabetseproduit[(Letteroccurs)|letter<-alphabetoccurs[(lettreseproduit)|lettre<-alphabetseproduit[(letteroccurs)|letter<-alphabetoccurs<-[countBefore c letter s]]

--counts the occurrences of c immediately after every letter of the alphabet
countAllAfter :: Char -> String -> [(Char, Int)]
countAllAfter c s =[(Lettreseproduit)|letter<-alphabetseproduit[(Letteroccurs)|letter<-alphabetoccurs[(lettreseproduit)|lettre<-alphabetseproduit[(letteroccurs)|letter<-alphabetoccurs<-[countAfter c letter s]]

--attributes a letter frequency score to the first 6 letters in a string
matchFreqScoreFirst :: String -> Int
matchFreqScoreFirst [] = 0
matchFreqScoreFirst s
| elem (head sort_first) en_letter_most_freq = 1 + matchFreqScoreFirst (upload 1 sort_first)
| else = 0 + matchFreqScoreFirst (drop 1 sort_first)
where sort_first = takes 6 s

- assigns a letter frequency score to the last 6 letters of a string
matchFreqScoreLast :: String -> Int
matchFreqScoreLast [] = 0
matchFreqScoreLast s
| elem (head sort_last) en_letter_least_freq = 1 + matchFreqScoreLast (drop 1 sort_last)
otherwise = 0 + matchFreqScoreLast (drop 1 sort_last)
where sort_last = takes 6 (s inverse)

--shows the chains in the tuple in reverse order ETAOIN
reverseEtaoinSortFreqs :: [(Int, String)] -> [(Int, String)]
reverseEtaoinSortFreqs [] = []
reverseEtaoinSortFreqs [x]
  | length (snd x)> 1 = [(fst x, reverseEtaoinSort (snd x))]
  | otherwise = [x]
reverseEtaoinSortFreqs (x: xs)
| length (snd x)> 1 = (fst x, reverseEtaoinSort (snd x)): reverseEtaoinSortFreqs xs
otherwise = x: reverseEtaoinSortFreqs xs

- gives a list of frequencies and the corresponding group of letters
sortFreqToLetters :: String -> [(Int, String)]
sortFreqToLetters s = reverseEtaoinSortFreqs[(Snd(headgr)mapfstgr)|gr[(Snd(headgr)mapfstgr)|gr[(snd(headgr)mapfstgr)|gr[(snd(headgr)mapfstgr)|gr<- groupBy ((==) `on` snd) (sorted_freqs)]
    where
      sorted_freqs = (sortAlphabetCount s)

--inserts a letter in a "reverse_etaoin" ordered string keeping its order
reverseEtaoinInsert :: Char -> String -> String
reverseEtaoinInsert c [] = [c]
reverseEtaoinInsert c (x: xs)
| (getDictIndex c etaoin)> (getDictIndex x etaoin) = c: x: xs
otherwise = x: reverseEtaoinInsert c xs

--sort a string in the order ETAOIN reverse
reverseEtaoinSort :: String -> String
reverseEtaoinSort [] = []
reverseEtaoinSort (x: xs) = reverseEtaInInsert x (reverseEtaoinSort xs)

- gives the highest 2 ints in the lust of (Char, Int)
getHighestFreqScores :: [(Char,Int)] -> [Int]
scores getHighestFreqScores = [maximum (map (snd) scores),maximum (map (snd) rest)]
  where rest = removeAllTuplesByInt (maximum scores (map scores (snd)))

- sends the letters corresponding to the highest scores given
getHighestLetters :: [Int] -> [(Char,Int)] -> String
getHighestLetters the best scores [] = []
getHighestLetters highest scores
| elem (snd (top scores)) highest scores = fst (top scores): getHighestLetters highest scores (tail scores)
| otherwise = getHighestLetters highest scores (tail scores)

--given a sorted string reverse_etaoin, assigns a frequency matching score
matchFreqScore :: String -> Int
matchFreqScore s = matchFreqScoreFirst s + matchFreqScoreLast s

--get the sorted string in reverse order of a string
sortedEtaoinString :: String -> String
sortedEtaoinString x = concat (map (snd) (init (sortFreqToLetters x))))

César.hs

Ciphers.Cesar module where

import MyUtils
import Data.Char

--encrypte (n) or decrypt (-n)
caesarShift :: Int -> String -> String
caesarShift n xs =[Décalagenx|X[Shiftnx|x[décalagenx|X[shiftnx|x<- map (toLower) xs]

--given a string, shifts it 26 times and generates a list with all of the shifted strings
--one of the elements might mean something
breakCaesar :: String -> [String]



breakCaesar xs = [s | n<-[(0)..(25)], s <- [caesarShift (-n) (map (toLower) xs)]]

Vigenere.hs

Ciphers.Vigenere module where

import MyUtils
import Data.Char

--encrypts the plain text with the given key
vigenereEncrypt :: String -> String -> String
vigenereEncrypt key plain text = result ints2text
where result = map (`mod` 26) (zipWith (+) keyCycle intPlainText)
keyCycle = (cycle (key text2ints))
intPlainText = text2ints (map (toLower) (filter (isAlphaNum) plain text))

--decrypt the encrypted text with the given key
vigenereDecrypt :: String -> String -> String
vigenereDecrypt key ciphertext = result ints2text
where result = map (`mod` 26) (zipWith (-) intciphertext keyCycle)
keyCycle = (cycle (key text2ints))
intciphertext = text2ints (map (toLower) (filter (isAlphaNum) ciphertext))

ADFGVX.hs

module Ciphers.ADFGVX where

import Control.Monad
to import System.Directory
import Data.List
import Data.Char
Import Data.Maybe
import MyUtils

grid = sequence ["adfgvx","adfgvx"]
alpha_nums = zip ['a'..'z'] [1..]    ++ zip ['0'..'9'] [27..]







- creates a file with a random substitution key
createSubstitutionKey :: IO ()
createSubstitutionKey = do
let filename = "my_grid.txt"
fileExists <- doesFileExist (filename)
when fileExists (file name removeFile)
Rands <- genRandNrs 1 36--random list of alpha_nums indexes
  writeFile filename (toDictValue rands alpha_nums)

--fills the ADFGVX grid with the given string
fillGrid :: String -> [(String,Char)]



fillGrid s = zip grid s

- replace all the characters of a string by their respective values ​​in the grid ADFGVX
substitutionStep :: String -> [(String,Char)] -> String
substitutionStep plain text filled_grid = concat (toDictValue plain text filled_grid)

- assigns each letter of the ciphertext to each letter of the key cyclically
- if the ciphertext leaves empty spaces on the belt, fills it with "a" encrypted
createKeyGrid :: String -> String -> [(Char,Char)]
createKeyGrid key ciphertext = zip (cycle key) fit_ciphertext
where fit_ciphertext = if length (ciphertext) `mod` length (key) == 0 then ciphertext other ciphertext ++ replicate (remainder) a & # 39;
remainder = key length - length (ciphertext) `mod` length (key)

--sort the columns of the key grid in alphabetical order
sortKeyGrid :: String -> [(Char,Char)] -> [(Char,Char)]
SortKeyGrid key [] = []
key sortKeyGrid keygrid = sortOn (fst) (hold key (length key)) ++ (SortKeyGrid key key (key length))

--guts the key grid with the columns as lines
groupByCols :: Eq a => [(a,b)] -> [(a,b)]
groupByCols [] = []
groupByCols [x] = [x]
groupByCols (x: xs) = [x] ++ (filter ( t -> fst (t) == fst (x)) xs) ++ groupByCols (filter ( t2 -> fst (t2) / = fst (x)) xs)

--give the elements of the key grid as a string
transpositionStep :: String -> [(Char,Char)] -> String
transpositionStep key keygrid = map (snd) (groupByCols saved_keygrid)
where trie-clégrid = KeyKeyGrid sort key

- with a key, sorts the key and fills the grid in the same way as during the encryption process
recreateKeyGrid :: String -> String -> [(Char,String)]
recreateKeyGrid key ciphertext = zip (key-sort) (groupN nrows ciphertext)
where nrows = cipher_text_size `div` key_size
sorted key = sort key
cipher_text_size = length ciphertext
key-size = key length

--sort the columns of the grid by the order of the password
unSortKeyGrid :: String -> [(Char,String)] -> [(Char,String)]
unSortKeyGrid key [] = []
unSortKeyGrid key keygrid = found: unSortKeyGrid (remove 1 key) (delete key found)
where found = fromJust (search ( x -> fst (x) == master key) keygrid)

- retrieve untransposed text from unsorted grid
getPreCipherText :: [(Char,String)] -> [String]
getPreCipherText keygrid = groupN 2 [s | n<-[1..nrows], s<-getNthSpacedLetters (nrows) n gridstring]--(map (head) (map (snd) keygrid)) ++ getPreCipherText (map (tail) (map (snd) keygrid))
  where gridstring = concat (map (snd) keygrid)
        nrows = length (snd (head keygrid))

--converts the untransposed text into plaintext
getPlainText :: [String] -> [(String,Char)]    -> String
getPlainText preciphertext adfgvxgrid = map ( x -> convertFrom x adfgvxgrid) preciphertext

--Algorithm of encryption
adfgvxEncrypt :: String -> String -> String -> String
adfgvxEncrypt key_substitution_solution plain text = keySimposition transpositionStep
where keygrid = createKeyGrid key ciphertext1
ciphertext1 = substitutionStep (filter (isAlphaNum) (map (at the bottom of the text))) my_grid
my_grid = fillGrid substitution_key

- decryption algorithm
adfgvxDecrypt :: String -> String -> String -> String
adfgvxDecrypt override key encryption key = getPlainText preciphertext my_grid
where my_grid = fillGrid substitution_key
preciphertext = getPreCipherText (unSortKeyGrid key keygrid)
keygrid = recreateKeyGrid encrypted text key

VigenereCrack.hs

Codebreaking.VigenereCrack module where

import Ciphers.Cesar
import Ciphers.Vigenere
import Codebreaking.Cryptanalysis
import MyUtils
import Control.Monad
to import System.Exit
import System.Console.ANSI
import Control.Concurrent
import Data.Function

- given two numbers representing the min and max sizes of the substrings that can be repeated along the ciphertext and the ciphertext provides a list of all possible lengths of the vigenere key
guessKeyLength :: Int -> Int -> String -> [Int]
guessKeyLength n1 n2 cryptogram = commonFactors (multRepeatSpacing (repeatedSubs n1 n2 cryptogram) cryptogram)

- with a list of possible key sizes and encrypted text, divides the ciphertext into subkey parts for each possible key size
groupBySubkeys :: [Int] -> String -> [(Int,String)]
sizes groupBySubkeys ciphertext = [(keysize,x) | keysize<-sizes, n<-[1..keysize], X<-[getNthSpacedLetters keysize n ciphertext]]

--attributes a frequency score to each caesar shift of the string
subkeyScores :: String -> [(Char,Int)]



subkeyScores s = zip alphabet[MatchFreqScoredécalé|moved[MatchFreqScoreshifted|-shifted[matchFreqScoredécalé|déplacé[matchFreqScoreshifted|shifted<- map (sortedEtaoinString) (breakCaesar s)]

--filters the most likely subkeys out of the string
filterSubkey :: (Int,String) -> (Int, String)
filterSubkey subkey_group = (key size, candidates)
where keysize = fst subkey_group
string = snd subkey_group
candidates = getHighestLetters (getHighestFreqScores (subkeyScores (string))) (subkeyScores (string))

- sort the possible subkeys for each position of each possible key size
Possible keys :: [(Int,String)] -> [(Int,String)]
possibleSubkeys subkey_groups = map (filterSubkey) subkey_groups

--with a key size, removes key components
getKeysizeGroup :: Int -> [(Int,String)] -> [(Int,String)]
getKeysizeGroup x group = group of filters ( i -> fst i == x)

- gives a list of possible sub-keys and their respective size, gives the list of all keys for all possible sizes
possibleKeys :: [(Int,String)] -> [String]
possibleKeys subkeys =[Key|tailledeclé<-tailledecléclé[Key|keysize<-keysizeskey[clé|tailledeclé<-tailledecléclé[key|keysize<-keysizeskey<-keys keysize]
  where keysizes = delRepeated (map (fst) subkeys)
        keys x = sequence (map (snd) (getKeysizeGroup x subkeys))

--tries all the keys
bruteForceKeys :: [String] -> String -> IO ()
bruteForceKeys [] ciphertext = putStrLn " nDone"
rawForceKeys key ciphertext = do
leave key = head keys
putStrLn ""
putStrLn ("Attempt with the key:" ++ key ++ ":")
threadDelay 500000
print (vigenereDecrypt key ciphertext)
bruteForceKeys (drop 1 keys) ciphertext

--kasiski Algorithm
--interaction of the user
crackVigenere :: String -> IO ()
crackVigenere ciphertext = do
putStrLn "Enter the minimum size of repeated words:"
readMin <- getLine
putStrLn "Enter the maximum size of repeated words:"
readMax <- getLine
let minsize = (read readMin :: Int)
maxsize = (read readMax :: Int)
let key_lengths = guessKeyLength minimum size encrypted text
--putStrLn "Key length possible:"
erase everything
putStrLn "Possible keys:"
putStrLn "Calculation of possible key lengths ..."
--print (key lengths)
let subkey_groups = groupBySubkeys key length of encrypted text
--putStrLn "Subkey groups for each possible key size:"
--print (subkey_groups)
let subkeys = possibleSubkeys subkey_groups
--putStrLn "Possible sub-keys:"
--print (subkeys)
let keys = possibleKeys subkeys
print (keys)
forever to do $
putStrLn "1 - Try a key"
putStrLn "2 - brute force attack"
putStrLn "r - Retry"
putStrLn "e - Exit"
contribution <- getLine
  case input of
    "1" -> make
key <- getLine
      let plaintext = vigenereDecrypt key ciphertext
      print (plaintext)
    "2" -> bruteForceKeys key ciphertext
"r" -> crackVigenere cryptogram
"e" -> exitSuccess
otherwise -> do
putStrLn "Please enter a valid option."
exitFailure
`` `