module Codec.Encryption.OpenPGP.CFB (
decrypt
, decryptNoNonce
, decryptOpenPGPCfb
, encryptNoNonce
) where
import Codec.Encryption.OpenPGP.BlockCipher (withSymmetricCipher)
import Codec.Encryption.OpenPGP.Internal.HOBlockCipher
import Codec.Encryption.OpenPGP.Types
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>), (<*>))
#endif
import Control.Monad (liftM)
import qualified Data.ByteString as B
decryptOpenPGPCfb :: SymmetricAlgorithm -> B.ByteString -> B.ByteString -> Either String B.ByteString
decryptOpenPGPCfb Plaintext ciphertext _ = return ciphertext
decryptOpenPGPCfb sa ciphertext keydata = withSymmetricCipher sa keydata $ \bc -> do
nonce <- decrypt1 ciphertext 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 ct cipher = paddedCfbDecrypt cipher (B.replicate (blockSize cipher) 0) (B.take (blockSize cipher + 2) ct)
decrypt2 :: HOBlockCipher cipher => B.ByteString -> cipher -> Either String B.ByteString
decrypt2 ct cipher = let i = B.take (blockSize cipher) (B.drop 2 ct) in paddedCfbDecrypt cipher i (B.drop (blockSize cipher + 2) ct)
decrypt :: SymmetricAlgorithm -> B.ByteString -> B.ByteString -> Either String B.ByteString
decrypt Plaintext ciphertext _ = return ciphertext
decrypt sa ciphertext keydata = withSymmetricCipher sa keydata $ \bc -> do
(nonce, cleartext) <- liftM (B.splitAt (blockSize bc + 2)) (decrypt' ciphertext bc)
if nonceCheck bc nonce then return cleartext else Left "Session key quickcheck failed"
where
decrypt' :: HOBlockCipher cipher => B.ByteString -> cipher -> Either String B.ByteString
decrypt' ct cipher = paddedCfbDecrypt cipher (B.replicate (blockSize cipher) 0) ct
decryptNoNonce :: SymmetricAlgorithm -> IV -> B.ByteString -> B.ByteString -> Either String B.ByteString
decryptNoNonce Plaintext _ ciphertext _ = return ciphertext
decryptNoNonce sa iv ciphertext keydata = withSymmetricCipher sa keydata (decrypt' ciphertext)
where
decrypt' :: HOBlockCipher cipher => B.ByteString -> cipher -> Either String B.ByteString
decrypt' ct cipher = paddedCfbDecrypt cipher (unIV iv) ct
nonceCheck :: HOBlockCipher cipher => cipher -> B.ByteString -> Bool
nonceCheck bc = (==) <$> B.take 2 . B.drop (blockSize bc 2) <*> B.drop (blockSize bc)
encryptNoNonce :: SymmetricAlgorithm -> S2K -> IV -> B.ByteString -> B.ByteString -> Either String B.ByteString
encryptNoNonce Plaintext _ _ payload _ = return payload
encryptNoNonce sa s2k iv payload keydata = withSymmetricCipher sa keydata (encrypt' payload)
where
encrypt' :: HOBlockCipher cipher => B.ByteString -> cipher -> Either String B.ByteString
encrypt' ct cipher = paddedCfbEncrypt cipher (unIV iv) ct