package tls
import (
"crypto"
"crypto/ecdh"
"crypto/hmac"
"crypto/internal/fips140/tls13"
"crypto/mlkem"
"errors"
"hash"
"io"
)
func (c *cipherSuiteTLS13 ) nextTrafficSecret (trafficSecret []byte ) []byte {
return tls13 .ExpandLabel (c .hash .New , trafficSecret , "traffic upd" , nil , c .hash .Size ())
}
func (c *cipherSuiteTLS13 ) trafficKey (trafficSecret []byte ) (key , iv []byte ) {
key = tls13 .ExpandLabel (c .hash .New , trafficSecret , "key" , nil , c .keyLen )
iv = tls13 .ExpandLabel (c .hash .New , trafficSecret , "iv" , nil , aeadNonceLength )
return
}
func (c *cipherSuiteTLS13 ) finishedHash (baseKey []byte , transcript hash .Hash ) []byte {
finishedKey := tls13 .ExpandLabel (c .hash .New , baseKey , "finished" , nil , c .hash .Size ())
verifyData := hmac .New (c .hash .New , finishedKey )
verifyData .Write (transcript .Sum (nil ))
return verifyData .Sum (nil )
}
func (c *cipherSuiteTLS13 ) exportKeyingMaterial (s *tls13 .MasterSecret , transcript hash .Hash ) func (string , []byte , int ) ([]byte , error ) {
expMasterSecret := s .ExporterMasterSecret (transcript )
return func (label string , context []byte , length int ) ([]byte , error ) {
return expMasterSecret .Exporter (label , context , length ), nil
}
}
type keySharePrivateKeys struct {
ecdhe *ecdh .PrivateKey
mlkem crypto .Decapsulator
}
type keyExchange interface {
keyShares(rand io .Reader ) (*keySharePrivateKeys , []keyShare , error )
serverSharedSecret(rand io .Reader , clientKeyShare []byte ) ([]byte , keyShare , error )
clientSharedSecret(priv *keySharePrivateKeys , serverKeyShare []byte ) ([]byte , error )
}
func keyExchangeForCurveID(id CurveID ) (keyExchange , error ) {
newMLKEMPrivateKey768 := func (b []byte ) (crypto .Decapsulator , error ) {
return mlkem .NewDecapsulationKey768 (b )
}
newMLKEMPrivateKey1024 := func (b []byte ) (crypto .Decapsulator , error ) {
return mlkem .NewDecapsulationKey1024 (b )
}
newMLKEMPublicKey768 := func (b []byte ) (crypto .Encapsulator , error ) {
return mlkem .NewEncapsulationKey768 (b )
}
newMLKEMPublicKey1024 := func (b []byte ) (crypto .Encapsulator , error ) {
return mlkem .NewEncapsulationKey1024 (b )
}
switch id {
case X25519 :
return &ecdhKeyExchange {id , ecdh .X25519 ()}, nil
case CurveP256 :
return &ecdhKeyExchange {id , ecdh .P256 ()}, nil
case CurveP384 :
return &ecdhKeyExchange {id , ecdh .P384 ()}, nil
case CurveP521 :
return &ecdhKeyExchange {id , ecdh .P521 ()}, nil
case X25519MLKEM768 :
return &hybridKeyExchange {id , ecdhKeyExchange {X25519 , ecdh .X25519 ()},
32 , mlkem .EncapsulationKeySize768 , mlkem .CiphertextSize768 ,
newMLKEMPrivateKey768 , newMLKEMPublicKey768 }, nil
case SecP256r1MLKEM768 :
return &hybridKeyExchange {id , ecdhKeyExchange {CurveP256 , ecdh .P256 ()},
65 , mlkem .EncapsulationKeySize768 , mlkem .CiphertextSize768 ,
newMLKEMPrivateKey768 , newMLKEMPublicKey768 }, nil
case SecP384r1MLKEM1024 :
return &hybridKeyExchange {id , ecdhKeyExchange {CurveP384 , ecdh .P384 ()},
97 , mlkem .EncapsulationKeySize1024 , mlkem .CiphertextSize1024 ,
newMLKEMPrivateKey1024 , newMLKEMPublicKey1024 }, nil
default :
return nil , errors .New ("tls: unsupported key exchange" )
}
}
type ecdhKeyExchange struct {
id CurveID
curve ecdh .Curve
}
func (ke *ecdhKeyExchange ) keyShares (rand io .Reader ) (*keySharePrivateKeys , []keyShare , error ) {
priv , err := ke .curve .GenerateKey (rand )
if err != nil {
return nil , nil , err
}
return &keySharePrivateKeys {ecdhe : priv }, []keyShare {{ke .id , priv .PublicKey ().Bytes ()}}, nil
}
func (ke *ecdhKeyExchange ) serverSharedSecret (rand io .Reader , clientKeyShare []byte ) ([]byte , keyShare , error ) {
key , err := ke .curve .GenerateKey (rand )
if err != nil {
return nil , keyShare {}, err
}
peerKey , err := ke .curve .NewPublicKey (clientKeyShare )
if err != nil {
return nil , keyShare {}, err
}
sharedKey , err := key .ECDH (peerKey )
if err != nil {
return nil , keyShare {}, err
}
return sharedKey , keyShare {ke .id , key .PublicKey ().Bytes ()}, nil
}
func (ke *ecdhKeyExchange ) clientSharedSecret (priv *keySharePrivateKeys , serverKeyShare []byte ) ([]byte , error ) {
peerKey , err := ke .curve .NewPublicKey (serverKeyShare )
if err != nil {
return nil , err
}
sharedKey , err := priv .ecdhe .ECDH (peerKey )
if err != nil {
return nil , err
}
return sharedKey , nil
}
type hybridKeyExchange struct {
id CurveID
ecdh ecdhKeyExchange
ecdhElementSize int
mlkemPublicKeySize int
mlkemCiphertextSize int
newMLKEMPrivateKey func ([]byte ) (crypto .Decapsulator , error )
newMLKEMPublicKey func ([]byte ) (crypto .Encapsulator , error )
}
func (ke *hybridKeyExchange ) keyShares (rand io .Reader ) (*keySharePrivateKeys , []keyShare , error ) {
priv , ecdhShares , err := ke .ecdh .keyShares (rand )
if err != nil {
return nil , nil , err
}
seed := make ([]byte , mlkem .SeedSize )
if _ , err := io .ReadFull (rand , seed ); err != nil {
return nil , nil , err
}
priv .mlkem , err = ke .newMLKEMPrivateKey (seed )
if err != nil {
return nil , nil , err
}
var shareData []byte
if ke .id == X25519MLKEM768 {
shareData = append (priv .mlkem .Encapsulator ().Bytes (), ecdhShares [0 ].data ...)
} else {
shareData = append (ecdhShares [0 ].data , priv .mlkem .Encapsulator ().Bytes ()...)
}
return priv , []keyShare {{ke .id , shareData }, ecdhShares [0 ]}, nil
}
func (ke *hybridKeyExchange ) serverSharedSecret (rand io .Reader , clientKeyShare []byte ) ([]byte , keyShare , error ) {
if len (clientKeyShare ) != ke .ecdhElementSize +ke .mlkemPublicKeySize {
return nil , keyShare {}, errors .New ("tls: invalid client key share length for hybrid key exchange" )
}
var ecdhShareData , mlkemShareData []byte
if ke .id == X25519MLKEM768 {
mlkemShareData = clientKeyShare [:ke .mlkemPublicKeySize ]
ecdhShareData = clientKeyShare [ke .mlkemPublicKeySize :]
} else {
ecdhShareData = clientKeyShare [:ke .ecdhElementSize ]
mlkemShareData = clientKeyShare [ke .ecdhElementSize :]
}
ecdhSharedSecret , ks , err := ke .ecdh .serverSharedSecret (rand , ecdhShareData )
if err != nil {
return nil , keyShare {}, err
}
mlkemPeerKey , err := ke .newMLKEMPublicKey (mlkemShareData )
if err != nil {
return nil , keyShare {}, err
}
mlkemSharedSecret , mlkemKeyShare := mlkemPeerKey .Encapsulate ()
var sharedKey []byte
if ke .id == X25519MLKEM768 {
sharedKey = append (mlkemSharedSecret , ecdhSharedSecret ...)
ks .data = append (mlkemKeyShare , ks .data ...)
} else {
sharedKey = append (ecdhSharedSecret , mlkemSharedSecret ...)
ks .data = append (ks .data , mlkemKeyShare ...)
}
ks .group = ke .id
return sharedKey , ks , nil
}
func (ke *hybridKeyExchange ) clientSharedSecret (priv *keySharePrivateKeys , serverKeyShare []byte ) ([]byte , error ) {
if len (serverKeyShare ) != ke .ecdhElementSize +ke .mlkemCiphertextSize {
return nil , errors .New ("tls: invalid server key share length for hybrid key exchange" )
}
var ecdhShareData , mlkemShareData []byte
if ke .id == X25519MLKEM768 {
mlkemShareData = serverKeyShare [:ke .mlkemCiphertextSize ]
ecdhShareData = serverKeyShare [ke .mlkemCiphertextSize :]
} else {
ecdhShareData = serverKeyShare [:ke .ecdhElementSize ]
mlkemShareData = serverKeyShare [ke .ecdhElementSize :]
}
ecdhSharedSecret , err := ke .ecdh .clientSharedSecret (priv , ecdhShareData )
if err != nil {
return nil , err
}
mlkemSharedSecret , err := priv .mlkem .Decapsulate (mlkemShareData )
if err != nil {
return nil , err
}
var sharedKey []byte
if ke .id == X25519MLKEM768 {
sharedKey = append (mlkemSharedSecret , ecdhSharedSecret ...)
} else {
sharedKey = append (ecdhSharedSecret , mlkemSharedSecret ...)
}
return sharedKey , nil
}
The pages are generated with Golds v0.8.3-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .