Skip to content

MTProto 2.0 #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/TgSharp.Core/Network/MtProtoSender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ public class MtProtoSender

private readonly TcpTransport transport;
private readonly Session session;
private readonly Random random;

public readonly List<ulong> needConfirmation = new List<ulong>();

public MtProtoSender(TcpTransport transport, Session session)
{
this.transport = transport;
this.session = session;
this.random = new Random();
}

private int GenerateSequence(bool confirmed)
Expand Down Expand Up @@ -74,7 +76,12 @@ private int GenerateSequence(bool confirmed)

byte[] msgKey;
byte[] ciphertext;
using (MemoryStream plaintextPacket = makeMemory(8 + 8 + 8 + 4 + 4 + packet.Length))

int size = 8 + 8 + 8 + 4 + 4 + packet.Length;
var randomPaddingLength = random.Next(1024 / 16) * 16 + 16 - size % 16;
size += randomPaddingLength;

using (MemoryStream plaintextPacket = makeMemory(size))
{
using (BinaryWriter plaintextWriter = new BinaryWriter(plaintextPacket))
{
Expand All @@ -85,7 +92,11 @@ private int GenerateSequence(bool confirmed)
plaintextWriter.Write(packet.Length);
plaintextWriter.Write(packet);

msgKey = Helpers.CalcMsgKey(plaintextPacket.GetBuffer());
var padding = new byte[randomPaddingLength];
random.NextBytes(padding);
plaintextWriter.Write(padding);

msgKey = Helpers.CalcMsgKey(session.AuthKey.Data, plaintextPacket.GetBuffer());
ciphertext = AES.EncryptAES(Helpers.CalcKey(session.AuthKey.Data, msgKey, true), plaintextPacket.GetBuffer());
}
}
Expand Down
65 changes: 21 additions & 44 deletions src/TgSharp.Core/Utils/Helpers.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Security.Cryptography;
using TgSharp.Core.MTProto.Crypto;

Expand Down Expand Up @@ -27,69 +28,45 @@ public static byte[] GenerateRandomBytes(int num)
return data;
}

public static AESKeyData CalcKey(byte[] sharedKey, byte[] msgKey, bool client)
public static AESKeyData CalcKey(byte[] authKey, byte[] msgKey, bool client)
{
int x = client ? 0 : 8;
byte[] buffer = new byte[48];

Array.Copy(msgKey, 0, buffer, 0, 16); // buffer[0:16] = msgKey
Array.Copy(sharedKey, x, buffer, 16, 32); // buffer[16:48] = authKey[x:x+32]
byte[] sha1a = sha1(buffer); // sha1a = sha1(buffer)
//sha256_a = SHA256 (msg_key + substr (auth_key, x, 36));
var sha256A = SHA256(msgKey.Concat(authKey.Skip(x).Take(36)).ToArray());
//sha256_b = SHA256 (substr (auth_key, 40+x, 36) + msg_key);
var sha256B = SHA256(authKey.Skip(40 + x).Take(36).Concat(msgKey).ToArray());
//aes_key = substr (sha256_a, 0, 8) + substr (sha256_b, 8, 16) + substr (sha256_a, 24, 8);
var key = sha256A.Take(8).Concat(sha256B.Skip(8).Take(16)).Concat(sha256A.Skip(24).Take(8)).ToArray();
//aes_iv = substr (sha256_b, 0, 8) + substr (sha256_a, 8, 16) + substr (sha256_b, 24, 8);
var iv = sha256B.Take(8).Concat(sha256A.Skip(8).Take(16)).Concat(sha256B.Skip(24).Take(8)).ToArray();

Array.Copy(sharedKey, 32 + x, buffer, 0, 16); // buffer[0:16] = authKey[x+32:x+48]
Array.Copy(msgKey, 0, buffer, 16, 16); // buffer[16:32] = msgKey
Array.Copy(sharedKey, 48 + x, buffer, 32, 16); // buffer[32:48] = authKey[x+48:x+64]
byte[] sha1b = sha1(buffer); // sha1b = sha1(buffer)

Array.Copy(sharedKey, 64 + x, buffer, 0, 32); // buffer[0:32] = authKey[x+64:x+96]
Array.Copy(msgKey, 0, buffer, 32, 16); // buffer[32:48] = msgKey
byte[] sha1c = sha1(buffer); // sha1c = sha1(buffer)

Array.Copy(msgKey, 0, buffer, 0, 16); // buffer[0:16] = msgKey
Array.Copy(sharedKey, 96 + x, buffer, 16, 32); // buffer[16:48] = authKey[x+96:x+128]
byte[] sha1d = sha1(buffer); // sha1d = sha1(buffer)

byte[] key = new byte[32]; // key = sha1a[0:8] + sha1b[8:20] + sha1c[4:16]
Array.Copy(sha1a, 0, key, 0, 8);
Array.Copy(sha1b, 8, key, 8, 12);
Array.Copy(sha1c, 4, key, 20, 12);

byte[] iv = new byte[32]; // iv = sha1a[8:20] + sha1b[0:8] + sha1c[16:20] + sha1d[0:8]
Array.Copy(sha1a, 8, iv, 0, 12);
Array.Copy(sha1b, 0, iv, 12, 8);
Array.Copy(sha1c, 16, iv, 20, 4);
Array.Copy(sha1d, 0, iv, 24, 8);

return new AESKeyData(key, iv);
}

public static byte[] CalcMsgKey(byte[] data)
public static byte[] CalcMsgKey(byte[] authKey, byte[] data)
{
byte[] msgKey = new byte[16];
Array.Copy(sha1(data), 4, msgKey, 0, 16);
return msgKey;
}
//msg_key_large = SHA256 (substr (auth_key, 88+0, 32) + plaintext + random_padding);
var msgKeyLarge = SHA256(authKey.Skip(88).Take(32).Concat(data).ToArray());

public static byte[] CalcMsgKey(byte[] data, int offset, int limit)
{
byte[] msgKey = new byte[16];
Array.Copy(sha1(data, offset, limit), 4, msgKey, 0, 16);
return msgKey;
//msg_key = substr (msg_key_large, 8, 16);
return msgKeyLarge.Skip(8).Take(16).ToArray();
}

public static byte[] sha1(byte[] data)
public static byte[] SHA256(byte[] data)
{
using (SHA1 sha1 = new SHA1Managed())
using (SHA256 sha256 = new SHA256Managed())
{
return sha1.ComputeHash(data);
return sha256.ComputeHash(data);
}
}

public static byte[] sha1(byte[] data, int offset, int limit)
public static byte[] SHA256(byte[] data, int offset, int limit)
{
using (SHA1 sha1 = new SHA1Managed())
using (SHA256 sha256 = new SHA256Managed())
{
return sha1.ComputeHash(data, offset, limit);
return sha256.ComputeHash(data, offset, limit);
}
}
}
Expand Down