Recover UDP crypto after packet loss
This commit is contained in:
committed by
Brandon McGinty
parent
90f8a1ca5f
commit
4510c25350
+16
-3
@@ -292,10 +292,13 @@ func (cs *cryptState15) decrypt15(packet []byte) ([]byte, error) {
|
||||
backupIV(cs.decryptIV[:])
|
||||
restore = true
|
||||
} else if ivByte > cs.decryptIV[0] && diff > 0 {
|
||||
// We missed packets; catch up. Already handled above.
|
||||
// We missed packets; move the low IV byte forward.
|
||||
cs.decryptIV[0] = ivByte
|
||||
} else if ivByte < cs.decryptIV[0] && diff > 0 {
|
||||
// Wrapped forward; advance and catch up.
|
||||
advanceIV(cs.decryptIV[:])
|
||||
// We missed packets across a low-byte wrap. The IV's higher
|
||||
// bytes must advance even though the received low byte is set
|
||||
// below rather than incremented.
|
||||
advanceIVHighBytes(cs.decryptIV[:])
|
||||
cs.decryptIV[0] = ivByte
|
||||
} else {
|
||||
return nil, errors.New("gumble: OCB IV too far off")
|
||||
@@ -340,6 +343,16 @@ func advanceIV(iv []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
// advanceIVHighBytes advances all but the low IV byte as a little-endian integer.
|
||||
func advanceIVHighBytes(iv []byte) {
|
||||
for i := 1; i < len(iv); i++ {
|
||||
iv[i]++
|
||||
if iv[i] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// backupIV decrements a 16-byte IV as a little-endian integer.
|
||||
func backupIV(iv []byte) {
|
||||
for i := 0; i < len(iv); i++ {
|
||||
|
||||
@@ -32,6 +32,75 @@ func TestAdvanceIV(t *testing.T) {
|
||||
}
|
||||
|
||||
// Regression coverage for the native IV carry path at the 255->256 wrap.
|
||||
func TestCryptState15DecryptsAfterMissedPackets(t *testing.T) {
|
||||
key := mustDecodeHex("93360b0f86a926c4561563469026eb94")
|
||||
nonce := mustDecodeHex("10000000000000000000000000000000")
|
||||
out, in := &cryptState15{}, &cryptState15{}
|
||||
if err := out.setup15(key, nonce, nonce); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := in.setup15(key, nonce, nonce); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
first, err := out.encrypt15([]byte("first"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := in.decrypt15(first); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
if _, err := out.encrypt15([]byte("dropped")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
last, err := out.encrypt15([]byte("after loss"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plain, err := in.decrypt15(last)
|
||||
if err != nil || !bytes.Equal(plain, []byte("after loss")) {
|
||||
t.Fatalf("decrypt after missed packets = %q, %v", plain, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCryptState15DecryptsAfterMissedPacketsAcrossIVByteWrap(t *testing.T) {
|
||||
key := mustDecodeHex("93360b0f86a926c4561563469026eb94")
|
||||
nonce := mustDecodeHex("fa000000000000000000000000000000")
|
||||
out, in := &cryptState15{}, &cryptState15{}
|
||||
if err := out.setup15(key, nonce, nonce); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := in.setup15(key, nonce, nonce); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
first, err := out.encrypt15([]byte("before wrap"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := in.decrypt15(first); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := 0; i < 6; i++ {
|
||||
if _, err := out.encrypt15([]byte("dropped")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
last, err := out.encrypt15([]byte("after wrap"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plain, err := in.decrypt15(last)
|
||||
if err != nil || !bytes.Equal(plain, []byte("after wrap")) {
|
||||
t.Fatalf("decrypt after missed packets across IV wrap = %q, %v", plain, err)
|
||||
}
|
||||
if in.decryptIV[0] != 2 || in.decryptIV[1] != 1 {
|
||||
t.Fatalf("unexpected IV after wrapped loss: %x", in.decryptIV[:2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestCryptState15DecryptsAcrossIVByteWrap(t *testing.T) {
|
||||
key := mustDecodeHex("93360b0f86a926c4561563469026eb94")
|
||||
clientNonce := mustDecodeHex("ff000000000000000000000000000000")
|
||||
|
||||
Reference in New Issue
Block a user