    {-# LANGUAGE OverloadedStrings #-}
    -- |
    -- Module      : Network.TLS.KeySchedule
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : unknown
    --
    module Network.TLS.KeySchedule
        ( hkdfExtract
        , hkdfExpandLabel
        , deriveSecret
        ) where

    import qualified Crypto.Hash as H
    import Crypto.KDF.HKDF
    import Data.ByteArray (convert)
    import qualified Data.ByteString as BS
    import Network.TLS.Crypto
    import Network.TLS.Wire
    import Network.TLS.Imports

    ----------------------------------------------------------------

    hkdfExtract :: Hash -> ByteString -> ByteString -> ByteString
    hkdfExtract :: Hash -> ByteString -> ByteString -> ByteString
    hkdfExtract SHA1   salt :: ByteString
    salt ikm :: ByteString
    ikm = PRK SHA1 -> ByteString
    forall bin bout.
    (ByteArrayAccess bin, ByteArray bout) =>
    bin -> bout
    convert (ByteString -> ByteString -> PRK SHA1
    forall a salt ikm.
    (HashAlgorithm a, ByteArrayAccess salt, ByteArrayAccess ikm) =>
    salt -> ikm -> PRK a
    extract ByteString
    salt ByteString
    ikm :: PRK H.SHA1)
    hkdfExtract SHA256 salt :: ByteString
    salt ikm :: ByteString
    ikm = PRK SHA256 -> ByteString
    forall bin bout.
    (ByteArrayAccess bin, ByteArray bout) =>
    bin -> bout
    convert (ByteString -> ByteString -> PRK SHA256
    forall a salt ikm.
    (HashAlgorithm a, ByteArrayAccess salt, ByteArrayAccess ikm) =>
    salt -> ikm -> PRK a
    extract ByteString
    salt ByteString
    ikm :: PRK H.SHA256)
    hkdfExtract SHA384 salt :: ByteString
    salt ikm :: ByteString
    ikm = PRK SHA384 -> ByteString
    forall bin bout.
    (ByteArrayAccess bin, ByteArray bout) =>
    bin -> bout
    convert (ByteString -> ByteString -> PRK SHA384
    forall a salt ikm.
    (HashAlgorithm a, ByteArrayAccess salt, ByteArrayAccess ikm) =>
    salt -> ikm -> PRK a
    extract ByteString
    salt ByteString
    ikm :: PRK H.SHA384)
    hkdfExtract SHA512 salt :: ByteString
    salt ikm :: ByteString
    ikm = PRK SHA512 -> ByteString
    forall bin bout.
    (ByteArrayAccess bin, ByteArray bout) =>
    bin -> bout
    convert (ByteString -> ByteString -> PRK SHA512
    forall a salt ikm.
    (HashAlgorithm a, ByteArrayAccess salt, ByteArrayAccess ikm) =>
    salt -> ikm -> PRK a
    extract ByteString
    salt ByteString
    ikm :: PRK H.SHA512)
    hkdfExtract _ _ _           = [Char] -> ByteString
    forall a. HasCallStack => [Char] -> a
    error "hkdfExtract: unsupported hash"

    ----------------------------------------------------------------

    deriveSecret :: Hash -> ByteString -> ByteString -> ByteString -> ByteString
    deriveSecret :: Hash -> ByteString -> ByteString -> ByteString -> ByteString
    deriveSecret h :: Hash
    h secret :: ByteString
    secret label :: ByteString
    label hashedMsgs :: ByteString
    hashedMsgs =
        Hash -> ByteString -> ByteString -> ByteString -> Int -> ByteString
    hkdfExpandLabel Hash
    h ByteString
    secret ByteString
    label ByteString
    hashedMsgs Int
    outlen
      where
        outlen :: Int
    outlen = Hash -> Int
    hashDigestSize Hash
    h

    ----------------------------------------------------------------

    hkdfExpandLabel :: Hash
                    -> ByteString
                    -> ByteString
                    -> ByteString
                    -> Int
                    -> ByteString
    hkdfExpandLabel :: Hash -> ByteString -> ByteString -> ByteString -> Int -> ByteString
    hkdfExpandLabel h :: Hash
    h secret :: ByteString
    secret label :: ByteString
    label ctx :: ByteString
    ctx outlen :: Int
    outlen = Hash -> ByteString -> ByteString -> Int -> ByteString
    expand' Hash
    h ByteString
    secret ByteString
    hkdfLabel Int
    outlen
      where
        hkdfLabel :: ByteString
    hkdfLabel = Put -> ByteString
    runPut (Put -> ByteString) -> Put -> ByteString
    forall a b. (a -> b) -> a -> b
    $ do
            Word16 -> Put
    putWord16 (Word16 -> Put) -> Word16 -> Put
    forall a b. (a -> b) -> a -> b
    $ Int -> Word16
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    outlen
            ByteString -> Put
    putOpaque8 ("tls13 " ByteString -> ByteString -> ByteString
    `BS.append` ByteString
    label)
            ByteString -> Put
    putOpaque8 ByteString
    ctx

    expand' :: Hash -> ByteString -> ByteString -> Int -> ByteString
    expand' :: Hash -> ByteString -> ByteString -> Int -> ByteString
    expand' SHA1   secret :: ByteString
    secret label :: ByteString
    label len :: Int
    len = PRK SHA1 -> ByteString -> Int -> ByteString
    forall a info out.
    (HashAlgorithm a, ByteArrayAccess info, ByteArray out) =>
    PRK a -> info -> Int -> out
    expand (ByteString -> PRK SHA1
    forall ikm a. ByteArrayAccess ikm => ikm -> PRK a
    extractSkip ByteString
    secret :: PRK H.SHA1)   ByteString
    label Int
    len
    expand' SHA256 secret :: ByteString
    secret label :: ByteString
    label len :: Int
    len = PRK SHA256 -> ByteString -> Int -> ByteString
    forall a info out.
    (HashAlgorithm a, ByteArrayAccess info, ByteArray out) =>
    PRK a -> info -> Int -> out
    expand (ByteString -> PRK SHA256
    forall ikm a. ByteArrayAccess ikm => ikm -> PRK a
    extractSkip ByteString
    secret :: PRK H.SHA256) ByteString
    label Int
    len
    expand' SHA384 secret :: ByteString
    secret label :: ByteString
    label len :: Int
    len = PRK SHA384 -> ByteString -> Int -> ByteString
    forall a info out.
    (HashAlgorithm a, ByteArrayAccess info, ByteArray out) =>
    PRK a -> info -> Int -> out
    expand (ByteString -> PRK SHA384
    forall ikm a. ByteArrayAccess ikm => ikm -> PRK a
    extractSkip ByteString
    secret :: PRK H.SHA384) ByteString
    label Int
    len
    expand' SHA512 secret :: ByteString
    secret label :: ByteString
    label len :: Int
    len = PRK SHA512 -> ByteString -> Int -> ByteString
    forall a info out.
    (HashAlgorithm a, ByteArrayAccess info, ByteArray out) =>
    PRK a -> info -> Int -> out
    expand (ByteString -> PRK SHA512
    forall ikm a. ByteArrayAccess ikm => ikm -> PRK a
    extractSkip ByteString
    secret :: PRK H.SHA512) ByteString
    label Int
    len
    expand' _ _ _ _ = [Char] -> ByteString
    forall a. HasCallStack => [Char] -> a
    error "expand'"

    ----------------------------------------------------------------