File: MAC.hs

package info (click to toggle)
haskell-tls 2.1.8-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,056 kB
  • sloc: haskell: 15,695; makefile: 3
file content (79 lines) | stat: -rw-r--r-- 2,508 bytes parent folder | download
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
module Network.TLS.MAC (
    macSSL,
    hmac,
    prf_MD5,
    prf_SHA1,
    prf_SHA256,
    prf_TLS,
    prf_MD5SHA1,
) where

import qualified Data.ByteArray as B (xor)
import qualified Data.ByteString as B
import Network.TLS.Crypto
import Network.TLS.Imports
import Network.TLS.Types

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