package gateway import ( "crypto/aes" "crypto/cipher" "encoding/binary" "testing" ) func TestEncryptedRTSPRejectsTagReplayAndReorderedHostFrames(t *testing.T) { key := []byte("0123456789abcdef") codec, err := newEncryptedRTSPCodec(key) if err != nil { t.Fatal(err) } first := hostEncryptedRTSPFrame(t, key, 1, []byte("RTSP/1.0 200 OK\r\n\r\n")) if plaintext, err := codec.OpenHost(first); err != nil || string(plaintext) != "RTSP/1.0 200 OK\r\n\r\n" { t.Fatalf("OpenHost() = %q, %v", plaintext, err) } if _, err := codec.OpenHost(first); err == nil { t.Fatal("OpenHost() accepted a replayed frame") } tampered := hostEncryptedRTSPFrame(t, key, 2, []byte("RTSP/1.0 200 OK\r\n\r\n")) tampered[len(tampered)-1] ^= 0x01 if _, err := codec.OpenHost(tampered); err == nil { t.Fatal("OpenHost() accepted a tag failure") } third := hostEncryptedRTSPFrame(t, key, 3, []byte("RTSP/1.0 200 OK\r\n\r\n")) if _, err := codec.OpenHost(third); err != nil { t.Fatalf("OpenHost() sequence 3 error = %v", err) } second := hostEncryptedRTSPFrame(t, key, 2, []byte("RTSP/1.0 200 OK\r\n\r\n")) if _, err := codec.OpenHost(second); err == nil { t.Fatal("OpenHost() accepted an out-of-order frame") } } func hostEncryptedRTSPFrame(t *testing.T, key []byte, sequence uint32, plaintext []byte) []byte { t.Helper() block, err := aes.NewCipher(key) if err != nil { t.Fatal(err) } aead, err := cipher.NewGCM(block) if err != nil { t.Fatal(err) } nonce := encryptedRTSPNonce(sequence, 'H', 'R') sealed := aead.Seal(nil, nonce[:], plaintext, nil) frame := make([]byte, encryptedRTSPHeaderSize+len(plaintext)) binary.BigEndian.PutUint32(frame[:4], uint32(len(plaintext))|0x80000000) binary.BigEndian.PutUint32(frame[4:8], sequence) copy(frame[8:24], sealed[len(plaintext):]) copy(frame[24:], sealed[:len(plaintext)]) return frame }