diff --git a/Network/TLS/Cap.hs b/Network/TLS/Cap.hs
new file mode 100644
--- /dev/null
+++ b/Network/TLS/Cap.hs
@@ -0,0 +1,19 @@
+-- |
+-- Module      : Network.TLS.Cap
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+
+module Network.TLS.Cap
+	( hasHelloExtensions
+	, hasExplicitBlockIV
+	) where
+
+import Network.TLS.Struct
+
+hasHelloExtensions, hasExplicitBlockIV :: Version -> Bool
+
+hasHelloExtensions ver = ver >= TLS12
+hasExplicitBlockIV ver = ver >= TLS11
diff --git a/Network/TLS/Cipher.hs b/Network/TLS/Cipher.hs
--- a/Network/TLS/Cipher.hs
+++ b/Network/TLS/Cipher.hs
@@ -37,11 +37,11 @@
 
 data CipherTypeFunctions =
 	  CipherNoneF -- special value for 0
-	| CipherBlockF (Key -> IV -> L.ByteString -> L.ByteString)
-	               (Key -> IV -> L.ByteString -> L.ByteString)
+	| CipherBlockF (Key -> IV -> B.ByteString -> B.ByteString)
+	               (Key -> IV -> B.ByteString -> B.ByteString)
 	| CipherStreamF (Key -> IV)
-	                (IV -> L.ByteString -> (L.ByteString, IV))
-	                (IV -> L.ByteString -> (L.ByteString, IV))
+	                (IV -> B.ByteString -> (B.ByteString, IV))
+	                (IV -> B.ByteString -> (B.ByteString, IV))
 
 data CipherKeyExchangeType =
 	  CipherKeyExchangeRSA
@@ -63,7 +63,7 @@
 	, cipherKeyBlockSize :: Word8
 	, cipherPaddingSize  :: Word8
 	, cipherKeyExchange  :: CipherKeyExchangeType
-	, cipherHMAC         :: L.ByteString -> L.ByteString -> L.ByteString
+	, cipherHMAC         :: B.ByteString -> B.ByteString -> B.ByteString
 	, cipherF            :: CipherTypeFunctions
 	, cipherMinVer       :: Maybe Version
 	}
@@ -82,29 +82,32 @@
 cipherExchangeNeedMoreData CipherKeyExchangeECDH_RSA    = True
 cipherExchangeNeedMoreData CipherKeyExchangeECDHE_ECDSA = True
 
-repack :: Int -> L.ByteString -> [B.ByteString]
+repack :: Int -> B.ByteString -> [B.ByteString]
 repack bs x =
-	if L.length x > fromIntegral bs
+	if B.length x > bs
 		then
-			let (c1, c2) = L.splitAt (fromIntegral bs) x in
-			B.pack (L.unpack c1) : repack 16 c2
+			let (c1, c2) = B.splitAt bs x in
+			B.pack (B.unpack c1) : repack 16 c2
 		else
-			[ B.pack (L.unpack x) ]
+			[ x ]
 
-aes128_cbc_encrypt :: Key -> IV -> L.ByteString -> L.ByteString
-aes128_cbc_encrypt key iv d = AES.crypt AES.CBC key iv AES.Encrypt d16
+lazyToStrict :: L.ByteString -> B.ByteString
+lazyToStrict = B.concat . L.toChunks
+
+aes128_cbc_encrypt :: Key -> IV -> B.ByteString -> B.ByteString
+aes128_cbc_encrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Encrypt d16
 	where d16 = L.fromChunks $ repack 16 d
 
-aes128_cbc_decrypt :: Key -> IV -> L.ByteString -> L.ByteString
-aes128_cbc_decrypt key iv d = AES.crypt AES.CBC key iv AES.Decrypt d16
+aes128_cbc_decrypt :: Key -> IV -> B.ByteString -> B.ByteString
+aes128_cbc_decrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Decrypt d16
 	where d16 = L.fromChunks $ repack 16 d
 
-aes256_cbc_encrypt :: Key -> IV -> L.ByteString -> L.ByteString
-aes256_cbc_encrypt key iv d = AES.crypt AES.CBC key iv AES.Encrypt d16
+aes256_cbc_encrypt :: Key -> IV -> B.ByteString -> B.ByteString
+aes256_cbc_encrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Encrypt d16
 	where d16 = L.fromChunks $ repack 16 d
 
-aes256_cbc_decrypt :: Key -> IV -> L.ByteString -> L.ByteString
-aes256_cbc_decrypt key iv d = AES.crypt AES.CBC key iv AES.Decrypt d16
+aes256_cbc_decrypt :: Key -> IV -> B.ByteString -> B.ByteString
+aes256_cbc_decrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Decrypt d16
 	where d16 = L.fromChunks $ repack 32 d
 
 toIV :: RC4.Ctx -> IV
@@ -119,11 +122,11 @@
 initF_rc4 :: Key -> IV
 initF_rc4 key     = toIV $ RC4.initCtx (B.unpack key)
 
-encryptF_rc4 :: IV -> L.ByteString -> (L.ByteString, IV)
-encryptF_rc4 iv d = (\(ctx, e) -> (e, toIV ctx)) $ RC4.encryptlazy (toCtx iv) d
+encryptF_rc4 :: IV -> B.ByteString -> (B.ByteString, IV)
+encryptF_rc4 iv d = (\(ctx, e) -> (e, toIV ctx)) $ RC4.encrypt (toCtx iv) d
 
-decryptF_rc4 :: IV -> L.ByteString -> (L.ByteString, IV)
-decryptF_rc4 iv e = (\(ctx, d) -> (d, toIV ctx)) $ RC4.decryptlazy (toCtx iv) e
+decryptF_rc4 :: IV -> B.ByteString -> (B.ByteString, IV)
+decryptF_rc4 iv e = (\(ctx, d) -> (d, toIV ctx)) $ RC4.decrypt (toCtx iv) e
 
 {-
 TLS 1.0 ciphers definition
@@ -171,7 +174,7 @@
 	, cipherIVSize       = 0
 	, cipherKeyBlockSize = 0
 	, cipherPaddingSize  = 0
-	, cipherHMAC         = (\_ _ -> L.empty)
+	, cipherHMAC         = (\_ _ -> B.empty)
 	, cipherKeyExchange  = CipherKeyExchangeRSA
 	, cipherF            = CipherNoneF
 	, cipherMinVer       = Nothing
diff --git a/Network/TLS/Client.hs b/Network/TLS/Client.hs
--- a/Network/TLS/Client.hs
+++ b/Network/TLS/Client.hs
@@ -39,6 +39,7 @@
 import Network.TLS.Sending
 import Network.TLS.Receiving
 import Network.TLS.SRandom
+import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
 import System.IO (Handle, hFlush)
 import Data.List (find)
@@ -83,23 +84,23 @@
 
 runTLSClient :: TLSClient m a -> TLSClientParams -> SRandomGen -> m (a, TLSStateClient)
 runTLSClient f params rng = runTLSClientST f (TLSStateClient { scParams = params, scTLSState = state, scCertRequested = False  })
-	where state = (newTLSState rng) { stVersion = TLS10, stClientContext = True }
+	where state = (newTLSState rng) { stVersion = cpConnectVersion params, stClientContext = True }
 
 {- | receive a single TLS packet or on error a TLSError -}
 recvPacket :: Handle -> TLSClient IO (Either TLSError Packet)
 recvPacket handle = do
-	hdr <- lift $ L.hGet handle 5 >>= return . decodeHeader
+	hdr <- lift $ B.hGet handle 5 >>= return . decodeHeader
 	case hdr of
 		Left err                          -> return $ Left err
 		Right header@(Header _ _ readlen) -> do
-			content <- lift $ L.hGet handle (fromIntegral readlen)
+			content <- lift $ B.hGet handle (fromIntegral readlen)
 			readPacket header (EncryptedData content)
 
 {- | send a single TLS packet -}
 sendPacket :: Handle -> Packet -> TLSClient IO ()
 sendPacket handle pkt = do
 	dataToSend <- writePacket pkt
-	lift $ L.hPut handle dataToSend
+	lift $ B.hPut handle dataToSend
 
 recvServerHello :: Handle -> TLSClient IO ()
 recvServerHello handle = do
@@ -150,7 +151,7 @@
 connectSendFinish :: Handle -> TLSClient IO ()
 connectSendFinish handle = do
 	cf <- getHandshakeDigest True
-	sendPacket handle (Handshake $ Finished $ L.unpack cf)
+	sendPacket handle (Handshake $ Finished $ B.unpack cf)
 
 {- | connect through a handle as a new TLS connection. -}
 connect :: Handle -> ClientRandom -> ClientKeyData -> TLSClient IO ()
@@ -184,24 +185,27 @@
 
 	return ()
 
-{- | sendData sends a bunch of data -}
-sendData :: Handle -> L.ByteString -> TLSClient IO ()
-sendData handle d = do
-	if L.length d > 16384
+sendDataChunk :: Handle -> B.ByteString -> TLSClient IO ()
+sendDataChunk handle d =
+	if B.length d > 16384
 		then do
-			let (sending, remain) = L.splitAt 16384 d
+			let (sending, remain) = B.splitAt 16384 d
 			sendPacket handle $ AppData sending
-			sendData handle remain
+			sendDataChunk handle remain
 		else
 			sendPacket handle $ AppData d
 
+{- | sendData sends a bunch of data -}
+sendData :: Handle -> L.ByteString -> TLSClient IO ()
+sendData handle d = mapM_ (sendDataChunk handle) (L.toChunks d)
+
 {- | recvData get data out of Data packet, and automatically try to renegociate if
  - a Handshake HelloRequest is received -}
 recvData :: Handle -> TLSClient IO L.ByteString
 recvData handle = do
 	pkt <- recvPacket handle
 	case pkt of
-		Right (AppData x) -> return x
+		Right (AppData x) -> return $ L.fromChunks [x]
 		Right (Handshake HelloRequest) -> do
 			-- SECURITY FIXME audit the rng here..
 			st <- getTLSState
@@ -209,7 +213,7 @@
 			let (premaster, rng'') = getRandomBytes rng' 46
 			putTLSState $ st { stRandomGen = rng'' }
 			let crand = fromJust $ clientRandom bytes
-			connect handle crand (ClientKeyData premaster)
+			connect handle crand (ClientKeyData $ B.pack premaster)
 			recvData handle
 		Left err          -> error ("error received: " ++ show err)
 		_                 -> error "unexpected item"
diff --git a/Network/TLS/Crypto.hs b/Network/TLS/Crypto.hs
--- a/Network/TLS/Crypto.hs
+++ b/Network/TLS/Crypto.hs
@@ -28,11 +28,13 @@
 import qualified Data.CryptoHash.SHA1 as SHA1
 import qualified Data.CryptoHash.MD5 as MD5
 import qualified Data.ByteString as B
-import Data.ByteString.Lazy (ByteString)
+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 Random
+import Control.Arrow (first)
+import System.Random
 
 data HashCtx =
 	  SHA1 !SHA1.Ctx
@@ -49,28 +51,28 @@
 initMD5 :: MD5.Ctx
 initMD5 = MD5.init
 
-updateMD5 :: MD5.Ctx -> B.ByteString -> MD5.Ctx
+updateMD5 :: MD5.Ctx -> ByteString -> MD5.Ctx
 updateMD5 = MD5.update
 
-finalizeMD5 :: MD5.Ctx -> B.ByteString
+finalizeMD5 :: MD5.Ctx -> ByteString
 finalizeMD5 = MD5.finalize
 
-hashMD5 :: ByteString -> B.ByteString
-hashMD5 = MD5.hashlazy
+hashMD5 :: ByteString -> ByteString
+hashMD5 = MD5.hash
 
 {- SHA1 -}
 
 initSHA1 :: SHA1.Ctx
 initSHA1 = SHA1.init
 
-updateSHA1 :: SHA1.Ctx -> B.ByteString -> SHA1.Ctx
+updateSHA1 :: SHA1.Ctx -> ByteString -> SHA1.Ctx
 updateSHA1 = SHA1.update
 
-finalizeSHA1 :: SHA1.Ctx -> B.ByteString
+finalizeSHA1 :: SHA1.Ctx -> ByteString
 finalizeSHA1 = SHA1.finalize
 
-hashSHA1 :: ByteString -> B.ByteString
-hashSHA1 = SHA1.hashlazy
+hashSHA1 :: ByteString -> ByteString
+hashSHA1 = SHA1.hash
 
 {- generic Hashing -}
 
@@ -94,8 +96,15 @@
  need to fix the RSA package to return "Either String X".
 -}
 
-rsaEncrypt :: RandomGen g => g -> PublicKey -> ByteString -> Maybe (ByteString, g)
-rsaEncrypt g pk b = teaspoon (RSA.rsaes_pkcs1_v1_5_encrypt g pk b)
+lazyToStrict :: L.ByteString -> B.ByteString
+lazyToStrict = B.concat . L.toChunks
 
-rsaDecrypt :: PrivateKey -> ByteString -> Maybe ByteString
-rsaDecrypt pk b = teaspoon (RSA.rsaes_pkcs1_v1_5_decrypt pk b)
+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 ]
diff --git a/Network/TLS/MAC.hs b/Network/TLS/MAC.hs
--- a/Network/TLS/MAC.hs
+++ b/Network/TLS/MAC.hs
@@ -10,54 +10,50 @@
 import qualified Data.CryptoHash.MD5 as MD5
 import qualified Data.CryptoHash.SHA1 as SHA1
 import qualified Data.CryptoHash.SHA256 as SHA256
-import qualified Data.ByteString.Lazy as L
 import qualified Data.ByteString as B
-import Data.ByteString.Lazy (ByteString)
+import Data.ByteString (ByteString)
 import Data.Bits (xor)
 
-lazyOfStrict :: B.ByteString -> ByteString
-lazyOfStrict b = L.fromChunks [ b ]
-
 hmac :: (ByteString -> ByteString) -> Int -> ByteString -> ByteString -> ByteString
 hmac f bl secret msg =
-	f $! L.append opad (f $! L.append ipad msg)
+	f $! B.append opad (f $! B.append ipad msg)
 	where
-		opad = L.map (xor 0x5c) k'
-		ipad = L.map (xor 0x36) k'
+		opad = B.map (xor 0x5c) k'
+		ipad = B.map (xor 0x36) k'
 
-		k' = L.append kt pad
+		k' = B.append kt pad
 			where
-			kt  = if L.length secret > fromIntegral bl then f secret else secret
-			pad = L.replicate (fromIntegral bl - L.length kt) 0
+			kt  = if B.length secret > fromIntegral bl then f secret else secret
+			pad = B.replicate (fromIntegral bl - B.length kt) 0
 
 hmacMD5 :: ByteString -> ByteString -> ByteString
-hmacMD5 secret msg = hmac (lazyOfStrict . MD5.hashlazy) 64 secret msg
+hmacMD5 secret msg = hmac MD5.hash 64 secret msg
 
 hmacSHA1 :: ByteString -> ByteString -> ByteString
-hmacSHA1 secret msg = hmac (lazyOfStrict . SHA1.hashlazy) 64 secret msg
+hmacSHA1 secret msg = hmac SHA1.hash 64 secret msg
 
 hmacSHA256 :: ByteString -> ByteString -> ByteString
-hmacSHA256 secret msg = hmac (lazyOfStrict . SHA256.hashlazy) 64 secret msg
+hmacSHA256 secret msg = hmac SHA256.hash 64 secret msg
 
 hmacIter :: (ByteString -> ByteString -> ByteString) -> ByteString -> ByteString -> ByteString -> Int -> [ByteString]
 hmacIter f secret seed aprev len =
 	let an = f secret aprev in
-	let out = f secret (L.concat [an, seed]) in
-	let digestsize = fromIntegral $ L.length out in
+	let out = f secret (B.concat [an, seed]) in
+	let digestsize = fromIntegral $ B.length out in
 	if digestsize >= len
-		then [ L.take (fromIntegral len) out ]
+		then [ B.take (fromIntegral len) out ]
 		else out : hmacIter f secret seed an (len - digestsize)
 
 prf_SHA1 :: ByteString -> ByteString -> Int -> ByteString
-prf_SHA1 secret seed len = L.concat $ hmacIter hmacSHA1 secret seed seed len
+prf_SHA1 secret seed len = B.concat $ hmacIter hmacSHA1 secret seed seed len
 
 prf_MD5 :: ByteString -> ByteString -> Int -> ByteString
-prf_MD5 secret seed len = L.concat $ hmacIter hmacMD5 secret seed seed len
+prf_MD5 secret seed len = B.concat $ hmacIter hmacMD5 secret seed seed len
 
 prf_MD5SHA1 :: ByteString -> ByteString -> Int -> ByteString
 prf_MD5SHA1 secret seed len =
-	L.pack $ L.zipWith xor (prf_MD5 s1 seed len) (prf_SHA1 s2 seed len)
+	B.pack $ B.zipWith xor (prf_MD5 s1 seed len) (prf_SHA1 s2 seed len)
 	where
-		slen  = L.length secret
-		s1    = L.take (slen `div` 2 + slen `mod` 2) secret
-		s2    = L.drop (slen `div` 2) secret
+		slen  = B.length secret
+		s1    = B.take (slen `div` 2 + slen `mod` 2) secret
+		s2    = B.drop (slen `div` 2) secret
diff --git a/Network/TLS/Packet.hs b/Network/TLS/Packet.hs
--- a/Network/TLS/Packet.hs
+++ b/Network/TLS/Packet.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE OverloadedStrings #-}
 -- |
 -- Module      : Network.TLS.Packet
 -- License     : BSD-style
@@ -36,20 +37,21 @@
 	, generateServerFinished
 	) where
 
-import Data.Word
+import Network.TLS.Struct
+import Network.TLS.Cap
 import Network.TLS.Wire
 import Data.Either (partitionEithers)
 import Data.Maybe (fromJust, isNothing)
 import Control.Applicative ((<$>))
 import Control.Monad
 import Control.Monad.Error
-import Network.TLS.Struct
 import Data.Certificate.X509
 import Network.TLS.Crypto
 import Network.TLS.MAC
