1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
|
-- |
-- Module : Network.TLS.MAC
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
module Network.TLS.MAC
( macSSL
, hmac
, prf_MD5
, prf_SHA1
, prf_SHA256
, prf_TLS
, prf_MD5SHA1
) where
import Network.TLS.Crypto
import Network.TLS.Types
import Network.TLS.Imports
import qualified Data.ByteArray as B (xor)
import qualified Data.ByteString as B
type HMAC = ByteString -> ByteString -> ByteString
macSSL :: Hash -> HMAC
macSSL alg secret msg =
f $! B.concat
[ secret
, B.replicate padLen 0x5c
, f $! B.concat [ secret, B.replicate padLen 0x36, msg ]
]
where
padLen = case alg of
MD5 -> 48
SHA1 -> 40
_ -> error ("internal error: macSSL called with " ++ show alg)
f = hash alg
hmac :: Hash -> HMAC
hmac alg secret msg = f $! B.append opad (f $! B.append ipad msg)
where opad = B.map (xor 0x5c) k'
ipad = B.map (xor 0x36) k'
f = hash alg
bl = hashBlockSize alg
k' = B.append kt pad
where kt = if B.length secret > fromIntegral bl then f secret else secret
pad = B.replicate (fromIntegral bl - B.length kt) 0
hmacIter :: HMAC -> ByteString -> ByteString -> ByteString -> Int -> [ByteString]
hmacIter f secret seed aprev len =
let an = f secret aprev in
let out = f secret (B.concat [an, seed]) in
let digestsize = B.length out in
if digestsize >= len
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 = B.concat $ hmacIter (hmac SHA1) secret seed seed len
prf_MD5 :: ByteString -> ByteString -> Int -> ByteString
prf_MD5 secret seed len = B.concat $ hmacIter (hmac MD5) secret seed seed len
prf_MD5SHA1 :: ByteString -> ByteString -> Int -> ByteString
prf_MD5SHA1 secret seed len =
B.xor (prf_MD5 s1 seed len) (prf_SHA1 s2 seed len)
where slen = B.length secret
s1 = B.take (slen `div` 2 + slen `mod` 2) secret
s2 = B.drop (slen `div` 2) secret
prf_SHA256 :: ByteString -> ByteString -> Int -> ByteString
prf_SHA256 secret seed len = B.concat $ hmacIter (hmac SHA256) secret seed seed len
-- | For now we ignore the version, but perhaps some day the PRF will depend
-- not only on the cipher PRF algorithm, but also on the protocol version.
prf_TLS :: Version -> Hash -> ByteString -> ByteString -> Int -> ByteString
prf_TLS _ halg secret seed len =
B.concat $ hmacIter (hmac halg) secret seed seed len
|