    -- Cryptonite.hs: shim for cryptonite
    -- Copyright © 2016  Clint Adams
    -- This software is released under the terms of the Expat license.
    -- (See the LICENSE file).
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE PackageImports #-}
    {-# LANGUAGE UndecidableInstances #-}

    module Codec.Encryption.OpenPGP.Internal.Cryptonite
      ( HOWrappedCCT(..)
      ) where

    import Control.Error.Util (note)
    import qualified "cryptonite" Crypto.Cipher.Types as CCT
    import qualified Crypto.Error as CE
    import Data.Bifunctor (bimap)
    import qualified Data.ByteString as B

    import Codec.Encryption.OpenPGP.Internal.HOBlockCipher

    newtype HOWrappedCCT a =
      HWCCT a

    instance CCT.BlockCipher cipher => HOBlockCipher (HOWrappedCCT cipher) where
      cipherInit :: ByteString -> Either String (HOWrappedCCT cipher)
    cipherInit = (CryptoError -> String)
    -> (cipher -> HOWrappedCCT cipher)
    -> Either CryptoError cipher
    -> Either String (HOWrappedCCT cipher)
    forall (p :: * -> * -> *) a b c d.
    Bifunctor p =>
    (a -> b) -> (c -> d) -> p a c -> p b d
    bimap CryptoError -> String
    forall a. Show a => a -> String
    show cipher -> HOWrappedCCT cipher
    forall a. a -> HOWrappedCCT a
    HWCCT (Either CryptoError cipher -> Either String (HOWrappedCCT cipher))
    -> (ByteString -> Either CryptoError cipher)
    -> ByteString
    -> Either String (HOWrappedCCT cipher)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CryptoFailable cipher -> Either CryptoError cipher
    forall a. CryptoFailable a -> Either CryptoError a
    CE.eitherCryptoError (CryptoFailable cipher -> Either CryptoError cipher)
    -> (ByteString -> CryptoFailable cipher)
    -> ByteString
    -> Either CryptoError cipher
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> CryptoFailable cipher
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    CCT.cipherInit
      cipherName :: HOWrappedCCT cipher -> String
    cipherName (HWCCT c :: cipher
    c) = cipher -> String
    forall cipher. Cipher cipher => cipher -> String
    CCT.cipherName cipher
    c
      cipherKeySize :: HOWrappedCCT cipher -> KeySizeSpecifier
    cipherKeySize (HWCCT c :: cipher
    c) = cipher -> KeySizeSpecifier
    forall cipher. Cipher cipher => cipher -> KeySizeSpecifier
    CCT.cipherKeySize cipher
    c
      blockSize :: HOWrappedCCT cipher -> Int
    blockSize (HWCCT c :: cipher
    c) = cipher -> Int
    forall cipher. BlockCipher cipher => cipher -> Int
    CCT.blockSize cipher
    c
      cfbEncrypt :: HOWrappedCCT cipher
    -> ByteString -> ByteString -> Either String ByteString
    cfbEncrypt (HWCCT c :: cipher
    c) iv :: ByteString
    iv bs :: ByteString
    bs =
        ByteString -> Either String (IV cipher)
    forall cipher.
    BlockCipher cipher =>
    ByteString -> Either String (IV cipher)
    hammerIV ByteString
    iv Either String (IV cipher)
    -> (IV cipher -> Either String ByteString)
    -> Either String ByteString
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \i :: IV cipher
    i -> ByteString -> Either String ByteString
    forall (m :: * -> *) a. Monad m => a -> m a
    return (cipher -> IV cipher -> ByteString -> ByteString
    forall cipher ba.
    (BlockCipher cipher, ByteArray ba) =>
    cipher -> IV cipher -> ba -> ba
    CCT.cfbEncrypt cipher
    c IV cipher
    i ByteString
    bs)
      cfbDecrypt :: HOWrappedCCT cipher
    -> ByteString -> ByteString -> Either String ByteString
    cfbDecrypt (HWCCT c :: cipher
    c) iv :: ByteString
    iv bs :: ByteString
    bs =
        ByteString -> Either String (IV cipher)
    forall cipher.
    BlockCipher cipher =>
    ByteString -> Either String (IV cipher)
    hammerIV ByteString
    iv Either String (IV cipher)
    -> (IV cipher -> Either String ByteString)
    -> Either String ByteString
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \i :: IV cipher
    i -> ByteString -> Either String ByteString
    forall (m :: * -> *) a. Monad m => a -> m a
    return (cipher -> IV cipher -> ByteString -> ByteString
    forall cipher ba.
    (BlockCipher cipher, ByteArray ba) =>
    cipher -> IV cipher -> ba -> ba
    CCT.cfbDecrypt cipher
    c IV cipher
    i ByteString
    bs)

    hammerIV ::
         CCT.BlockCipher cipher => B.ByteString -> Either String (CCT.IV cipher)
    hammerIV :: ByteString -> Either String (IV cipher)
    hammerIV = String -> Maybe (IV cipher) -> Either String (IV cipher)
    forall a b. a -> Maybe b -> Either a b
    note "cryptonite bad IV" (Maybe (IV cipher) -> Either String (IV cipher))
    -> (ByteString -> Maybe (IV cipher))
    -> ByteString
    -> Either String (IV cipher)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> Maybe (IV cipher)
    forall b c. (ByteArrayAccess b, BlockCipher c) => b -> Maybe (IV c)
    CCT.makeIV