Encryption class public + TL Methods/Helpers

This commit is contained in:
Wizou 2025-10-31 00:14:48 +01:00
parent 48d005b605
commit 2e95576be5
3 changed files with 74 additions and 27 deletions

View file

@ -83,7 +83,7 @@ public class MTProtoGenerator : IIncrementalGenerator
ns = symbol.ContainingNamespace.ToString(); ns = symbol.ContainingNamespace.ToString();
name = symbol.Name; name = symbol.Name;
if (!namespaces.TryGetValue(ns, out var classes)) namespaces[ns] = classes = []; if (!namespaces.TryGetValue(ns, out var classes)) namespaces[ns] = classes = [];
if (name is "_Message" or "RpcResult" or "MsgCopy") if (name is "_Message" or "MsgCopy")
{ {
classes[name] = "\t\tpublic void WriteTL(BinaryWriter writer) => throw new NotSupportedException();"; classes[name] = "\t\tpublic void WriteTL(BinaryWriter writer) => throw new NotSupportedException();";
continue; continue;
@ -93,7 +93,7 @@ public class MTProtoGenerator : IIncrementalGenerator
else if (name != "Null") else if (name != "Null")
{ {
if (ns == "TL.Methods") if (ns == "TL.Methods")
methodsTL.AppendLine($"\t\t\t[0x{id:X8}] = {(ns == "TL" ? "" : ns + '.')}{name}{(symbol.IsGenericType ? "<IObject>" : "")}.ReadTL,"); methodsTL.AppendLine($"\t\t\t[0x{id:X8}] = {(ns == "TL" ? "" : ns + '.')}{name}{(symbol.IsGenericType ? "<object>" : "")}.ReadTL,");
if (ns != "TL.Methods" || name == "Ping") if (ns != "TL.Methods" || name == "Ping")
tableTL.AppendLine($"\t\t\t[0x{id:X8}] = {(ns == "TL" ? "" : ns + '.')}{name}.ReadTL,"); tableTL.AppendLine($"\t\t\t[0x{id:X8}] = {(ns == "TL" ? "" : ns + '.')}{name}.ReadTL,");
} }
@ -176,7 +176,7 @@ public class MTProtoGenerator : IIncrementalGenerator
writeTl.AppendLine($"writer.WriteTLMessages({member.Name});"); writeTl.AppendLine($"writer.WriteTLMessages({member.Name});");
break; break;
case "TL.IObject": case "TL.IMethod<X>": case "TL.IObject": case "TL.IMethod<X>":
readTL.AppendLine($"r.{member.Name} = {(memberType == "TL.IObject" ? "" : $"({memberType})")}reader.ReadTLObject();"); readTL.AppendLine($"r.{member.Name} = {(memberType == "TL.IObject" ? "reader.ReadTLObject()" : "reader.ReadTLMethod<X>()")};");
writeTl.AppendLine($"{member.Name}.WriteTL(writer);"); writeTl.AppendLine($"{member.Name}.WriteTL(writer);");
break; break;
case "System.Collections.Generic.Dictionary<long, TL.User>": case "System.Collections.Generic.Dictionary<long, TL.User>":
@ -187,14 +187,23 @@ public class MTProtoGenerator : IIncrementalGenerator
readTL.AppendLine($"r.{member.Name} = reader.ReadTLDictionary<ChatBase>();"); readTL.AppendLine($"r.{member.Name} = reader.ReadTLDictionary<ChatBase>();");
writeTl.AppendLine($"writer.WriteTLVector({member.Name}.Values.ToArray());"); writeTl.AppendLine($"writer.WriteTLVector({member.Name}.Values.ToArray());");
break; break;
case "object":
readTL.AppendLine($"r.{member.Name} = reader.ReadTLObject();");
writeTl.AppendLine($"writer.WriteTLValue({member.Name}, {member.Name}.GetType());");
break;
default: default:
if (member.Type is IArrayTypeSymbol arrayType) if (member.Type is IArrayTypeSymbol arrayType)
{ {
if (name is "FutureSalts") if (name is "FutureSalts")
{
readTL.AppendLine($"r.{member.Name} = reader.ReadTLRawVector<{memberType.Substring(0, memberType.Length - 2)}>(0x0949D9DC).ToArray();"); readTL.AppendLine($"r.{member.Name} = reader.ReadTLRawVector<{memberType.Substring(0, memberType.Length - 2)}>(0x0949D9DC).ToArray();");
writeTl.AppendLine($"writer.WriteTLRawVector({member.Name}, 16);");
}
else else
{
readTL.AppendLine($"r.{member.Name} = reader.ReadTLVector<{memberType.Substring(0, memberType.Length - 2)}>();"); readTL.AppendLine($"r.{member.Name} = reader.ReadTLVector<{memberType.Substring(0, memberType.Length - 2)}>();");
writeTl.AppendLine($"writer.WriteTLVector({member.Name});"); writeTl.AppendLine($"writer.WriteTLVector({member.Name});");
}
} }
else if (member.Type.BaseType.SpecialType == SpecialType.System_Enum) else if (member.Type.BaseType.SpecialType == SpecialType.System_Enum)
{ {

View file

@ -94,7 +94,7 @@ namespace WTelegram
if (serverDHparams is not ServerDHParamsOk serverDHparamsOk) throw new WTException("not server_DH_params_ok"); if (serverDHparams is not ServerDHParamsOk serverDHparamsOk) throw new WTException("not server_DH_params_ok");
if (serverDHparamsOk.nonce != nonce) throw new WTException("Nonce mismatch"); if (serverDHparamsOk.nonce != nonce) throw new WTException("Nonce mismatch");
if (serverDHparamsOk.server_nonce != resPQ.server_nonce) throw new WTException("Server Nonce mismatch"); if (serverDHparamsOk.server_nonce != resPQ.server_nonce) throw new WTException("Server Nonce mismatch");
var (tmp_aes_key, tmp_aes_iv) = ConstructTmpAESKeyIV(resPQ.server_nonce, pqInnerData.new_nonce); var (tmp_aes_key, tmp_aes_iv) = ConstructTmpAESKeyIV(sha1, resPQ.server_nonce, pqInnerData.new_nonce);
var answer = AES_IGE_EncryptDecrypt(serverDHparamsOk.encrypted_answer, tmp_aes_key, tmp_aes_iv, false); var answer = AES_IGE_EncryptDecrypt(serverDHparamsOk.encrypted_answer, tmp_aes_key, tmp_aes_iv, false);
using var answerReader = new BinaryReader(new MemoryStream(answer)); using var answerReader = new BinaryReader(new MemoryStream(answer));
@ -163,26 +163,26 @@ namespace WTelegram
session.AuthKey = authKey; session.AuthKey = authKey;
session.Salt = BinaryPrimitives.ReadInt64LittleEndian(pqInnerData.new_nonce.raw) ^ BinaryPrimitives.ReadInt64LittleEndian(resPQ.server_nonce.raw); session.Salt = BinaryPrimitives.ReadInt64LittleEndian(pqInnerData.new_nonce.raw) ^ BinaryPrimitives.ReadInt64LittleEndian(resPQ.server_nonce.raw);
session.OldSalt = session.Salt; session.OldSalt = session.Salt;
}
(byte[] key, byte[] iv) ConstructTmpAESKeyIV(TL.Int128 server_nonce, Int256 new_nonce) public static (byte[] key, byte[] iv) ConstructTmpAESKeyIV(SHA1 sha1, TL.Int128 server_nonce, Int256 new_nonce)
{ {
byte[] tmp_aes_key = new byte[32], tmp_aes_iv = new byte[32]; byte[] tmp_aes_key = new byte[32], tmp_aes_iv = new byte[32];
sha1.TransformBlock(new_nonce, 0, 32, null, 0); sha1.TransformBlock(new_nonce, 0, 32, null, 0);
sha1.TransformFinalBlock(server_nonce, 0, 16); sha1.TransformFinalBlock(server_nonce, 0, 16);
sha1.Hash.CopyTo(tmp_aes_key, 0); // tmp_aes_key := SHA1(new_nonce + server_nonce) sha1.Hash.CopyTo(tmp_aes_key, 0); // tmp_aes_key := SHA1(new_nonce + server_nonce)
sha1.Initialize(); sha1.Initialize();
sha1.TransformBlock(server_nonce, 0, 16, null, 0); sha1.TransformBlock(server_nonce, 0, 16, null, 0);
sha1.TransformFinalBlock(new_nonce, 0, 32); sha1.TransformFinalBlock(new_nonce, 0, 32);
Array.Copy(sha1.Hash, 0, tmp_aes_key, 20, 12); // + SHA1(server_nonce, new_nonce)[0:12] Array.Copy(sha1.Hash, 0, tmp_aes_key, 20, 12); // + SHA1(server_nonce, new_nonce)[0:12]
Array.Copy(sha1.Hash, 12, tmp_aes_iv, 0, 8); // tmp_aes_iv != SHA1(server_nonce, new_nonce)[12:8] Array.Copy(sha1.Hash, 12, tmp_aes_iv, 0, 8); // tmp_aes_iv != SHA1(server_nonce, new_nonce)[12:8]
sha1.Initialize(); sha1.Initialize();
sha1.TransformBlock(new_nonce, 0, 32, null, 0); sha1.TransformBlock(new_nonce, 0, 32, null, 0);
sha1.TransformFinalBlock(new_nonce, 0, 32); sha1.TransformFinalBlock(new_nonce, 0, 32);
sha1.Hash.CopyTo(tmp_aes_iv, 8); // + SHA(new_nonce + new_nonce) sha1.Hash.CopyTo(tmp_aes_iv, 8); // + SHA(new_nonce + new_nonce)
Array.Copy(new_nonce, 0, tmp_aes_iv, 28, 4); // + new_nonce[0:4] Array.Copy(new_nonce, 0, tmp_aes_iv, 28, 4); // + new_nonce[0:4]
sha1.Initialize(); sha1.Initialize();
return (tmp_aes_key, tmp_aes_iv); return (tmp_aes_key, tmp_aes_iv);
}
} }
internal static void CheckGoodPrime(BigInteger p, int g) internal static void CheckGoodPrime(BigInteger p, int g)
@ -278,7 +278,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
-----END RSA PUBLIC KEY-----"); -----END RSA PUBLIC KEY-----");
} }
internal static byte[] EncryptDecryptMessage(Span<byte> input, bool encrypt, int x, byte[] authKey, byte[] msgKey, int msgKeyOffset, SHA256 sha256) public static byte[] EncryptDecryptMessage(Span<byte> input, bool encrypt, int x, byte[] authKey, byte[] msgKey, int msgKeyOffset, SHA256 sha256)
{ {
// first, construct AES key & IV // first, construct AES key & IV
byte[] aes_key = new byte[32], aes_iv = new byte[32]; byte[] aes_key = new byte[32], aes_iv = new byte[32];
@ -299,7 +299,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
return AES_IGE_EncryptDecrypt(input, aes_key, aes_iv, encrypt); return AES_IGE_EncryptDecrypt(input, aes_key, aes_iv, encrypt);
} }
internal static byte[] AES_IGE_EncryptDecrypt(Span<byte> input, byte[] aes_key, byte[] aes_iv, bool encrypt) public static byte[] AES_IGE_EncryptDecrypt(Span<byte> input, byte[] aes_key, byte[] aes_iv, bool encrypt)
{ {
if (input.Length % 16 != 0) throw new WTException("AES_IGE input size not divisible by 16"); if (input.Length % 16 != 0) throw new WTException("AES_IGE input size not divisible by 16");

View file

@ -16,7 +16,7 @@ namespace TL
#else #else
public interface IObject { } public interface IObject { }
#endif #endif
public interface IMethod<ReturnType> : IObject { } public interface IMethod<out ReturnType> : IObject { }
public interface IPeerResolver { IPeerInfo UserOrChat(Peer peer); } public interface IPeerResolver { IPeerInfo UserOrChat(Peer peer); }
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Class)]
@ -105,6 +105,17 @@ namespace TL
#endif #endif
} }
public static IMethod<X> ReadTLMethod<X>(this BinaryReader reader)
{
uint ctorNb = reader.ReadUInt32();
if (!Layer.Methods.TryGetValue(ctorNb, out var ctor))
throw new WTelegram.WTException($"Cannot find method for ctor #{ctorNb:x}");
var method = ctor?.Invoke(reader);
if (method is IMethod<bool> && typeof(X) == typeof(object))
method = new BoolMethod { query = method };
return (IMethod<X>)method;
}
internal static void WriteTLValue(this BinaryWriter writer, object value, Type valueType) internal static void WriteTLValue(this BinaryWriter writer, object value, Type valueType)
{ {
if (value == null) if (value == null)
@ -222,6 +233,21 @@ namespace TL
writer.WriteTLValue(array.GetValue(i), elementType); writer.WriteTLValue(array.GetValue(i), elementType);
} }
internal static void WriteTLRawVector(this BinaryWriter writer, Array array, int elementSize)
{
var startPos = writer.BaseStream.Position;
int count = array.Length;
var elementType = array.GetType().GetElementType();
for (int i = count - 1; i >= 0; i--)
{
writer.BaseStream.Position = startPos + i * elementSize;
writer.WriteTLValue(array.GetValue(i), elementType);
}
writer.BaseStream.Position = startPos;
writer.Write(count);
writer.BaseStream.Position = startPos + count * elementSize + 4;
}
internal static List<T> ReadTLRawVector<T>(this BinaryReader reader, uint ctorNb) internal static List<T> ReadTLRawVector<T>(this BinaryReader reader, uint ctorNb)
{ {
int count = reader.ReadInt32(); int count = reader.ReadInt32();
@ -443,4 +469,16 @@ namespace TL
[TLDef(0x3072CFA1)] //gzip_packed#3072cfa1 packed_data:bytes = Object [TLDef(0x3072CFA1)] //gzip_packed#3072cfa1 packed_data:bytes = Object
public sealed partial class GzipPacked : IObject { public byte[] packed_data; } public sealed partial class GzipPacked : IObject { public byte[] packed_data; }
public sealed class Null<X> : IObject
{
public readonly static Null<X> Instance = new();
public void WriteTL(BinaryWriter writer) => writer.WriteTLNull(typeof(X));
}
public sealed class BoolMethod : IMethod<object>
{
public IObject query;
public void WriteTL(BinaryWriter writer) => query.WriteTL(writer);
}
} }