From 6b08a451da6cfe4cc769aa4003eaa37a972b8804 Mon Sep 17 00:00:00 2001 From: Davide Beatrici Date: Sat, 23 Nov 2019 04:38:20 +0100 Subject: [PATCH] Mayaqua: implement R-UDP version 2, powered by ChaCha20-Poly1305 --- src/Mayaqua/Network.c | 368 ++++++++++++++++++++++++++++-------------- src/Mayaqua/Network.h | 7 + 2 files changed, 257 insertions(+), 118 deletions(-) diff --git a/src/Mayaqua/Network.c b/src/Mayaqua/Network.c index 7c91fbe1..6e5bddaf 100644 --- a/src/Mayaqua/Network.c +++ b/src/Mayaqua/Network.c @@ -2397,65 +2397,109 @@ void RUDPInterruptProc(RUDP_STACK *r) void RUDPBulkSend(RUDP_STACK *r, RUDP_SESSION *se, void *data, UINT data_size) { UCHAR *buf; - UINT buf_size; - UINT padding_size; - UINT i; - CRYPT *c; - UCHAR crypt_key_src[SHA1_SIZE * 2]; - UCHAR crypt_key[SHA1_SIZE]; - UINT icmp_type = 0; - UCHAR sign[SHA1_SIZE]; - UCHAR iv[SHA1_SIZE + 1]; + UINT i, icmp_type, buf_size, padding_size; // Validate arguments if (r == NULL || se == NULL || (data == NULL && data_size != 0)) { return; } - padding_size = Rand32() % 31 + 1; - - buf_size = SHA1_SIZE + SHA1_SIZE + sizeof(UINT64) + data_size + padding_size; - buf = Malloc(buf_size); - - // SEQ NO - WRITE_UINT64(buf + SHA1_SIZE + SHA1_SIZE, se->BulkNextSeqNo); - se->BulkNextSeqNo++; - - // Data - Copy(buf + SHA1_SIZE + SHA1_SIZE + sizeof(UINT64), data, data_size); - - // Padding - for (i = 0;i < padding_size;i++) + if (se->BulkSendKey->Size == RUDP_BULK_KEY_SIZE_V2) { - buf[SHA1_SIZE + SHA1_SIZE + sizeof(UINT64) + data_size + i] = (UCHAR)padding_size; - } + UCHAR *tmp, iv[RUDP_BULK_IV_SIZE_V2]; + UINT size; + CIPHER *c; - // Encryption - Copy(iv, se->BulkNextIv, SHA1_SIZE); - Copy(crypt_key_src + 0, se->BulkSendKey->Data, SHA1_SIZE); - Copy(crypt_key_src + SHA1_SIZE, iv, SHA1_SIZE); - Sha1(crypt_key, crypt_key_src, SHA1_SIZE * 2); - c = NewCrypt(crypt_key, sizeof(crypt_key)); - Encrypt(c, buf + SHA1_SIZE + SHA1_SIZE, buf + SHA1_SIZE + SHA1_SIZE, sizeof(UINT64) + data_size + padding_size); - FreeCrypt(c); + padding_size = Rand32() % 31 + 1; - // IV - Copy(buf + SHA1_SIZE, iv, SHA1_SIZE); + size = sizeof(UINT64) + data_size + padding_size; - // Sign - if (se->UseHMac == false) - { - Copy(buf + 0, se->BulkSendKey->Data, SHA1_SIZE); - Sha1(sign, buf, SHA1_SIZE + SHA1_SIZE + sizeof(UINT64) + data_size + padding_size); - Copy(buf + 0, sign, SHA1_SIZE); + // Packet: IV + Encrypted(SEQ_NO + Data + padding) + MAC + buf_size = RUDP_BULK_IV_SIZE_V2 + sizeof(UINT64) + data_size + padding_size + RUDP_BULK_MAC_SIZE_V2; + buf = Malloc(buf_size); + + // IV + Copy(iv, se->BulkNextIv_V2, RUDP_BULK_IV_SIZE_V2); + Copy(buf, iv, RUDP_BULK_IV_SIZE_V2); + + // SEQ NO + WRITE_UINT64(buf + RUDP_BULK_IV_SIZE_V2, se->BulkNextSeqNo); + se->BulkNextSeqNo++; + + // Data + Copy(buf + RUDP_BULK_IV_SIZE_V2 + sizeof(UINT64), data, data_size); + + // Padding + for (i = 0;i < padding_size;i++) + { + buf[RUDP_BULK_IV_SIZE_V2 + sizeof(UINT64) + data_size + i] = (UCHAR)padding_size; + } + + size = sizeof(UINT64) + data_size + padding_size; + tmp = buf + RUDP_BULK_IV_SIZE_V2; + + // Encryption + c = NewCipher("ChaCha20-Poly1305"); + SetCipherKey(c, se->BulkSendKey->Data, true); + CipherProcessAead(c, iv, tmp + size, RUDP_BULK_MAC_SIZE_V2, tmp, tmp, size - RUDP_BULK_MAC_SIZE_V2, NULL, 0); + FreeCipher(c); + + // Next IV + Copy(se->BulkNextIv_V2, buf + sizeof(UINT64) + data_size + padding_size, RUDP_BULK_IV_SIZE_V2); } else { - HMacSha1(buf + 0, se->BulkSendKey->Data, SHA1_SIZE, buf + SHA1_SIZE, SHA1_SIZE + sizeof(UINT64) + data_size + padding_size); - } + UCHAR crypt_key_src[SHA1_SIZE * 2]; + UCHAR crypt_key[SHA1_SIZE]; + UCHAR sign[SHA1_SIZE]; + UCHAR iv[SHA1_SIZE]; + CRYPT *c; - // Next IV - Copy(se->BulkNextIv, buf + buf_size - SHA1_SIZE, SHA1_SIZE); + padding_size = Rand32() % 31 + 1; + + buf_size = SHA1_SIZE + SHA1_SIZE + sizeof(UINT64) + data_size + padding_size; + buf = Malloc(buf_size); + + // SEQ NO + WRITE_UINT64(buf + SHA1_SIZE + SHA1_SIZE, se->BulkNextSeqNo); + se->BulkNextSeqNo++; + + // Data + Copy(buf + SHA1_SIZE + SHA1_SIZE + sizeof(UINT64), data, data_size); + + // Padding + for (i = 0;i < padding_size;i++) + { + buf[SHA1_SIZE + SHA1_SIZE + sizeof(UINT64) + data_size + i] = (UCHAR)padding_size; + } + + // Encryption + Copy(iv, se->BulkNextIv, SHA1_SIZE); + Copy(crypt_key_src + 0, se->BulkSendKey->Data, SHA1_SIZE); + Copy(crypt_key_src + SHA1_SIZE, iv, SHA1_SIZE); + Sha1(crypt_key, crypt_key_src, SHA1_SIZE * 2); + c = NewCrypt(crypt_key, sizeof(crypt_key)); + Encrypt(c, buf + SHA1_SIZE + SHA1_SIZE, buf + SHA1_SIZE + SHA1_SIZE, sizeof(UINT64) + data_size + padding_size); + FreeCrypt(c); + + // IV + Copy(buf + SHA1_SIZE, iv, SHA1_SIZE); + + // Sign + if (se->UseHMac == false) + { + Copy(buf + 0, se->BulkSendKey->Data, SHA1_SIZE); + Sha1(sign, buf, SHA1_SIZE + SHA1_SIZE + sizeof(UINT64) + data_size + padding_size); + Copy(buf + 0, sign, SHA1_SIZE); + } + else + { + HMacSha1(buf + 0, se->BulkSendKey->Data, SHA1_SIZE, buf + SHA1_SIZE, SHA1_SIZE + sizeof(UINT64) + data_size + padding_size); + } + + // Next IV + Copy(se->BulkNextIv, buf + buf_size - SHA1_SIZE, SHA1_SIZE); + } if (r->Protocol == RUDP_PROTOCOL_ICMP) { @@ -2465,6 +2509,7 @@ void RUDPBulkSend(RUDP_STACK *r, RUDP_SESSION *se, void *data, UINT data_size) { icmp_type = se->Dns_TranId; } + RUDPSendPacket(r, &se->YourIp, se->YourPort, buf, buf_size, icmp_type); Free(buf); @@ -2591,40 +2636,71 @@ bool RUDPCheckSignOfRecvPacket(RUDP_STACK *r, RUDP_SESSION *se, void *recv_data, } // Verification signature (bulk packet) - if (se->UseHMac == false) + if (se->BulkRecvKey->Size == RUDP_BULK_KEY_SIZE_V2) { - Copy(sign, p, SHA1_SIZE); - Copy(p, se->BulkRecvKey->Data, SHA1_SIZE); - Sha1(sign2, p, recv_size); - Copy(p, sign, SHA1_SIZE); + UCHAR *iv = p; + CIPHER *c; - if (Cmp(sign, sign2, SHA1_SIZE) == 0) + // Packet: IV + Encrypted(SEQ_NO + Data + padding) + MAC + // IV + if (size < RUDP_BULK_IV_SIZE_V2) { + return false; + } + iv = p; + p += RUDP_BULK_IV_SIZE_V2; + size -= RUDP_BULK_IV_SIZE_V2; + + // Decrypt + if (size < (RUDP_BULK_MAC_SIZE_V2 + 1)) + { + return false; + } + + c = NewCipher("ChaCha20-Poly1305"); + SetCipherKey(c, se->BulkRecvKey->Data, false); + size = CipherProcessAead(c, iv, p + size, RUDP_BULK_MAC_SIZE_V2, r->TmpBuf, p, size - RUDP_BULK_MAC_SIZE_V2, NULL, 0); + FreeCipher(c); + + if (size == 0) + { + return false; + } + + return true; + } + else + { + if (se->UseHMac == false) + { + Copy(sign, p, SHA1_SIZE); + Copy(p, se->BulkRecvKey->Data, SHA1_SIZE); + Sha1(sign2, p, recv_size); + Copy(p, sign, SHA1_SIZE); + + if (Cmp(sign, sign2, SHA1_SIZE) == 0) + { + return true; + } + } + + HMacSha1(sign2, se->BulkRecvKey->Data, SHA1_SIZE, p + SHA1_SIZE, size - SHA1_SIZE); + if (Cmp(p, sign2, SHA1_SIZE) == 0) + { + se->UseHMac = true; return true; } } - HMacSha1(sign2, se->BulkRecvKey->Data, SHA1_SIZE, p + SHA1_SIZE, size - SHA1_SIZE); - if (Cmp(p, sign2, SHA1_SIZE) == 0) - { - se->UseHMac = true; - return true; - } - return false; } // Process the received packet (bulk) bool RUDPProcessBulkRecvPacket(RUDP_STACK *r, RUDP_SESSION *se, void *recv_data, UINT recv_size) { - UCHAR sign[SHA1_SIZE]; - UCHAR sign2[SHA1_SIZE]; UCHAR *p; UCHAR *iv; UINT size; - UCHAR keygen[SHA1_SIZE * 2]; - UCHAR key[SHA1_SIZE]; - CRYPT *c; UCHAR padlen; UINT64 seq_no; UCHAR *payload; @@ -2642,15 +2718,85 @@ bool RUDPProcessBulkRecvPacket(RUDP_STACK *r, RUDP_SESSION *se, void *recv_data, return false; } - // Validate the signature - if (se->UseHMac == false) + if (se->BulkRecvKey->Size == RUDP_BULK_KEY_SIZE_V2) { - Copy(sign, p, SHA1_SIZE); - Copy(p, se->BulkRecvKey->Data, SHA1_SIZE); - Sha1(sign2, p, recv_size); - Copy(p, sign, SHA1_SIZE); + UINT ret; + CIPHER *c; - if (Cmp(sign, sign2, SHA1_SIZE) != 0) + // Packet: IV + Encrypted(SEQ_NO + Data + padding) + MAC + // IV + if (size < RUDP_BULK_IV_SIZE_V2) + { + WHERE; + return false; + } + iv = p; + p += RUDP_BULK_IV_SIZE_V2; + size -= RUDP_BULK_IV_SIZE_V2; + + // Decrypt + if (size < (RUDP_BULK_MAC_SIZE_V2 + 1)) + { + WHERE; + return false; + } + + c = NewCipher("ChaCha20-Poly1305"); + SetCipherKey(c, se->BulkRecvKey->Data, false); + ret = CipherProcessAead(c, iv, p + size, RUDP_BULK_MAC_SIZE_V2, p, p, size - RUDP_BULK_MAC_SIZE_V2, NULL, 0); + FreeCipher(c); + + if (ret == 0) + { + WHERE; + return false; + } + + size -= RUDP_BULK_MAC_SIZE_V2; + + // padlen + padlen = p[size - 1]; + if (padlen == 0) + { + WHERE; + return false; + } + if (size < padlen) + { + WHERE; + return false; + } + size -= padlen; + } + else + { + CRYPT *c; + UCHAR sign[SHA1_SIZE], sign2[SHA1_SIZE]; + UCHAR key[SHA1_SIZE], keygen[SHA1_SIZE * 2]; + + // Validate the signature + if (se->UseHMac == false) + { + Copy(sign, p, SHA1_SIZE); + Copy(p, se->BulkRecvKey->Data, SHA1_SIZE); + Sha1(sign2, p, recv_size); + Copy(p, sign, SHA1_SIZE); + + if (Cmp(sign, sign2, SHA1_SIZE) != 0) + { + HMacSha1(sign2, se->BulkRecvKey->Data, SHA1_SIZE, p + SHA1_SIZE, recv_size - SHA1_SIZE); + + if (Cmp(p, sign2, SHA1_SIZE) != 0) + { + return false; + } + else + { + se->UseHMac = true; + } + } + } + else { HMacSha1(sign2, se->BulkRecvKey->Data, SHA1_SIZE, p + SHA1_SIZE, recv_size - SHA1_SIZE); @@ -2658,61 +2804,45 @@ bool RUDPProcessBulkRecvPacket(RUDP_STACK *r, RUDP_SESSION *se, void *recv_data, { return false; } - else - { - se->UseHMac = true; - } } - else - { - } - } - else - { - HMacSha1(sign2, se->BulkRecvKey->Data, SHA1_SIZE, p + SHA1_SIZE, recv_size - SHA1_SIZE); - if (Cmp(p, sign2, SHA1_SIZE) != 0) + p += SHA1_SIZE; + size -= SHA1_SIZE; + + // IV + if (size < SHA1_SIZE) { return false; } - } + iv = p; + p += SHA1_SIZE; + size -= SHA1_SIZE; - p += SHA1_SIZE; - size -= SHA1_SIZE; + // Decrypt + if (size < 1) + { + return false; + } + Copy(keygen + 0, se->BulkRecvKey->Data, SHA1_SIZE); + Copy(keygen + SHA1_SIZE, iv, SHA1_SIZE); + Sha1(key, keygen, sizeof(keygen)); - // IV - if (size < SHA1_SIZE) - { - return false; - } - iv = p; - p += SHA1_SIZE; - size -= SHA1_SIZE; + c = NewCrypt(key, sizeof(key)); + Encrypt(c, p, p, size); + FreeCrypt(c); - // Decrypt - if (size < 1) - { - return false; + // padlen + padlen = p[size - 1]; + if (padlen == 0) + { + return false; + } + if (size < padlen) + { + return false; + } + size -= padlen; } - Copy(keygen + 0, se->BulkRecvKey->Data, SHA1_SIZE); - Copy(keygen + SHA1_SIZE, iv, SHA1_SIZE); - Sha1(key, keygen, sizeof(keygen)); - - c = NewCrypt(key, sizeof(key)); - Encrypt(c, p, p, size); - FreeCrypt(c); - - // padlen - padlen = p[size - 1]; - if (padlen == 0) - { - return false; - } - if (size < padlen) - { - return false; - } - size -= padlen; // SEQ NO seq_no = READ_UINT64(p); @@ -3525,8 +3655,8 @@ RUDP_SESSION *RUDPNewSession(bool server_mode, IP *my_ip, UINT my_port, IP *your RUDP_SESSION *se; UCHAR key1[SHA1_SIZE]; UCHAR key2[SHA1_SIZE]; - UCHAR bulk_send_key[SHA1_SIZE]; - UCHAR bulk_recv_key[SHA1_SIZE]; + UCHAR bulk_send_key[RUDP_BULK_KEY_SIZE_MAX]; + UCHAR bulk_recv_key[RUDP_BULK_KEY_SIZE_MAX]; BUF *b; se = ZeroMalloc(sizeof(RUDP_SESSION)); @@ -3612,6 +3742,8 @@ RUDP_SESSION *RUDPNewSession(bool server_mode, IP *my_ip, UINT my_port, IP *your se->BulkRecvKey = NewSharedBuffer(bulk_recv_key, sizeof(bulk_recv_key)); Rand(se->BulkNextIv, sizeof(se->BulkNextIv)); + Rand(se->BulkNextIv_V2, sizeof(se->BulkNextIv_V2)); + se->BulkNextSeqNo = 1; return se; diff --git a/src/Mayaqua/Network.h b/src/Mayaqua/Network.h index fcf923b0..44351d5c 100644 --- a/src/Mayaqua/Network.h +++ b/src/Mayaqua/Network.h @@ -576,6 +576,12 @@ struct IPBLOCK #define RUDP_TIMEOUT 12000 // Time-out of R-UDP communication #define RUDP_DIRECT_CONNECT_TIMEOUT 5000 // R-UDP direct connection time-out #define RUDP_MAX_SEGMENT_SIZE 512 // Maximum segment size +#define RUDP_BULK_KEY_SIZE_MAX 128 // Bulk key size Max + +#define RUDP_BULK_KEY_SIZE_V2 32 // V2: Bulk key size +#define RUDP_BULK_IV_SIZE_V2 12 // V2: Bulk IV size +#define RUDP_BULK_MAC_SIZE_V2 16 // V2: Bulk MAC size + // Maximum R-UDP packet size #define RUDP_MAX_PACKET_SIZE (RUDP_MAX_SEGMENT_SIZE + sizeof(UINT64) * RUDP_MAX_NUM_ACK + SHA1_SIZE * 2 + sizeof(UINT64) * 4 + sizeof(UINT) + 255) #define RUDP_MAX_NUM_ACK 64 // Maximum number of ACKs @@ -664,6 +670,7 @@ struct RUDP_SESSION UINT64 BulkNextSeqNo; // Next SEQ NO to the bulk send bool FlushBulkSendTube; // Flag to be Flush the bulk send Tube UINT64 BulkRecvSeqNoMax; // Highest sequence number received + UCHAR BulkNextIv_V2[RUDP_BULK_IV_SIZE_V2]; // Next IV to the bulk send (version 2) }; // NAT Traversal Server Information