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)

Feistel Cipher Image from Wikipedia

Tags: Haskell