{-# OPTIONS_HADDOCK hide #-} {-# LANGUAGE ExistentialQuantification #-} module Network.TLS.Crypto ( HashCtx(..) , hashInit , hashUpdate , hashUpdateSSL , hashFinal -- * constructor , hashMD5SHA1 , hashSHA256 -- * key exchange generic interface , PublicKey(..) , PrivateKey(..) , HashDescr(..) , kxEncrypt , kxDecrypt , kxSign , kxVerify , KxError(..) ) where import qualified Crypto.Hash.SHA256 as SHA256 import qualified Crypto.Hash.SHA1 as SHA1 import qualified Crypto.Hash.MD5 as MD5 import qualified Data.ByteString as B import Data.ByteString (ByteString) import Crypto.PubKey.HashDescr import qualified Crypto.PubKey.RSA as RSA import qualified Crypto.PubKey.RSA.PKCS15 as RSA import Crypto.Random.API data PublicKey = PubRSA RSA.PublicKey data PrivateKey = PrivRSA RSA.PrivateKey instance Show PublicKey where show (_) = "PublicKey(..)" instance Show PrivateKey where show (_) = "privateKey(..)" data KxError = RSAError RSA.Error deriving (Show) class HashCtxC a where hashCName :: a -> String hashCInit :: a -> a hashCUpdate :: a -> B.ByteString -> a hashCUpdateSSL :: a -> (B.ByteString,B.ByteString) -> a hashCFinal :: a -> B.ByteString data HashCtx = forall h . HashCtxC h => HashCtx h instance Show HashCtx where show (HashCtx c) = hashCName c {- MD5 & SHA1 joined -} data HashMD5SHA1 = HashMD5SHA1 SHA1.Ctx MD5.Ctx instance HashCtxC HashMD5SHA1 where hashCName _ = "MD5-SHA1" hashCInit _ = HashMD5SHA1 SHA1.init MD5.init hashCUpdate (HashMD5SHA1 sha1ctx md5ctx) b = HashMD5SHA1 (SHA1.update sha1ctx b) (MD5.update md5ctx b) hashCUpdateSSL (HashMD5SHA1 sha1ctx md5ctx) (b1,b2) = HashMD5SHA1 (SHA1.update sha1ctx b2) (MD5.update md5ctx b1) hashCFinal (HashMD5SHA1 sha1ctx md5ctx) = B.concat [MD5.finalize md5ctx, SHA1.finalize sha1ctx] data HashSHA256 = HashSHA256 SHA256.Ctx instance HashCtxC HashSHA256 where hashCName _ = "SHA256" hashCInit _ = HashSHA256 SHA256.init hashCUpdate (HashSHA256 ctx) b = HashSHA256 (SHA256.update ctx b) hashCUpdateSSL _ _ = undefined hashCFinal (HashSHA256 ctx) = SHA256.finalize ctx -- functions to use the hidden class. hashInit :: HashCtx -> HashCtx hashInit (HashCtx h) = HashCtx $ hashCInit h hashUpdate :: HashCtx -> B.ByteString -> HashCtx hashUpdate (HashCtx h) b = HashCtx $ hashCUpdate h b hashUpdateSSL :: HashCtx -> (B.ByteString,B.ByteString) -> HashCtx hashUpdateSSL (HashCtx h) bs = HashCtx $ hashCUpdateSSL h bs hashFinal :: HashCtx -> B.ByteString hashFinal (HashCtx h) = hashCFinal h -- real hash constructors hashMD5SHA1, hashSHA256 :: HashCtx hashMD5SHA1 = HashCtx (HashMD5SHA1 SHA1.init MD5.init) hashSHA256 = HashCtx (HashSHA256 SHA256.init) {- key exchange methods encrypt and decrypt for each supported algorithm -} generalizeRSAWithRNG :: CPRG g => (Either RSA.Error a, g) -> (Either KxError a, g) generalizeRSAWithRNG (Left e, g) = (Left (RSAError e), g) generalizeRSAWithRNG (Right x, g) = (Right x, g) kxEncrypt :: CPRG g => g -> PublicKey -> ByteString -> (Either KxError ByteString, g) kxEncrypt g (PubRSA pk) b = generalizeRSAWithRNG $ RSA.encrypt g pk b kxDecrypt :: CPRG g => g -> PrivateKey -> ByteString -> (Either KxError ByteString, g) kxDecrypt g (PrivRSA pk) b = generalizeRSAWithRNG $ RSA.decryptSafer g pk b -- Verify that the signature matches the given message, using the -- public key. -- kxVerify :: PublicKey -> HashDescr -> ByteString -> ByteString -> Bool kxVerify (PubRSA pk) hashDescr msg sign = RSA.verify hashDescr pk msg sign -- Sign the given message using the private key. -- kxSign :: CPRG g => g -> PrivateKey -> HashDescr -> ByteString -> (Either KxError ByteString, g) kxSign g (PrivRSA pk) hashDescr msg = generalizeRSAWithRNG $ RSA.signSafer g hashDescr pk msg