Remove OLDKEY/MTPROTO1 code

This commit is contained in:
Wizou 2022-02-11 02:43:48 +01:00
parent 2982e09c9b
commit 3fe9002f2e
4 changed files with 22 additions and 113 deletions

View file

@ -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

View file

@ -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,20 +282,17 @@ 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)
{
byte[] yXOR = new byte[16];
for (int i = 0; i < input.Length; i += 16)
{
for (int j = 0; j < 16; j++)
yXOR[j] = (byte)(input[i + j] ^ yPrev[j]);
aesCrypto.TransformBlock(yXOR, 0, 16, output, i);
for (int j = 0; j < 16; j++)
output[i + j] ^= xPrev[j];
xPrev = input.Slice(i, 16);
yPrev = output.AsSpan(i, 16);
}
for (int j = 0; j < 16; j++)
yXOR[j] = (byte)(input[i + j] ^ yPrev[j]);
aesCrypto.TransformBlock(yXOR, 0, 16, output, i);
for (int j = 0; j < 16; j++)
output[i + j] ^= xPrev[j];
xPrev = input.Slice(i, 16);
yPrev = output.AsSpan(i, 16);
}
return output;
}