-- S2K.hs: OpenPGP (RFC4880) string-to-key conversion -- Copyright © 2013 Clint Adams -- This software is released under the terms of the Expat license. -- (See the LICENSE file). 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" -- in bytes keySize :: SymmetricAlgorithm -> Int keySize Plaintext = 0 keySize IDEA = 16 -- according to https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm keySize TripleDES = 24 -- RFC 4880 says 168 bits (derived from 192 bits) but we don't know who does the derivation 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)