forked from quic-go/quic-go
Unfortunately QUIC uses non-standard tag sizes with both AES-GCM and Poly1305. Adopting AES-GCM seems much harder, so I changed it to Chacha20Poly1305 and only made some slight changes to an existing algo. This should probably be double-checked at some point.
45 lines
1.1 KiB
Go
45 lines
1.1 KiB
Go
package crypto
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"io"
|
|
|
|
"github.com/lucas-clemente/quic-go/protocol"
|
|
"github.com/lucas-clemente/quic-go/utils"
|
|
|
|
"golang.org/x/crypto/hkdf"
|
|
)
|
|
|
|
// DeriveKeysChacha20 derives the client and server keys and creates a matching chacha20poly1305 instance
|
|
func DeriveKeysChacha20(sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte) (AEAD, error) {
|
|
var info bytes.Buffer
|
|
info.Write([]byte("QUIC key expansion\x00"))
|
|
utils.WriteUint64(&info, uint64(connID))
|
|
info.Write(chlo)
|
|
info.Write(scfg)
|
|
info.Write(cert)
|
|
|
|
r := hkdf.New(sha256.New, sharedSecret, nonces, info.Bytes())
|
|
|
|
otherKey := make([]byte, 32)
|
|
myKey := make([]byte, 32)
|
|
otherIV := make([]byte, 4)
|
|
myIV := make([]byte, 4)
|
|
|
|
if _, err := io.ReadFull(r, otherKey); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := io.ReadFull(r, myKey); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := io.ReadFull(r, otherIV); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := io.ReadFull(r, myIV); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return NewAEADChacha20Poly1305(otherKey, myKey, otherIV, myIV)
|
|
}
|