-----------------------------------------------------------------------------
-- |
-- Module      :  Codec.Encryption.Modes
-- Copyright   :  (c) Dominic Steinitz 2001-2003
-- License     :  BSD-style (see the file ReadMe.tex)
-- 
-- Maintainer  :  dominic.steinitz@blueyonder.co.uk
-- Stability   :  experimental
-- Portability :  portable
--
-- This module currently supports Cipher Block Chaining (CBC) mode.
-- See <http://www.itl.nist.gov/fipspubs/fip81.htm> for further details.
-- 
-----------------------------------------------------------------------------

module Codec.Encryption.Modes (
   -- * Function types
   cbc, unCbc 
	      ) where

import Data.Word
import Data.Bits

-- * CBC or Cipher Block Chaining Mode

-- | In CBC or Cipher Block Chaining mode each block is XORed with 
-- the previous enciphered block before encryption.  For the first 
-- block, start with an initialization vector.
-- Take an encryption function, an initialisation vector, a key and
-- a list of blocks and return the encrypted blocks using CBC.

cbc :: Bits block =>
       (key -> block -> block) -> 
       block -> 
       key ->
       [block] -> 
       [block]

cbc e iv k ps = 
   ciphers where
      ciphers = map (e k) feedIns
      feedIns = zipWith xor (iv : ciphers) ps

-- | To  decipher in CBC or Cipher Block Chaining mode, decipher 
-- each block, then XOR the result with the previous block of 
-- plaintext result.  Note that the initialization vector is treated as the 
-- zeroth block of plaintext.
-- Take a decryption function, an initialisation vector, a key and a list
-- of encrypted blocks using CBC and return plaintext blocks.

unCbc :: Bits block =>
         (key -> block -> block) -> 
         block -> 
         key ->
         [block] -> 
         [block]

unCbc d iv k ms =
   outOfCbcs where
      beforeXOrs = map (d k) ms
      outOfCbcs  = zipWith xor (iv : ms) beforeXOrs