hs-tls/Network/TLS/Crypto.hs
2010-09-26 16:07:29 +01:00

110 lines
2.6 KiB
Haskell

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 ]