hs-tls/core/Network/TLS/Crypto.hs

141 lines
4.7 KiB
Haskell
Raw Normal View History

2011-03-02 08:43:05 +00:00
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE ExistentialQuantification #-}
2010-09-09 21:47:19 +00:00
module Network.TLS.Crypto
2013-07-12 06:27:28 +00:00
( HashCtx(..)
, hashInit
, hashUpdate
, hashUpdateSSL
, hashFinal
2013-12-11 07:53:55 +00:00
, module Network.TLS.Crypto.DH
2013-07-12 06:27:28 +00:00
-- * constructor
, hashMD5SHA1
, hashSHA1
2013-07-12 06:27:28 +00:00
, hashSHA256
-- * key exchange generic interface
, PubKey(..)
, PrivKey(..)
, PublicKey
, PrivateKey
, HashDescr(..)
, kxEncrypt
, kxDecrypt
, kxSign
, kxVerify
, KxError(..)
) where
2010-09-09 21:47:19 +00:00
2011-08-14 15:18:22 +00:00
import qualified Crypto.Hash.SHA256 as SHA256
import qualified Crypto.Hash.SHA1 as SHA1
import qualified Crypto.Hash.MD5 as MD5
2010-09-09 21:47:19 +00:00
import qualified Data.ByteString as B
import Data.ByteString (ByteString)
2012-12-30 15:31:13 +00:00
import Crypto.PubKey.HashDescr
import qualified Crypto.PubKey.RSA as RSA
import qualified Crypto.PubKey.RSA.PKCS15 as RSA
import Crypto.Random
import Data.X509 (PrivKey(..), PubKey(..))
2013-12-11 07:54:32 +00:00
import Network.TLS.Crypto.DH
{-# DEPRECATED PublicKey "use PubKey" #-}
type PublicKey = PubKey
{-# DEPRECATED PrivateKey "use PrivKey" #-}
type PrivateKey = PrivKey
data KxError =
RSAError RSA.Error
| KxUnsupported
deriving (Show)
2010-09-09 21:47:19 +00:00
class HashCtxC a where
2013-07-12 06:27:28 +00:00
hashCName :: a -> String
hashCInit :: a -> a
hashCUpdate :: a -> B.ByteString -> a
hashCUpdateSSL :: a -> (B.ByteString,B.ByteString) -> a
hashCFinal :: a -> B.ByteString
2010-09-09 21:47:19 +00:00
data HashCtx = forall h . HashCtxC h => HashCtx h
2010-09-09 21:47:19 +00:00
instance Show HashCtx where
2013-07-12 06:27:28 +00:00
show (HashCtx c) = hashCName c
2010-09-09 21:47:19 +00:00
{- MD5 & SHA1 joined -}
data HashMD5SHA1 = HashMD5SHA1 SHA1.Ctx MD5.Ctx
instance HashCtxC HashMD5SHA1 where
2013-07-12 06:27:28 +00:00
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]
newtype HashSHA1 = HashSHA1 SHA1.Ctx
instance HashCtxC HashSHA1 where
hashCName _ = "SHA1"
hashCInit _ = HashSHA1 SHA1.init
hashCUpdate (HashSHA1 ctx) b = HashSHA1 (SHA1.update ctx b)
hashCUpdateSSL (HashSHA1 ctx) (_,b2) = HashSHA1 (SHA1.update ctx b2)
hashCFinal (HashSHA1 ctx) = SHA1.finalize ctx
newtype HashSHA256 = HashSHA256 SHA256.Ctx
2011-08-14 15:18:22 +00:00
instance HashCtxC HashSHA256 where
2013-07-12 06:27:28 +00:00
hashCName _ = "SHA256"
hashCInit _ = HashSHA256 SHA256.init
hashCUpdate (HashSHA256 ctx) b = HashSHA256 (SHA256.update ctx b)
hashCUpdateSSL _ _ = error "CUpdateSSL with HashSHA256"
2013-07-12 06:27:28 +00:00
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) -- ^ (for the md5 context, for the sha1 context)
-> HashCtx
hashUpdateSSL (HashCtx h) bs = HashCtx $ hashCUpdateSSL h bs
hashFinal :: HashCtx -> B.ByteString
hashFinal (HashCtx h) = hashCFinal h
-- real hash constructors
hashMD5SHA1, hashSHA1, hashSHA256 :: HashCtx
hashMD5SHA1 = HashCtx (HashMD5SHA1 SHA1.init MD5.init)
hashSHA1 = HashCtx (HashSHA1 SHA1.init)
2011-08-14 15:18:22 +00:00
hashSHA256 = HashCtx (HashSHA256 SHA256.init)
2010-09-09 21:47:19 +00:00
{- key exchange methods encrypt and decrypt for each supported algorithm -}
2010-09-09 21:47:19 +00:00
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 (PubKeyRSA pk) b = generalizeRSAWithRNG $ RSA.encrypt g pk b
kxEncrypt g _ _ = (Left KxUnsupported, g)
2012-12-05 08:16:32 +00:00
kxDecrypt :: CPRG g => g -> PrivateKey -> ByteString -> (Either KxError ByteString, g)
kxDecrypt g (PrivKeyRSA pk) b = generalizeRSAWithRNG $ RSA.decryptSafer g pk b
kxDecrypt g _ _ = (Left KxUnsupported, g)
-- Verify that the signature matches the given message, using the
-- public key.
--
2012-12-30 15:31:13 +00:00
kxVerify :: PublicKey -> HashDescr -> ByteString -> ByteString -> Bool
kxVerify (PubKeyRSA pk) hashDescr msg sign = RSA.verify hashDescr pk msg sign
kxVerify _ _ _ _ = False
-- Sign the given message using the private key.
--
2012-12-30 15:31:13 +00:00
kxSign :: CPRG g => g -> PrivateKey -> HashDescr -> ByteString -> (Either KxError ByteString, g)
kxSign g (PrivKeyRSA pk) hashDescr msg =
2012-12-30 15:31:13 +00:00
generalizeRSAWithRNG $ RSA.signSafer g hashDescr pk msg
kxSign g _ _ _ =
(Left KxUnsupported, g)