-import Data.ByteString.Lazy (ByteString)
-import qualified Data.ByteString.Lazy as L (pack, length, concat, fromChunks)
+import Data.ByteString (ByteString)
 import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as BC
+import qualified Data.ByteString.Lazy as L
 
 {-
  - decode and encode headers
@@ -89,7 +91,7 @@
 
 {- decode and encode HANDSHAKE -}
 
-decodeHandshakeHeader :: ByteString -> Either TLSError (HandshakeType, ByteString)
+decodeHandshakeHeader :: ByteString -> Either TLSError (HandshakeType, Bytes)
 decodeHandshakeHeader = runGet $ do
 	tyopt <- getWord8 >>= return . valToType
 	ty <- if isNothing tyopt
@@ -99,7 +101,7 @@
 	content <- getBytes len
 	empty <- isEmpty
 	unless empty (throwError (Error_Internal_Packet_Remaining 1))
-	return (ty, L.fromChunks [content])
+	return (ty, content)
 
 decodeHandshake :: Version -> HandshakeType -> ByteString -> Either TLSError Handshake
 decodeHandshake ver ty = runGet $ case ty of
@@ -125,7 +127,7 @@
 	ciphers      <- getWords16
 	compressions <- getWords8
 	r            <- remaining
-	exts <- if ver >= TLS12 && r > 0
+	exts <- if hasHelloExtensions ver && r > 0
 		then fmap fromIntegral getWord16 >>= getExtensions >>= return . Just
 		else return Nothing
 	return $ ClientHello ver random session ciphers compressions exts
@@ -138,7 +140,7 @@
 	cipherid      <- getWord16
 	compressionid <- getWord8
 	r             <- remaining
-	exts <- if ver >= TLS12 && r > 0
+	exts <- if hasHelloExtensions ver && r > 0
 		then fmap fromIntegral getWord16 >>= getExtensions >>= return . Just
 		else return Nothing
 	return $ ServerHello ver random session cipherid compressionid exts
@@ -161,7 +163,8 @@
 	-- so just return the remaining string.
 	len <- if ver >= TLS12
 		then remaining
-		else return 12
+		else if ver == SSL3 then return 36
+			else return 12
 	opaque <- getBytes (fromIntegral len)
 	return $ Finished $ B.unpack opaque
 
@@ -230,9 +233,9 @@
 encodeHandshake :: Handshake -> ByteString
 encodeHandshake o =
 	let content = runPut $ encodeHandshakeContent o in
-	let len = fromIntegral $ L.length content in
+	let len = fromIntegral $ B.length content in
 	let header = runPut $ encodeHandshakeHeader (typeOfHandshake o) len in
-	L.concat [ header, content ]
+	B.concat [ header, content ]
 
 encodeHandshakeHeader :: HandshakeType -> Int -> Put
 encodeHandshakeHeader ty len = putWord8 (valOfType ty) >> putWord24 len
@@ -254,10 +257,10 @@
 	                   >> putExtensions exts >> return ()
 
 encodeHandshakeContent (Certificates certs) =
-	putWord24 len >> putLazyByteString certbs
+	putWord24 len >> putBytes certbs
 	where
 		certbs = runPut $ mapM_ putCert certs
-		len    = fromIntegral $ L.length certbs
+		len    = fromIntegral $ B.length certbs
 
 encodeHandshakeContent (ClientKeyXchg version random) = do
 	putVersion version
@@ -275,7 +278,7 @@
 	case sigAlgs of
 		Nothing -> return ()
 		Just l  -> putWords16 $ map (\(x,y) -> (fromIntegral $ valOfType x) * 256 + (fromIntegral $ valOfType y)) l
-	putByteString $ B.pack certAuthorities
+	putBytes $ B.pack certAuthorities
 
 encodeHandshakeContent (CertVerify _) = undefined
 
@@ -295,8 +298,8 @@
 	where (major, minor) = numericalVer ver
 
 {- FIXME make sure it return error if not 32 available -}
-getRandom32 :: Get [Word8]
-getRandom32 = B.unpack <$> getBytes 32
+getRandom32 :: Get Bytes
+getRandom32 = getBytes 32
 
 getServerRandom32 :: Get ServerRandom
 getServerRandom32 = ServerRandom <$> getRandom32
@@ -304,8 +307,8 @@
 getClientRandom32 :: Get ClientRandom
 getClientRandom32 = ClientRandom <$> getRandom32
 
-putRandom32 :: [Word8] -> Put
-putRandom32 = mapM_ putWord8
+putRandom32 :: Bytes -> Put
+putRandom32 = putBytes
 
 putClientRandom32 :: ClientRandom -> Put
 putClientRandom32 (ClientRandom r) = putRandom32 r
@@ -314,25 +317,25 @@
 putServerRandom32 (ServerRandom r) = putRandom32 r
 
 getClientKeyData46 :: Get ClientKeyData
-getClientKeyData46 = ClientKeyData . B.unpack <$> getBytes 46
+getClientKeyData46 = ClientKeyData <$> getBytes 46
 
 putClientKeyData46 :: ClientKeyData -> Put
-putClientKeyData46 (ClientKeyData d) = mapM_ putWord8 d
+putClientKeyData46 (ClientKeyData d) = putBytes d
 
 getSession :: Get Session
 getSession = do
 	len8 <- getWord8
 	case fromIntegral len8 of
 		0   -> return $ Session Nothing
-		len -> Session . Just . B.unpack <$> getBytes len
+		len -> Session . Just <$> getBytes len
 
 putSession :: Session -> Put
 putSession (Session session) =
 	case session of
 		Nothing -> putWord8 0
-		Just s  -> putWord8 (fromIntegral $ length s) >> mapM_ putWord8 s
+		Just s  -> putWord8 (fromIntegral $ B.length s) >> putBytes s
 
-getCerts :: Int -> Get [B.ByteString]
+getCerts :: Int -> Get [Bytes]
 getCerts 0   = return []
 getCerts len = do
 	certlen <- getWord24
@@ -341,8 +344,8 @@
 	return (cert : certxs)
 
 putCert :: Certificate -> Put
-putCert cert = putWord24 (fromIntegral $ L.length content) >> putLazyByteString content
-	where content = encodeCertificate cert
+putCert cert = putWord24 (fromIntegral $ B.length content) >> putBytes content
+	where content = B.concat $ L.toChunks $ encodeCertificate cert
 
 getExtensions :: Int -> Get [Extension]
 getExtensions 0   = return []
@@ -357,12 +360,12 @@
 putExtension (ty, l) = do
 	putWord16 ty
 	putWord16 (fromIntegral $ length l)
-	putByteString (B.pack l)
+	putBytes (B.pack l)
 
 putExtensions :: Maybe [Extension] -> Put
 putExtensions Nothing   = return ()
 putExtensions (Just es) =
-	putWord16 (fromIntegral $ L.length extbs) >> putLazyByteString extbs
+	putWord16 (fromIntegral $ B.length extbs) >> putBytes extbs
 	where
 		extbs = runPut $ mapM_ putExtension es
 
@@ -381,29 +384,48 @@
 {-
  - generate things for packet content
  -}
-generateMasterSecret :: ByteString -> ClientRandom -> ServerRandom -> ByteString
-generateMasterSecret premasterSecret (ClientRandom c) (ServerRandom s) =
+generateMasterSecret_TLS, generateMasterSecret_SSL :: Bytes -> ClientRandom -> ServerRandom -> Bytes
+generateMasterSecret_TLS premasterSecret (ClientRandom c) (ServerRandom s) =
 	prf_MD5SHA1 premasterSecret seed 48
 	where
-		label = map (toEnum . fromEnum) "master secret"
-		seed = L.concat $ map L.pack [ label, c, s]
+		seed = B.concat [ BC.pack "master secret", c, s ]
 
-generateKeyBlock :: ClientRandom -> ServerRandom -> ByteString -> Int -> ByteString
+generateMasterSecret_SSL premasterSecret (ClientRandom c) (ServerRandom s) =
+	B.concat $ map (computeMD5 . BC.pack) [ "A", "BB", "CCC" ]
+	where
+		computeMD5  label = hashMD5 $ B.concat [ premasterSecret, computeSHA1 label ]
+		computeSHA1 label = hashSHA1 $ B.concat [ label, premasterSecret, c, s ]
+
+generateMasterSecret :: Version -> Bytes -> ClientRandom -> ServerRandom -> Bytes
+generateMasterSecret ver =
+	if ver < TLS10 then generateMasterSecret_SSL else generateMasterSecret_TLS
+
+generateKeyBlock :: ClientRandom -> ServerRandom -> Bytes -> Int -> Bytes
 generateKeyBlock (ClientRandom c) (ServerRandom s) mastersecret kbsize =
 	prf_MD5SHA1 mastersecret seed kbsize
 	where
-		label = map (toEnum . fromEnum) "key expansion"
-		seed = L.concat $ map L.pack [ label, s, c ]
+		seed = B.concat [ BC.pack "key expansion", s, c ]
 
-generateFinished :: String -> ByteString -> HashCtx -> HashCtx -> ByteString
-generateFinished label mastersecret md5ctx sha1ctx =
+generateFinished_TLS :: Bytes -> Bytes -> HashCtx -> HashCtx -> Bytes
+generateFinished_TLS label mastersecret md5ctx sha1ctx =
 	prf_MD5SHA1 mastersecret seed 12
 	where
-		plabel = B.pack $ map (toEnum . fromEnum) label
-		seed = L.fromChunks [ plabel, finalizeHash md5ctx, finalizeHash sha1ctx ]
+		seed = B.concat [ label, finalizeHash md5ctx, finalizeHash sha1ctx ]
 
-generateClientFinished :: ByteString -> HashCtx -> HashCtx -> ByteString
-generateClientFinished = generateFinished "client finished"
+generateFinished_SSL :: Bytes -> Bytes -> HashCtx -> HashCtx -> Bytes
+generateFinished_SSL sender mastersecret md5ctx sha1ctx =
+	B.concat [md5hash, sha1hash]
+	where
+		md5hash = hashMD5 $ B.concat [ mastersecret, pad2, md5left ]
+		sha1hash = hashSHA1 $ B.concat [ mastersecret, pad2, sha1left ]
+		pad2 = B.empty -- FIXME
+		md5left = hashMD5 B.empty
+		sha1left = hashSHA1 B.empty
 
-generateServerFinished :: ByteString -> HashCtx -> HashCtx -> ByteString
-generateServerFinished = generateFinished "server finished"
+generateClientFinished :: Version -> Bytes -> HashCtx -> HashCtx -> Bytes
+generateClientFinished ver =
+	if ver < TLS10 then generateFinished_SSL "CLNT" else generateFinished_TLS (BC.pack "client finished")
+
+generateServerFinished :: Version -> Bytes -> HashCtx -> HashCtx -> Bytes
+generateServerFinished ver =
+	if ver < TLS10 then generateFinished_SSL "SRVR" else generateFinished_TLS (BC.pack "server finished")
diff --git a/Network/TLS/Receiving.hs b/Network/TLS/Receiving.hs
--- a/Network/TLS/Receiving.hs
+++ b/Network/TLS/Receiving.hs
@@ -19,10 +19,12 @@
 import Control.Monad.Error
 import Data.Maybe
 
-import Data.ByteString.Lazy (ByteString)
+import Data.ByteString (ByteString)
 import qualified Data.ByteString.Lazy as L
 import qualified Data.ByteString as B
 
+import Network.TLS.Util
+import Network.TLS.Cap
 import Network.TLS.Struct
 import Network.TLS.Packet
 import Network.TLS.State
@@ -72,14 +74,14 @@
 decryptRSA :: MonadTLSState m => ByteString -> m (Maybe ByteString)
 decryptRSA econtent = do
 	rsapriv <- getTLSState >>= return . fromJust . hstRSAPrivateKey . fromJust . stHandshake
-	return $ rsaDecrypt rsapriv (L.drop 2 econtent)
+	return $ rsaDecrypt rsapriv (B.drop 2 econtent)
 
 setMasterSecretRandom :: ByteString -> TLSRead ()
 setMasterSecretRandom content = do
 	st <- getTLSState
-	let (bytes, g') = getRandomBytes (stRandomGen st) (fromIntegral $ L.length content)
+	let (bytes, g') = getRandomBytes (stRandomGen st) (fromIntegral $ B.length content)
 	putTLSState $ st { stRandomGen = g' }
-	setMasterSecret (L.pack bytes)
+	setMasterSecret (B.pack bytes)
 
 processClientKeyXchg :: Version -> ByteString -> TLSRead ()
 processClientKeyXchg ver content = do
@@ -93,7 +95,7 @@
 processClientFinished fdata = do
 	cc <- getTLSState >>= return . stClientContext
 	expected <- getHandshakeDigest (not cc)
-	when (expected /= L.pack fdata) $ do
+	when (expected /= B.pack fdata) $ do
 		-- FIXME don't fail, but report the error so that the code can send a BadMac Alert.
 		fail ("client mac failure: expecting " ++ show expected ++ " received " ++ (show $L.pack fdata))
 	return ()
@@ -110,7 +112,7 @@
 			return econtent
 	hs <- case (ty, decodeHandshake ver ty content) of
 		(_, Right x)                            -> return x
-		(HandshakeType_ClientKeyXchg, Left _)   -> return $ ClientKeyXchg SSL2 (ClientKeyData $ replicate 0xff 46)
+		(HandshakeType_ClientKeyXchg, Left _)   -> return $ ClientKeyXchg SSL2 (ClientKeyData $ B.replicate 46 0xff)
 		(_, Left err)                           -> throwError err
 	clientmode <- isClientContext
 	case hs of
@@ -127,31 +129,40 @@
 	when (finishHandshakeTypeMaterial ty) (updateHandshakeDigest dcontent)
 	return $ Handshake hs
 
-decryptContentReally :: Header -> EncryptedData -> TLSRead ByteString
-decryptContentReally hdr e = do
-	st <- getTLSState
-	unencrypted_content <- decryptData e
-	let digestSize = cipherDigestSize $ fromJust $ stCipher st
-	let (unencrypted_msg, digest) = L.splitAt (L.length unencrypted_content - fromIntegral digestSize) unencrypted_content
-	let (Header pt ver _) = hdr
-	let new_hdr = Header pt ver (fromIntegral $ L.length unencrypted_msg)
-	expected_digest <- makeDigest False new_hdr unencrypted_msg
 
-	if expected_digest == digest
-		then return $ unencrypted_msg
-		else throwError $ Error_Digest (L.unpack expected_digest, L.unpack digest)
-
 decryptContent :: Header -> EncryptedData -> TLSRead ByteString
 decryptContent hdr e@(EncryptedData b) = do
 	st <- getTLSState
 	if stRxEncrypted st
-		then decryptContentReally hdr e
+		then decryptData e >>= getCipherData hdr
 		else return b
 
-takelast :: Int -> [a] -> [a]
-takelast i b = drop (length b - i) b
+getCipherData :: Header -> CipherData -> TLSRead ByteString
+getCipherData hdr cdata = do
+	-- check if the MAC is valid.
+	macValid <- case cipherDataMAC cdata of
+		Nothing     -> return True
+		Just digest -> do
+			let (Header pt ver _) = hdr
+			let new_hdr = Header pt ver (fromIntegral $ B.length $ cipherDataContent cdata)
+			expected_digest <- makeDigest False new_hdr $ cipherDataContent cdata
+			if expected_digest == digest
+				then return True
+				else return False
 
-decryptData :: EncryptedData -> TLSRead ByteString
+	-- check if the padding is filled with the correct pattern if it exists
+	paddingValid <- case cipherDataPadding cdata of
+		Nothing  -> return True
+		Just pad -> do
+			let b = B.length pad - 1
+			return $ maybe True (const False) $ B.find (/= fromIntegral b) pad
+
+	unless (and $! [ macValid, paddingValid ]) $ do
+		throwError $ Error_Digest ([], [])
+
+	return $ cipherDataContent cdata
+
+decryptData :: EncryptedData -> TLSRead CipherData
 decryptData (EncryptedData econtent) = do
 	st <- getTLSState
 
@@ -159,32 +170,44 @@
 		[ ("cipher", isNothing $ stCipher st)
 		, ("crypt state", isNothing $ stRxCryptState st) ]
 
-	let cipher = fromJust $ stCipher st
-	let cst = fromJust $ stRxCryptState st
+	let cipher       = fromJust $ stCipher st
+	let cst          = fromJust $ stRxCryptState st
 	let padding_size = fromIntegral $ cipherPaddingSize cipher
-
-	let writekey = B.pack $ cstKey cst
-	let iv = B.pack $ cstIV cst
+	let digestSize   = fromIntegral $ cipherDigestSize cipher
+	let writekey     = cstKey cst
 
-	contentpadded <- case cipherF cipher of
+	case cipherF cipher of
 		CipherNoneF -> fail "none decrypt"
 		CipherBlockF _ decryptF -> do
 			{- update IV -}
-			let newiv = takelast padding_size $ L.unpack econtent
+			let (iv, econtent') =
+				if hasExplicitBlockIV $ stVersion st
+					then B.splitAt (fromIntegral $ cipherIVSize cipher) econtent
+					else (cstIV cst, econtent)
+			let newiv = fromJust $ takelast padding_size econtent'
 			putTLSState $ st { stRxCryptState = Just $ cst { cstIV = newiv } }
-			return $ decryptF writekey iv econtent
+
+			let content' = decryptF writekey iv econtent'
+			let paddinglength = fromIntegral (B.last content') + 1
+			let contentlen = B.length content' - paddinglength - digestSize
+			let (content, mac, padding) = fromJust $ partition3 content' (contentlen, digestSize, paddinglength)
+			return $ CipherData
+				{ cipherDataContent = content
+				, cipherDataMAC     = Just mac
+				, cipherDataPadding = Just padding
+				}
 		CipherStreamF initF _ decryptF -> do
-			let (content, newiv) = decryptF (if iv /= B.empty then iv else initF writekey) econtent
+			let iv = cstIV cst
+			let (content', newiv) = decryptF (if iv /= B.empty then iv else initF writekey) econtent
 			{- update Ctx -}
-			putTLSState $ st { stRxCryptState = Just $ cst { cstIV = B.unpack newiv } }
-			return $ content
-	let content =
-		if cipherPaddingSize cipher > 0
-			then
-				let pb = L.last contentpadded + 1 in
-				fst $ L.splitAt ((L.length contentpadded) - fromIntegral pb) contentpadded
-			else contentpadded
-	return content
+			let contentlen        = B.length content' - digestSize
+			let (content, mac, _) = fromJust $ partition3 content' (contentlen, digestSize, 0)
+			putTLSState $ st { stRxCryptState = Just $ cst { cstIV = newiv } }
+			return $ CipherData
+				{ cipherDataContent = content
+				, cipherDataMAC     = Just mac
+				, cipherDataPadding = Nothing
+				}
 
 processCertificates :: [Certificate] -> TLSRead ()
 processCertificates certs = do
diff --git a/Network/TLS/SRandom.hs b/Network/TLS/SRandom.hs
--- a/Network/TLS/SRandom.hs
+++ b/Network/TLS/SRandom.hs
@@ -7,7 +7,7 @@
 	, getRandomBytes
 	) where
 
-import Random
+import System.Random
 import Control.Arrow (first)
 import Data.Word
 
diff --git a/Network/TLS/Sending.hs b/Network/TLS/Sending.hs
--- a/Network/TLS/Sending.hs
+++ b/Network/TLS/Sending.hs
@@ -15,13 +15,14 @@
 	) where
 
 import Control.Monad.State
-import Data.Binary.Put (runPut, putWord16be)
 import Data.Maybe
 
-import Data.ByteString.Lazy (ByteString)
-import qualified Data.ByteString.Lazy as L
+import Data.ByteString (ByteString)
 import qualified Data.ByteString as B
 
+import Network.TLS.Util
+import Network.TLS.Cap
+import Network.TLS.Wire
 import Network.TLS.Struct
 import Network.TLS.Packet
 import Network.TLS.State
@@ -36,7 +37,7 @@
 makePacketData pkt = do
 	ver <- getTLSState >>= return . stVersion
 	content <- writePacketContent pkt
-	let hdr = Header (packetType pkt) ver (fromIntegral $ L.length content)
+	let hdr = Header (packetType pkt) ver (fromIntegral $ B.length content)
 	return (hdr, content)
 
 {-
@@ -73,7 +74,7 @@
  - marshall packet data
  -}
 encodePacket :: MonadTLSState m => (Header, ByteString) -> m ByteString
-encodePacket (hdr, content) = return $ L.concat [ encodeHeader hdr, content ]
+encodePacket (hdr, content) = return $ B.concat [ encodeHeader hdr, content ]
 
 
 {-
@@ -105,13 +106,10 @@
 encryptContent :: MonadTLSState m => (Header, ByteString) -> m (Header, ByteString)
 encryptContent (hdr@(Header pt ver _), content) = do
 	digest <- makeDigest True hdr content
-	encrypted_msg <- encryptData $ L.concat [content, digest]
-	let hdrnew = Header pt ver (fromIntegral $ L.length encrypted_msg)
+	encrypted_msg <- encryptData $ B.concat [content, digest]
+	let hdrnew = Header pt ver (fromIntegral $ B.length encrypted_msg)
 	return (hdrnew, encrypted_msg)
 
-takelast :: Int -> [a] -> [a]
-takelast i b = drop (length b - i) b
-
 encryptData :: MonadTLSState m => ByteString -> m ByteString
 encryptData content = do
 	st <- getTLSState
@@ -124,27 +122,30 @@
 	let cst = fromJust $ stTxCryptState st
 	let padding_size = fromIntegral $ cipherPaddingSize cipher
 
-	let msg_len = L.length content
+	let msg_len = B.length content
 	let padding = if padding_size > 0
 		then
 			let padbyte = padding_size - (msg_len `mod` padding_size) in
 			let padbyte' = if padbyte == 0 then padding_size else padbyte in
-			L.replicate padbyte' (fromIntegral (padbyte' - 1))
+			B.replicate padbyte' (fromIntegral (padbyte' - 1))
 		else
-			L.empty
-	let writekey = B.pack $ cstKey cst
-	let iv = B.pack $ cstIV cst
+			B.empty
+	let writekey = cstKey cst
 
 	econtent <- case cipherF cipher of
 		CipherNoneF -> fail "none encrypt"
 		CipherBlockF encrypt _ -> do
-			let e = encrypt writekey iv (L.concat [ content, padding ])
-			let newiv = takelast (fromIntegral padding_size) $ L.unpack e
+			let iv = cstIV cst
+			let e = encrypt writekey iv (B.concat [ content, padding ])
+			let newiv = fromJust $ takelast (fromIntegral $ cipherIVSize cipher) e
 			putTLSState $ st { stTxCryptState = Just $ cst { cstIV = newiv } }
-			return e
+			return $ if hasExplicitBlockIV $ stVersion st
+				then B.concat [iv,e]
+				else e
 		CipherStreamF initF encryptF _ -> do
+			let iv = cstIV cst
 			let (e, newiv) = encryptF (if iv /= B.empty then iv else initF writekey) content
-			putTLSState $ st { stTxCryptState = Just $ cst { cstIV = B.unpack newiv } }
+			putTLSState $ st { stTxCryptState = Just $ cst { cstIV = newiv } }
 			return e
 	return econtent
 
@@ -159,9 +160,9 @@
 	let premastersecret = runPut $ encodeHandshakeContent ckx
 	setMasterSecret premastersecret
 	econtent <- encryptRSA premastersecret
-	let extralength = runPut $ putWord16be $ fromIntegral $ L.length econtent
-	let hdr = runPut $ encodeHandshakeHeader (typeOfHandshake ckx) (fromIntegral (L.length econtent + 2))
-	return $ L.concat [hdr, extralength, econtent]
+	let extralength = runPut $ putWord16 $ fromIntegral $ B.length econtent
+	let hdr = runPut $ encodeHandshakeHeader (typeOfHandshake ckx) (fromIntegral (B.length econtent + 2))
+	return $ B.concat [hdr, extralength, econtent]
 
 writePacketContent pkt@(Handshake (ClientHello ver crand _ _ _ _)) = do
 	cc <- isClientContext
diff --git a/Network/TLS/Server.hs b/Network/TLS/Server.hs
--- a/Network/TLS/Server.hs
+++ b/Network/TLS/Server.hs
@@ -40,10 +40,11 @@
 import Network.TLS.Sending
 import Network.TLS.Receiving
 import Network.TLS.SRandom
+import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
 import System.IO (Handle, hFlush)
 
-type TLSServerCert = (L.ByteString, Certificate, CertificateKey.PrivateKey)
+type TLSServerCert = (B.ByteString, Certificate, CertificateKey.PrivateKey)
 
 data TLSServerCallbacks = TLSServerCallbacks
 	{ cbCertificates :: Maybe ([Certificate] -> IO Bool) -- ^ optional callback to verify certificates
@@ -84,23 +85,23 @@
 
 runTLSServer :: TLSServer m a -> TLSServerParams -> SRandomGen -> m (a, TLSStateServer)
 runTLSServer f params rng = runTLSServerST f (TLSStateServer { scParams = params, scTLSState = state })
-	where state = (newTLSState rng) { stVersion = TLS10, stClientContext = False }
+	where state = (newTLSState rng) { stClientContext = False }
 
 {- | receive a single TLS packet or on error a TLSError -}
 recvPacket :: Handle -> TLSServer IO (Either TLSError Packet)
 recvPacket handle = do
-	hdr <- lift $ L.hGet handle 5 >>= return . decodeHeader
+	hdr <- lift $ B.hGet handle 5 >>= return . decodeHeader
 	case hdr of
 		Left err -> return $ Left err
 		Right header@(Header _ _ readlen) -> do
-			content <- lift $ L.hGet handle (fromIntegral readlen)
+			content <- lift $ B.hGet handle (fromIntegral readlen)
 			readPacket header (EncryptedData content)
 
 {- | send a single TLS packet -}
 sendPacket :: Handle -> Packet -> TLSServer IO ()
 sendPacket handle pkt = do
 	dataToSend <- writePacket pkt
-	lift $ L.hPut handle dataToSend
+	lift $ B.hPut handle dataToSend
 
 handleClientHello :: Handshake -> TLSServer IO ()
 handleClientHello (ClientHello ver _ _ ciphers compressionID _) = do
@@ -173,7 +174,7 @@
 	when needkeyxchg $ do
 		let skg = SKX_RSA Nothing
 		sendPacket handle (Handshake $ ServerKeyXchg skg)
-	-- FIXME we don't do this on a Anonyous server
+	-- FIXME we don't do this on a Anonymous server
 	when (spWantClientCert sp) $ do
 		let certTypes = [ CertificateType_RSA_Sign ]
 		let creq = CertRequest certTypes Nothing [0,0,0]
@@ -183,7 +184,7 @@
 handshakeSendFinish :: Handle -> TLSServer IO ()
 handshakeSendFinish handle = do
 	cf <- getHandshakeDigest False
-	sendPacket handle (Handshake $ Finished $ L.unpack cf)
+	sendPacket handle (Handshake $ Finished $ B.unpack cf)
 
 {- after receiving a client hello, we need to redo a handshake -}
 handshake :: Handle -> ServerRandom -> TLSServer IO ()
@@ -213,17 +214,20 @@
 
 	return ()
 
-{- | sendData sends a bunch of data -}
-sendData :: Handle -> L.ByteString -> TLSServer IO ()
-sendData handle d =
-	if L.length d > 16384
+sendDataChunk :: Handle -> B.ByteString -> TLSServer IO ()
+sendDataChunk handle d =
+	if B.length d > 16384
 		then do
-			let (sending, remain) = L.splitAt 16384 d
+			let (sending, remain) = B.splitAt 16384 d
 			sendPacket handle $ AppData sending
-			sendData handle remain
+			sendDataChunk handle remain
 		else
 			sendPacket handle $ AppData d
 
+{- | sendData sends a bunch of data -}
+sendData :: Handle -> L.ByteString -> TLSServer IO ()
+sendData handle d = mapM_ (sendDataChunk handle) (L.toChunks d)
+
 {- | recvData get data out of Data packet, and automatically renegociate if
  - a Handshake ClientHello is received -}
 recvData :: Handle -> TLSServer IO L.ByteString
@@ -238,7 +242,7 @@
 			let srand = fromJust $ serverRandom bytes
 			handshake handle srand
 			recvData handle
-		Right (AppData x) -> return x
+		Right (AppData x) -> return $ L.fromChunks [x]
 		Left err          -> error ("error received: " ++ show err)
 		_                 -> error "unexpected item"
 
diff --git a/Network/TLS/State.hs b/Network/TLS/State.hs
--- a/Network/TLS/State.hs
+++ b/Network/TLS/State.hs
@@ -37,14 +37,14 @@
 
 import Data.Word
 import Data.Maybe (fromJust, isNothing)
+import Network.TLS.Util
 import Network.TLS.Struct
 import Network.TLS.SRandom
 import Network.TLS.Wire
 import Network.TLS.Packet
 import Network.TLS.Crypto
 import Network.TLS.Cipher
-import Data.ByteString.Lazy (ByteString)
-import qualified Data.ByteString.Lazy as L
+import qualified Data.ByteString as B
 import Control.Monad
 
 assert :: Monad m => String -> [(String,Bool)] -> m ()
@@ -52,9 +52,9 @@
 	when assumption $ fail (fctname ++ ": assumption about " ++ name ++ " failed")
 
 data TLSCryptState = TLSCryptState
-	{ cstKey        :: ![Word8]
-	, cstIV         :: ![Word8]
-	, cstMacSecret  :: L.ByteString
+	{ cstKey        :: !Bytes
+	, cstIV         :: !Bytes
+	, cstMacSecret  :: !Bytes
 	} deriving (Show)
 
 data TLSMacState = TLSMacState
@@ -65,7 +65,7 @@
 	{ hstClientVersion   :: !(Version)
 	, hstClientRandom    :: !ClientRandom
 	, hstServerRandom    :: !(Maybe ServerRandom)
-	, hstMasterSecret    :: !(Maybe [Word8])
+	, hstMasterSecret    :: !(Maybe Bytes)
 	, hstRSAPublicKey    :: !(Maybe PublicKey)
 	, hstRSAPrivateKey   :: !(Maybe PrivateKey)
 	, hstHandshakeDigest :: Maybe (HashCtx, HashCtx) -- FIXME could be only 1 hash in tls12
@@ -73,7 +73,6 @@
 
 data TLSState = TLSState
 	{ stClientContext :: Bool
-	, stClientVersion :: !(Maybe Version)
 	, stVersion       :: !Version
 	, stHandshake     :: !(Maybe TLSHandshakeState)
 	, stTxEncrypted   :: Bool
@@ -93,7 +92,6 @@
 newTLSState :: SRandomGen -> TLSState
 newTLSState rng = TLSState
 	{ stClientContext = False
-	, stClientVersion = Nothing
 	, stVersion       = TLS10
 	, stHandshake     = Nothing
 	, stTxEncrypted   = False
@@ -109,7 +107,7 @@
 modifyTLSState :: (MonadTLSState m) => (TLSState -> TLSState) -> m ()
 modifyTLSState f = getTLSState >>= \st -> putTLSState (f st)
 
-makeDigest :: (MonadTLSState m) => Bool -> Header -> ByteString -> m ByteString
+makeDigest :: (MonadTLSState m) => Bool -> Header -> Bytes -> m Bytes
 makeDigest w hdr content = do
 	st <- getTLSState
 	assert "make digest"
@@ -120,7 +118,7 @@
 	let ms = fromJust $ if w then stTxMacState st else stRxMacState st
 	let cipher = fromJust $ stCipher st
 
-	let hmac_msg = L.concat [ encodeWord64 $ msSequence ms, encodeHeader hdr, content ]
+	let hmac_msg = B.concat [ encodeWord64 $ msSequence ms, encodeHeader hdr, content ]
 	let digest = (cipherHMAC cipher) (cstMacSecret cst) hmac_msg
 
 	let newms = ms { msSequence = (msSequence ms) + 1 }
@@ -152,7 +150,7 @@
 setServerRandom :: MonadTLSState m => ServerRandom -> m ()
 setServerRandom ran = updateHandshake "srand" (\hst -> hst { hstServerRandom = Just ran })
 
-setMasterSecret :: MonadTLSState m => ByteString -> m ()
+setMasterSecret :: MonadTLSState m => Bytes -> m ()
 setMasterSecret premastersecret = do
 	st <- getTLSState
 	hasValidHandshake "master secret"
@@ -160,8 +158,8 @@
 		[ ("server random", (isNothing $ hstServerRandom $ fromJust $ stHandshake st)) ]
 
 	updateHandshake "master secret" (\hst ->
-		let ms = generateMasterSecret premastersecret (hstClientRandom hst) (fromJust $ hstServerRandom hst) in
-		hst { hstMasterSecret = Just $ L.unpack ms } )
+		let ms = generateMasterSecret (stVersion st) premastersecret (hstClientRandom hst) (fromJust $ hstServerRandom hst) in
+		hst { hstMasterSecret = Just ms } )
 	return ()
 
 setPublicKey :: MonadTLSState m => PublicKey -> m ()
@@ -184,26 +182,23 @@
 	let cc = stClientContext st
 	let cipher = fromJust $ stCipher st
 	let keyblockSize = fromIntegral $ cipherKeyBlockSize cipher
-	let digestSize = cipherDigestSize cipher
-	let keySize = cipherKeySize cipher
-	let ivSize = cipherIVSize cipher
+	let digestSize = fromIntegral $ cipherDigestSize cipher
+	let keySize = fromIntegral $ cipherKeySize cipher
+	let ivSize = fromIntegral $ cipherIVSize cipher
 	let kb = generateKeyBlock (hstClientRandom hst)
 	                          (fromJust $ hstServerRandom hst)
-	                          (L.pack $ fromJust $ hstMasterSecret hst) keyblockSize
-	let (cMACSecret, r1) = L.splitAt (fromIntegral digestSize) kb
-	let (sMACSecret, r2) = L.splitAt (fromIntegral digestSize) r1
-	let (cWriteKey, r3)  = L.splitAt (fromIntegral keySize) r2
-	let (sWriteKey, r4)  = L.splitAt (fromIntegral keySize) r3
-	let (cWriteIV,  r5)  = L.splitAt (fromIntegral ivSize) r4
-	let (sWriteIV,  _)   = L.splitAt (fromIntegral ivSize) r5
+	                          (fromJust $ hstMasterSecret hst) keyblockSize
 
+	let (cMACSecret, sMACSecret, cWriteKey, sWriteKey, cWriteIV, sWriteIV) =
+		fromJust $ partition6 kb (digestSize, digestSize, keySize, keySize, ivSize, ivSize)
+
 	let cstClient = TLSCryptState
-		{ cstKey        = L.unpack cWriteKey
-		, cstIV         = L.unpack cWriteIV
+		{ cstKey        = cWriteKey
+		, cstIV         = cWriteIV
 		, cstMacSecret  = cMACSecret }
 	let cstServer = TLSCryptState
-		{ cstKey        = L.unpack sWriteKey
-		, cstIV         = L.unpack sWriteIV
+		{ cstKey        = sWriteKey
+		, cstIV         = sWriteIV
 		, cstMacSecret  = sMACSecret }
 	let msClient = TLSMacState { msSequence = 0 }
 	let msServer = TLSMacState { msSequence = 0 }
@@ -250,22 +245,23 @@
 	hasValidHandshake n
 	modifyTLSState (\st -> st { stHandshake = maybe Nothing (Just . f) (stHandshake st) })
 
-updateHandshakeDigest :: MonadTLSState m => ByteString -> m ()
+updateHandshakeDigest :: MonadTLSState m => Bytes -> m ()
 updateHandshakeDigest content = updateHandshake "update digest" (\hs ->
-	let ctxs = case hstHandshakeDigest hs of
+	let (c1, c2) = case hstHandshakeDigest hs of
 		Nothing                -> (initHash HashTypeSHA1, initHash HashTypeMD5)
 		Just (sha1ctx, md5ctx) -> (sha1ctx, md5ctx) in
-	let (nc1, nc2) = foldl (\(c1, c2) s -> (updateHash c1 s, updateHash c2 s)) ctxs $ L.toChunks content in
+	let nc1 = updateHash c1 content in
+	let nc2 = updateHash c2 content in
 	hs { hstHandshakeDigest = Just (nc1, nc2) }
 	)
 
-getHandshakeDigest :: MonadTLSState m => Bool -> m ByteString
+getHandshakeDigest :: MonadTLSState m => Bool -> m Bytes
 getHandshakeDigest client = do
 	st <- getTLSState
 	let hst = fromJust $ stHandshake st
 	let (sha1ctx, md5ctx) = fromJust $ hstHandshakeDigest hst
 	let msecret = fromJust $ hstMasterSecret hst
-	return $ (if client then generateClientFinished else generateServerFinished) (L.pack msecret) md5ctx sha1ctx
+	return $ (if client then generateClientFinished else generateServerFinished) (stVersion st) msecret md5ctx sha1ctx
 
 endHandshake :: MonadTLSState m => m ()
 endHandshake = modifyTLSState (\st -> st { stHandshake = Nothing })
diff --git a/Network/TLS/Struct.hs b/Network/TLS/Struct.hs
--- a/Network/TLS/Struct.hs
+++ b/Network/TLS/Struct.hs
@@ -8,9 +8,11 @@
 -- the Struct module contains all definitions and values of the TLS protocol
 --
 module Network.TLS.Struct
-	( Version(..)
+	( Bytes
+	, Version(..)
 	, ConnectionEnd(..)
 	, CipherType(..)
+	, CipherData(..)
 	, Extension
 	, EncryptedData(..)
 	, CertificateType(..)
@@ -41,14 +43,23 @@
 	, typeOfHandshake
 	) where
 
-import Data.ByteString.Lazy (ByteString)
+import Data.ByteString (ByteString, pack)
 import Data.Word
 import Data.Certificate.X509
 
+type Bytes = ByteString
+
 data Version = SSL2 | SSL3 | TLS10 | TLS11 | TLS12 deriving (Show, Eq, Ord)
 
 data ConnectionEnd = ConnectionServer | ConnectionClient
 data CipherType = CipherStream | CipherBlock | CipherAEAD
+
+data CipherData = CipherData
+	{ cipherDataContent :: Bytes
+	, cipherDataMAC     :: Maybe Bytes
+	, cipherDataPadding :: Maybe Bytes
+	} deriving (Show,Eq)
+
 data CertificateType =
 	  CertificateType_RSA_Sign         -- TLS10
 	| CertificateType_DSS_Sign         -- TLS10
@@ -107,17 +118,17 @@
 
 data Header = Header ProtocolType Version Word16 deriving (Show, Eq)
 
-newtype ServerRandom = ServerRandom [Word8] deriving (Show, Eq)
-newtype ClientRandom = ClientRandom [Word8] deriving (Show, Eq)
-newtype ClientKeyData = ClientKeyData [Word8] deriving (Show, Eq)
-newtype Session = Session (Maybe [Word8]) deriving (Show, Eq)
+newtype ServerRandom = ServerRandom Bytes deriving (Show, Eq)
+newtype ClientRandom = ClientRandom Bytes deriving (Show, Eq)
+newtype ClientKeyData = ClientKeyData Bytes deriving (Show, Eq)
+newtype Session = Session (Maybe Bytes) deriving (Show, Eq)
 type CipherID = Word16
 type CompressionID = Word8
 type FinishedData = [Word8]
 type Extension = (Word16, [Word8])
 
-constrRandom32 :: ([Word8] -> a) -> [Word8] -> Maybe a
-constrRandom32 constr l = if length l == 32 then Just (constr l) else Nothing
+constrRandom32 :: (Bytes -> a) -> [Word8] -> Maybe a
+constrRandom32 constr l = if length l == 32 then Just (constr $ pack l) else Nothing
 
 serverRandom :: [Word8] -> Maybe ServerRandom
 serverRandom l = constrRandom32 ServerRandom l
diff --git a/Network/TLS/Util.hs b/Network/TLS/Util.hs
new file mode 100644
--- /dev/null
+++ b/Network/TLS/Util.hs
@@ -0,0 +1,37 @@
+module Network.TLS.Util
+	( sub
+	, takelast
+	, partition3
+	, partition6
+	) where
+
+import Network.TLS.Struct (Bytes)
+import Network.TLS.Wire
+import qualified Data.ByteString as B
+
+sub :: Bytes -> Int -> Int -> Maybe Bytes
+sub b offset len
+	| B.length b < offset + len = Nothing
+	| otherwise                 = Just $ B.take len $ snd $ B.splitAt offset b
+
+takelast :: Int -> Bytes -> Maybe Bytes
+takelast i b
+	| B.length b >= i = sub b (B.length b - i) i
+	| otherwise       = Nothing
+
+partition3 :: Bytes -> (Int,Int,Int) -> Maybe (Bytes, Bytes, Bytes)
+partition3 bytes (d1,d2,d3) = either (const Nothing) Just $ (flip runGet) bytes $ do
+	p1 <- getBytes d1
+	p2 <- getBytes d2
+	p3 <- getBytes d3
+	return (p1,p2,p3)
+
+partition6 :: Bytes -> (Int,Int,Int,Int,Int,Int) -> Maybe (Bytes, Bytes, Bytes, Bytes, Bytes, Bytes)
+partition6 bytes (d1,d2,d3,d4,d5,d6) = either (const Nothing) Just $ (flip runGet) bytes $ do
+	p1 <- getBytes d1
+	p2 <- getBytes d2
+	p3 <- getBytes d3
+	p4 <- getBytes d4
+	p5 <- getBytes d5
+	p6 <- getBytes d6
+	return (p1,p2,p3,p4,p5,p6)
diff --git a/Network/TLS/Wire.hs b/Network/TLS/Wire.hs
--- a/Network/TLS/Wire.hs
+++ b/Network/TLS/Wire.hs
@@ -30,14 +30,13 @@
 	, putWord16
 	, putWords16
 	, putWord24
-	, putByteString
-	, putLazyByteString
+	, putBytes
 	, encodeWord64
 	) where
 
-import qualified Data.Binary.Get as Bin
-import Data.Binary.Put
-import Data.ByteString (ByteString)
+import qualified Data.Binary.Get as G
+import qualified Data.Binary.Put as P
+import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
 import Control.Applicative ((<$>))
 import Control.Monad.Error
@@ -49,32 +48,32 @@
 	noMsg = Error_Misc ""
 	strMsg = Error_Misc
 
-newtype Get a = GE { runGE :: ErrorT TLSError Bin.Get a }
+newtype Get a = GE { runGE :: ErrorT TLSError G.Get a }
 	deriving (Monad, MonadError TLSError)
 
 instance Functor Get where
 	fmap f = GE . fmap f . runGE
 
-liftGet :: Bin.Get a -> Get a
+liftGet :: G.Get a -> Get a
 liftGet = GE . lift
 
-runGet :: Get a -> L.ByteString -> Either TLSError a
-runGet f b = Bin.runGet (runErrorT (runGE f)) b
+runGet :: Get a -> Bytes -> Either TLSError a
+runGet f b = G.runGet (runErrorT (runGE f)) (L.fromChunks [b])
 
 remaining :: Get Int
-remaining = fromIntegral <$> liftGet Bin.remaining
+remaining = fromIntegral <$> liftGet G.remaining
 
 bytesRead :: Get Int
-bytesRead = fromIntegral <$> liftGet Bin.bytesRead
+bytesRead = fromIntegral <$> liftGet G.bytesRead
 
 getWord8 :: Get Word8
-getWord8 = liftGet Bin.getWord8
+getWord8 = liftGet G.getWord8
 
 getWords8 :: Get [Word8]
 getWords8 = getWord8 >>= \lenb -> replicateM (fromIntegral lenb) getWord8
 
 getWord16 :: Get Word16
-getWord16 = liftGet Bin.getWord16be
+getWord16 = liftGet G.getWord16be
 
 getWords16 :: Get [Word16]
 getWords16 = getWord16 >>= \lenb -> replicateM (fromIntegral lenb `div` 2) getWord16
@@ -86,8 +85,8 @@
 	c <- fromIntegral <$> getWord8
 	return $ (a `shiftL` 16) .|. (b `shiftL` 8) .|. c
 
-getBytes :: Int -> Get ByteString
-getBytes i = liftGet $ Bin.getBytes i
+getBytes :: Int -> Get Bytes
+getBytes i = liftGet $ G.getBytes i
 
 processBytes :: Int -> Get a -> Get a
 processBytes i f = do
@@ -99,15 +98,20 @@
 		else throwError (Error_Internal_Packet_ByteProcessed r1 r2 i)
 	
 isEmpty :: Get Bool
-isEmpty = liftGet Bin.isEmpty
+isEmpty = liftGet G.isEmpty
 
+type Put = P.Put
+
+putWord8 :: Word8 -> Put
+putWord8 = P.putWord8
+
 putWords8 :: [Word8] -> Put
 putWords8 l = do
-	putWord8 $ fromIntegral (length l)
-	mapM_ putWord8 l
+	P.putWord8 $ fromIntegral (length l)
+	mapM_ P.putWord8 l
 
 putWord16 :: Word16 -> Put
-putWord16 = putWord16be
+putWord16 = P.putWord16be
 
 putWords16 :: [Word16] -> Put
 putWords16 l = do
@@ -119,7 +123,16 @@
 	let a = fromIntegral ((i `shiftR` 16) .&. 0xff)
 	let b = fromIntegral ((i `shiftR` 8) .&. 0xff)
 	let c = fromIntegral (i .&. 0xff)
-	mapM_ putWord8 [a,b,c]
+	mapM_ P.putWord8 [a,b,c]
 
-encodeWord64 :: Word64 -> L.ByteString
-encodeWord64 = runPut . putWord64be
+putBytes :: Bytes -> Put
+putBytes = P.putByteString
+
+lazyToBytes :: L.ByteString -> Bytes
+lazyToBytes = B.concat . L.toChunks
+
+runPut :: Put -> Bytes
+runPut = lazyToBytes . P.runPut
+
+encodeWord64 :: Word64 -> Bytes
+encodeWord64 = runPut . P.putWord64be
diff --git a/Stunnel.hs b/Stunnel.hs
--- a/Stunnel.hs
+++ b/Stunnel.hs
@@ -28,7 +28,7 @@
 import qualified Network.TLS.Client as C
 import qualified Network.TLS.Server as S
 
-import Random
+import System.Random
 import qualified Codec.Crypto.AES.Random as AESRand
 
 ciphers :: [Cipher]
@@ -62,7 +62,7 @@
 	ranByte <- B.head <$> AESRand.randBytes 1
 	_ <- AESRand.randBytes (fromIntegral ranByte)
 	clientRandom <- fromJust . clientRandom . B.unpack <$> AESRand.randBytes 32
-	premasterRandom <- (ClientKeyData . B.unpack) <$> AESRand.randBytes 46
+	premasterRandom <- ClientKeyData <$> AESRand.randBytes 46
 	seqInit <- conv . B.unpack <$> AESRand.randBytes 4
 
 	handle <- connectTo host (PortNumber $ fromIntegral port)
@@ -70,7 +70,7 @@
 
 	let clientstate = C.TLSClientParams
 		{ C.cpConnectVersion = TLS10
-		, C.cpAllowedVersions = [ TLS10 ]
+		, C.cpAllowedVersions = [ TLS10, TLS11 ]
 		, C.cpSession = Nothing
 		, C.cpCiphers = ciphers
 		, C.cpCertificate = Nothing
@@ -94,7 +94,7 @@
 	seqInit <- conv . B.unpack <$> AESRand.randBytes 4
 
 	let serverstate = S.TLSServerParams
-		{ S.spAllowedVersions = [TLS10]
+		{ S.spAllowedVersions = [TLS10,TLS11]
 		, S.spSessions = []
 		, S.spCiphers = ciphers
 		, S.spCertificate = Just (certdata, cert, pk)
@@ -118,13 +118,13 @@
 	putStrLn "usage: stunnel [client|server] <params...>"
 	exitFailure
 
-readCertificate :: FilePath -> IO (L.ByteString, Certificate)
+readCertificate :: FilePath -> IO (B.ByteString, Certificate)
 readCertificate filepath = do
 	content <- B.readFile filepath
 	let certdata = case parsePEMCert content of
 		Left err -> error ("cannot read PEM certificate: " ++ err)
-		Right x  -> L.fromChunks [x]
-	let cert = case decodeCertificate certdata of
+		Right x  -> x
+	let cert = case decodeCertificate $ L.fromChunks [certdata] of
 		Left err -> error ("cannot decode certificate: " ++ err)
 		Right x  -> x
 	return (certdata, cert)
diff --git a/TODO b/TODO
--- a/TODO
+++ b/TODO
@@ -20,6 +20,11 @@
 - properly separate different version of the protocol
 - implement AEAD
 
+ssl3:
+
+- finish generation of stuff
+- test with popular server
+
 code cleanup:
 
 - remove show derivation on internal crypto state
@@ -27,16 +32,15 @@
 
 security audit:
 
-- add unit tests for pure parts
+- add more unit tests for pure parts
 - fix SRandomGen and random usage with proper CPRNG
 - match security recommendation from the RFC
 - audit the RSA implementation and the usage in TLS (remove spoon).
 
 misc:
 
-- verify it works with gnutls
 - stunnel: use crypto secure random generator
-- stunnel: actually make it works like stunnel instead of hardcoding the data and the port.
+- stunnel: actually make it works like stunnel instead of hardcoding the data received/sent
 - investigate an iteratee interface
 - portability
 - implement more ciphers
diff --git a/Tests.hs b/Tests.hs
--- a/Tests.hs
+++ b/Tests.hs
@@ -3,18 +3,20 @@
 import Test.QuickCheck
 import Test.QuickCheck.Test
 
+import qualified Data.ByteString as B
 import Network.TLS.Struct
 import Network.TLS.Packet
 import Control.Monad
+import Control.Applicative ((<$>))
 import System.IO
 
 liftM6 f m1 m2 m3 m4 m5 m6 = do { x1 <- m1; x2 <- m2; x3 <- m3; x4 <- m4; x5 <- m5; x6 <- m6; return (f x1 x2 x3 x4 x5 x6) }
 
 someWords8 :: Int -> Gen [Word8] 
-someWords8 i = replicateM i (fromIntegral `fmap` (choose (0,255) :: Gen Int))
+someWords8 i = replicateM i (fromIntegral <$> (choose (0,255) :: Gen Int))
 
 someWords16 :: Int -> Gen [Word16] 
-someWords16 i = replicateM i (fromIntegral `fmap` (choose (0,65535) :: Gen Int))
+someWords16 i = replicateM i (fromIntegral <$> (choose (0,65535) :: Gen Int))
 
 instance Arbitrary Version where
 	arbitrary = elements [ SSL2, SSL3, TLS10, TLS11, TLS12 ]
@@ -27,10 +29,10 @@
 		, ProtocolType_AppData ]
 
 instance Arbitrary Word8 where
-	arbitrary = fromIntegral `fmap` (choose (0,255) :: Gen Int)
+	arbitrary = fromIntegral <$> (choose (0,255) :: Gen Int)
 
 instance Arbitrary Word16 where
-	arbitrary = fromIntegral `fmap` (choose (0,65535) :: Gen Int)
+	arbitrary = fromIntegral <$> (choose (0,65535) :: Gen Int)
 
 instance Arbitrary Header where
 	arbitrary = do
@@ -40,20 +42,20 @@
 		return $ Header pt ver len
 
 instance Arbitrary ClientRandom where
-	arbitrary = ClientRandom `fmap` someWords8 32
+	arbitrary = ClientRandom . B.pack <$> someWords8 32
 
 instance Arbitrary ServerRandom where
-	arbitrary = ServerRandom `fmap` someWords8 32
+	arbitrary = ServerRandom . B.pack <$> someWords8 32
 
 instance Arbitrary ClientKeyData where
-	arbitrary = ClientKeyData `fmap` someWords8 46
+	arbitrary = ClientKeyData . B.pack <$> someWords8 46
 
 instance Arbitrary Session where
 	arbitrary = do
 		i <- choose (1,2) :: Gen Int
 		case i of
 			1 -> return $ Session Nothing
-			2 -> (Session . Just) `fmap` someWords8 32
+			2 -> Session . Just . B.pack <$> someWords8 32
 
 arbitraryCiphersIDs :: Gen [Word16]
 arbitraryCiphersIDs = choose (0,200) >>= someWords16
diff --git a/tls.cabal b/tls.cabal
--- a/tls.cabal
+++ b/tls.cabal
@@ -1,5 +1,5 @@
 Name:                tls
-Version:             0.1.2
+Version:             0.1.3
 Description:
    Implementation of the TLS protocol, focusing on purity and more type-checking.
    .
@@ -15,6 +15,7 @@
 Category:            Network
 stability:           experimental
 Cabal-Version:       >=1.6
+Homepage:            http://github.com/vincenthz/hs-tls
 data-files:          README, TODO
 
 Flag test
@@ -32,7 +33,7 @@
                      binary >= 0.5,
                      bytestring,
                      vector,
-                     haskell98,
+                     random,
                      AES, RSA, spoon,
                      cryptocipher,
                      certificate >= 0.2
@@ -42,12 +43,14 @@
                      Network.TLS.Cipher
                      Network.TLS.SRandom
                      Network.TLS.MAC
-  other-modules:     Network.TLS.Compression
+  other-modules:     Network.TLS.Cap
+                     Network.TLS.Compression
                      Network.TLS.Crypto
                      Network.TLS.Packet
                      Network.TLS.State
                      Network.TLS.Sending
                      Network.TLS.Receiving
+                     Network.TLS.Util
                      Network.TLS.Wire
   ghc-options:       -Wall
 
@@ -63,7 +66,7 @@
   Main-is:           Tests.hs
   if flag(test)
     Buildable:       True
-    Build-Depends:   base >= 3 && < 5, HUnit, QuickCheck >= 2 && < 2.3, bytestring, haskell98
+    Build-Depends:   base >= 3 && < 5, HUnit, QuickCheck >= 2 && < 2.3, bytestring, random
   else
     Buildable:       False
 
