diff --git a/generator/MTProtoGenerator.cs b/generator/MTProtoGenerator.cs index 4fd169d..26011b6 100644 --- a/generator/MTProtoGenerator.cs +++ b/generator/MTProtoGenerator.cs @@ -32,6 +32,7 @@ public class MTProtoGenerator : IIncrementalGenerator var nullables = LoadNullables(layer); var namespaces = new Dictionary>(); // namespace,class,methods var tableTL = new StringBuilder(); + var methodsTL = new StringBuilder(); var source = new StringBuilder(); source .AppendLine("using System;") @@ -46,6 +47,9 @@ public class MTProtoGenerator : IIncrementalGenerator tableTL .AppendLine("\t\tpublic static readonly Dictionary> Table = new()") .AppendLine("\t\t{"); + methodsTL + .AppendLine("\t\tpublic static readonly Dictionary> Methods = new()") + .AppendLine("\t\t{"); foreach (var classDecl in unit.classes) { @@ -86,8 +90,13 @@ public class MTProtoGenerator : IIncrementalGenerator } if (id == 0x3072CFA1) // GzipPacked tableTL.AppendLine($"\t\t\t[0x{id:X8}] = reader => (IObject)reader.ReadTLGzipped(typeof(IObject)),"); - else if (name != "Null" && (ns != "TL.Methods" || name == "Ping")) - tableTL.AppendLine($"\t\t\t[0x{id:X8}] = {(ns == "TL" ? "" : ns + '.')}{name}.ReadTL,"); + else if (name != "Null") + { + if (ns == "TL.Methods") + methodsTL.AppendLine($"\t\t\t[0x{id:X8}] = {(ns == "TL" ? "" : ns + '.')}{name}{(symbol.IsGenericType ? "" : "")}.ReadTL,"); + if (ns != "TL.Methods" || name == "Ping") + tableTL.AppendLine($"\t\t\t[0x{id:X8}] = {(ns == "TL" ? "" : ns + '.')}{name}.ReadTL,"); + } var override_ = symbol.BaseType == object_ ? "" : "override "; if (name == "Messages_AffectedMessages") override_ = "virtual "; //if (symbol.Constructors[0].IsImplicitlyDeclared) @@ -213,7 +222,8 @@ public class MTProtoGenerator : IIncrementalGenerator foreach (var nullable in nullables) tableTL.AppendLine($"\t\t\t[0x{nullable.Value:X8}] = null,"); tableTL.AppendLine("\t\t};"); - namespaces["TL"]["Layer"] = tableTL.ToString(); + methodsTL.AppendLine("\t\t};"); + namespaces["TL"]["Layer"] = tableTL.ToString() + methodsTL.ToString(); foreach (var namesp in namespaces) { source.Append("namespace ").AppendLine(namesp.Key).Append('{'); diff --git a/src/Client.cs b/src/Client.cs index 08b6207..be24bf3 100644 --- a/src/Client.cs +++ b/src/Client.cs @@ -185,10 +185,6 @@ namespace WTelegram return Console.ReadLine(); } - /// Load a specific Telegram server public key - /// A string starting with -----BEGIN RSA PUBLIC KEY----- - public static void LoadPublicKey(string pem) => Encryption.LoadPublicKey(pem); - /// Builds a structure that is used to validate a 2FA password /// Password validation configuration. You can obtain this via Account_GetPassword or through OnOther as part of the login process /// The password to validate @@ -358,7 +354,7 @@ namespace WTelegram if (await stream.FullReadAsync(data, 4, ct) != 4) throw new WTException(ConnectionShutDown); #if OBFUSCATION - _recvCtr.EncryptDecrypt(data, 4); + _recvCtr.EncryptDecrypt(data.AsSpan(0, 4)); #endif int payloadLen = BinaryPrimitives.ReadInt32LittleEndian(data); if (payloadLen <= 0) @@ -370,7 +366,7 @@ namespace WTelegram if (await stream.FullReadAsync(data, payloadLen, ct) != payloadLen) throw new WTException("Could not read frame data : Connection shut down"); #if OBFUSCATION - _recvCtr.EncryptDecrypt(data, payloadLen); + _recvCtr.EncryptDecrypt(data.AsSpan(0, payloadLen)); #endif obj = ReadFrame(data, payloadLen); } @@ -1526,7 +1522,7 @@ namespace WTelegram int frameLength = (int)memStream.Length; BinaryPrimitives.WriteInt32LittleEndian(buffer, frameLength - 4); // patch payload_len with correct value #if OBFUSCATION - _sendCtr?.EncryptDecrypt(buffer, frameLength); + _sendCtr?.EncryptDecrypt(buffer.AsSpan(0, frameLength)); #endif if (_networkStream != null) await _networkStream.WriteAsync(buffer, 0, frameLength); diff --git a/src/Encryption.cs b/src/Encryption.cs index 957c537..09f6caa 100644 --- a/src/Encryption.cs +++ b/src/Encryption.cs @@ -13,7 +13,7 @@ using static WTelegram.Compat; namespace WTelegram { - internal static class Encryption + public static class Encryption { private static readonly Dictionary PublicKeys = []; internal static readonly RandomNumberGenerator RNG = RandomNumberGenerator.Create(); @@ -237,6 +237,8 @@ namespace WTelegram throw new WTException("g^a or g^b is not between 2^{2048-64} and dh_prime - 2^{2048-64}"); } + /// Load a specific Telegram server public key + /// A string starting with -----BEGIN RSA PUBLIC KEY----- public static void LoadPublicKey(string pem) { using var rsa = RSA.Create(); @@ -319,7 +321,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB } #if OBFUSCATION - internal sealed class AesCtr(byte[] key, byte[] ivec) : IDisposable + public sealed class AesCtr(byte[] key, byte[] ivec) : IDisposable { readonly ICryptoTransform _encryptor = AesECB.CreateEncryptor(key, null); readonly byte[] _ecount = new byte[16]; @@ -327,9 +329,9 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB public void Dispose() => _encryptor.Dispose(); - public void EncryptDecrypt(byte[] buffer, int length) + public void EncryptDecrypt(Span buffer) { - for (int i = 0; i < length; i++) + for (int i = 0; i < buffer.Length; i++) { if (_num == 0) { @@ -373,7 +375,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB var sendCtr = new AesCtr(sendKey, sendIV); var recvCtr = new AesCtr(recvKey, recvIV); var encrypted = (byte[])preamble.Clone(); - sendCtr.EncryptDecrypt(encrypted, 64); + sendCtr.EncryptDecrypt(encrypted); for (int i = 56; i < 64; i++) preamble[i] = encrypted[i]; return (sendCtr, recvCtr, preamble);