    -- CryptoCipherTypes.hs: shim for crypto-cipher-types stuff (current nettle)
    -- Copyright © 2016-2024  Clint Adams
    -- This software is released under the terms of the Expat license.
    -- (See the LICENSE file).
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE PackageImports #-}
    {-# LANGUAGE UndecidableInstances #-}

    module Codec.Encryption.OpenPGP.Internal.CryptoCipherTypes
      ( HOWrappedOldCCT(..)
      ) where

    import Control.Error.Util (note)
    import qualified "crypto-cipher-types" Crypto.Cipher.Types as OldCCT
    import qualified "crypton" Crypto.Cipher.Types as CCT
    import qualified Data.ByteString as B

    import Codec.Encryption.OpenPGP.Internal.HOBlockCipher

    newtype HOWrappedOldCCT a =
      HWOCCT a

    instance OldCCT.BlockCipher cipher =>
             HOBlockCipher (HOWrappedOldCCT cipher) where
      cipherInit :: ByteString -> Either String (HOWrappedOldCCT cipher)
    cipherInit =
        (cipher -> HOWrappedOldCCT cipher)
    -> Either String cipher -> Either String (HOWrappedOldCCT cipher)
    forall a b. (a -> b) -> Either String a -> Either String b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap cipher -> HOWrappedOldCCT cipher
    forall a. a -> HOWrappedOldCCT a
    HWOCCT (Either String cipher -> Either String (HOWrappedOldCCT cipher))
    -> (ByteString -> Either String cipher)
    -> ByteString
    -> Either String (HOWrappedOldCCT cipher)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
        (KeyError -> Either String cipher)
    -> (Key cipher -> Either String cipher)
    -> Either KeyError (Key cipher)
    -> Either String cipher
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (Either String cipher -> KeyError -> Either String cipher
    forall a b. a -> b -> a
    const (String -> Either String cipher
    forall a b. a -> Either a b
    Left String
    "nettle invalid key")) (cipher -> Either String cipher
    forall a b. b -> Either a b
    Right (cipher -> Either String cipher)
    -> (Key cipher -> cipher) -> Key cipher -> Either String cipher
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key cipher -> cipher
    forall cipher. Cipher cipher => Key cipher -> cipher
    OldCCT.cipherInit) (Either KeyError (Key cipher) -> Either String cipher)
    -> (ByteString -> Either KeyError (Key cipher))
    -> ByteString
    -> Either String cipher
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
        ByteString -> Either KeyError (Key cipher)
    forall b c.
    (ToSecureMem b, Cipher c) =>
    b -> Either KeyError (Key c)
    OldCCT.makeKey
      cipherName :: HOWrappedOldCCT cipher -> String
    cipherName (HWOCCT cipher
    c) = cipher -> String
    forall cipher. Cipher cipher => cipher -> String
    OldCCT.cipherName cipher
    c
      cipherKeySize :: HOWrappedOldCCT cipher -> KeySizeSpecifier
    cipherKeySize (HWOCCT cipher
    c) = KeySizeSpecifier -> KeySizeSpecifier
    convertKSS (KeySizeSpecifier -> KeySizeSpecifier)
    -> (cipher -> KeySizeSpecifier) -> cipher -> KeySizeSpecifier
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . cipher -> KeySizeSpecifier
    forall cipher. Cipher cipher => cipher -> KeySizeSpecifier
    OldCCT.cipherKeySize (cipher -> KeySizeSpecifier) -> cipher -> KeySizeSpecifier
    forall a b. (a -> b) -> a -> b
    $ cipher
    c
      blockSize :: HOWrappedOldCCT cipher -> Int
    blockSize (HWOCCT cipher
    c) = cipher -> Int
    forall cipher. BlockCipher cipher => cipher -> Int
    OldCCT.blockSize cipher
    c
      cfbEncrypt :: HOWrappedOldCCT cipher
    -> ByteString -> ByteString -> Either String ByteString
    cfbEncrypt (HWOCCT cipher
    c) ByteString
    iv 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 a b.
    Either String a -> (a -> Either String b) -> Either String b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \IV cipher
    i -> ByteString -> Either String ByteString
    forall a. a -> Either String a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (cipher -> IV cipher -> ByteString -> ByteString
    forall cipher.
    BlockCipher cipher =>
    cipher -> IV cipher -> ByteString -> ByteString
    OldCCT.cfbEncrypt cipher
    c IV cipher
    i ByteString
    bs)
      cfbDecrypt :: HOWrappedOldCCT cipher
    -> ByteString -> ByteString -> Either String ByteString
    cfbDecrypt (HWOCCT cipher
    c) ByteString
    iv 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 a b.
    Either String a -> (a -> Either String b) -> Either String b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \IV cipher
    i -> ByteString -> Either String ByteString
    forall a. a -> Either String a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (cipher -> IV cipher -> ByteString -> ByteString
    forall cipher.
    BlockCipher cipher =>
    cipher -> IV cipher -> ByteString -> ByteString
    OldCCT.cfbDecrypt cipher
    c IV cipher
    i ByteString
    bs)
      paddedCfbEncrypt :: HOWrappedOldCCT cipher
    -> ByteString -> ByteString -> Either String ByteString
    paddedCfbEncrypt HOWrappedOldCCT cipher
    _ ByteString
    _ ByteString
    _ =
        String -> Either String ByteString
    forall a b. a -> Either a b
    Left String
    "padding for nettle-encryption not implemented yet"
      paddedCfbDecrypt :: HOWrappedOldCCT cipher
    -> ByteString -> ByteString -> Either String ByteString
    paddedCfbDecrypt (HWOCCT cipher
    cipher) ByteString
    iv ByteString
    ciphertext =
        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 a b.
    Either String a -> (a -> Either String b) -> Either String b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \IV cipher
    i ->
          ByteString -> Either String ByteString
    forall a. a -> Either String a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int -> ByteString -> ByteString
    B.take (ByteString -> Int
    B.length ByteString
    ciphertext) (cipher -> IV cipher -> ByteString -> ByteString
    forall cipher.
    BlockCipher cipher =>
    cipher -> IV cipher -> ByteString -> ByteString
    OldCCT.cfbDecrypt cipher
    cipher IV cipher
    i ByteString
    padded))
        where
          padded :: ByteString
    padded =
            ByteString
    ciphertext ByteString -> ByteString -> ByteString
    `B.append`
            [Word8] -> ByteString
    B.pack
              (Int -> Word8 -> [Word8]
    forall a. Int -> a -> [a]
    replicate
                 (cipher -> Int
    forall cipher. BlockCipher cipher => cipher -> Int
    OldCCT.blockSize cipher
    cipher Int -> Int -> Int
    forall a. Num a => a -> a -> a
    -
                  (ByteString -> Int
    B.length ByteString
    ciphertext Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `mod` cipher -> Int
    forall cipher. BlockCipher cipher => cipher -> Int
    OldCCT.blockSize cipher
    cipher))
                 Word8
    0)

    convertKSS :: OldCCT.KeySizeSpecifier -> CCT.KeySizeSpecifier
    convertKSS :: KeySizeSpecifier -> KeySizeSpecifier
    convertKSS (OldCCT.KeySizeRange Int
    a Int
    b) = Int -> Int -> KeySizeSpecifier
    CCT.KeySizeRange Int
    a Int
    b
    convertKSS (OldCCT.KeySizeEnum [Int]
    as) = [Int] -> KeySizeSpecifier
    CCT.KeySizeEnum [Int]
    as
    convertKSS (OldCCT.KeySizeFixed Int
    a) = Int -> KeySizeSpecifier
    CCT.KeySizeFixed Int
    a

    hammerIV ::
         OldCCT.BlockCipher cipher
      => B.ByteString
      -> Either String (OldCCT.IV cipher)
    hammerIV :: forall cipher.
    BlockCipher cipher =>
    ByteString -> Either String (IV cipher)
    hammerIV = String -> Maybe (IV cipher) -> Either String (IV cipher)
    forall a b. a -> Maybe b -> Either a b
    note String
    "nettle 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. (Byteable b, BlockCipher c) => b -> Maybe (IV c)
    OldCCT.makeIV