quic-0.3.2: Network/QUIC/Crypto/Keys.hs
{-# LANGUAGE BinaryLiterals #-}
{-# LANGUAGE OverloadedStrings #-}
module Network.QUIC.Crypto.Keys (
defaultCipher,
initialSecrets,
clientInitialSecret,
serverInitialSecret,
aeadKey,
initialVector,
nextSecret,
headerProtectionKey,
) where
import qualified Control.Exception as E
import Data.ByteArray (ScrubbedBytes, convert)
import Network.TLS hiding (Version)
import Network.TLS.Extra.Cipher
import Network.TLS.QUIC
import Network.QUIC.Crypto.Types
import Network.QUIC.Imports
import Network.QUIC.Types
----------------------------------------------------------------
defaultCipher :: Cipher
defaultCipher = cipher13_AES_128_GCM_SHA256
----------------------------------------------------------------
initialSalt :: Version -> Salt
initialSalt Draft29 =
"\xaf\xbf\xec\x28\x99\x93\xd2\x4c\x9e\x97\x86\xf1\x9c\x61\x11\xe0\x43\x90\xa8\x99"
initialSalt Version1 =
"\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17\x9a\xe6\xa4\xc8\x0c\xad\xcc\xbb\x7f\x0a"
initialSalt Version2 =
"\x0d\xed\xe3\xde\xf7\x00\xa6\xdb\x81\x93\x81\xbe\x6e\x26\x9d\xcb\xf9\xbd\x2e\xd9"
initialSalt (Version v) = E.throw $ VersionIsUnknown v
initialSecrets :: Version -> CID -> TrafficSecrets InitialSecret
initialSecrets v c = (clientInitialSecret v c, serverInitialSecret v c)
clientInitialSecret :: Version -> CID -> ClientTrafficSecret InitialSecret
clientInitialSecret v c = ClientTrafficSecret $ initialSecret v c $ Label "client in"
serverInitialSecret :: Version -> CID -> ServerTrafficSecret InitialSecret
serverInitialSecret v c = ServerTrafficSecret $ initialSecret v c $ Label "server in"
initialSecret :: Version -> CID -> Label -> ScrubbedBytes
initialSecret Draft29 = initialSecret' $ initialSalt Draft29
initialSecret Version1 = initialSecret' $ initialSalt Version1
initialSecret Version2 = initialSecret' $ initialSalt Version2
initialSecret _ = \_ _ -> "not supported"
initialSecret' :: ByteString -> CID -> Label -> ScrubbedBytes
initialSecret' salt cid (Label label) = secret
where
cipher = defaultCipher
hash = cipherHash cipher
iniSecret = hkdfExtract hash (convert salt) (convert $ fromCID cid)
hashSize = hashDigestSize hash
secret = hkdfExpandLabel hash iniSecret label "" hashSize
aeadKey :: Version -> Cipher -> Secret -> Key
aeadKey Draft29 = genKey $ Label "quic key"
aeadKey Version1 = genKey $ Label "quic key"
aeadKey Version2 = genKey $ Label "quicv2 key"
aeadKey _ = genKey $ Label "not supported"
headerProtectionKey :: Version -> Cipher -> Secret -> Key
headerProtectionKey Draft29 = genKey $ Label "quic hp"
headerProtectionKey Version1 = genKey $ Label "quic hp"
headerProtectionKey Version2 = genKey $ Label "quicv2 hp"
headerProtectionKey _ = genKey $ Label "not supported"
genKey :: Label -> Cipher -> Secret -> Key
genKey (Label label) cipher (Secret secret) = Key key
where
hash = cipherHash cipher
bulk = cipherBulk cipher
keySize = bulkKeySize bulk
key = hkdfExpandLabel hash secret label "" keySize
initialVector :: Version -> Cipher -> Secret -> IV
initialVector ver cipher (Secret secret) = IV iv
where
label = ivLabel ver
hash = cipherHash cipher
bulk = cipherBulk cipher
ivSize = max 8 (bulkIVSize bulk + bulkExplicitIV bulk)
iv = hkdfExpandLabel hash secret label "" ivSize
ivLabel :: Version -> ByteString
ivLabel Draft29 = "quic iv"
ivLabel Version1 = "quic iv"
ivLabel Version2 = "quicv2 iv"
ivLabel _ = "not supported"
nextSecret :: Version -> Cipher -> Secret -> Secret
nextSecret ver cipher (Secret secN) = Secret secN1
where
label = kuLabel ver
hash = cipherHash cipher
hashSize = hashDigestSize hash
secN1 = hkdfExpandLabel hash secN label "" hashSize
kuLabel :: Version -> ByteString
kuLabel Draft29 = "quic ku"
kuLabel Version1 = "quic ku"
kuLabel Version2 = "quicv2 ku"
kuLabel _ = "not supported"