{-# LANGUAGE BinaryLiterals #-} {-# LANGUAGE OverloadedStrings #-} module Network.QUIC.Crypto.Keys ( defaultCipher, initialSecrets, clientInitialSecret, serverInitialSecret, aeadKey, initialVector, nextSecret, headerProtectionKey, ) where import Network.TLS hiding (Version) import Network.TLS.Extra.Cipher import Network.TLS.QUIC import qualified UnliftIO.Exception as E import Network.QUIC.Crypto.Types import Network.QUIC.Imports import Network.QUIC.Types ---------------------------------------------------------------- defaultCipher :: Cipher defaultCipher = cipher_TLS13_AES128GCM_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.impureThrow $ 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 -> ByteString initialSecret Draft29 = initialSecret' $ initialSalt Draft29 initialSecret Version1 = initialSecret' $ initialSalt Version1 initialSecret Version2 = initialSecret' $ initialSalt Version2 initialSecret _ = \_ _ -> "not supported" initialSecret' :: ByteString -> CID -> Label -> ByteString initialSecret' salt cid (Label label) = secret where cipher = defaultCipher hash = cipherHash cipher iniSecret = hkdfExtract hash salt $ 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"