Skip to content

Commit e8113f0

Browse files
committed
Use the spare field in the encrypted video header as the frame number
This allows us to skip decrypting extra FEC shards after a frame was reassembled.
1 parent a517f7c commit e8113f0

File tree

4 files changed

+31
-1
lines changed

4 files changed

+31
-1
lines changed

src/RtpVideoQueue.c

+4
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,10 @@ static void submitCompletedFrame(PRTP_VIDEO_QUEUE queue) {
535535
}
536536
}
537537

538+
uint32_t RtpvGetCurrentFrameNumber(PRTP_VIDEO_QUEUE queue) {
539+
return queue->currentFrameNumber;
540+
}
541+
538542
int RtpvAddPacket(PRTP_VIDEO_QUEUE queue, PRTP_PACKET packet, int length, PRTPV_QUEUE_ENTRY packetEntry) {
539543
if (isBefore16(packet->sequenceNumber, queue->nextContiguousSequenceNumber)) {
540544
// Reject packets behind our current buffer window

src/RtpVideoQueue.h

+1
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,5 @@ typedef struct _RTP_VIDEO_QUEUE {
5353
void RtpvInitializeQueue(PRTP_VIDEO_QUEUE queue);
5454
void RtpvCleanupQueue(PRTP_VIDEO_QUEUE queue);
5555
int RtpvAddPacket(PRTP_VIDEO_QUEUE queue, PRTP_PACKET packet, int length, PRTPV_QUEUE_ENTRY packetEntry);
56+
uint32_t RtpvGetCurrentFrameNumber(PRTP_VIDEO_QUEUE queue);
5657
void RtpvSubmitQueuedPackets(PRTP_VIDEO_QUEUE queue);

src/Video.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ typedef struct _QUEUED_DECODE_UNIT {
1414
// for FEC stays a multiple of 16 too.
1515
typedef struct _ENC_VIDEO_HEADER {
1616
uint8_t iv[12];
17-
uint32_t unused;
17+
uint32_t frameNumber;
1818
uint8_t tag[16];
1919
} ENC_VIDEO_HEADER, *PENC_VIDEO_HEADER;
2020

src/VideoStream.c

+25
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,31 @@ static void VideoReceiveThreadProc(void* context) {
187187
if (encrypted) {
188188
PENC_VIDEO_HEADER encHeader = (PENC_VIDEO_HEADER)encryptedBuffer;
189189

190+
// If this frame is below our current frame number, discard it before decryption
191+
// to save CPU cycles decrypting FEC shards for a frame we already reassembled.
192+
//
193+
// Since this is happening _before_ decryption, this packet is not trusted yet.
194+
// It's imperative that we do not mutate any state based on this packet until
195+
// after it has been decrypted successfully!
196+
//
197+
// It's possible for an attacker to inject a fake packet that has any value of
198+
// header fields they want, however this provides them no benefit because we will
199+
// simply drop said packet here (if it's below the current frame number) or it
200+
// will pass this check and be dropped during decryption (if contents is tampered)
201+
// or after decryption in the RTP queue (if it's a replay of a previous authentic
202+
// packet from the host).
203+
//
204+
// In short, an attacker spoofing this value via MITM or sending malicious values
205+
// impersonating the host from off-link doesn't gain them anything. If they have
206+
// a true MITM, they can DoS our connection by just dropping all our traffic, so
207+
// tampering with packets to fail this check doesn't accomplish anything they
208+
// couldn't already do. If they're not on-link, we just throw their malicious
209+
// traffic away (as mentioned in the paragraph above) and continue accepting
210+
// legitmate video traffic.
211+
if (encHeader->frameNumber && LE32(encHeader->frameNumber) < RtpvGetCurrentFrameNumber(&rtpQueue)) {
212+
continue;
213+
}
214+
190215
if (!PltDecryptMessage(decryptionCtx, ALGORITHM_AES_GCM, 0,
191216
(unsigned char*)StreamConfig.remoteInputAesKey, sizeof(StreamConfig.remoteInputAesKey),
192217
encHeader->iv, sizeof(encHeader->iv),

0 commit comments

Comments
 (0)