    {-# LANGUAGE ForeignFunctionInterface         #-}
    {-# LANGUAGE DataKinds                        #-}
    {-# LANGUAGE MultiParamTypeClasses            #-}
    {-# LANGUAGE FlexibleInstances                #-}

    -- | Portable C implementation of AES ciphers.
    module Raaz.Cipher.AES.CBC.Implementation.CPortable
           ( aes128cbcI, aes192cbcI, aes256cbcI
           ) where

    import Control.Applicative
    import Control.Monad.IO.Class   ( liftIO )
    import Foreign.Ptr              ( Ptr    )
    import Prelude

    import Raaz.Core
    import Raaz.Cipher.Internal
    import Raaz.Cipher.AES.Internal

    ------------- Memory for 128-bit cbc --------------

    -- | Memory for aes-128-cbc
    data M128 = M128 { M128 -> MemoryCell EKEY128
    m128ekey :: MemoryCell EKEY128
                     , M128 -> MemoryCell IV
    m128iv   :: MemoryCell IV
                     }

    instance Memory M128  where
      memoryAlloc :: Alloc M128
    memoryAlloc     = MemoryCell EKEY128 -> MemoryCell IV -> M128
    M128 (MemoryCell EKEY128 -> MemoryCell IV -> M128)
    -> TwistRF AllocField (BYTES Int) (MemoryCell EKEY128)
    -> TwistRF AllocField (BYTES Int) (MemoryCell IV -> M128)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> TwistRF AllocField (BYTES Int) (MemoryCell EKEY128)
    forall m. Memory m => Alloc m
    memoryAlloc TwistRF AllocField (BYTES Int) (MemoryCell IV -> M128)
    -> TwistRF AllocField (BYTES Int) (MemoryCell IV) -> Alloc M128
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> TwistRF AllocField (BYTES Int) (MemoryCell IV)
    forall m. Memory m => Alloc m
    memoryAlloc
      unsafeToPointer :: M128 -> Pointer
    unsafeToPointer = MemoryCell EKEY128 -> Pointer
    forall m. Memory m => m -> Pointer
    unsafeToPointer (MemoryCell EKEY128 -> Pointer)
    -> (M128 -> MemoryCell EKEY128) -> M128 -> Pointer
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . M128 -> MemoryCell EKEY128
    m128ekey

    instance Initialisable M128 (KEY128, IV) where
      initialise :: (KEY128, IV) -> MT M128 ()
    initialise (k :: KEY128
    k,iv :: IV
    iv) = do
        (M128 -> MemoryCell EKEY128)
    -> MT (MemoryCell EKEY128) () -> MT M128 ()
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M128 -> MemoryCell EKEY128
    m128ekey (MT (MemoryCell EKEY128) () -> MT M128 ())
    -> MT (MemoryCell EKEY128) () -> MT M128 ()
    forall a b. (a -> b) -> a -> b
    $ do KEY128 -> MT (MemoryCell EKEY128) ()
    forall m v. Initialisable m v => v -> MT m ()
    initialise KEY128
    k
                                  (Ptr EKEY128 -> IO ()) -> MT (MemoryCell EKEY128) ()
    forall (mT :: * -> * -> *) a b.
    (MemoryThread mT, Storable a) =>
    (Ptr a -> IO b) -> mT (MemoryCell a) b
    withCellPointer ((Ptr EKEY128 -> IO ()) -> MT (MemoryCell EKEY128) ())
    -> (Ptr EKEY128 -> IO ()) -> MT (MemoryCell EKEY128) ()
    forall a b. (a -> b) -> a -> b
    $ Int -> Ptr EKEY128 -> IO ()
    forall ekey. Int -> Ptr ekey -> IO ()
    c_transpose 11
        (M128 -> MemoryCell IV) -> MT (MemoryCell IV) () -> MT M128 ()
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M128 -> MemoryCell IV
    m128iv   (MT (MemoryCell IV) () -> MT M128 ())
    -> MT (MemoryCell IV) () -> MT M128 ()
    forall a b. (a -> b) -> a -> b
    $ do IV -> MT (MemoryCell IV) ()
    forall m v. Initialisable m v => v -> MT m ()
    initialise IV
    iv
                                  (Ptr IV -> IO ()) -> MT (MemoryCell IV) ()
    forall (mT :: * -> * -> *) a b.
    (MemoryThread mT, Storable a) =>
    (Ptr a -> IO b) -> mT (MemoryCell a) b
    withCellPointer ((Ptr IV -> IO ()) -> MT (MemoryCell IV) ())
    -> (Ptr IV -> IO ()) -> MT (MemoryCell IV) ()
    forall a b. (a -> b) -> a -> b
    $ Int -> Ptr IV -> IO ()
    forall ekey. Int -> Ptr ekey -> IO ()
    c_transpose 1

    ------------- Memory for 192-bit cbc --------------

    -- | Memory for aes-192-cbc
    data M192 = M192 { M192 -> MemoryCell EKEY192
    m192ekey :: MemoryCell EKEY192
                     , M192 -> MemoryCell IV
    m192iv   :: MemoryCell IV
                     }

    instance Memory M192  where
      memoryAlloc :: Alloc M192
    memoryAlloc     = MemoryCell EKEY192 -> MemoryCell IV -> M192
    M192 (MemoryCell EKEY192 -> MemoryCell IV -> M192)
    -> TwistRF AllocField (BYTES Int) (MemoryCell EKEY192)
    -> TwistRF AllocField (BYTES Int) (MemoryCell IV -> M192)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> TwistRF AllocField (BYTES Int) (MemoryCell EKEY192)
    forall m. Memory m => Alloc m
    memoryAlloc TwistRF AllocField (BYTES Int) (MemoryCell IV -> M192)
    -> TwistRF AllocField (BYTES Int) (MemoryCell IV) -> Alloc M192
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> TwistRF AllocField (BYTES Int) (MemoryCell IV)
    forall m. Memory m => Alloc m
    memoryAlloc
      unsafeToPointer :: M192 -> Pointer
    unsafeToPointer = MemoryCell EKEY192 -> Pointer
    forall m. Memory m => m -> Pointer
    unsafeToPointer (MemoryCell EKEY192 -> Pointer)
    -> (M192 -> MemoryCell EKEY192) -> M192 -> Pointer
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . M192 -> MemoryCell EKEY192
    m192ekey

    instance Initialisable M192 (KEY192, IV) where
      initialise :: (KEY192, IV) -> MT M192 ()
    initialise (k :: KEY192
    k,iv :: IV
    iv) = do
        (M192 -> MemoryCell EKEY192)
    -> MT (MemoryCell EKEY192) () -> MT M192 ()
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M192 -> MemoryCell EKEY192
    m192ekey (MT (MemoryCell EKEY192) () -> MT M192 ())
    -> MT (MemoryCell EKEY192) () -> MT M192 ()
    forall a b. (a -> b) -> a -> b
    $ do KEY192 -> MT (MemoryCell EKEY192) ()
    forall m v. Initialisable m v => v -> MT m ()
    initialise KEY192
    k
                                  (Ptr EKEY192 -> IO ()) -> MT (MemoryCell EKEY192) ()
    forall (mT :: * -> * -> *) a b.
    (MemoryThread mT, Storable a) =>
    (Ptr a -> IO b) -> mT (MemoryCell a) b
    withCellPointer ((Ptr EKEY192 -> IO ()) -> MT (MemoryCell EKEY192) ())
    -> (Ptr EKEY192 -> IO ()) -> MT (MemoryCell EKEY192) ()
    forall a b. (a -> b) -> a -> b
    $ Int -> Ptr EKEY192 -> IO ()
    forall ekey. Int -> Ptr ekey -> IO ()
    c_transpose 13
        (M192 -> MemoryCell IV) -> MT (MemoryCell IV) () -> MT M192 ()
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M192 -> MemoryCell IV
    m192iv   (MT (MemoryCell IV) () -> MT M192 ())
    -> MT (MemoryCell IV) () -> MT M192 ()
    forall a b. (a -> b) -> a -> b
    $ do IV -> MT (MemoryCell IV) ()
    forall m v. Initialisable m v => v -> MT m ()
    initialise IV
    iv
                                  (Ptr IV -> IO ()) -> MT (MemoryCell IV) ()
    forall (mT :: * -> * -> *) a b.
    (MemoryThread mT, Storable a) =>
    (Ptr a -> IO b) -> mT (MemoryCell a) b
    withCellPointer ((Ptr IV -> IO ()) -> MT (MemoryCell IV) ())
    -> (Ptr IV -> IO ()) -> MT (MemoryCell IV) ()
    forall a b. (a -> b) -> a -> b
    $ Int -> Ptr IV -> IO ()
    forall ekey. Int -> Ptr ekey -> IO ()
    c_transpose 1

    ------------- Memory for 256-bit cbc --------------

    -- | Memory for aes-256-cbc
    data M256 = M256 { M256 -> MemoryCell EKEY256
    m256ekey :: MemoryCell EKEY256
                     , M256 -> MemoryCell IV
    m256iv   :: MemoryCell IV
                     }

    instance Memory M256  where
      memoryAlloc :: Alloc M256
    memoryAlloc     = MemoryCell EKEY256 -> MemoryCell IV -> M256
    M256 (MemoryCell EKEY256 -> MemoryCell IV -> M256)
    -> TwistRF AllocField (BYTES Int) (MemoryCell EKEY256)
    -> TwistRF AllocField (BYTES Int) (MemoryCell IV -> M256)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> TwistRF AllocField (BYTES Int) (MemoryCell EKEY256)
    forall m. Memory m => Alloc m
    memoryAlloc TwistRF AllocField (BYTES Int) (MemoryCell IV -> M256)
    -> TwistRF AllocField (BYTES Int) (MemoryCell IV) -> Alloc M256
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> TwistRF AllocField (BYTES Int) (MemoryCell IV)
    forall m. Memory m => Alloc m
    memoryAlloc
      unsafeToPointer :: M256 -> Pointer
    unsafeToPointer = MemoryCell EKEY256 -> Pointer
    forall m. Memory m => m -> Pointer
    unsafeToPointer (MemoryCell EKEY256 -> Pointer)
    -> (M256 -> MemoryCell EKEY256) -> M256 -> Pointer
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . M256 -> MemoryCell EKEY256
    m256ekey

    instance Initialisable M256 (KEY256, IV) where
      initialise :: (KEY256, IV) -> MT M256 ()
    initialise (k :: KEY256
    k,iv :: IV
    iv) = do
        (M256 -> MemoryCell EKEY256)
    -> MT (MemoryCell EKEY256) () -> MT M256 ()
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M256 -> MemoryCell EKEY256
    m256ekey (MT (MemoryCell EKEY256) () -> MT M256 ())
    -> MT (MemoryCell EKEY256) () -> MT M256 ()
    forall a b. (a -> b) -> a -> b
    $ do KEY256 -> MT (MemoryCell EKEY256) ()
    forall m v. Initialisable m v => v -> MT m ()
    initialise KEY256
    k
                                  (Ptr EKEY256 -> IO ()) -> MT (MemoryCell EKEY256) ()
    forall (mT :: * -> * -> *) a b.
    (MemoryThread mT, Storable a) =>
    (Ptr a -> IO b) -> mT (MemoryCell a) b
    withCellPointer ((Ptr EKEY256 -> IO ()) -> MT (MemoryCell EKEY256) ())
    -> (Ptr EKEY256 -> IO ()) -> MT (MemoryCell EKEY256) ()
    forall a b. (a -> b) -> a -> b
    $ Int -> Ptr EKEY256 -> IO ()
    forall ekey. Int -> Ptr ekey -> IO ()
    c_transpose 15
        (M256 -> MemoryCell IV) -> MT (MemoryCell IV) () -> MT M256 ()
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M256 -> MemoryCell IV
    m256iv   (MT (MemoryCell IV) () -> MT M256 ())
    -> MT (MemoryCell IV) () -> MT M256 ()
    forall a b. (a -> b) -> a -> b
    $ do IV -> MT (MemoryCell IV) ()
    forall m v. Initialisable m v => v -> MT m ()
    initialise IV
    iv
                                  (Ptr IV -> IO ()) -> MT (MemoryCell IV) ()
    forall (mT :: * -> * -> *) a b.
    (MemoryThread mT, Storable a) =>
    (Ptr a -> IO b) -> mT (MemoryCell a) b
    withCellPointer ((Ptr IV -> IO ()) -> MT (MemoryCell IV) ())
    -> (Ptr IV -> IO ()) -> MT (MemoryCell IV) ()
    forall a b. (a -> b) -> a -> b
    $ Int -> Ptr IV -> IO ()
    forall ekey. Int -> Ptr ekey -> IO ()
    c_transpose 1

    ------------------- 128-bit CBC Implementation ----------------

    -- | Implementation of 128-bit AES in CBC mode using Portable C.
    aes128cbcI :: Implementation (AES 128 'CBC)
    aes128cbcI :: Implementation (AES 128 'CBC)
    aes128cbcI = CipherI (AES 128 'CBC) M128 M128 -> SomeCipherI (AES 128 'CBC)
    forall cipher encMem decMem.
    CipherM cipher encMem decMem =>
    CipherI cipher encMem decMem -> SomeCipherI cipher
    SomeCipherI CipherI (AES 128 'CBC) M128 M128
    cbc128CPortable

    -- | 128-bit AES in CBC mode using Portable C.
    cbc128CPortable :: CipherI (AES 128 'CBC) M128 M128
    cbc128CPortable :: CipherI (AES 128 'CBC) M128 M128
    cbc128CPortable =
      CipherI :: forall cipher encMem decMem.
    String
    -> String
    -> (Pointer -> BLOCKS cipher -> MT encMem ())
    -> (Pointer -> BLOCKS cipher -> MT decMem ())
    -> Alignment
    -> CipherI cipher encMem decMem
    CipherI { cipherIName :: String
    cipherIName = "aes128cbc-cportable"
              , cipherIDescription :: String
    cipherIDescription =
                "128-bit AES in cbc mode implemented in Portable C"
              , encryptBlocks :: Pointer -> BLOCKS (AES 128 'CBC) -> MT M128 ()
    encryptBlocks = Pointer -> BLOCKS (AES 128 'CBC) -> MT M128 ()
    cbc128Encrypt
              , decryptBlocks :: Pointer -> BLOCKS (AES 128 'CBC) -> MT M128 ()
    decryptBlocks = Pointer -> BLOCKS (AES 128 'CBC) -> MT M128 ()
    cbc128Decrypt
              , cipherStartAlignment :: Alignment
    cipherStartAlignment = Alignment
    wordAlignment
              }

    -- | The encryption action.
    cbc128Encrypt :: Pointer -> BLOCKS (AES 128 'CBC) -> MT M128 ()
    cbc128Encrypt :: Pointer -> BLOCKS (AES 128 'CBC) -> MT M128 ()
    cbc128Encrypt buf :: Pointer
    buf nBlocks :: BLOCKS (AES 128 'CBC)
    nBlocks =
      do Ptr EKEY128
    eKeyPtr <- (M128 -> MemoryCell EKEY128)
    -> MT (MemoryCell EKEY128) (Ptr EKEY128) -> MT M128 (Ptr EKEY128)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M128 -> MemoryCell EKEY128
    m128ekey MT (MemoryCell EKEY128) (Ptr EKEY128)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         Ptr IV
    ivPtr   <- (M128 -> MemoryCell IV)
    -> MT (MemoryCell IV) (Ptr IV) -> MT M128 (Ptr IV)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M128 -> MemoryCell IV
    m128iv   MT (MemoryCell IV) (Ptr IV)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         IO () -> MT M128 ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> MT M128 ()) -> IO () -> MT M128 ()
    forall a b. (a -> b) -> a -> b
    $ Pointer -> Int -> Int -> Ptr EKEY128 -> Ptr IV -> IO ()
    forall ekey iv.
    Pointer -> Int -> Int -> Ptr ekey -> Ptr iv -> IO ()
    c_aes_cbc_e Pointer
    buf (BLOCKS (AES 128 'CBC) -> Int
    forall a. Enum a => a -> Int
    fromEnum BLOCKS (AES 128 'CBC)
    nBlocks) 10 Ptr EKEY128
    eKeyPtr Ptr IV
    ivPtr

    -- | The decryption action.
    cbc128Decrypt :: Pointer -> BLOCKS (AES 128 'CBC) -> MT M128 ()
    cbc128Decrypt :: Pointer -> BLOCKS (AES 128 'CBC) -> MT M128 ()
    cbc128Decrypt buf :: Pointer
    buf nBlocks :: BLOCKS (AES 128 'CBC)
    nBlocks =
      do Ptr EKEY128
    eKeyPtr <- (M128 -> MemoryCell EKEY128)
    -> MT (MemoryCell EKEY128) (Ptr EKEY128) -> MT M128 (Ptr EKEY128)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M128 -> MemoryCell EKEY128
    m128ekey MT (MemoryCell EKEY128) (Ptr EKEY128)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         Ptr IV
    ivPtr   <- (M128 -> MemoryCell IV)
    -> MT (MemoryCell IV) (Ptr IV) -> MT M128 (Ptr IV)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M128 -> MemoryCell IV
    m128iv   MT (MemoryCell IV) (Ptr IV)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         IO () -> MT M128 ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> MT M128 ()) -> IO () -> MT M128 ()
    forall a b. (a -> b) -> a -> b
    $ Pointer -> Int -> Int -> Ptr EKEY128 -> Ptr IV -> IO ()
    forall ekey iv.
    Pointer -> Int -> Int -> Ptr ekey -> Ptr iv -> IO ()
    c_aes_cbc_d Pointer
    buf (BLOCKS (AES 128 'CBC) -> Int
    forall a. Enum a => a -> Int
    fromEnum BLOCKS (AES 128 'CBC)
    nBlocks) 10 Ptr EKEY128
    eKeyPtr Ptr IV
    ivPtr

    ------------------- 192-bit CBC Implementation ----------------

    -- | Implementation of 192-bit AES in CBC mode using Portable C.
    aes192cbcI :: Implementation (AES 192 'CBC)
    aes192cbcI :: Implementation (AES 192 'CBC)
    aes192cbcI = CipherI (AES 192 'CBC) M192 M192 -> SomeCipherI (AES 192 'CBC)
    forall cipher encMem decMem.
    CipherM cipher encMem decMem =>
    CipherI cipher encMem decMem -> SomeCipherI cipher
    SomeCipherI CipherI (AES 192 'CBC) M192 M192
    cbc192CPortable

    -- | 192-bit AES in CBC mode using Portable C.
    cbc192CPortable :: CipherI (AES 192 'CBC) M192 M192
    cbc192CPortable :: CipherI (AES 192 'CBC) M192 M192
    cbc192CPortable =
      CipherI :: forall cipher encMem decMem.
    String
    -> String
    -> (Pointer -> BLOCKS cipher -> MT encMem ())
    -> (Pointer -> BLOCKS cipher -> MT decMem ())
    -> Alignment
    -> CipherI cipher encMem decMem
    CipherI { cipherIName :: String
    cipherIName = "aes192cbc-cportable"
              , cipherIDescription :: String
    cipherIDescription =
                "192-bit AES in cbc mode implemented in Portable C"
              , encryptBlocks :: Pointer -> BLOCKS (AES 192 'CBC) -> MT M192 ()
    encryptBlocks = Pointer -> BLOCKS (AES 192 'CBC) -> MT M192 ()
    cbc192Encrypt
              , decryptBlocks :: Pointer -> BLOCKS (AES 192 'CBC) -> MT M192 ()
    decryptBlocks = Pointer -> BLOCKS (AES 192 'CBC) -> MT M192 ()
    cbc192Decrypt
              , cipherStartAlignment :: Alignment
    cipherStartAlignment = Alignment
    wordAlignment
              }

    -- | The encryption action.
    cbc192Encrypt :: Pointer -> BLOCKS (AES 192 'CBC) -> MT M192 ()
    cbc192Encrypt :: Pointer -> BLOCKS (AES 192 'CBC) -> MT M192 ()
    cbc192Encrypt buf :: Pointer
    buf nBlocks :: BLOCKS (AES 192 'CBC)
    nBlocks =
      do Ptr EKEY192
    eKeyPtr <- (M192 -> MemoryCell EKEY192)
    -> MT (MemoryCell EKEY192) (Ptr EKEY192) -> MT M192 (Ptr EKEY192)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M192 -> MemoryCell EKEY192
    m192ekey MT (MemoryCell EKEY192) (Ptr EKEY192)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         Ptr IV
    ivPtr   <- (M192 -> MemoryCell IV)
    -> MT (MemoryCell IV) (Ptr IV) -> MT M192 (Ptr IV)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M192 -> MemoryCell IV
    m192iv   MT (MemoryCell IV) (Ptr IV)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         IO () -> MT M192 ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> MT M192 ()) -> IO () -> MT M192 ()
    forall a b. (a -> b) -> a -> b
    $ Pointer -> Int -> Int -> Ptr EKEY192 -> Ptr IV -> IO ()
    forall ekey iv.
    Pointer -> Int -> Int -> Ptr ekey -> Ptr iv -> IO ()
    c_aes_cbc_e Pointer
    buf (BLOCKS (AES 192 'CBC) -> Int
    forall a. Enum a => a -> Int
    fromEnum BLOCKS (AES 192 'CBC)
    nBlocks) 12 Ptr EKEY192
    eKeyPtr Ptr IV
    ivPtr

    -- | The decryption action.
    cbc192Decrypt :: Pointer -> BLOCKS (AES 192 'CBC) -> MT M192 ()
    cbc192Decrypt :: Pointer -> BLOCKS (AES 192 'CBC) -> MT M192 ()
    cbc192Decrypt buf :: Pointer
    buf nBlocks :: BLOCKS (AES 192 'CBC)
    nBlocks =
      do Ptr EKEY192
    eKeyPtr <- (M192 -> MemoryCell EKEY192)
    -> MT (MemoryCell EKEY192) (Ptr EKEY192) -> MT M192 (Ptr EKEY192)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M192 -> MemoryCell EKEY192
    m192ekey MT (MemoryCell EKEY192) (Ptr EKEY192)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         Ptr IV
    ivPtr   <- (M192 -> MemoryCell IV)
    -> MT (MemoryCell IV) (Ptr IV) -> MT M192 (Ptr IV)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M192 -> MemoryCell IV
    m192iv   MT (MemoryCell IV) (Ptr IV)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         IO () -> MT M192 ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> MT M192 ()) -> IO () -> MT M192 ()
    forall a b. (a -> b) -> a -> b
    $ Pointer -> Int -> Int -> Ptr EKEY192 -> Ptr IV -> IO ()
    forall ekey iv.
    Pointer -> Int -> Int -> Ptr ekey -> Ptr iv -> IO ()
    c_aes_cbc_d Pointer
    buf (BLOCKS (AES 192 'CBC) -> Int
    forall a. Enum a => a -> Int
    fromEnum BLOCKS (AES 192 'CBC)
    nBlocks) 12 Ptr EKEY192
    eKeyPtr Ptr IV
    ivPtr

    ------------------- 256-bit CBC Implementation ----------------

    -- | Implementation of 256-bit AES in CBC mode using Portable C.
    aes256cbcI :: Implementation (AES 256 'CBC)
    aes256cbcI :: Implementation (AES 256 'CBC)
    aes256cbcI = CipherI (AES 256 'CBC) M256 M256 -> SomeCipherI (AES 256 'CBC)
    forall cipher encMem decMem.
    CipherM cipher encMem decMem =>
    CipherI cipher encMem decMem -> SomeCipherI cipher
    SomeCipherI CipherI (AES 256 'CBC) M256 M256
    cbc256CPortable

    -- | 256-bit AES in CBC mode using Portable C.
    cbc256CPortable :: CipherI (AES 256 'CBC) M256 M256
    cbc256CPortable :: CipherI (AES 256 'CBC) M256 M256
    cbc256CPortable =
      CipherI :: forall cipher encMem decMem.
    String
    -> String
    -> (Pointer -> BLOCKS cipher -> MT encMem ())
    -> (Pointer -> BLOCKS cipher -> MT decMem ())
    -> Alignment
    -> CipherI cipher encMem decMem
    CipherI { cipherIName :: String
    cipherIName = "aes256cbc-cportable"
              , cipherIDescription :: String
    cipherIDescription =
                "256-bit AES in cbc mode implemented in Portable C"
              , encryptBlocks :: Pointer -> BLOCKS (AES 256 'CBC) -> MT M256 ()
    encryptBlocks = Pointer -> BLOCKS (AES 256 'CBC) -> MT M256 ()
    cbc256Encrypt
              , decryptBlocks :: Pointer -> BLOCKS (AES 256 'CBC) -> MT M256 ()
    decryptBlocks = Pointer -> BLOCKS (AES 256 'CBC) -> MT M256 ()
    cbc256Decrypt
              , cipherStartAlignment :: Alignment
    cipherStartAlignment = Alignment
    wordAlignment

              }

    -- | The encryption action.
    cbc256Encrypt :: Pointer -> BLOCKS (AES 256 'CBC) -> MT M256 ()
    cbc256Encrypt :: Pointer -> BLOCKS (AES 256 'CBC) -> MT M256 ()
    cbc256Encrypt buf :: Pointer
    buf nBlocks :: BLOCKS (AES 256 'CBC)
    nBlocks =
      do Ptr EKEY256
    eKeyPtr <- (M256 -> MemoryCell EKEY256)
    -> MT (MemoryCell EKEY256) (Ptr EKEY256) -> MT M256 (Ptr EKEY256)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M256 -> MemoryCell EKEY256
    m256ekey MT (MemoryCell EKEY256) (Ptr EKEY256)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         Ptr IV
    ivPtr   <- (M256 -> MemoryCell IV)
    -> MT (MemoryCell IV) (Ptr IV) -> MT M256 (Ptr IV)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M256 -> MemoryCell IV
    m256iv   MT (MemoryCell IV) (Ptr IV)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         IO () -> MT M256 ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> MT M256 ()) -> IO () -> MT M256 ()
    forall a b. (a -> b) -> a -> b
    $ Pointer -> Int -> Int -> Ptr EKEY256 -> Ptr IV -> IO ()
    forall ekey iv.
    Pointer -> Int -> Int -> Ptr ekey -> Ptr iv -> IO ()
    c_aes_cbc_e Pointer
    buf (BLOCKS (AES 256 'CBC) -> Int
    forall a. Enum a => a -> Int
    fromEnum BLOCKS (AES 256 'CBC)
    nBlocks) 14 Ptr EKEY256
    eKeyPtr Ptr IV
    ivPtr

    -- | The decryption action.
    cbc256Decrypt :: Pointer -> BLOCKS (AES 256 'CBC) -> MT M256 ()
    cbc256Decrypt :: Pointer -> BLOCKS (AES 256 'CBC) -> MT M256 ()
    cbc256Decrypt buf :: Pointer
    buf nBlocks :: BLOCKS (AES 256 'CBC)
    nBlocks =
      do Ptr EKEY256
    eKeyPtr <- (M256 -> MemoryCell EKEY256)
    -> MT (MemoryCell EKEY256) (Ptr EKEY256) -> MT M256 (Ptr EKEY256)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M256 -> MemoryCell EKEY256
    m256ekey MT (MemoryCell EKEY256) (Ptr EKEY256)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         Ptr IV
    ivPtr   <- (M256 -> MemoryCell IV)
    -> MT (MemoryCell IV) (Ptr IV) -> MT M256 (Ptr IV)
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory M256 -> MemoryCell IV
    m256iv   MT (MemoryCell IV) (Ptr IV)
    forall (mT :: * -> * -> *) a.
    (MemoryThread mT, Storable a) =>
    mT (MemoryCell a) (Ptr a)
    getCellPointer
         IO () -> MT M256 ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> MT M256 ()) -> IO () -> MT M256 ()
    forall a b. (a -> b) -> a -> b
    $ Pointer -> Int -> Int -> Ptr EKEY256 -> Ptr IV -> IO ()
    forall ekey iv.
    Pointer -> Int -> Int -> Ptr ekey -> Ptr iv -> IO ()
    c_aes_cbc_d Pointer
    buf (BLOCKS (AES 256 'CBC) -> Int
    forall a. Enum a => a -> Int
    fromEnum BLOCKS (AES 256 'CBC)
    nBlocks) 14 Ptr EKEY256
    eKeyPtr Ptr IV
    ivPtr

    --------------------- Foreign functions ------------------------

    -- | Transpose AES matrices.
    foreign import ccall unsafe
      "raaz/cipher/aes/common.h raazAESTranspose"
      c_transpose :: Int -> Ptr ekey -> IO ()

    -- | CBC encrypt.
    foreign import ccall unsafe
      "raaz/cipher/aes/cportable.h raazAESCBCEncryptCPortable"
      c_aes_cbc_e :: Pointer  -- Input
                  -> Int      -- number of blocks
                  -> Int      -- rounds
                  -> Ptr ekey -- extended key
                  -> Ptr iv   -- iv
                  -> IO ()
    -- | CBC decrypt
    foreign import ccall unsafe
      "raaz/cipher/aes/cportable.h raazAESCBCDecryptCPortable"
      c_aes_cbc_d :: Pointer  -- Input
                  -> Int      -- number of blocks
                  -> Int      -- rounds
                  -> Ptr ekey -- extened key
                  -> Ptr iv  -- iv
                  -> IO ()