mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2025-12-06 06:52:01 +01:00
Improve security by preventing replay attacks
This commit is contained in:
parent
3be28f0fbd
commit
a8d2dfcfa1
4
FAQ.md
4
FAQ.md
|
|
@ -94,7 +94,7 @@ If you use the Github source project in an old .NET Framework 4.x or .NET Core x
|
|||
To fix this, you should also switch to using the [WTelegramClient Nuget package](https://www.nuget.org/packages/WTelegramClient) as it will install the required dependencies for it to work.
|
||||
|
||||
<a name="abuse"></a>
|
||||
#### 7. I get errors FLOOD_WAIT_X or PEER_FLOOD, PHONE_NUMBER_BANNED. I can't import phone numbers.
|
||||
#### 7. I get errors FLOOD_WAIT_X or PEER_FLOOD, PHONE_NUMBER_BANNED, USER_DEACTIVATED_BAN. I can't import phone numbers.
|
||||
|
||||
You can get these kind of problems if you abuse Telegram [Terms of Service](https://telegram.org/tos), or the [API Terms of Service](https://core.telegram.org/api/terms), or make excessive requests.
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ If you think your phone number was banned from Telegram for a wrong reason, you
|
|||
In any case, WTelegramClient is not responsible for the bad usage of the library and we are not affiliated to Telegram teams, so there is nothing we can do.
|
||||
|
||||
<a name="prevent-ban"></a>
|
||||
#### 8. How to not get banned from Telegram?
|
||||
#### 8. How to NOT get banned from Telegram?
|
||||
|
||||
**Do not share publicly your app's ID and hash!** They cannot be regenerated and are bound to your Telegram account.
|
||||
|
||||
|
|
|
|||
|
|
@ -383,12 +383,27 @@ namespace WTelegram
|
|||
byte[] decrypted_data = EncryptDecryptMessage(data.AsSpan(24, (dataLen - 24) & ~0xF), false, _dcSession.AuthKey, data, 8, _sha256Recv);
|
||||
if (decrypted_data.Length < 36) // header below+ctorNb
|
||||
throw new ApplicationException($"Decrypted packet too small: {decrypted_data.Length}");
|
||||
_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();
|
||||
using var reader = new TL.BinaryReader(new MemoryStream(decrypted_data), this);
|
||||
var serverSalt = reader.ReadInt64(); // int64 salt
|
||||
var sessionId = reader.ReadInt64(); // int64 session_id
|
||||
var msgId = reader.ReadInt64(); // int64 message_id
|
||||
var seqno = reader.ReadInt32(); // int32 msg_seqno
|
||||
var length = reader.ReadInt32(); // int32 message_data_length
|
||||
|
||||
if (length < 0 || length % 4 != 0) throw new ApplicationException($"Invalid message_data_length: {length}");
|
||||
if (decrypted_data.Length - 32 - length is < 12 or > 1024) throw new ApplicationException($"Invalid message padding length: {decrypted_data.Length - 32}-{length}");
|
||||
if (sessionId != _dcSession.Id) throw new ApplicationException($"Unexpected session ID: {sessionId} != {_dcSession.Id}");
|
||||
if ((msgId & 1) == 0) throw new ApplicationException($"msg_id is not odd: {msgId}");
|
||||
if (!_dcSession.CheckNewMsgId(msgId))
|
||||
{
|
||||
Helpers.Log(3, $"{_dcSession.DcID}>Ignoring duplicate or old msg_id {msgId}");
|
||||
return null;
|
||||
}
|
||||
if (_lastRecvMsgId == 0) // resync ServerTicksOffset on first message
|
||||
_dcSession.ServerTicksOffset = (msgId >> 32) * 10000000 - DateTime.UtcNow.Ticks + 621355968000000000L;
|
||||
var msgStamp = MsgIdToStamp(_lastRecvMsgId = msgId);
|
||||
|
|
@ -401,15 +416,7 @@ namespace WTelegram
|
|||
if (_saltChangeCounter >= 30)
|
||||
throw new ApplicationException($"Server salt changed too often! Security issue?");
|
||||
}
|
||||
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 (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();
|
||||
|
||||
var ctorNb = reader.ReadUInt32();
|
||||
if (ctorNb != Layer.BadMsgCtor && (msgStamp - DateTime.UtcNow).Ticks / TimeSpan.TicksPerSecond is > 30 or < -300)
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
|||
|
||||
private static byte[] AES_IGE_EncryptDecrypt(Span<byte> input, byte[] aes_key, byte[] aes_iv, bool encrypt)
|
||||
{
|
||||
if (input.Length % 16 != 0) throw new ApplicationException("intput size not divisible by 16");
|
||||
if (input.Length % 16 != 0) throw new ApplicationException("AES_IGE input size not divisible by 16");
|
||||
|
||||
// code adapted from PHP implementation found at https://mgp25.com/AESIGE/
|
||||
var output = new byte[input.Length];
|
||||
|
|
|
|||
|
|
@ -33,6 +33,41 @@ namespace WTelegram
|
|||
internal int DcID => DataCenter?.id ?? 0;
|
||||
internal IPEndPoint EndPoint => DataCenter == null ? null : new(IPAddress.Parse(DataCenter.ip_address), DataCenter.port);
|
||||
internal void Renew() { Helpers.Log(3, $"Renewing session on DC {DcID}..."); Id = Helpers.RandomLong(); Seqno = 0; LastSentMsgId = 0; }
|
||||
|
||||
const int msgIdsN = 512;
|
||||
private long[] msgIds;
|
||||
private int msgIdsHead;
|
||||
internal bool CheckNewMsgId(long msg_id)
|
||||
{
|
||||
if (msgIds == null)
|
||||
{
|
||||
msgIds = new long[msgIdsN];
|
||||
for (int i = 0; i < msgIdsN; i++) msgIds[i] = msg_id;
|
||||
return true;
|
||||
}
|
||||
int newHead = (msgIdsHead + 1) % msgIdsN;
|
||||
if (msg_id > msgIds[msgIdsHead])
|
||||
msgIds[msgIdsHead = newHead] = msg_id;
|
||||
else if (msg_id <= msgIds[newHead])
|
||||
return false;
|
||||
else
|
||||
{
|
||||
int min = 0, max = msgIdsN - 1;
|
||||
while (min <= max) // binary search (rotated at newHead)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int sign = msg_id.CompareTo(msgIds[(mid + newHead) % msgIdsN]);
|
||||
if (sign == 0) return false;
|
||||
else if (sign < 0) max = mid - 1;
|
||||
else min = mid + 1;
|
||||
}
|
||||
msgIdsHead = newHead;
|
||||
for (min = (min + newHead) % msgIdsN; newHead != min;)
|
||||
msgIds[newHead] = msgIds[newHead = newHead == 0 ? msgIdsN - 1 : newHead - 1];
|
||||
msgIds[min] = msg_id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime SessionStart => _sessionStart;
|
||||
|
|
|
|||
Loading…
Reference in a new issue