mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2026-02-16 02:21:07 +00:00
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.
This commit is contained in:
@@ -535,6 +535,10 @@ static void submitCompletedFrame(PRTP_VIDEO_QUEUE queue) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t RtpvGetCurrentFrameNumber(PRTP_VIDEO_QUEUE queue) {
|
||||
return queue->currentFrameNumber;
|
||||
}
|
||||
|
||||
int RtpvAddPacket(PRTP_VIDEO_QUEUE queue, PRTP_PACKET packet, int length, PRTPV_QUEUE_ENTRY packetEntry) {
|
||||
if (isBefore16(packet->sequenceNumber, queue->nextContiguousSequenceNumber)) {
|
||||
// Reject packets behind our current buffer window
|
||||
|
||||
@@ -53,4 +53,5 @@ typedef struct _RTP_VIDEO_QUEUE {
|
||||
void RtpvInitializeQueue(PRTP_VIDEO_QUEUE queue);
|
||||
void RtpvCleanupQueue(PRTP_VIDEO_QUEUE queue);
|
||||
int RtpvAddPacket(PRTP_VIDEO_QUEUE queue, PRTP_PACKET packet, int length, PRTPV_QUEUE_ENTRY packetEntry);
|
||||
uint32_t RtpvGetCurrentFrameNumber(PRTP_VIDEO_QUEUE queue);
|
||||
void RtpvSubmitQueuedPackets(PRTP_VIDEO_QUEUE queue);
|
||||
|
||||
@@ -14,7 +14,7 @@ typedef struct _QUEUED_DECODE_UNIT {
|
||||
// for FEC stays a multiple of 16 too.
|
||||
typedef struct _ENC_VIDEO_HEADER {
|
||||
uint8_t iv[12];
|
||||
uint32_t unused;
|
||||
uint32_t frameNumber;
|
||||
uint8_t tag[16];
|
||||
} ENC_VIDEO_HEADER, *PENC_VIDEO_HEADER;
|
||||
|
||||
|
||||
@@ -187,6 +187,31 @@ static void VideoReceiveThreadProc(void* context) {
|
||||
if (encrypted) {
|
||||
PENC_VIDEO_HEADER encHeader = (PENC_VIDEO_HEADER)encryptedBuffer;
|
||||
|
||||
// If this frame is below our current frame number, discard it before decryption
|
||||
// to save CPU cycles decrypting FEC shards for a frame we already reassembled.
|
||||
//
|
||||
// Since this is happening _before_ decryption, this packet is not trusted yet.
|
||||
// It's imperative that we do not mutate any state based on this packet until
|
||||
// after it has been decrypted successfully!
|
||||
//
|
||||
// It's possible for an attacker to inject a fake packet that has any value of
|
||||
// header fields they want, however this provides them no benefit because we will
|
||||
// simply drop said packet here (if it's below the current frame number) or it
|
||||
// will pass this check and be dropped during decryption (if contents is tampered)
|
||||
// or after decryption in the RTP queue (if it's a replay of a previous authentic
|
||||
// packet from the host).
|
||||
//
|
||||
// In short, an attacker spoofing this value via MITM or sending malicious values
|
||||
// impersonating the host from off-link doesn't gain them anything. If they have
|
||||
// a true MITM, they can DoS our connection by just dropping all our traffic, so
|
||||
// tampering with packets to fail this check doesn't accomplish anything they
|
||||
// couldn't already do. If they're not on-link, we just throw their malicious
|
||||
// traffic away (as mentioned in the paragraph above) and continue accepting
|
||||
// legitmate video traffic.
|
||||
if (encHeader->frameNumber && LE32(encHeader->frameNumber) < RtpvGetCurrentFrameNumber(&rtpQueue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!PltDecryptMessage(decryptionCtx, ALGORITHM_AES_GCM, 0,
|
||||
(unsigned char*)StreamConfig.remoteInputAesKey, sizeof(StreamConfig.remoteInputAesKey),
|
||||
encHeader->iv, sizeof(encHeader->iv),
|
||||
|
||||
Reference in New Issue
Block a user