    -- CFB.hs: OpenPGP (RFC4880) CFB mode
    -- Copyright © 2013-2019  Clint Adams
    -- Copyright © 2013  Daniel Kahn Gillmor
    -- This software is released under the terms of the Expat license.
    -- (See the LICENSE file).
    module Codec.Encryption.OpenPGP.CFB
      ( decrypt
      , decryptPreservingNonce
      , decryptNoNonce
      , decryptOpenPGPCfb
      , encryptNoNonce
      ) where

    import Codec.Encryption.OpenPGP.BlockCipher (withSymmetricCipher)
    import Codec.Encryption.OpenPGP.Internal.HOBlockCipher
    import Codec.Encryption.OpenPGP.Types
    import qualified Data.ByteString as B

    decryptOpenPGPCfb ::
         SymmetricAlgorithm
      -> B.ByteString
      -> B.ByteString
      -> Either String B.ByteString
    decryptOpenPGPCfb :: SymmetricAlgorithm
    -> ByteString -> ByteString -> Either String ByteString
    decryptOpenPGPCfb SymmetricAlgorithm
    Plaintext ByteString
    ciphertext ByteString
    _ = ByteString -> Either String ByteString
    forall a. a -> Either String a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ByteString
    ciphertext
    decryptOpenPGPCfb SymmetricAlgorithm
    sa ByteString
    ciphertext ByteString
    keydata =
      SymmetricAlgorithm
    -> ByteString -> HOCipher ByteString -> Either String ByteString
    forall a.
    SymmetricAlgorithm -> ByteString -> HOCipher a -> Either String a
    withSymmetricCipher SymmetricAlgorithm
    sa ByteString
    keydata (HOCipher ByteString -> Either String ByteString)
    -> HOCipher ByteString -> Either String ByteString
    forall a b. (a -> b) -> a -> b
    $ \cipher
    bc -> do
        nonce <- ByteString -> cipher -> Either String ByteString
    forall cipher.
    HOBlockCipher cipher =>
    ByteString -> cipher -> Either String ByteString
    decrypt1 ByteString
    ciphertext cipher
    bc
        cleartext <- decrypt2 ciphertext bc
        if nonceCheck bc nonce
          then return cleartext
          else Left "Session key quickcheck failed"
      where
        decrypt1 ::
             HOBlockCipher cipher
          => B.ByteString
          -> cipher
          -> Either String B.ByteString
        decrypt1 :: forall cipher.
    HOBlockCipher cipher =>
    ByteString -> cipher -> Either String ByteString
    decrypt1 ByteString
    ct cipher
    cipher =
          cipher -> ByteString -> ByteString -> Either String ByteString
    forall cipher.
    HOBlockCipher cipher =>
    cipher -> ByteString -> ByteString -> Either String ByteString
    paddedCfbDecrypt
            cipher
    cipher
            (Int -> Word8 -> ByteString
    B.replicate (cipher -> Int
    forall cipher. HOBlockCipher cipher => cipher -> Int
    blockSize cipher
    cipher) Word8
    0)
            (Int -> ByteString -> ByteString
    B.take (cipher -> Int
    forall cipher. HOBlockCipher cipher => cipher -> Int
    blockSize cipher
    cipher Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    2) ByteString
    ct)
        decrypt2 ::
             HOBlockCipher cipher
          => B.ByteString
          -> cipher
          -> Either String B.ByteString
        decrypt2 :: forall cipher.
    HOBlockCipher cipher =>
    ByteString -> cipher -> Either String ByteString
    decrypt2 ByteString
    ct cipher
    cipher =
          let i :: ByteString
    i = Int -> ByteString -> ByteString
    B.take (cipher -> Int
    forall cipher. HOBlockCipher cipher => cipher -> Int
    blockSize cipher
    cipher) (Int -> ByteString -> ByteString
    B.drop Int
    2 ByteString
    ct)
           in cipher -> ByteString -> ByteString -> Either String ByteString
    forall cipher.
    HOBlockCipher cipher =>
    cipher -> ByteString -> ByteString -> Either String ByteString
    paddedCfbDecrypt cipher
    cipher ByteString
    i (Int -> ByteString -> ByteString
    B.drop (cipher -> Int
    forall cipher. HOBlockCipher cipher => cipher -> Int
    blockSize cipher
    cipher Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    2) ByteString
    ct)

    -- should deprecate this?
    decrypt ::
         SymmetricAlgorithm
      -> B.ByteString
      -> B.ByteString
      -> Either String B.ByteString
    decrypt :: SymmetricAlgorithm
    -> ByteString -> ByteString -> Either String ByteString
    decrypt SymmetricAlgorithm
    x ByteString
    y ByteString
    z = (ByteString, ByteString) -> ByteString
    forall a b. (a, b) -> b
    snd ((ByteString, ByteString) -> ByteString)
    -> Either String (ByteString, ByteString)
    -> Either String ByteString
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (SymmetricAlgorithm
    -> ByteString
    -> ByteString
    -> Either String (ByteString, ByteString)
    decryptPreservingNonce SymmetricAlgorithm
    x ByteString
    y ByteString
    z)

    decryptPreservingNonce ::
         SymmetricAlgorithm
      -> B.ByteString
      -> B.ByteString
      -> Either String (B.ByteString, B.ByteString)
    decryptPreservingNonce :: SymmetricAlgorithm
    -> ByteString
    -> ByteString
    -> Either String (ByteString, ByteString)
    decryptPreservingNonce SymmetricAlgorithm
    Plaintext ByteString
    ciphertext ByteString
    _ = (ByteString, ByteString) -> Either String (ByteString, ByteString)
    forall a. a -> Either String a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (ByteString
    forall a. Monoid a => a
    mempty, ByteString
    ciphertext)
    decryptPreservingNonce SymmetricAlgorithm
    sa ByteString
    ciphertext ByteString
    keydata =
      SymmetricAlgorithm
    -> ByteString
    -> HOCipher (ByteString, ByteString)
    -> Either String (ByteString, ByteString)
    forall a.
    SymmetricAlgorithm -> ByteString -> HOCipher a -> Either String a
    withSymmetricCipher SymmetricAlgorithm
    sa ByteString
    keydata (HOCipher (ByteString, ByteString)
     -> Either String (ByteString, ByteString))
    -> HOCipher (ByteString, ByteString)
    -> Either String (ByteString, ByteString)
    forall a b. (a -> b) -> a -> b
    $ \cipher
    bc -> do
        (nonce, cleartext) <-
          (ByteString -> (ByteString, ByteString))
    -> Either String ByteString
    -> Either String (ByteString, ByteString)
    forall a b. (a -> b) -> Either String a -> Either String b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Int -> ByteString -> (ByteString, ByteString)
    B.splitAt (cipher -> Int
    forall cipher. HOBlockCipher cipher => cipher -> Int
    blockSize cipher
    bc Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    2)) (ByteString -> cipher -> Either String ByteString
    forall cipher.
    HOBlockCipher cipher =>
    ByteString -> cipher -> Either String ByteString
    decrypt' ByteString
    ciphertext cipher
    bc)
        if nonceCheck bc nonce
          then return (nonce, cleartext)
          else Left "Session key quickcheck failed"
      where
        decrypt' ::
             HOBlockCipher cipher
          => B.ByteString
          -> cipher
          -> Either String B.ByteString
        decrypt' :: forall cipher.
    HOBlockCipher cipher =>
    ByteString -> cipher -> Either String ByteString
    decrypt' ByteString
    ct cipher
    cipher =
          cipher -> ByteString -> ByteString -> Either String ByteString
    forall cipher.
    HOBlockCipher cipher =>
    cipher -> ByteString -> ByteString -> Either String ByteString
    paddedCfbDecrypt cipher
    cipher (Int -> Word8 -> ByteString
    B.replicate (cipher -> Int
    forall cipher. HOBlockCipher cipher => cipher -> Int
    blockSize cipher
    cipher) Word8
    0) ByteString
    ct

    decryptNoNonce ::
         SymmetricAlgorithm
      -> IV
      -> B.ByteString
      -> B.ByteString
      -> Either String B.ByteString
    decryptNoNonce :: SymmetricAlgorithm
    -> IV -> ByteString -> ByteString -> Either String ByteString
    decryptNoNonce SymmetricAlgorithm
    Plaintext IV
    _ ByteString
    ciphertext ByteString
    _ = ByteString -> Either String ByteString
    forall a. a -> Either String a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ByteString
    ciphertext
    decryptNoNonce SymmetricAlgorithm
    sa IV
    iv ByteString
    ciphertext ByteString
    keydata =
      SymmetricAlgorithm
    -> ByteString -> HOCipher ByteString -> Either String ByteString
    forall a.
    SymmetricAlgorithm -> ByteString -> HOCipher a -> Either String a
    withSymmetricCipher SymmetricAlgorithm
    sa ByteString
    keydata (ByteString -> cipher -> Either String ByteString
    forall cipher.
    HOBlockCipher cipher =>
    ByteString -> cipher -> Either String ByteString
    decrypt' ByteString
    ciphertext)
      where
        decrypt' ::
             HOBlockCipher cipher
          => B.ByteString
          -> cipher
          -> Either String B.ByteString
        decrypt' :: forall cipher.
    HOBlockCipher cipher =>
    ByteString -> cipher -> Either String ByteString
    decrypt' ByteString
    ct cipher
    cipher = cipher -> ByteString -> ByteString -> Either String ByteString
    forall cipher.
    HOBlockCipher cipher =>
    cipher -> ByteString -> ByteString -> Either String ByteString
    paddedCfbDecrypt cipher
    cipher (IV -> ByteString
    unIV IV
    iv) ByteString
    ct

    nonceCheck :: HOBlockCipher cipher => cipher -> B.ByteString -> Bool
    nonceCheck :: forall cipher. HOBlockCipher cipher => cipher -> ByteString -> Bool
    nonceCheck cipher
    bc =
      ByteString -> ByteString -> Bool
    forall a. Eq a => a -> a -> Bool
    (==) (ByteString -> ByteString -> Bool)
    -> (ByteString -> ByteString) -> ByteString -> ByteString -> Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Int -> ByteString -> ByteString
    B.take Int
    2 (ByteString -> ByteString)
    -> (ByteString -> ByteString) -> ByteString -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> ByteString -> ByteString
    B.drop (cipher -> Int
    forall cipher. HOBlockCipher cipher => cipher -> Int
    blockSize cipher
    bc Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    2) (ByteString -> ByteString -> Bool)
    -> (ByteString -> ByteString) -> ByteString -> Bool
    forall a b.
    (ByteString -> a -> b) -> (ByteString -> a) -> ByteString -> b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> Int -> ByteString -> ByteString
    B.drop (cipher -> Int
    forall cipher. HOBlockCipher cipher => cipher -> Int
    blockSize cipher
    bc)

    encryptNoNonce ::
         SymmetricAlgorithm
      -> S2K
      -> IV
      -> B.ByteString
      -> B.ByteString
      -> Either String B.ByteString
    encryptNoNonce :: SymmetricAlgorithm
    -> S2K
    -> IV
    -> ByteString
    -> ByteString
    -> Either String ByteString
    encryptNoNonce SymmetricAlgorithm
    Plaintext S2K
    _ IV
    _ ByteString
    payload ByteString
    _ = ByteString -> Either String ByteString
    forall a. a -> Either String a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ByteString
    payload
    encryptNoNonce SymmetricAlgorithm
    sa S2K
    s2k IV
    iv ByteString
    payload ByteString
    keydata =
      SymmetricAlgorithm
    -> ByteString -> HOCipher ByteString -> Either String ByteString
    forall a.
    SymmetricAlgorithm -> ByteString -> HOCipher a -> Either String a
    withSymmetricCipher SymmetricAlgorithm
    sa ByteString
    keydata (ByteString -> cipher -> Either String ByteString
    forall cipher.
    HOBlockCipher cipher =>
    ByteString -> cipher -> Either String ByteString
    encrypt' ByteString
    payload)
      where
        encrypt' ::
             HOBlockCipher cipher
          => B.ByteString
          -> cipher
          -> Either String B.ByteString
        encrypt' :: forall cipher.
    HOBlockCipher cipher =>
    ByteString -> cipher -> Either String ByteString
    encrypt' ByteString
    ct cipher
    cipher = cipher -> ByteString -> ByteString -> Either String ByteString
    forall cipher.
    HOBlockCipher cipher =>
    cipher -> ByteString -> ByteString -> Either String ByteString
    paddedCfbEncrypt cipher
    cipher (IV -> ByteString
    unIV IV
    iv) ByteString
    ct