Merge pull request #2331 from lucas-clemente/chacha20-bug-workaround

add a workaround for the ChaCha20 bug
This commit is contained in:
Marten Seemann
2020-01-31 15:32:28 +07:00
committed by GitHub

View File

@@ -3,6 +3,7 @@ package handshake
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"github.com/marten-seemann/chacha20"
@@ -91,10 +92,27 @@ func newChaChaHeaderProtector(suite *qtls.CipherSuiteTLS13, trafficSecret []byte
}
func (p *chachaHeaderProtector) DecryptHeader(sample []byte, firstByte *byte, hdrBytes []byte) {
// Workaround for https://github.com/lucas-clemente/quic-go/issues/2326.
// The ChaCha20 implementation panics when the nonce is 0xffffffff.
// Don't apply header protection in that case.
// The packet will end up undecryptable, but it only applies to 1 in 2^32 packets.
if sample[0] == 0xff && sample[1] == 0xff && sample[2] == 0xff && sample[3] == 0xff {
return
}
p.apply(sample, firstByte, hdrBytes)
}
func (p *chachaHeaderProtector) EncryptHeader(sample []byte, firstByte *byte, hdrBytes []byte) {
// Workaround for https://github.com/lucas-clemente/quic-go/issues/2326.
// The ChaCha20 implementation panics when the nonce is 0xffffffff.
// Apply header protection with a random mask, in order to not leak any data.
// The packet will end up undecryptable, but this only applies to 1 in 2^32 packets.
if sample[0] == 0xff && sample[1] == 0xff && sample[2] == 0xff && sample[3] == 0xff {
if _, err := rand.Read(p.mask[:]); err != nil {
panic("couldn't get rand for ChaCha20 bug workaround")
}
p.applyMask(firstByte, hdrBytes)
}
p.apply(sample, firstByte, hdrBytes)
}
@@ -107,7 +125,10 @@ func (p *chachaHeaderProtector) apply(sample []byte, firstByte *byte, hdrBytes [
}
copy(p.sampleBuf[:], sample)
chacha20.XORKeyStream(p.mask[:], p.mask[:], &p.sampleBuf, &p.key)
p.applyMask(firstByte, hdrBytes)
}
func (p *chachaHeaderProtector) applyMask(firstByte *byte, hdrBytes []byte) {
if p.isLongHeader {
*firstByte ^= p.mask[0] & 0xf
} else {