-- 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 Plaintext ciphertext :: ByteString
ciphertext _ = ByteString -> Either String ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
ciphertext
decryptOpenPGPCfb sa :: SymmetricAlgorithm
sa ciphertext :: ByteString
ciphertext keydata :: 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
$ \bc :: cipher
bc -> do
    ByteString
nonce <- ByteString -> cipher -> Either String ByteString
forall cipher.
HOBlockCipher cipher =>
ByteString -> cipher -> Either String ByteString
decrypt1 ByteString
ciphertext cipher
bc
    ByteString
cleartext <- ByteString -> cipher -> Either String ByteString
forall cipher.
HOBlockCipher cipher =>
ByteString -> cipher -> Either String ByteString
decrypt2 ByteString
ciphertext cipher
bc
    if cipher -> ByteString -> Bool
forall cipher. HOBlockCipher cipher => cipher -> ByteString -> Bool
nonceCheck cipher
bc ByteString
nonce
      then ByteString -> Either String ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
cleartext
      else String -> Either String ByteString
forall a b. a -> Either a b
Left "Session key quickcheck failed"
  where
    decrypt1 ::
         HOBlockCipher cipher
      => B.ByteString
      -> cipher
      -> Either String B.ByteString
    decrypt1 :: ByteString -> cipher -> Either String ByteString
decrypt1 ct :: ByteString
ct cipher :: 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) 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
+ 2) ByteString
ct)
    decrypt2 ::
         HOBlockCipher cipher
      => B.ByteString
      -> cipher
      -> Either String B.ByteString
    decrypt2 :: ByteString -> cipher -> Either String ByteString
decrypt2 ct :: ByteString
ct cipher :: 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 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
+ 2) ByteString
ct)

-- should deprecate this?
decrypt ::
     SymmetricAlgorithm
  -> B.ByteString
  -> B.ByteString
  -> Either String B.ByteString
decrypt :: SymmetricAlgorithm
-> ByteString -> ByteString -> Either String ByteString
decrypt x :: SymmetricAlgorithm
x y :: ByteString
y z :: 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 Plaintext ciphertext :: ByteString
ciphertext _ = (ByteString, ByteString) -> Either String (ByteString, ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString
forall a. Monoid a => a
mempty, ByteString
ciphertext)
decryptPreservingNonce sa :: SymmetricAlgorithm
sa ciphertext :: ByteString
ciphertext keydata :: 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
$ \bc :: cipher
bc -> do
    (nonce :: ByteString
nonce, cleartext :: ByteString
cleartext) <-
      (ByteString -> (ByteString, ByteString))
-> Either String ByteString
-> Either String (ByteString, ByteString)
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
+ 2)) (ByteString -> cipher -> Either String ByteString
forall cipher.
HOBlockCipher cipher =>
ByteString -> cipher -> Either String ByteString
decrypt' ByteString
ciphertext cipher
bc)
    if cipher -> ByteString -> Bool
forall cipher. HOBlockCipher cipher => cipher -> ByteString -> Bool
nonceCheck cipher
bc ByteString
nonce
      then (ByteString, ByteString) -> Either String (ByteString, ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString
nonce, ByteString
cleartext)
      else String -> Either String (ByteString, ByteString)
forall a b. a -> Either a b
Left "Session key quickcheck failed"
  where
    decrypt' ::
         HOBlockCipher cipher
      => B.ByteString
      -> cipher
      -> Either String B.ByteString
    decrypt' :: ByteString -> cipher -> Either String ByteString
decrypt' ct :: ByteString
ct cipher :: 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) 0) ByteString
ct

decryptNoNonce ::
     SymmetricAlgorithm
  -> IV
  -> B.ByteString
  -> B.ByteString
  -> Either String B.ByteString
decryptNoNonce :: SymmetricAlgorithm
-> IV -> ByteString -> ByteString -> Either String ByteString
decryptNoNonce Plaintext _ ciphertext :: ByteString
ciphertext _ = ByteString -> Either String ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
ciphertext
decryptNoNonce sa :: SymmetricAlgorithm
sa iv :: IV
iv ciphertext :: ByteString
ciphertext keydata :: 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' :: ByteString -> cipher -> Either String ByteString
decrypt' ct :: ByteString
ct cipher :: 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 :: cipher -> ByteString -> Bool
nonceCheck bc :: 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 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
- 2) (ByteString -> ByteString -> Bool)
-> (ByteString -> ByteString) -> ByteString -> Bool
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 Plaintext _ _ payload :: ByteString
payload _ = ByteString -> Either String ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
payload
encryptNoNonce sa :: SymmetricAlgorithm
sa s2k :: S2K
s2k iv :: IV
iv payload :: ByteString
payload keydata :: 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' :: ByteString -> cipher -> Either String ByteString
encrypt' ct :: ByteString
ct cipher :: 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