module Codec.Encryption.OpenPGP.S2K (
string2Key
,skesk2Key
) where
import Codec.Encryption.OpenPGP.Types
import Control.Monad.Loops (untilM_)
import Control.Monad.Trans.State.Lazy (execState, get, put)
import qualified Crypto.Hash.SHA1 as SHA1
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
string2Key :: S2K -> Int -> BL.ByteString -> B.ByteString
string2Key (Simple SHA1) ksz bs = B.take (fromIntegral ksz) $ hashpp SHA1.hashlazy ksz bs
string2Key (Salted SHA1 salt) ksz bs = string2Key (Simple SHA1) ksz (BL.append (BL.fromChunks [salt]) bs)
string2Key (IteratedSalted SHA1 salt cnt) ksz bs = string2Key (Simple SHA1) ksz (BL.take (fromIntegral cnt) . BL.cycle $ BL.append (BL.fromChunks [salt]) bs)
string2Key _ _ _ = error "FIXME: unimplemented S2K hash"
keySize :: SymmetricAlgorithm -> Int
keySize Plaintext = 0
keySize IDEA = 16
keySize TripleDES = 24
keySize CAST5 = 16
keySize Blowfish = 16
keySize ReservedSAFER = undefined
keySize ReservedDES = undefined
keySize AES128 = 16
keySize AES192 = 24
keySize AES256 = 32
keySize Twofish = 32
keySize (OtherSA _) = undefined
skesk2Key :: SKESK -> BL.ByteString -> B.ByteString
skesk2Key (SKESK 4 sa s2k Nothing) pass = string2Key s2k (keySize sa) pass
skesk2Key _ _ = error "FIXME"
hashpp :: (BL.ByteString -> B.ByteString) -> Int -> BL.ByteString -> B.ByteString
hashpp hf keysize pp = snd (execState (hashround `untilM_` bigEnough) (0, B.empty))
where
hashround = get >>= \(ctr, bs) -> put (ctr + 1, bs `B.append` hf (nulpad ctr `BL.append` pp))
nulpad = BL.pack . flip replicate 0
bigEnough = get >>= \(_, bs) -> return (B.length bs >= keysize)