mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2025-12-06 06:52:01 +01:00
Remove OLDKEY/MTPROTO1 code
This commit is contained in:
parent
2982e09c9b
commit
3fe9002f2e
|
|
@ -14,6 +14,8 @@ and add at least these variables with adequate value: **api_id, api_hash, phone_
|
|||
Remember that these are just simple example codes that you should adjust to your needs.
|
||||
In real production code, you might want to properly test the success of each operation or handle exceptions.
|
||||
|
||||
More examples can also be found in answers to [StackOverflow questions](https://stackoverflow.com/questions/tagged/wtelegramclient).
|
||||
|
||||
<a name="msg-by-name"></a>
|
||||
### Send a message to someone by @username
|
||||
```csharp
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ static async Task Main(string[] _)
|
|||
}
|
||||
```
|
||||
When run, this will prompt you interactively for your App **api_hash** and **api_id** (that you obtain through Telegram's [API development tools](https://my.telegram.org/apps) page) and try to connect to Telegram servers.
|
||||
Those api hash/id represent your application and one can be used for handling many user accounts.
|
||||
|
||||
Then it will attempt to sign-in *(login)* as a user for which you must enter the **phone_number** and the **verification_code** that will be sent to this user (for example through SMS or another Telegram client app the user is connected to).
|
||||
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ namespace WTelegram
|
|||
/// <summary>This event will be called when an unsollicited update/message is sent by Telegram servers</summary>
|
||||
/// <remarks>See <see href="https://github.com/wiz0u/WTelegramClient/tree/master/Examples/Program_ListenUpdate.cs">Examples/Program_ListenUpdate.cs</see> for how to use this</remarks>
|
||||
public event Action<IObject> Update;
|
||||
public delegate Task<TcpClient> TcpFactory(string host, int port);
|
||||
/// <summary>Used to create a TcpClient connected to the given address/port, or throw an exception on failure</summary>
|
||||
public TcpFactory TcpHandler { get; set; } = DefaultTcpHandler;
|
||||
public delegate Task<TcpClient> TcpFactory(string host, int port);
|
||||
/// <summary>Url for using a MTProxy. https://t.me/proxy?server=... </summary>
|
||||
public string MTProxyUrl { get; set; }
|
||||
/// <summary>Telegram configuration, obtained at connection time</summary>
|
||||
|
|
@ -71,13 +71,8 @@ namespace WTelegram
|
|||
private const int FilePartSize = 512 * 1024;
|
||||
private const string ConnectionShutDown = "Could not read payload length : Connection shut down";
|
||||
private readonly SemaphoreSlim _parallelTransfers = new(10); // max parallel part uploads/downloads
|
||||
#if MTPROTO1
|
||||
private readonly SHA1 _sha1 = SHA1.Create();
|
||||
private readonly SHA1 _sha1Recv = SHA1.Create();
|
||||
#else
|
||||
private readonly SHA256 _sha256 = SHA256.Create();
|
||||
private readonly SHA256 _sha256Recv = SHA256.Create();
|
||||
#endif
|
||||
#if OBFUSCATION
|
||||
private AesCtr _sendCtr, _recvCtr;
|
||||
#endif
|
||||
|
|
@ -575,11 +570,7 @@ namespace WTelegram
|
|||
}
|
||||
else
|
||||
{
|
||||
#if MTPROTO1
|
||||
byte[] decrypted_data = EncryptDecryptMessage(data.AsSpan(24, dataLen - 24), false, _dcSession.AuthKey, data, 8, _sha1Recv);
|
||||
#else
|
||||
byte[] decrypted_data = EncryptDecryptMessage(data.AsSpan(24, (dataLen - 24) & ~0xF), false, _dcSession.AuthKey, data, 8, _sha256Recv);
|
||||
#endif
|
||||
if (decrypted_data.Length < 36) // header below+ctorNb
|
||||
throw new ApplicationException($"Decrypted packet too small: {decrypted_data.Length}");
|
||||
using var reader = new TL.BinaryReader(new MemoryStream(decrypted_data), this);
|
||||
|
|
@ -603,18 +594,13 @@ namespace WTelegram
|
|||
if (sessionId != _dcSession.Id) throw new ApplicationException($"Unexpected session ID {sessionId} != {_dcSession.Id}");
|
||||
if ((msgId & 1) == 0) throw new ApplicationException($"Invalid server msgId {msgId}");
|
||||
if ((seqno & 1) != 0) lock (_msgsToAck) _msgsToAck.Add(msgId);
|
||||
#if MTPROTO1
|
||||
if (decrypted_data.Length - 32 - length is < 0 or > 15) throw new ApplicationException($"Unexpected decrypted message_data_length {length} / {decrypted_data.Length - 32}");
|
||||
if (!data.AsSpan(8, 16).SequenceEqual(_sha1Recv.ComputeHash(decrypted_data, 0, 32 + length).AsSpan(4)))
|
||||
throw new ApplicationException($"Mismatch between MsgKey & decrypted SHA1");
|
||||
#else
|
||||
if (decrypted_data.Length - 32 - length is < 12 or > 1024) throw new ApplicationException($"Unexpected decrypted message_data_length {length} / {decrypted_data.Length - 32}");
|
||||
_sha256Recv.TransformBlock(_dcSession.AuthKey, 96, 32, null, 0);
|
||||
_sha256Recv.TransformFinalBlock(decrypted_data, 0, decrypted_data.Length);
|
||||
if (!data.AsSpan(8, 16).SequenceEqual(_sha256Recv.Hash.AsSpan(8, 16)))
|
||||
throw new ApplicationException($"Mismatch between MsgKey & decrypted SHA256");
|
||||
_sha256Recv.Initialize();
|
||||
#endif
|
||||
|
||||
var ctorNb = reader.ReadUInt32();
|
||||
if (ctorNb != Layer.BadMsgCtor && (msgStamp - DateTime.UtcNow).Ticks / TimeSpan.TicksPerSecond is > 30 or < -300)
|
||||
{ // msg_id values that belong over 30 seconds in the future or over 300 seconds in the past are to be ignored.
|
||||
|
|
@ -677,12 +663,7 @@ namespace WTelegram
|
|||
{
|
||||
using var clearStream = new MemoryStream(1024);
|
||||
using var clearWriter = new BinaryWriter(clearStream, Encoding.UTF8);
|
||||
#if MTPROTO1
|
||||
const int prepend = 0;
|
||||
#else
|
||||
const int prepend = 32;
|
||||
clearWriter.Write(_dcSession.AuthKey, 88, prepend);
|
||||
#endif
|
||||
clearWriter.Write(_dcSession.AuthKey, 88, 32);
|
||||
clearWriter.Write(_dcSession.Salt); // int64 salt
|
||||
clearWriter.Write(_dcSession.Id); // int64 session_id
|
||||
clearWriter.Write(msgId); // int64 message_id
|
||||
|
|
@ -693,24 +674,16 @@ namespace WTelegram
|
|||
else
|
||||
Helpers.Log(1, $"{_dcSession.DcID}>Sending {msg.GetType().Name.TrimEnd('_'),-40} {MsgIdToStamp(msgId):u} (svc)");
|
||||
clearWriter.WriteTLObject(msg); // bytes message_data
|
||||
int clearLength = (int)clearStream.Length - prepend; // length before padding (= 32 + message_data_length)
|
||||
int clearLength = (int)clearStream.Length - 32; // length before padding (= 32 + message_data_length)
|
||||
int padding = (0x7FFFFFF0 - clearLength) % 16;
|
||||
#if !MTPROTO1
|
||||
padding += _random.Next(1, 64) * 16; // MTProto 2.0 padding must be between 12..1024 with total length divisible by 16
|
||||
#endif
|
||||
clearStream.SetLength(prepend + clearLength + padding);
|
||||
clearStream.SetLength(32 + clearLength + padding);
|
||||
byte[] clearBuffer = clearStream.GetBuffer();
|
||||
BinaryPrimitives.WriteInt32LittleEndian(clearBuffer.AsSpan(prepend + 28), clearLength - 32); // patch message_data_length
|
||||
RNG.GetBytes(clearBuffer, prepend + clearLength, padding);
|
||||
#if MTPROTO1
|
||||
var msgKeyLarge = _sha1.ComputeHash(clearBuffer, 0, clearLength); // padding excluded from computation!
|
||||
const int msgKeyOffset = 4; // msg_key = low 128-bits of SHA1(plaintext)
|
||||
byte[] encrypted_data = EncryptDecryptMessage(clearBuffer.AsSpan(prepend, clearLength + padding), true, _dcSession.AuthKey, msgKeyLarge, msgKeyOffset, _sha1);
|
||||
#else
|
||||
var msgKeyLarge = _sha256.ComputeHash(clearBuffer, 0, prepend + clearLength + padding);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(clearBuffer.AsSpan(60), clearLength - 32); // patch message_data_length
|
||||
RNG.GetBytes(clearBuffer, 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)
|
||||
byte[] encrypted_data = EncryptDecryptMessage(clearBuffer.AsSpan(prepend, clearLength + padding), true, _dcSession.AuthKey, msgKeyLarge, msgKeyOffset, _sha256);
|
||||
#endif
|
||||
byte[] encrypted_data = EncryptDecryptMessage(clearBuffer.AsSpan(32, clearLength + padding), true, _dcSession.AuthKey, msgKeyLarge, msgKeyOffset, _sha256);
|
||||
|
||||
writer.Write(_dcSession.AuthKeyID); // int64 auth_key_id
|
||||
writer.Write(msgKeyLarge, msgKeyOffset, 16); // int128 msg_key
|
||||
|
|
|
|||
|
|
@ -33,11 +33,7 @@ namespace WTelegram
|
|||
|
||||
//1)
|
||||
var nonce = new Int128(RNG);
|
||||
#if MTPROTO1
|
||||
var resPQ = await client.ReqPQ(nonce);
|
||||
#else
|
||||
var resPQ = await client.ReqPqMulti(nonce);
|
||||
#endif
|
||||
//2)
|
||||
if (resPQ.nonce != nonce) throw new ApplicationException("Nonce mismatch");
|
||||
var fingerprint = resPQ.server_public_key_fingerprints.FirstOrDefault(PublicKeys.ContainsKey);
|
||||
|
|
@ -62,19 +58,6 @@ namespace WTelegram
|
|||
};
|
||||
byte[] encrypted_data = null;
|
||||
{
|
||||
#if OLDKEY
|
||||
using var clearStream = new MemoryStream(255);
|
||||
clearStream.Position = 20; // skip SHA1 area (to be patched)
|
||||
using var writer = new BinaryWriter(clearStream, Encoding.UTF8);
|
||||
writer.WriteTLObject(pqInnerData);
|
||||
int clearLength = (int)clearStream.Length; // length before padding (= 20 + message_data_length)
|
||||
if (clearLength > 255) throw new ApplicationException("PQInnerData too big");
|
||||
byte[] clearBuffer = clearStream.GetBuffer();
|
||||
RNG.GetBytes(clearBuffer, clearLength, 255 - clearLength);
|
||||
sha1.ComputeHash(clearBuffer, 20, clearLength - 20).CopyTo(clearBuffer, 0); // patch with SHA1
|
||||
encrypted_data = BigInteger.ModPow(BigEndianInteger(clearBuffer), // encrypt with RSA key
|
||||
BigEndianInteger(publicKey.e), BigEndianInteger(publicKey.n)).ToByteArray(true, true);
|
||||
#else
|
||||
//4.1) RSA_PAD(data, server_public_key)
|
||||
using var clearStream = new MemoryStream(256);
|
||||
using var writer = new BinaryWriter(clearStream, Encoding.UTF8);
|
||||
|
|
@ -101,7 +84,6 @@ namespace WTelegram
|
|||
if (x < n) // if good result, encrypt with RSA key:
|
||||
encrypted_data = BigInteger.ModPow(x, BigEndianInteger(publicKey.e), n).To256Bytes();
|
||||
} // otherwise, repeat the steps
|
||||
#endif
|
||||
}
|
||||
var serverDHparams = await client.ReqDHParams(pqInnerData.nonce, pqInnerData.server_nonce, pqInnerData.p, pqInnerData.q, fingerprint, encrypted_data);
|
||||
//5)
|
||||
|
|
@ -250,17 +232,6 @@ namespace WTelegram
|
|||
|
||||
private static void LoadDefaultPublicKeys()
|
||||
{
|
||||
#if OLDKEY
|
||||
// Old Public Key (C3B42B026CE86B21)
|
||||
LoadPublicKey(@"-----BEGIN RSA PUBLIC KEY-----
|
||||
MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6
|
||||
lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS
|
||||
an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw
|
||||
Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+
|
||||
8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n
|
||||
Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
-----END RSA PUBLIC KEY-----");
|
||||
#else
|
||||
// Production Public Key (D09D1D85DE64FD85)
|
||||
LoadPublicKey(@"-----BEGIN RSA PUBLIC KEY-----
|
||||
MIIBCgKCAQEA6LszBcC1LGzyr992NzE0ieY+BSaOW622Aa9Bd4ZHLl+TuFQ4lo4g
|
||||
|
|
@ -279,42 +250,8 @@ j25sIWeYPHYeOrFp/eXaqhISP6G+q2IeTaWTXpwZj4LzXq5YOpk4bYEQ6mvRq7D1
|
|||
aHWfYmlEGepfaYR8Q0YqvvhYtMte3ITnuSJs171+GDqpdKcSwHnd6FudwGO4pcCO
|
||||
j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
||||
-----END RSA PUBLIC KEY-----");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MTPROTO1
|
||||
internal static byte[] EncryptDecryptMessage(Span<byte> input, bool encrypt, byte[] authKey, byte[] msgKey, int msgKeyOffset, SHA1 sha1)
|
||||
{
|
||||
// first, construct AES key & IV
|
||||
byte[] aes_key = new byte[32], aes_iv = new byte[32];
|
||||
int x = encrypt ? 0 : 8;
|
||||
sha1.TransformBlock(msgKey, msgKeyOffset, 16, null, 0); // msgKey
|
||||
sha1.TransformFinalBlock(authKey, x, 32); // authKey[x:32]
|
||||
var sha1_a = sha1.Hash;
|
||||
sha1.Initialize();
|
||||
sha1.TransformBlock(authKey, 32 + x, 16, null, 0); // authKey[32+x:16]
|
||||
sha1.TransformBlock(msgKey, msgKeyOffset, 16, null, 0); // msgKey
|
||||
sha1.TransformFinalBlock(authKey, 48 + x, 16); // authKey[48+x:16]
|
||||
var sha1_b = sha1.Hash;
|
||||
sha1.Initialize();
|
||||
sha1.TransformBlock(authKey, 64 + x, 32, null, 0); // authKey[64+x:32]
|
||||
sha1.TransformFinalBlock(msgKey, msgKeyOffset, 16); // msgKey
|
||||
var sha1_c = sha1.Hash;
|
||||
sha1.Initialize();
|
||||
sha1.TransformBlock(msgKey, msgKeyOffset, 16, null, 0); // msgKey
|
||||
sha1.TransformFinalBlock(authKey, 96 + x, 32); // authKey[96+x:32]
|
||||
var sha1_d = sha1.Hash;
|
||||
sha1.Initialize();
|
||||
Array.Copy(sha1_a, 0, aes_key, 0, 8);
|
||||
Array.Copy(sha1_b, 8, aes_key, 8, 12);
|
||||
Array.Copy(sha1_c, 4, aes_key, 20, 12);
|
||||
Array.Copy(sha1_a, 8, aes_iv, 0, 12);
|
||||
Array.Copy(sha1_b, 0, aes_iv, 12, 8);
|
||||
Array.Copy(sha1_c, 16, aes_iv, 20, 4);
|
||||
Array.Copy(sha1_d, 0, aes_iv, 24, 8);
|
||||
return AES_IGE_EncryptDecrypt(input, aes_key, aes_iv, encrypt);
|
||||
}
|
||||
#else
|
||||
internal static byte[] EncryptDecryptMessage(Span<byte> input, bool encrypt, byte[] authKey, byte[] msgKey, int msgKeyOffset, SHA256 sha256)
|
||||
{
|
||||
// first, construct AES key & IV
|
||||
|
|
@ -336,7 +273,6 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
|||
Array.Copy(sha256_b, 24, aes_iv, 24, 8);
|
||||
return AES_IGE_EncryptDecrypt(input, aes_key, aes_iv, encrypt);
|
||||
}
|
||||
#endif
|
||||
|
||||
private static byte[] AES_IGE_EncryptDecrypt(Span<byte> input, byte[] aes_key, byte[] aes_iv, bool encrypt)
|
||||
{
|
||||
|
|
@ -346,9 +282,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
|||
var output = new byte[input.Length];
|
||||
var xPrev = aes_iv.AsSpan(encrypt ? 16 : 0, 16);
|
||||
var yPrev = aes_iv.AsSpan(encrypt ? 0 : 16, 16);
|
||||
var aesCrypto = encrypt ? AesECB.CreateEncryptor(aes_key, null) : AesECB.CreateDecryptor(aes_key, null);
|
||||
using (aesCrypto)
|
||||
{
|
||||
using var aesCrypto = encrypt ? AesECB.CreateEncryptor(aes_key, null) : AesECB.CreateDecryptor(aes_key, null);
|
||||
byte[] yXOR = new byte[16];
|
||||
for (int i = 0; i < input.Length; i += 16)
|
||||
{
|
||||
|
|
@ -360,7 +294,6 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
|||
xPrev = input.Slice(i, 16);
|
||||
yPrev = output.AsSpan(i, 16);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue