summaryrefslogtreecommitdiff
path: root/Data/OpenPGP/Util/Decrypt.hs
blob: 637d754e3ab28a35996145cf3156142e4ceb02a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
{-# LANGUAGE RankNTypes, CPP #-}
module Data.OpenPGP.Util.Decrypt where

import qualified Data.ByteString.Lazy as LZ
import Crypto.Error
import qualified Crypto.Cipher.AES as Vincent
import qualified Crypto.Cipher.Blowfish as Vincent
import qualified Crypto.Cipher.Types as Vincent
import Crypto.Cipher.Cast5 (CAST5_128)
import Crypto.Cipher.ThomasToVincent
import qualified Data.OpenPGP as OpenPGP
import Data.OpenPGP.Util.Base


-- decryption codec for withS2K
simpleUnCFB :: (Vincent.BlockCipher k) => k -> Vincent.IV k -> LZ.ByteString -> LZ.ByteString
simpleUnCFB k iv = padThenUnpad k (toLazyBS . Vincent.cfbDecrypt k iv . LZ.toStrict)

withS2K' :: OpenPGP.SymmetricAlgorithm -> Maybe OpenPGP.S2K -> LZ.ByteString
            -> (forall b. Vincent.BlockCipher b => b -> x) -> x
withS2K' OpenPGP.AES128   s2k s f = f (string2key s2k s :: Vincent.AES128)
withS2K' OpenPGP.AES192   s2k s f = f (string2key s2k s :: Vincent.AES192)
withS2K' OpenPGP.AES256   s2k s f = f (string2key s2k s :: Vincent.AES256)
withS2K' OpenPGP.Blowfish s2k s f = f (string2key s2k s :: Vincent.Blowfish128)
withS2K' OpenPGP.CAST5    s2k s f = f (string2key s2k s :: ThomasToVincent CAST5_128)

string2key :: (Vincent.BlockCipher k) => Maybe OpenPGP.S2K -> LZ.ByteString -> k
string2key ms2k s = cipher
    where
#if defined(VERSION_cryptonite)
    CryptoPassed cipher = Vincent.cipherInit k
    k = LZ.toStrict $ LZ.take ksize $ maybe s (\s2k -> OpenPGP.string2key hashBySymbol s2k s) ms2k
#else
    cipher = Vincent.cipherInit k
    Right k = Vincent.makeKey $ toStrictBS $
        LZ.take ksize $ maybe s (\s2k -> OpenPGP.string2key hashBySymbol s2k s) ms2k
#endif
    ksize = case Vincent.cipherKeySize cipher of
                Vincent.KeySizeFixed n -> fromIntegral n
                Vincent.KeySizeEnum xs -> error $ "Unknown key size in string2key"
                Vincent.KeySizeRange min max -> error $ "Unknown key size range in string2key"

-- Apply a function f to a zero-padded bytestring s to a multiple
-- of the blocksize for cyper k.
-- Then drop the same number of bytes from the result of f.
padThenUnpad :: (Vincent.BlockCipher k) => k -> (LZ.ByteString -> LZ.ByteString) -> LZ.ByteString -> LZ.ByteString
padThenUnpad k f s = dropPadEnd (f padded)
    where
        dropPadEnd s = LZ.take (LZ.length s - padAmount) s
        padded = s `LZ.append` LZ.replicate padAmount 0
        padAmount = blksize - (LZ.length s `mod` blksize)
        blksize = fromIntegral $ Vincent.blockSize k