mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2025-12-06 06:52:01 +01:00
various optimizations
This commit is contained in:
parent
3784ad00ad
commit
a45cd0f44e
|
|
@ -396,7 +396,7 @@ namespace WTelegram
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
byte[] decrypted_data = EncryptDecryptMessage(data.AsSpan(24, (dataLen - 24) & ~0xF), false, _dcSession.AuthKey, data, 8, _sha256Recv);
|
byte[] decrypted_data = EncryptDecryptMessage(data.AsSpan(24, (dataLen - 24) & ~0xF), false, 8, _dcSession.AuthKey, data, 8, _sha256Recv);
|
||||||
if (decrypted_data.Length < 36) // header below+ctorNb
|
if (decrypted_data.Length < 36) // header below+ctorNb
|
||||||
throw new ApplicationException($"Decrypted packet too small: {decrypted_data.Length}");
|
throw new ApplicationException($"Decrypted packet too small: {decrypted_data.Length}");
|
||||||
_sha256Recv.TransformBlock(_dcSession.AuthKey, 96, 32, null, 0);
|
_sha256Recv.TransformBlock(_dcSession.AuthKey, 96, 32, null, 0);
|
||||||
|
|
@ -1217,7 +1217,7 @@ namespace WTelegram
|
||||||
RNG.GetBytes(clearBuffer, 32 + clearLength, padding);
|
RNG.GetBytes(clearBuffer, 32 + clearLength, padding);
|
||||||
var msgKeyLarge = _sha256.ComputeHash(clearBuffer, 0, 32 + clearLength + padding);
|
var msgKeyLarge = _sha256.ComputeHash(clearBuffer, 0, 32 + clearLength + padding);
|
||||||
const int msgKeyOffset = 8; // msg_key = middle 128-bits of SHA256(authkey_part+plaintext+padding)
|
const int msgKeyOffset = 8; // msg_key = middle 128-bits of SHA256(authkey_part+plaintext+padding)
|
||||||
byte[] encrypted_data = EncryptDecryptMessage(clearBuffer.AsSpan(32, clearLength + padding), true, _dcSession.AuthKey, msgKeyLarge, msgKeyOffset, _sha256);
|
byte[] encrypted_data = EncryptDecryptMessage(clearBuffer.AsSpan(32, clearLength + padding), true, 0, _dcSession.AuthKey, msgKeyLarge, msgKeyOffset, _sha256);
|
||||||
|
|
||||||
writer.Write(_dcSession.AuthKeyID); // int64 auth_key_id
|
writer.Write(_dcSession.AuthKeyID); // int64 auth_key_id
|
||||||
writer.Write(msgKeyLarge, msgKeyOffset, 16); // int128 msg_key
|
writer.Write(msgKeyLarge, msgKeyOffset, 16); // int128 msg_key
|
||||||
|
|
@ -1302,6 +1302,7 @@ namespace WTelegram
|
||||||
{
|
{
|
||||||
if (x <= FloodRetryThreshold)
|
if (x <= FloodRetryThreshold)
|
||||||
{
|
{
|
||||||
|
if (x == 0) x =1;
|
||||||
await Task.Delay(x * 1000);
|
await Task.Delay(x * 1000);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ namespace WTelegram
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ValidityChecks(BigInteger p, int g)
|
internal static void ValidityChecks(BigInteger p, int g)
|
||||||
{
|
{
|
||||||
Helpers.Log(2, "Verifying encryption key safety... (this should happen only once per DC)");
|
Helpers.Log(2, "Verifying encryption key safety... (this should happen only once per DC)");
|
||||||
// check that 2^2047 <= p < 2^2048
|
// check that 2^2047 <= p < 2^2048
|
||||||
|
|
@ -201,11 +201,33 @@ namespace WTelegram
|
||||||
})
|
})
|
||||||
throw new ApplicationException("Bad prime mod 4g");
|
throw new ApplicationException("Bad prime mod 4g");
|
||||||
// check whether p is a safe prime (meaning that both p and (p - 1) / 2 are prime)
|
// check whether p is a safe prime (meaning that both p and (p - 1) / 2 are prime)
|
||||||
|
if (SafePrimes.Contains(p)) return;
|
||||||
if (!p.IsProbablePrime()) throw new ApplicationException("p is not a prime number");
|
if (!p.IsProbablePrime()) throw new ApplicationException("p is not a prime number");
|
||||||
if (!((p - 1) / 2).IsProbablePrime()) throw new ApplicationException("(p - 1) / 2 is not a prime number");
|
if (!((p - 1) / 2).IsProbablePrime()) throw new ApplicationException("(p - 1) / 2 is not a prime number");
|
||||||
|
SafePrimes.Add(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ValidityChecksDH(BigInteger g_a, BigInteger g_b, BigInteger dh_prime)
|
private static readonly HashSet<BigInteger> SafePrimes = new() { new(new byte[] // C71CAEB9C6B1C904...
|
||||||
|
{
|
||||||
|
0x5B, 0xCC, 0x2F, 0xB9, 0xE3, 0xD8, 0x9C, 0x11, 0x03, 0x04, 0xB1, 0x34, 0xF0, 0xAD, 0x4F, 0x6F,
|
||||||
|
0xBF, 0x54, 0x24, 0x4B, 0xD0, 0x15, 0x4E, 0x2E, 0xEE, 0x05, 0xB1, 0x35, 0xF6, 0x15, 0x81, 0x0D,
|
||||||
|
0x1F, 0x85, 0x29, 0xE9, 0x0C, 0x85, 0x56, 0xD9, 0x59, 0xF9, 0x7B, 0xF4, 0x49, 0x28, 0xED, 0x0D,
|
||||||
|
0x05, 0x70, 0xED, 0x5E, 0xFF, 0xA9, 0x7F, 0xF8, 0xA0, 0xBE, 0x3E, 0xE8, 0x15, 0xFC, 0x18, 0xE4,
|
||||||
|
0xE4, 0x9A, 0x5B, 0xEF, 0x8F, 0x92, 0xA3, 0x9C, 0xFF, 0xD6, 0xB0, 0x65, 0xC4, 0x6B, 0x9C, 0x16,
|
||||||
|
0x8D, 0x17, 0xB1, 0x2D, 0x58, 0x46, 0xDD, 0xB9, 0xB4, 0x65, 0x59, 0x0D, 0x95, 0xED, 0x17, 0xFD,
|
||||||
|
0x54, 0x47, 0x28, 0xF1, 0x0E, 0x4E, 0x14, 0xB3, 0x14, 0x2A, 0x4B, 0xA8, 0xD8, 0x74, 0xBA, 0x0D,
|
||||||
|
0x41, 0x6B, 0x0F, 0x6B, 0xB5, 0x53, 0x27, 0x16, 0x7E, 0x90, 0x51, 0x10, 0x81, 0x95, 0xA6, 0xA4,
|
||||||
|
0xA4, 0xF9, 0x7C, 0xE6, 0xBE, 0x60, 0x90, 0x3A, 0x4F, 0x3C, 0x8E, 0x37, 0x9B, 0xFA, 0x08, 0x07,
|
||||||
|
0x88, 0x49, 0xCC, 0xC8, 0x4A, 0x1D, 0xCD, 0x5B, 0x1D, 0x94, 0x2A, 0xBB, 0x96, 0xFE, 0x77, 0x24,
|
||||||
|
0x64, 0x5F, 0x59, 0x8C, 0xAF, 0x8F, 0xF1, 0x54, 0x84, 0x32, 0x69, 0x29, 0x51, 0x46, 0x97, 0xDC,
|
||||||
|
0xAB, 0x13, 0x6B, 0x6B, 0xFE, 0xD4, 0x8C, 0xC6, 0x5A, 0x70, 0x58, 0x94, 0xF6, 0x51, 0xFD, 0x20,
|
||||||
|
0x37, 0x7C, 0xCE, 0x4C, 0xD4, 0xAE, 0x43, 0x95, 0x13, 0x25, 0xC9, 0x0A, 0x6E, 0x6F, 0x33, 0xFA,
|
||||||
|
0xDB, 0xF4, 0x30, 0x25, 0xD2, 0x93, 0x94, 0x22, 0x58, 0x40, 0xC1, 0xA7, 0x0A, 0x8A, 0x19, 0x48,
|
||||||
|
0x0F, 0x93, 0x3D, 0x56, 0x37, 0xD0, 0x34, 0x49, 0xC1, 0x21, 0x3E, 0x8E, 0x23, 0x40, 0x0D, 0x98,
|
||||||
|
0x73, 0x3F, 0xF1, 0x70, 0x2F, 0x52, 0x6C, 0x8E, 0x04, 0xC9, 0xB1, 0xC6, 0xB9, 0xAE, 0x1C, 0xC7, 0x00
|
||||||
|
})};
|
||||||
|
|
||||||
|
internal static void ValidityChecksDH(BigInteger g_a, BigInteger g_b, BigInteger dh_prime)
|
||||||
{
|
{
|
||||||
// check that g, g_a and g_b are greater than 1 and less than dh_prime - 1.
|
// check that g, g_a and g_b are greater than 1 and less than dh_prime - 1.
|
||||||
// We recommend checking that g_a and g_b are between 2^{2048-64} and dh_prime - 2^{2048-64} as well.
|
// We recommend checking that g_a and g_b are between 2^{2048-64} and dh_prime - 2^{2048-64} as well.
|
||||||
|
|
@ -254,11 +276,10 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
||||||
-----END RSA PUBLIC KEY-----");
|
-----END RSA PUBLIC KEY-----");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static byte[] EncryptDecryptMessage(Span<byte> input, bool encrypt, byte[] authKey, byte[] msgKey, int msgKeyOffset, SHA256 sha256)
|
internal 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];
|
||||||
int x = encrypt ? 0 : 8;
|
|
||||||
sha256.TransformBlock(msgKey, msgKeyOffset, 16, null, 0); // msgKey
|
sha256.TransformBlock(msgKey, msgKeyOffset, 16, null, 0); // msgKey
|
||||||
sha256.TransformFinalBlock(authKey, x, 36); // authKey[x:36]
|
sha256.TransformFinalBlock(authKey, x, 36); // authKey[x:36]
|
||||||
var sha256_a = sha256.Hash;
|
var sha256_a = sha256.Hash;
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ namespace WTelegram
|
||||||
public static readonly JsonSerializerOptions JsonOptions = new() { IncludeFields = true, WriteIndented = true,
|
public static readonly JsonSerializerOptions JsonOptions = new() { IncludeFields = true, WriteIndented = true,
|
||||||
IgnoreReadOnlyProperties = true, DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull };
|
IgnoreReadOnlyProperties = true, DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull };
|
||||||
|
|
||||||
private static readonly ConsoleColor[] LogLevelToColor = new[] { ConsoleColor.DarkGray, ConsoleColor.DarkCyan, ConsoleColor.Cyan,
|
private static readonly ConsoleColor[] LogLevelToColor = new[] { ConsoleColor.DarkGray, ConsoleColor.DarkCyan,
|
||||||
ConsoleColor.Yellow, ConsoleColor.Red, ConsoleColor.Magenta, ConsoleColor.DarkBlue };
|
ConsoleColor.Cyan, ConsoleColor.Yellow, ConsoleColor.Red, ConsoleColor.Magenta, ConsoleColor.DarkBlue };
|
||||||
private static void DefaultLogger(int level, string message)
|
private static void DefaultLogger(int level, string message)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = LogLevelToColor[level];
|
Console.ForegroundColor = LogLevelToColor[level];
|
||||||
|
|
@ -34,9 +34,10 @@ namespace WTelegram
|
||||||
public static long RandomLong()
|
public static long RandomLong()
|
||||||
{
|
{
|
||||||
#if NETCOREAPP2_1_OR_GREATER
|
#if NETCOREAPP2_1_OR_GREATER
|
||||||
Span<long> span = stackalloc long[1];
|
long value = 0;
|
||||||
System.Security.Cryptography.RandomNumberGenerator.Fill(System.Runtime.InteropServices.MemoryMarshal.AsBytes(span));
|
System.Security.Cryptography.RandomNumberGenerator.Fill(System.Runtime.InteropServices.MemoryMarshal.AsBytes(
|
||||||
return span[0];
|
System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref value, 1)));
|
||||||
|
return value;
|
||||||
#else
|
#else
|
||||||
var span = new byte[8];
|
var span = new byte[8];
|
||||||
Encryption.RNG.GetBytes(span);
|
Encryption.RNG.GetBytes(span);
|
||||||
|
|
@ -168,14 +169,12 @@ namespace WTelegram
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int MillerRabinIterations { get; set; } = 64; // 64 is OpenSSL default for 2048-bits numbers
|
public static int MillerRabinIterations { get; set; } = 64; // 64 is OpenSSL default for 2048-bits numbers
|
||||||
private static readonly HashSet<BigInteger> GoodPrimes = new();
|
|
||||||
/// <summary>Miller–Rabin primality test</summary>
|
/// <summary>Miller–Rabin primality test</summary>
|
||||||
/// <param name="n">The number to check for primality</param>
|
/// <param name="n">The number to check for primality</param>
|
||||||
public static bool IsProbablePrime(this BigInteger n)
|
public static bool IsProbablePrime(this BigInteger n)
|
||||||
{
|
{
|
||||||
var n_minus_one = n - BigInteger.One;
|
var n_minus_one = n - BigInteger.One;
|
||||||
if (n_minus_one.Sign <= 0) return false;
|
if (n_minus_one.Sign <= 0) return false;
|
||||||
if (GoodPrimes.Contains(n)) return true;
|
|
||||||
|
|
||||||
int s;
|
int s;
|
||||||
var d = n_minus_one;
|
var d = n_minus_one;
|
||||||
|
|
@ -210,7 +209,6 @@ namespace WTelegram
|
||||||
}
|
}
|
||||||
if (r == 0) return false;
|
if (r == 0) return false;
|
||||||
}
|
}
|
||||||
GoodPrimes.Add(n);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ namespace TL
|
||||||
internal class BinaryReader : System.IO.BinaryReader
|
internal class BinaryReader : System.IO.BinaryReader
|
||||||
{
|
{
|
||||||
public readonly WTelegram.Client Client;
|
public readonly WTelegram.Client Client;
|
||||||
public BinaryReader(Stream stream, WTelegram.Client client) : base(stream) => Client = client;
|
public BinaryReader(Stream stream, WTelegram.Client client, bool leaveOpen = false) : base(stream, Encoding.UTF8, leaveOpen) => Client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class Serialization
|
internal static class Serialization
|
||||||
|
|
@ -57,7 +57,7 @@ namespace TL
|
||||||
var tlDef = type.GetCustomAttribute<TLDefAttribute>();
|
var tlDef = type.GetCustomAttribute<TLDefAttribute>();
|
||||||
var ctorNb = tlDef.CtorNb;
|
var ctorNb = tlDef.CtorNb;
|
||||||
writer.Write(ctorNb);
|
writer.Write(ctorNb);
|
||||||
IEnumerable<FieldInfo> fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
IEnumerable<FieldInfo> fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
|
||||||
if (tlDef.inheritBefore) fields = fields.GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g);
|
if (tlDef.inheritBefore) fields = fields.GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g);
|
||||||
uint flags = 0;
|
uint flags = 0;
|
||||||
IfFlagAttribute ifFlag;
|
IfFlagAttribute ifFlag;
|
||||||
|
|
@ -81,7 +81,7 @@ namespace TL
|
||||||
if (type == null) return null; // nullable ctor (class meaning is associated with null)
|
if (type == null) return null; // nullable ctor (class meaning is associated with null)
|
||||||
var tlDef = type.GetCustomAttribute<TLDefAttribute>();
|
var tlDef = type.GetCustomAttribute<TLDefAttribute>();
|
||||||
var obj = Activator.CreateInstance(type, true);
|
var obj = Activator.CreateInstance(type, true);
|
||||||
IEnumerable<FieldInfo> fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
IEnumerable<FieldInfo> fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
|
||||||
if (tlDef.inheritBefore) fields = fields.GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g);
|
if (tlDef.inheritBefore) fields = fields.GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g);
|
||||||
uint flags = 0;
|
uint flags = 0;
|
||||||
IfFlagAttribute ifFlag;
|
IfFlagAttribute ifFlag;
|
||||||
|
|
@ -91,7 +91,7 @@ namespace TL
|
||||||
object value = reader.ReadTLValue(field.FieldType);
|
object value = reader.ReadTLValue(field.FieldType);
|
||||||
field.SetValue(obj, value);
|
field.SetValue(obj, value);
|
||||||
if (field.FieldType.IsEnum && field.Name == "flags") flags = (uint)value;
|
if (field.FieldType.IsEnum && field.Name == "flags") flags = (uint)value;
|
||||||
if (reader.Client.CollectAccessHash) reader.Client.CollectField(field, obj, value);
|
if (reader.Client?.CollectAccessHash == true) reader.Client.CollectField(field, obj, value);
|
||||||
}
|
}
|
||||||
return (IObject)obj;
|
return (IObject)obj;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue