module Network.TLS.Crypto ( HashType(..) , HashCtx -- * incremental interface with algorithm type wrapping for genericity , initHash , updateHash , finalizeHash -- * single pass lazy bytestring interface for each algorithm , hashMD5 , hashSHA1 -- * incremental interface for each algorithm , initMD5 , updateMD5 , finalizeMD5 , initSHA1 , updateSHA1 , finalizeSHA1 -- * RSA stuff , PublicKey(..) , PrivateKey(..) , rsaEncrypt , rsaDecrypt ) where import qualified Data.CryptoHash.SHA1 as SHA1 import qualified Data.CryptoHash.MD5 as MD5 import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L import Data.ByteString (ByteString) import Codec.Crypto.RSA (PublicKey(..), PrivateKey(..)) import qualified Codec.Crypto.RSA as RSA import Control.Spoon import Control.Arrow (first) import System.Random data HashCtx = SHA1 !SHA1.Ctx | MD5 !MD5.Ctx instance Show HashCtx where show (SHA1 _) = "sha1" show (MD5 _) = "md5" data HashType = HashTypeSHA1 | HashTypeMD5 {- MD5 -} initMD5 :: MD5.Ctx initMD5 = MD5.init updateMD5 :: MD5.Ctx -> ByteString -> MD5.Ctx updateMD5 = MD5.update finalizeMD5 :: MD5.Ctx -> ByteString finalizeMD5 = MD5.finalize hashMD5 :: ByteString -> ByteString hashMD5 = MD5.hash {- SHA1 -} initSHA1 :: SHA1.Ctx initSHA1 = SHA1.init updateSHA1 :: SHA1.Ctx -> ByteString -> SHA1.Ctx updateSHA1 = SHA1.update finalizeSHA1 :: SHA1.Ctx -> ByteString finalizeSHA1 = SHA1.finalize hashSHA1 :: ByteString -> ByteString hashSHA1 = SHA1.hash {- generic Hashing -} initHash :: HashType -> HashCtx initHash HashTypeSHA1 = SHA1 (initSHA1) initHash HashTypeMD5 = MD5 (initMD5) updateHash :: HashCtx -> B.ByteString -> HashCtx updateHash (SHA1 ctx) = SHA1 . updateSHA1 ctx updateHash (MD5 ctx) = MD5 . updateMD5 ctx finalizeHash :: HashCtx -> B.ByteString finalizeHash (SHA1 ctx) = finalizeSHA1 ctx finalizeHash (MD5 ctx) = finalizeMD5 ctx {- RSA reexport and maybification -} {- on using spoon: because we use rsa Encrypt/Decrypt in a pure context, catching the exception when the key is not correctly set or the data isn't correct. need to fix the RSA package to return "Either String X". -} lazyToStrict :: L.ByteString -> B.ByteString lazyToStrict = B.concat . L.toChunks rsaEncrypt :: RandomGen g => g -> PublicKey -> B.ByteString -> Maybe (B.ByteString, g) rsaEncrypt g pk b = maybe Nothing (Just . first lazyToStrict) $ teaspoon (RSA.rsaes_pkcs1_v1_5_encrypt g pk blazy) where blazy = L.fromChunks [ b ] rsaDecrypt :: PrivateKey -> B.ByteString -> Maybe B.ByteString rsaDecrypt pk b = maybe Nothing (Just . lazyToStrict) $ teaspoon (RSA.rsaes_pkcs1_v1_5_decrypt pk blazy) where blazy = L.fromChunks [ b ]