mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2026-01-27 02:34:18 +01:00
new TLS client hello generation
This commit is contained in:
parent
35c492de4f
commit
5adde27f88
|
|
@ -152,17 +152,7 @@ namespace WTelegram
|
|||
reply_to_msg_id: reply_to_msg_id == 0 ? null : reply_to_msg_id, schedule_date: schedule_date == default ? null : schedule_date);
|
||||
RaiseUpdate(updates);
|
||||
int msgId = -1;
|
||||
foreach (var update in updates.UpdateList)
|
||||
{
|
||||
switch (update)
|
||||
{
|
||||
case UpdateMessageID updMsgId when updMsgId.random_id == random_id: msgId = updMsgId.id; break;
|
||||
case UpdateNewMessage { message: Message message } when message.id == msgId: return message;
|
||||
case UpdateNewScheduledMessage { message: Message schedMsg } when schedMsg.id == msgId: return schedMsg;
|
||||
}
|
||||
}
|
||||
if (updates is UpdateShortSentMessage sent)
|
||||
{
|
||||
return new Message
|
||||
{
|
||||
flags = (Message.Flags)sent.flags | (reply_to_msg_id == 0 ? 0 : Message.Flags.has_reply_to) | (peer is InputPeerSelf ? 0 : Message.Flags.has_from_id),
|
||||
|
|
@ -171,6 +161,14 @@ namespace WTelegram
|
|||
from_id = peer is InputPeerSelf ? null : new PeerUser { user_id = _session.UserId },
|
||||
peer_id = InputToPeer(peer)
|
||||
};
|
||||
foreach (var update in updates.UpdateList)
|
||||
{
|
||||
switch (update)
|
||||
{
|
||||
case UpdateMessageID updMsgId when updMsgId.random_id == random_id: msgId = updMsgId.id; break;
|
||||
case UpdateNewMessage { message: Message message } when message.id == msgId: return message;
|
||||
case UpdateNewScheduledMessage { message: Message schedMsg } when schedMsg.id == msgId: return schedMsg;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
115
src/TlsStream.cs
115
src/TlsStream.cs
|
|
@ -85,39 +85,43 @@ namespace WTelegram
|
|||
throw new WTException("TLS Handshake failed");
|
||||
}
|
||||
|
||||
static readonly byte[] TlsClientHello1 = new byte[11] {
|
||||
static readonly byte[] TlsClientHello1 = new byte[11] { // https://tls13.xargs.org/#client-hello/annotated
|
||||
0x16, 0x03, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0xfc, 0x03, 0x03 };
|
||||
// digest[32]
|
||||
// 0x20
|
||||
// random[32]
|
||||
// 0x00, 0x20, grease(0) GREASE are two identical bytes ending with nibble 'A'
|
||||
// 0x00, 0x20
|
||||
// grease(0) GREASE are two identical bytes ending with nibble 'A'
|
||||
static readonly byte[] TlsClientHello2 = new byte[34] {
|
||||
0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xcc, 0xa9,
|
||||
0xcc, 0xa8, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, 0x01, 0x00, 0x01, 0x93 };
|
||||
// grease(2), 0x00, 0x00, 0x00, 0x00
|
||||
// len { len { 0x00 len { domain } } } len is 16-bit big-endian length of the following block of data
|
||||
static readonly byte[] TlsClientHello3 = new byte[101] {
|
||||
0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08,
|
||||
0x4A, 0x4A, // = grease(4)
|
||||
0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00,
|
||||
0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31,
|
||||
0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x12, 0x00,
|
||||
0x10, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08, 0x06, 0x06,
|
||||
0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x33, 0x00, 0x2b, 0x00, 0x29,
|
||||
0x4A, 0x4A, // = grease(4)
|
||||
0x00, 0x01, 0x00, 0x00, 0x1d, 0x00, 0x20 };
|
||||
// random[32] = public key
|
||||
static readonly byte[] TlsClientHello4 = new byte[35] {
|
||||
0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x2b, 0x00, 0x0b, 0x0a,
|
||||
0x6A, 0x6A, // = grease(6)
|
||||
0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x03, 0x01, 0x00, 0x1b, 0x00, 0x03, 0x02, 0x00, 0x02,
|
||||
0x3A, 0x3A, // = grease(3)
|
||||
0xcc, 0xa8, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35,
|
||||
0x01, 0x00, 0x01, 0x93 };
|
||||
// grease(2)
|
||||
// 0x00, 0x00
|
||||
static readonly byte[] TlsClientHello3 = new byte[134] {
|
||||
// 0x00, 0x00, len { len { 0x00 len { domain } } } len is 16-bit big-endian length of the following block of data
|
||||
0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x4A, 0x4A,/*=grease(4)*/ 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
|
||||
0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
|
||||
0x00, 0x0d, 0x00, 0x12, 0x00, 0x10, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01,
|
||||
0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31,
|
||||
0x00, 0x12, 0x00, 0x00,
|
||||
0x00, 0x17, 0x00, 0x00,
|
||||
0x00, 0x1b, 0x00, 0x03, 0x02, 0x00, 0x02,
|
||||
0x00, 0x23, 0x00, 0x00,
|
||||
0x00, 0x2b, 0x00, 0x07, 0x06, 0x6A, 0x6A,/*=grease(6) */ 0x03, 0x04, 0x03, 0x03,
|
||||
0x00, 0x2d, 0x00, 0x02, 0x01, 0x01,
|
||||
0x00, 0x33, 0x00, 0x2b, 0x00, 0x29, 0x4A, 0x4A,/*=grease(4) */ 0x00, 0x01, 0x00, 0x00, 0x1d, 0x00, 0x20, /* random[32] */
|
||||
0x44, 0x69, 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32,
|
||||
0xff, 0x01, 0x00, 0x01, 0x00,
|
||||
};
|
||||
// grease(3)
|
||||
static readonly byte[] TlsClientHello4 = new byte[5] {
|
||||
0x00, 0x01, 0x00, 0x00, 0x15 };
|
||||
// len { padding } padding with NUL bytes to reach 517 bytes
|
||||
|
||||
static byte[] TlsClientHello(byte[] key, byte[] domain)
|
||||
{
|
||||
int dlen = domain.Length;
|
||||
var greases = new byte[7];
|
||||
Encryption.RNG.GetBytes(greases);
|
||||
for (int i = 0; i < 7; i++) greases[i] = (byte)((greases[i] & 0xF0) + 0x0A);
|
||||
|
|
@ -130,19 +134,54 @@ namespace WTelegram
|
|||
buffer[78] = buffer[79] = greases[0];
|
||||
TlsClientHello2.CopyTo(buffer, 80);
|
||||
buffer[114] = buffer[115] = greases[2];
|
||||
buffer[121] = (byte)(dlen + 5);
|
||||
buffer[123] = (byte)(dlen + 3);
|
||||
buffer[126] = (byte)dlen;
|
||||
domain.CopyTo(buffer, 127);
|
||||
TlsClientHello3.CopyTo(buffer, 127 + dlen);
|
||||
buffer[142 + dlen] = buffer[143 + dlen] = greases[4];
|
||||
buffer[219 + dlen] = buffer[220 + dlen] = greases[4];
|
||||
Encryption.RNG.GetBytes(buffer, 228 + dlen, 32); // public key
|
||||
buffer[228 + dlen + 31] &= 0x7F; // must be positive
|
||||
TlsClientHello4.CopyTo(buffer, 260 + dlen);
|
||||
buffer[271 + dlen] = buffer[272 + dlen] = greases[6];
|
||||
buffer[288 + dlen] = buffer[289 + dlen] = greases[3];
|
||||
buffer[296 + dlen] = (byte)(220 - dlen);
|
||||
|
||||
int dlen = domain.Length;
|
||||
var server_name = new byte[dlen + 9];
|
||||
server_name[3] = (byte)(dlen + 5);
|
||||
server_name[5] = (byte)(dlen + 3);
|
||||
server_name[8] = (byte)dlen;
|
||||
domain.CopyTo(server_name, 9);
|
||||
|
||||
var key_share = new byte[47];
|
||||
Array.Copy(TlsClientHello3, 105, key_share, 0, 15);
|
||||
key_share[6] = key_share[7] = greases[4];
|
||||
Encryption.RNG.GetBytes(key_share, 15, 32); // public key
|
||||
key_share[46] &= 0x7F; // must be positive
|
||||
|
||||
var random = new Random();
|
||||
var permutations = new ArraySegment<byte>[15];
|
||||
for (var i = 0; i < permutations.Length; i++)
|
||||
{
|
||||
var j = random.Next(0, i + 1);
|
||||
if (i != j) permutations[i] = permutations[j];
|
||||
permutations[j] = i switch
|
||||
{
|
||||
0 => new(server_name),
|
||||
1 => new(TlsClientHello3, 0, 9),
|
||||
2 => PatchGrease(TlsClientHello3[9..23], 6, greases[4]),
|
||||
3 => new(TlsClientHello3, 23, 6),
|
||||
4 => new(TlsClientHello3, 29, 22),
|
||||
5 => new(TlsClientHello3, 51, 18),
|
||||
6 => new(TlsClientHello3, 69, 4),
|
||||
7 => new(TlsClientHello3, 73, 4),
|
||||
8 => new(TlsClientHello3, 77, 7),
|
||||
9 => new(TlsClientHello3, 84, 4),
|
||||
10 => PatchGrease(TlsClientHello3[88..99], 5, greases[6]),
|
||||
11 => new(TlsClientHello3, 99, 6),
|
||||
12 => new(key_share),
|
||||
13 => new(TlsClientHello3, 120, 9),
|
||||
_ => new(TlsClientHello3, 129, 5),
|
||||
};
|
||||
}
|
||||
int offset = 118;
|
||||
foreach (var perm in permutations)
|
||||
{
|
||||
Array.Copy(perm.Array, perm.Offset, buffer, offset, perm.Count);
|
||||
offset += perm.Count;
|
||||
}
|
||||
buffer[offset++] = buffer[offset++] = greases[3];
|
||||
TlsClientHello4.CopyTo(buffer, offset);
|
||||
buffer[offset + 6] = (byte)(510 - offset);
|
||||
|
||||
// patch-in digest with timestamp
|
||||
using var hmac = new HMACSHA256(key);
|
||||
|
|
@ -152,6 +191,12 @@ namespace WTelegram
|
|||
BinaryPrimitives.WriteInt32LittleEndian(digest.AsSpan(28), stamp);
|
||||
digest.CopyTo(buffer, 11);
|
||||
return buffer;
|
||||
|
||||
static ArraySegment<byte> PatchGrease(byte[] buffer, int offset, byte grease)
|
||||
{
|
||||
buffer[offset] = buffer[offset + 1] = grease;
|
||||
return new(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue