    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Coded.Encryption.Blowfish
    -- Copyright   :  (c) Dominic Steinitz 2003
    -- License     :  BSD-style (see the file ReadMe.tex)
    --
    -- Maintainer  :  dominic.steinitz@blueyonder.co.uk
    -- Stability   :  experimental
    -- Portability :  non-portable
    --
    -- Takes the Blowfish module supplied by Doug Hoyte and wraps it so it can
    -- used with the standard modes.
    --
    -----------------------------------------------------------------------------

    module Codec.Encryption.Blowfish
       (
       -- * Function Types
       encrypt,
       decrypt
       ) where

    import Data.Bits
    import Data.Word
    import Data.Char
    import Codec.Utils
    import Codec.Encryption.BlowfishAux

    -- * Basic Blowfish Encryption

    -- | Basic Blowfish encryption which takes a key and a block of plaintext
    -- and returns the encrypted block of ciphertext according to the standard.
    -- Typical keys are Word8, Word16, Word32, Word64, Word128. See
    -- <http://www.counterpane.com/vectors.txt>.

    encrypt :: (Integral a) => a -> Word64 -> Word64
    encrypt k p = mergeWord32 (lo,hi) where
       lo = head e
       hi = head $ tail e
       e = bfEnc (bfMakeKey (map (chr . fromIntegral) (toOctets 256 k))) [lo',hi']
       (lo',hi') = (splitZord64 p)

    -- | Basic Blowfish decryption which takes a key and a block of ciphertext
    -- and returns the decrypted block of plaintext.

    decrypt :: (Integral a) => a -> Word64 -> Word64
    decrypt k p = mergeWord32 (lo,hi) where
       lo = head d
       hi = head $ tail d
       d = bfDec (bfMakeKey (map (chr . fromIntegral) (toOctets 256 k))) [lo',hi']
       (lo',hi') = splitZord64 p

    splitZord64 :: Word64 -> (Word32,Word32)
    splitZord64 x = (fromIntegral (shiftR (x .&. 0xffffffff00000000) 32),
                     fromIntegral (x .&. 0x00000000ffffffff))

    mergeWord32 :: (Word32,Word32) -> Word64
    mergeWord32 (lo,hi) = shift (fromIntegral lo) 32 + fromIntegral hi