also keys for the client in AESGCM key derivation

This commit is contained in:
Marten Seemann
2016-11-11 18:51:43 +07:00
parent 4b67aefb83
commit 731dd87872
4 changed files with 98 additions and 21 deletions

View File

@@ -21,15 +21,21 @@ import (
// }
// DeriveKeysAESGCM derives the client and server keys and creates a matching AES-GCM AEAD instance
func DeriveKeysAESGCM(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte) (AEAD, error) {
otherKey, myKey, otherIV, myIV, err := deriveKeys(forwardSecure, sharedSecret, nonces, connID, chlo, scfg, cert, divNonce, 16)
func DeriveKeysAESGCM(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte, pers protocol.Perspective) (AEAD, error) {
var swap bool
if pers == protocol.PerspectiveClient {
swap = true
}
otherKey, myKey, otherIV, myIV, err := deriveKeys(forwardSecure, sharedSecret, nonces, connID, chlo, scfg, cert, divNonce, 16, swap)
if err != nil {
return nil, err
}
return NewAEADAESGCM(otherKey, myKey, otherIV, myIV)
}
func deriveKeys(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo, scfg, cert, divNonce []byte, keyLen int) ([]byte, []byte, []byte, []byte, error) {
// deriveKeys derives the keys and the IVs
// swap should be set true if generating the values for the client, and false for the server
func deriveKeys(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo, scfg, cert, divNonce []byte, keyLen int, swap bool) ([]byte, []byte, []byte, []byte, error) {
var info bytes.Buffer
if forwardSecure {
info.Write([]byte("QUIC forward secure key expansion\x00"))
@@ -47,17 +53,33 @@ func deriveKeys(forwardSecure bool, sharedSecret, nonces []byte, connID protocol
if _, err := io.ReadFull(r, s); err != nil {
return nil, nil, nil, nil, err
}
otherKey := s[:keyLen]
myKey := s[keyLen : 2*keyLen]
otherIV := s[2*keyLen : 2*keyLen+4]
myIV := s[2*keyLen+4:]
key1 := s[:keyLen]
key2 := s[keyLen : 2*keyLen]
iv1 := s[2*keyLen : 2*keyLen+4]
iv2 := s[2*keyLen+4:]
var otherKey, myKey []byte
var otherIV, myIV []byte
if !forwardSecure {
if err := diversify(myKey, myIV, divNonce); err != nil {
if err := diversify(key2, iv2, divNonce); err != nil {
return nil, nil, nil, nil, err
}
}
if swap {
otherKey = key2
myKey = key1
otherIV = iv2
myIV = iv1
} else {
otherKey = key1
myKey = key2
otherIV = iv1
myIV = iv2
}
return otherKey, myKey, otherIV, myIV, nil
}

View File

@@ -87,7 +87,7 @@ var _ = Describe("KeyDerivation", func() {
// })
Context("AES-GCM", func() {
It("derives non-fs keys", func() {
It("derives non-forward secure keys", func() {
aead, err := DeriveKeysAESGCM(
false,
[]byte("0123456789012345678901"),
@@ -97,15 +97,66 @@ var _ = Describe("KeyDerivation", func() {
[]byte("scfg"),
[]byte("cert"),
[]byte("divnonce"),
protocol.PerspectiveServer,
)
Expect(err).ToNot(HaveOccurred())
chacha := aead.(*aeadAESGCM)
aesgcm := aead.(*aeadAESGCM)
// If the IVs match, the keys will match too, since the keys are read earlier
Expect(chacha.myIV).To(Equal([]byte{0x1c, 0xec, 0xac, 0x9b}))
Expect(chacha.otherIV).To(Equal([]byte{0x64, 0xef, 0x3c, 0x9}))
Expect(aesgcm.myIV).To(Equal([]byte{0x1c, 0xec, 0xac, 0x9b}))
Expect(aesgcm.otherIV).To(Equal([]byte{0x64, 0xef, 0x3c, 0x9}))
})
It("derives fs keys", func() {
It("uses the diversification nonce when generating non-forwared secure keys", func() {
aead1, err := DeriveKeysAESGCM(
false,
[]byte("0123456789012345678901"),
[]byte("nonce"),
protocol.ConnectionID(42),
[]byte("chlo"),
[]byte("scfg"),
[]byte("cert"),
[]byte("divnonce"),
protocol.PerspectiveServer,
)
Expect(err).ToNot(HaveOccurred())
aead2, err := DeriveKeysAESGCM(
false,
[]byte("0123456789012345678901"),
[]byte("nonce"),
protocol.ConnectionID(42),
[]byte("chlo"),
[]byte("scfg"),
[]byte("cert"),
[]byte("ecnonvid"),
protocol.PerspectiveServer,
)
Expect(err).ToNot(HaveOccurred())
aesgcm1 := aead1.(*aeadAESGCM)
aesgcm2 := aead2.(*aeadAESGCM)
Expect(aesgcm1.myIV).ToNot(Equal(aesgcm2.myIV))
Expect(aesgcm1.otherIV).To(Equal(aesgcm2.otherIV))
})
It("derives non-forward secure keys, for the other side", func() {
aead, err := DeriveKeysAESGCM(
false,
[]byte("0123456789012345678901"),
[]byte("nonce"),
protocol.ConnectionID(42),
[]byte("chlo"),
[]byte("scfg"),
[]byte("cert"),
[]byte("divnonce"),
protocol.PerspectiveClient,
)
Expect(err).ToNot(HaveOccurred())
aesgcm := aead.(*aeadAESGCM)
// If the IVs match, the keys will match too, since the keys are read earlier
Expect(aesgcm.otherIV).To(Equal([]byte{0x1c, 0xec, 0xac, 0x9b}))
Expect(aesgcm.myIV).To(Equal([]byte{0x64, 0xef, 0x3c, 0x9}))
})
It("derives forward secure keys", func() {
aead, err := DeriveKeysAESGCM(
true,
[]byte("0123456789012345678901"),
@@ -115,12 +166,13 @@ var _ = Describe("KeyDerivation", func() {
[]byte("scfg"),
[]byte("cert"),
nil,
protocol.PerspectiveServer,
)
Expect(err).ToNot(HaveOccurred())
chacha := aead.(*aeadAESGCM)
aesgcm := aead.(*aeadAESGCM)
// If the IVs match, the keys will match too, since the keys are read earlier
Expect(chacha.myIV).To(Equal([]byte{0x7, 0xad, 0xab, 0xb8}))
Expect(chacha.otherIV).To(Equal([]byte{0xf2, 0x7a, 0xcc, 0x42}))
Expect(aesgcm.myIV).To(Equal([]byte{0x7, 0xad, 0xab, 0xb8}))
Expect(aesgcm.otherIV).To(Equal([]byte{0xf2, 0x7a, 0xcc, 0x42}))
})
It("does not use div-nonce for FS key derivation", func() {
@@ -133,12 +185,13 @@ var _ = Describe("KeyDerivation", func() {
[]byte("scfg"),
[]byte("cert"),
[]byte("divnonce"),
protocol.PerspectiveServer,
)
Expect(err).ToNot(HaveOccurred())
chacha := aead.(*aeadAESGCM)
aesgcm := aead.(*aeadAESGCM)
// If the IVs match, the keys will match too, since the keys are read earlier
Expect(chacha.myIV).To(Equal([]byte{0x7, 0xad, 0xab, 0xb8}))
Expect(chacha.otherIV).To(Equal([]byte{0xf2, 0x7a, 0xcc, 0x42}))
Expect(aesgcm.myIV).To(Equal([]byte{0x7, 0xad, 0xab, 0xb8}))
Expect(aesgcm.otherIV).To(Equal([]byte{0xf2, 0x7a, 0xcc, 0x42}))
})
})
})

View File

@@ -15,7 +15,7 @@ import (
)
// KeyDerivationFunction is used for key derivation
type KeyDerivationFunction func(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte) (crypto.AEAD, error)
type KeyDerivationFunction func(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte, pers protocol.Perspective) (crypto.AEAD, error)
// KeyExchangeFunction is used to make a new KEX
type KeyExchangeFunction func() crypto.KeyExchange
@@ -304,6 +304,7 @@ func (h *cryptoSetupServer) handleCHLO(sni string, data []byte, cryptoData map[T
h.scfg.Get(),
certUncompressed,
h.diversificationNonce,
protocol.PerspectiveServer,
)
if err != nil {
return nil, err
@@ -328,6 +329,7 @@ func (h *cryptoSetupServer) handleCHLO(sni string, data []byte, cryptoData map[T
h.scfg.Get(),
certUncompressed,
nil,
protocol.PerspectiveServer,
)
if err != nil {
return nil, err

View File

@@ -82,7 +82,7 @@ func (mockAEAD) DiversificationNonce() []byte { return nil }
var expectedInitialNonceLen int
var expectedFSNonceLen int
func mockKeyDerivation(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte) (crypto.AEAD, error) {
func mockKeyDerivation(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte, pers protocol.Perspective) (crypto.AEAD, error) {
if forwardSecure {
Expect(nonces).To(HaveLen(expectedFSNonceLen))
} else {