Use a 12-byte AES-GCM IV for the new encryption features
This commit is contained in:
parent
7f99bebc72
commit
2597b5e779
2 changed files with 29 additions and 7 deletions
|
|
@ -501,6 +501,7 @@ static PNVCTL_TCP_PACKET_HEADER readNvctlPacketTcp(void) {
|
||||||
|
|
||||||
static bool encryptControlMessage(PNVCTL_ENCRYPTED_PACKET_HEADER encPacket, PNVCTL_ENET_PACKET_HEADER_V2 packet) {
|
static bool encryptControlMessage(PNVCTL_ENCRYPTED_PACKET_HEADER encPacket, PNVCTL_ENET_PACKET_HEADER_V2 packet) {
|
||||||
unsigned char iv[16] = { 0 };
|
unsigned char iv[16] = { 0 };
|
||||||
|
int ivSize;
|
||||||
int encryptedSize = sizeof(*packet) + packet->payloadLength;
|
int encryptedSize = sizeof(*packet) + packet->payloadLength;
|
||||||
|
|
||||||
// NB: Setting the IV must happen while encPacket->seq is still in native byte-order!
|
// NB: Setting the IV must happen while encPacket->seq is still in native byte-order!
|
||||||
|
|
@ -512,12 +513,18 @@ static bool encryptControlMessage(PNVCTL_ENCRYPTED_PACKET_HEADER encPacket, PNVC
|
||||||
iv[0] = (unsigned char)(encPacket->seq >> 0);
|
iv[0] = (unsigned char)(encPacket->seq >> 0);
|
||||||
|
|
||||||
// Set high bytes to something unique to ensure no IV collisions
|
// Set high bytes to something unique to ensure no IV collisions
|
||||||
iv[14] = (unsigned char)'C'; // Client originated
|
iv[10] = (unsigned char)'C'; // Client originated
|
||||||
iv[15] = (unsigned char)'C'; // Control stream
|
iv[11] = (unsigned char)'C'; // Control stream
|
||||||
|
|
||||||
|
// Use 12-byte IV which is ideal for AES-GCM
|
||||||
|
ivSize = 12;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// This is a truncating cast, but it's what Nvidia does, so we have to mimic it.
|
// This is a truncating cast, but it's what Nvidia does, so we have to mimic it.
|
||||||
iv[0] = (unsigned char)encPacket->seq;
|
iv[0] = (unsigned char)encPacket->seq;
|
||||||
|
|
||||||
|
// Nvidia's old style encryption uses a 16-byte IV
|
||||||
|
ivSize = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
encPacket->encryptedHeaderType = LE16(encPacket->encryptedHeaderType);
|
encPacket->encryptedHeaderType = LE16(encPacket->encryptedHeaderType);
|
||||||
|
|
@ -527,9 +534,11 @@ static bool encryptControlMessage(PNVCTL_ENCRYPTED_PACKET_HEADER encPacket, PNVC
|
||||||
packet->type = LE16(packet->type);
|
packet->type = LE16(packet->type);
|
||||||
packet->payloadLength = LE16(packet->payloadLength);
|
packet->payloadLength = LE16(packet->payloadLength);
|
||||||
|
|
||||||
|
LC_ASSERT(ivSize <= sizeof(iv));
|
||||||
|
LC_ASSERT(ivSize == 12 || ivSize == 16);
|
||||||
return PltEncryptMessage(encryptionCtx, ALGORITHM_AES_GCM, 0,
|
return PltEncryptMessage(encryptionCtx, ALGORITHM_AES_GCM, 0,
|
||||||
(unsigned char*)StreamConfig.remoteInputAesKey, sizeof(StreamConfig.remoteInputAesKey),
|
(unsigned char*)StreamConfig.remoteInputAesKey, sizeof(StreamConfig.remoteInputAesKey),
|
||||||
iv, sizeof(iv),
|
iv, ivSize,
|
||||||
(unsigned char*)(encPacket + 1), AES_GCM_TAG_LENGTH, // Write tag into the space after the encrypted header
|
(unsigned char*)(encPacket + 1), AES_GCM_TAG_LENGTH, // Write tag into the space after the encrypted header
|
||||||
(unsigned char*)packet, encryptedSize,
|
(unsigned char*)packet, encryptedSize,
|
||||||
((unsigned char*)(encPacket + 1)) + AES_GCM_TAG_LENGTH, &encryptedSize); // Write ciphertext after the GCM tag
|
((unsigned char*)(encPacket + 1)) + AES_GCM_TAG_LENGTH, &encryptedSize); // Write ciphertext after the GCM tag
|
||||||
|
|
@ -538,6 +547,7 @@ static bool encryptControlMessage(PNVCTL_ENCRYPTED_PACKET_HEADER encPacket, PNVC
|
||||||
// Caller must free() *packet on success!!!
|
// Caller must free() *packet on success!!!
|
||||||
static bool decryptControlMessageToV1(PNVCTL_ENCRYPTED_PACKET_HEADER encPacket, int encPacketLength, PNVCTL_ENET_PACKET_HEADER_V1* packet, int* packetLength) {
|
static bool decryptControlMessageToV1(PNVCTL_ENCRYPTED_PACKET_HEADER encPacket, int encPacketLength, PNVCTL_ENET_PACKET_HEADER_V1* packet, int* packetLength) {
|
||||||
unsigned char iv[16] = { 0 };
|
unsigned char iv[16] = { 0 };
|
||||||
|
int ivSize;
|
||||||
|
|
||||||
*packet = NULL;
|
*packet = NULL;
|
||||||
|
|
||||||
|
|
@ -566,12 +576,18 @@ static bool decryptControlMessageToV1(PNVCTL_ENCRYPTED_PACKET_HEADER encPacket,
|
||||||
iv[0] = (unsigned char)(encPacket->seq >> 0);
|
iv[0] = (unsigned char)(encPacket->seq >> 0);
|
||||||
|
|
||||||
// Set high bytes to something unique to ensure no IV collisions
|
// Set high bytes to something unique to ensure no IV collisions
|
||||||
iv[14] = (unsigned char)'H'; // Host originated
|
iv[10] = (unsigned char)'H'; // Host originated
|
||||||
iv[15] = (unsigned char)'C'; // Control stream
|
iv[11] = (unsigned char)'C'; // Control stream
|
||||||
|
|
||||||
|
// Use 12-byte IV which is ideal for AES-GCM
|
||||||
|
ivSize = 12;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// This is a truncating cast, but it's what Nvidia does, so we have to mimic it.
|
// This is a truncating cast, but it's what Nvidia does, so we have to mimic it.
|
||||||
iv[0] = (unsigned char)encPacket->seq;
|
iv[0] = (unsigned char)encPacket->seq;
|
||||||
|
|
||||||
|
// Nvidia's old style encryption uses a 16-byte IV
|
||||||
|
ivSize = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
int plaintextLength = encPacket->length - sizeof(encPacket->seq) - AES_GCM_TAG_LENGTH;
|
int plaintextLength = encPacket->length - sizeof(encPacket->seq) - AES_GCM_TAG_LENGTH;
|
||||||
|
|
@ -580,9 +596,11 @@ static bool decryptControlMessageToV1(PNVCTL_ENCRYPTED_PACKET_HEADER encPacket,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LC_ASSERT(ivSize <= sizeof(iv));
|
||||||
|
LC_ASSERT(ivSize == 12 || ivSize == 16);
|
||||||
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),
|
||||||
iv, sizeof(iv),
|
iv, ivSize,
|
||||||
(unsigned char*)(encPacket + 1), AES_GCM_TAG_LENGTH, // The tag is located right after the header
|
(unsigned char*)(encPacket + 1), AES_GCM_TAG_LENGTH, // The tag is located right after the header
|
||||||
((unsigned char*)(encPacket + 1)) + AES_GCM_TAG_LENGTH, plaintextLength, // The ciphertext is after the tag
|
((unsigned char*)(encPacket + 1)) + AES_GCM_TAG_LENGTH, plaintextLength, // The ciphertext is after the tag
|
||||||
(unsigned char*)*packet, &plaintextLength)) {
|
(unsigned char*)*packet, &plaintextLength)) {
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,12 @@ typedef struct _QUEUED_DECODE_UNIT {
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
// The encrypted video header must be a multiple
|
||||||
|
// of 16 bytes in size to ensure the block size
|
||||||
|
// for FEC stays a multiple of 16 too.
|
||||||
typedef struct _ENC_VIDEO_HEADER {
|
typedef struct _ENC_VIDEO_HEADER {
|
||||||
uint8_t iv[16];
|
uint8_t iv[12];
|
||||||
|
uint32_t unused;
|
||||||
uint8_t tag[16];
|
uint8_t tag[16];
|
||||||
} ENC_VIDEO_HEADER, *PENC_VIDEO_HEADER;
|
} ENC_VIDEO_HEADER, *PENC_VIDEO_HEADER;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue