1 May 2021
Implementing a Feistel Cipher in Haskell
I was reading about Feistel Ciphers, and thought it would be fun to implement a toy one. I have shared it below.
Wikipedia Feistel Cipher ArticleGithub Gist: Haskell Feistel Cipher
module Main where
import Data.Bits
type HashFunction = Int -> [Int] -> [Int]
data KeyGen = KeyGen (Int -> Int) Int
feistel :: HashFunction -> Int -> KeyGen -> Bool -> [Int] -> [Int]
feistel f n keyGen decode plain =
let (l, r) = foldl (pass f) (splitInHalf plain) (keys keyGen n decode)
in r ++ l
pass :: HashFunction -> ([Int], [Int]) -> Int -> ([Int], [Int])
pass f (l0, r0) k =
let l1 = r0
r1 = zipWith xor l0 (f k r0)
in (l1, r1)
splitInHalf :: [a] -> ([a], [a])
splitInHalf = splitAt =<< (`div` 2) . length
keys :: KeyGen -> Int -> Bool -> [Int]
keys keyGen n decode = (if decode then reverse else id) $ gen keyGen n
gen :: KeyGen -> Int -> [Int]
gen (KeyGen f seed) len = take len $ iterate f seed
-- Example usage
main :: IO ()
main =
let hashFunc x = map (+ x) -- yeah obviously this is a bad hash function
numOfPasses = 10
keyGen = KeyGen (* 2) 1 -- and this is not a good keyGen function or seed
plainText = "A Secret Message"
blockSize = 32
paddedPlainText =
if length plainText > blockSize
then take blockSize plainText
else plainText ++ replicate (blockSize - length plainText) ' '
x0 = map fromEnum paddedPlainText
x1 = feistel hashFunc numOfPasses keyGen True x0
x2 = feistel hashFunc numOfPasses keyGen False x1
x3 = feistel hashFunc numOfPasses keyGen True x2
x4 = feistel hashFunc numOfPasses keyGen False x3
in mapM_ print $ plainText : map (map toEnum) [x0, x1, x2, x3, x4]
A nice diagram copied from Wikipedia: (source)