mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2026-04-02 22:06:10 +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) {
|
int RtpvAddPacket(PRTP_VIDEO_QUEUE queue, PRTP_PACKET packet, int length, PRTPV_QUEUE_ENTRY packetEntry) {
|
||||||
if (isBefore16(packet->sequenceNumber, queue->nextContiguousSequenceNumber)) {
|
if (isBefore16(packet->sequenceNumber, queue->nextContiguousSequenceNumber)) {
|
||||||
// Reject packets behind our current buffer window
|
// Reject packets behind our current buffer window
|
||||||
|
|||||||
@@ -53,4 +53,5 @@ typedef struct _RTP_VIDEO_QUEUE {
|
|||||||
void RtpvInitializeQueue(PRTP_VIDEO_QUEUE queue);
|
void RtpvInitializeQueue(PRTP_VIDEO_QUEUE queue);
|
||||||
void RtpvCleanupQueue(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);
|
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);
|
void RtpvSubmitQueuedPackets(PRTP_VIDEO_QUEUE queue);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ typedef struct _QUEUED_DECODE_UNIT {
|
|||||||
// for FEC stays a multiple of 16 too.
|
// for FEC stays a multiple of 16 too.
|
||||||
typedef struct _ENC_VIDEO_HEADER {
|
typedef struct _ENC_VIDEO_HEADER {
|
||||||
uint8_t iv[12];
|
uint8_t iv[12];
|
||||||
uint32_t unused;
|
uint32_t frameNumber;
|
||||||
uint8_t tag[16];
|
uint8_t tag[16];
|
||||||
} ENC_VIDEO_HEADER, *PENC_VIDEO_HEADER;
|
} ENC_VIDEO_HEADER, *PENC_VIDEO_HEADER;
|
||||||
|
|
||||||
|
|||||||
@@ -187,6 +187,31 @@ static void VideoReceiveThreadProc(void* context) {
|
|||||||
if (encrypted) {
|
if (encrypted) {
|
||||||
PENC_VIDEO_HEADER encHeader = (PENC_VIDEO_HEADER)encryptedBuffer;
|
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,
|
if (!PltDecryptMessage(decryptionCtx, ALGORITHM_AES_GCM, 0,
|
||||||
(unsigned char*)StreamConfig.remoteInputAesKey, sizeof(StreamConfig.remoteInputAesKey),
|
(unsigned char*)StreamConfig.remoteInputAesKey, sizeof(StreamConfig.remoteInputAesKey),
|
||||||
encHeader->iv, sizeof(encHeader->iv),
|
encHeader->iv, sizeof(encHeader->iv),
|
||||||
|
|||||||
Reference in New Issue
Block a user