mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2026-01-04 07:39:58 +01:00
Fix SHA corruption due to concurrent use of static instance
This commit is contained in:
parent
8610f7e809
commit
52fb2a7831
|
|
@ -48,6 +48,13 @@ namespace WTelegram
|
|||
private Task _connecting;
|
||||
private CancellationTokenSource _cts;
|
||||
private int _reactorReconnects = 0;
|
||||
#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
|
||||
|
||||
/// <summary>Welcome to WTelegramClient! 😀</summary>
|
||||
/// <param name="configProvider">Config callback, is queried for: api_id, api_hash, session_pathname</param>
|
||||
|
|
@ -367,7 +374,11 @@ namespace WTelegram
|
|||
}
|
||||
else
|
||||
{
|
||||
byte[] decrypted_data = EncryptDecryptMessage(data.AsSpan(24, dataLen - 24), false, _dcSession.AuthKey, data, 8);
|
||||
#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), 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);
|
||||
|
|
@ -393,14 +404,14 @@ namespace WTelegram
|
|||
return null;
|
||||
#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)))
|
||||
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.Initialize();
|
||||
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)))
|
||||
_sha256Recv.Initialize();
|
||||
_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 SHA1");
|
||||
#endif
|
||||
var ctorNb = reader.ReadUInt32();
|
||||
|
|
@ -497,13 +508,14 @@ namespace WTelegram
|
|||
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!
|
||||
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);
|
||||
var msgKeyLarge = _sha256.ComputeHash(clearBuffer, 0, prepend + 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(prepend, clearLength + padding), true, _dcSession.AuthKey, msgKeyLarge, msgKeyOffset);
|
||||
|
||||
writer.Write(_dcSession.AuthKeyID); // int64 auth_key_id
|
||||
writer.Write(msgKeyLarge, msgKeyOffset, 16); // int128 msg_key
|
||||
|
|
|
|||
|
|
@ -15,18 +15,13 @@ namespace WTelegram
|
|||
internal static class Encryption
|
||||
{
|
||||
internal static readonly RNGCryptoServiceProvider RNG = new();
|
||||
internal static readonly SHA1 Sha1 = SHA1.Create();
|
||||
internal static readonly SHA256 Sha256 = SHA256.Create();
|
||||
#if MTPROTO1
|
||||
internal static readonly SHA1 Sha1Recv = SHA1.Create();
|
||||
#else
|
||||
internal static readonly SHA256 Sha256Recv = SHA256.Create();
|
||||
#endif
|
||||
private static readonly Dictionary<long, RSAPublicKey> PublicKeys = new();
|
||||
|
||||
internal static async Task CreateAuthorizationKey(Client client, Session.DCSession session)
|
||||
{
|
||||
if (PublicKeys.Count == 0) LoadDefaultPublicKeys();
|
||||
var sha1 = SHA1.Create();
|
||||
var sha256 = SHA256.Create();
|
||||
|
||||
//1)
|
||||
var nonce = new Int128(RNG);
|
||||
|
|
@ -68,7 +63,7 @@ namespace WTelegram
|
|||
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
|
||||
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
|
||||
|
|
@ -87,10 +82,10 @@ namespace WTelegram
|
|||
if (clearLength > 144) throw new ApplicationException("PQInnerData too big");
|
||||
byte[] clearBuffer = clearStream.GetBuffer();
|
||||
RNG.GetBytes(clearBuffer, 32 + clearLength, 192 - clearLength);
|
||||
Sha256.ComputeHash(clearBuffer, 0, 32 + 192).CopyTo(clearBuffer, 224); // append Sha256
|
||||
sha256.ComputeHash(clearBuffer, 0, 32 + 192).CopyTo(clearBuffer, 224); // append Sha256
|
||||
Array.Reverse(clearBuffer, 32, 192);
|
||||
var aes_encrypted = AES_IGE_EncryptDecrypt(clearBuffer.AsSpan(32, 224), aes_key, zero_iv, true);
|
||||
var hash_aes = Sha256.ComputeHash(aes_encrypted);
|
||||
var hash_aes = sha256.ComputeHash(aes_encrypted);
|
||||
for (int i = 0; i < 32; i++) // prefix aes_encrypted with temp_key_xor
|
||||
clearBuffer[i] = (byte)(aes_key[i] ^ hash_aes[i]);
|
||||
aes_encrypted.CopyTo(clearBuffer, 32);
|
||||
|
|
@ -115,7 +110,7 @@ namespace WTelegram
|
|||
if (answerObj is not ServerDHInnerData serverDHinnerData) throw new ApplicationException("not server_DH_inner_data");
|
||||
long padding = encryptedReader.BaseStream.Length - encryptedReader.BaseStream.Position;
|
||||
if (padding >= 16) throw new ApplicationException("Too much pad");
|
||||
if (!Enumerable.SequenceEqual(Sha1.ComputeHash(answer, 20, answer.Length - (int)padding - 20), answerHash))
|
||||
if (!Enumerable.SequenceEqual(sha1.ComputeHash(answer, 20, answer.Length - (int)padding - 20), answerHash))
|
||||
throw new ApplicationException("Answer SHA1 mismatch");
|
||||
if (serverDHinnerData.nonce != nonce) throw new ApplicationException("Nonce mismatch");
|
||||
if (serverDHinnerData.server_nonce != resPQ.server_nonce) throw new ApplicationException("Server Nonce mismatch");
|
||||
|
|
@ -147,7 +142,7 @@ namespace WTelegram
|
|||
clearStream.SetLength(clearLength + paddingToAdd);
|
||||
byte[] clearBuffer = clearStream.GetBuffer();
|
||||
RNG.GetBytes(clearBuffer, clearLength, paddingToAdd);
|
||||
Sha1.ComputeHash(clearBuffer, 20, clearLength - 20).CopyTo(clearBuffer, 0);
|
||||
sha1.ComputeHash(clearBuffer, 20, clearLength - 20).CopyTo(clearBuffer, 0);
|
||||
|
||||
encrypted_data = AES_IGE_EncryptDecrypt(clearBuffer.AsSpan(0, clearLength + paddingToAdd), tmp_aes_key, tmp_aes_iv, true);
|
||||
}
|
||||
|
|
@ -156,7 +151,7 @@ namespace WTelegram
|
|||
var gab = BigInteger.ModPow(g_a, b, dh_prime);
|
||||
var authKey = gab.ToByteArray(true, true);
|
||||
//8)
|
||||
var authKeyHash = Sha1.ComputeHash(authKey);
|
||||
var authKeyHash = sha1.ComputeHash(authKey);
|
||||
retry_id = BinaryPrimitives.ReadInt64LittleEndian(authKeyHash); // (auth_key_aux_hash)
|
||||
//9)
|
||||
if (setClientDHparamsAnswer is not DhGenOk dhGenOk) throw new ApplicationException("not dh_gen_ok");
|
||||
|
|
@ -166,29 +161,29 @@ namespace WTelegram
|
|||
pqInnerData.new_nonce.raw.CopyTo(expected_new_nonceN, 0);
|
||||
expected_new_nonceN[32] = 1;
|
||||
Array.Copy(authKeyHash, 0, expected_new_nonceN, 33, 8); // (auth_key_aux_hash)
|
||||
if (!Enumerable.SequenceEqual(dhGenOk.new_nonce_hash1.raw, Sha1.ComputeHash(expected_new_nonceN).Skip(4)))
|
||||
if (!Enumerable.SequenceEqual(dhGenOk.new_nonce_hash1.raw, sha1.ComputeHash(expected_new_nonceN).Skip(4)))
|
||||
throw new ApplicationException("setClientDHparamsAnswer.new_nonce_hashN mismatch");
|
||||
|
||||
session.AuthKeyID = BinaryPrimitives.ReadInt64LittleEndian(authKeyHash.AsSpan(12));
|
||||
session.AuthKey = authKey;
|
||||
session.Salt = BinaryPrimitives.ReadInt64LittleEndian(pqInnerData.new_nonce.raw) ^ BinaryPrimitives.ReadInt64LittleEndian(resPQ.server_nonce.raw);
|
||||
|
||||
static (byte[] key, byte[] iv) ConstructTmpAESKeyIV(Int128 server_nonce, Int256 new_nonce)
|
||||
(byte[] key, byte[] iv) ConstructTmpAESKeyIV(Int128 server_nonce, Int256 new_nonce)
|
||||
{
|
||||
byte[] tmp_aes_key = new byte[32], tmp_aes_iv = new byte[32];
|
||||
Sha1.Initialize();
|
||||
Sha1.TransformBlock(new_nonce, 0, 32, null, 0);
|
||||
Sha1.TransformFinalBlock(server_nonce, 0, 16);
|
||||
Sha1.Hash.CopyTo(tmp_aes_key, 0); // tmp_aes_key := SHA1(new_nonce + server_nonce)
|
||||
Sha1.Initialize();
|
||||
Sha1.TransformBlock(server_nonce, 0, 16, null, 0);
|
||||
Sha1.TransformFinalBlock(new_nonce, 0, 32);
|
||||
Array.Copy(Sha1.Hash, 0, tmp_aes_key, 20, 12); // + SHA1(server_nonce, new_nonce)[0:12]
|
||||
Array.Copy(Sha1.Hash, 12, tmp_aes_iv, 0, 8); // tmp_aes_iv != SHA1(server_nonce, new_nonce)[12:8]
|
||||
Sha1.Initialize();
|
||||
Sha1.TransformBlock(new_nonce, 0, 32, null, 0);
|
||||
Sha1.TransformFinalBlock(new_nonce, 0, 32);
|
||||
Sha1.Hash.CopyTo(tmp_aes_iv, 8); // + SHA(new_nonce + new_nonce)
|
||||
sha1.Initialize();
|
||||
sha1.TransformBlock(new_nonce, 0, 32, null, 0);
|
||||
sha1.TransformFinalBlock(server_nonce, 0, 16);
|
||||
sha1.Hash.CopyTo(tmp_aes_key, 0); // tmp_aes_key := SHA1(new_nonce + server_nonce)
|
||||
sha1.Initialize();
|
||||
sha1.TransformBlock(server_nonce, 0, 16, null, 0);
|
||||
sha1.TransformFinalBlock(new_nonce, 0, 32);
|
||||
Array.Copy(sha1.Hash, 0, tmp_aes_key, 20, 12); // + SHA1(server_nonce, new_nonce)[0:12]
|
||||
Array.Copy(sha1.Hash, 12, tmp_aes_iv, 0, 8); // tmp_aes_iv != SHA1(server_nonce, new_nonce)[12:8]
|
||||
sha1.Initialize();
|
||||
sha1.TransformBlock(new_nonce, 0, 32, null, 0);
|
||||
sha1.TransformFinalBlock(new_nonce, 0, 32);
|
||||
sha1.Hash.CopyTo(tmp_aes_iv, 8); // + SHA(new_nonce + new_nonce)
|
||||
Array.Copy(new_nonce, 0, tmp_aes_iv, 28, 4); // + new_nonce[0:4]
|
||||
return (tmp_aes_key, tmp_aes_iv);
|
||||
}
|
||||
|
|
@ -233,11 +228,12 @@ namespace WTelegram
|
|||
public static void LoadPublicKey(string pem)
|
||||
{
|
||||
using var rsa = RSA.Create();
|
||||
using var sha1 = SHA1.Create();
|
||||
rsa.ImportFromPem(pem);
|
||||
var rsaParam = rsa.ExportParameters(false);
|
||||
var publicKey = new RSAPublicKey { n = rsaParam.Modulus, e = rsaParam.Exponent };
|
||||
var bareData = publicKey.Serialize(); // bare serialization
|
||||
var fingerprint = BinaryPrimitives.ReadInt64LittleEndian(Sha1.ComputeHash(bareData, 4, bareData.Length - 4).AsSpan(12)); // 64 lower-order bits of SHA1
|
||||
var fingerprint = BinaryPrimitives.ReadInt64LittleEndian(sha1.ComputeHash(bareData, 4, bareData.Length - 4).AsSpan(12)); // 64 lower-order bits of SHA1
|
||||
PublicKeys[fingerprint] = publicKey;
|
||||
Helpers.Log(1, $"Loaded a public key with fingerprint {fingerprint:X}");
|
||||
}
|
||||
|
|
@ -276,13 +272,12 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
|||
#endif
|
||||
}
|
||||
|
||||
internal static byte[] EncryptDecryptMessage(Span<byte> input, bool encrypt, byte[] authKey, byte[] msgKey, int msgKeyOffset)
|
||||
#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;
|
||||
#if MTPROTO1
|
||||
var sha1 = encrypt ? Sha1 : Sha1Recv;
|
||||
sha1.Initialize();
|
||||
sha1.TransformBlock(msgKey, msgKeyOffset, 16, null, 0); // msgKey
|
||||
sha1.TransformFinalBlock(authKey, x, 32); // authKey[x:32]
|
||||
|
|
@ -307,8 +302,14 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
|||
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
|
||||
var sha256 = encrypt ? Sha256 : Sha256Recv;
|
||||
internal static byte[] EncryptDecryptMessage(Span<byte> input, bool encrypt, byte[] authKey, byte[] msgKey, int msgKeyOffset, SHA256 sha256)
|
||||
{
|
||||
// first, construct AES key & IV
|
||||
byte[] aes_key = new byte[32], aes_iv = new byte[32];
|
||||
int x = encrypt ? 0 : 8;
|
||||
sha256.Initialize();
|
||||
sha256.TransformBlock(msgKey, msgKeyOffset, 16, null, 0); // msgKey
|
||||
sha256.TransformFinalBlock(authKey, x, 36); // authKey[x:36]
|
||||
|
|
@ -323,9 +324,9 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
|||
Array.Copy(sha256_b, 0, aes_iv, 0, 8);
|
||||
Array.Copy(sha256_a, 8, aes_iv, 8, 16);
|
||||
Array.Copy(sha256_b, 24, aes_iv, 24, 8);
|
||||
#endif
|
||||
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)
|
||||
{
|
||||
|
|
@ -372,32 +373,33 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
|||
var g_256 = g.To256Bytes();
|
||||
ValidityChecks(p, algo.g);
|
||||
|
||||
Sha256.Initialize();
|
||||
Sha256.TransformBlock(algo.salt1, 0, algo.salt1.Length, null, 0);
|
||||
Sha256.TransformBlock(passwordBytes, 0, passwordBytes.Length, null, 0);
|
||||
Sha256.TransformFinalBlock(algo.salt1, 0, algo.salt1.Length);
|
||||
var hash = Sha256.Hash;
|
||||
Sha256.Initialize();
|
||||
Sha256.TransformBlock(algo.salt2, 0, algo.salt2.Length, null, 0);
|
||||
Sha256.TransformBlock(hash, 0, 32, null, 0);
|
||||
Sha256.TransformFinalBlock(algo.salt2, 0, algo.salt2.Length);
|
||||
hash = Sha256.Hash;
|
||||
using var sha256 = SHA256.Create();
|
||||
sha256.Initialize();
|
||||
sha256.TransformBlock(algo.salt1, 0, algo.salt1.Length, null, 0);
|
||||
sha256.TransformBlock(passwordBytes, 0, passwordBytes.Length, null, 0);
|
||||
sha256.TransformFinalBlock(algo.salt1, 0, algo.salt1.Length);
|
||||
var hash = sha256.Hash;
|
||||
sha256.Initialize();
|
||||
sha256.TransformBlock(algo.salt2, 0, algo.salt2.Length, null, 0);
|
||||
sha256.TransformBlock(hash, 0, 32, null, 0);
|
||||
sha256.TransformFinalBlock(algo.salt2, 0, algo.salt2.Length);
|
||||
hash = sha256.Hash;
|
||||
#if NETCOREAPP2_0_OR_GREATER
|
||||
using var derive = new Rfc2898DeriveBytes(hash, algo.salt1, 100000, HashAlgorithmName.SHA512);
|
||||
var pbkdf2 = derive.GetBytes(64);
|
||||
#else
|
||||
var pbkdf2 = PBKDF2_SHA512(hash, algo.salt1, 100000, 64);
|
||||
#endif
|
||||
Sha256.Initialize();
|
||||
Sha256.TransformBlock(algo.salt2, 0, algo.salt2.Length, null, 0);
|
||||
Sha256.TransformBlock(pbkdf2, 0, 64, null, 0);
|
||||
Sha256.TransformFinalBlock(algo.salt2, 0, algo.salt2.Length);
|
||||
var x = BigEndianInteger(Sha256.Hash);
|
||||
sha256.Initialize();
|
||||
sha256.TransformBlock(algo.salt2, 0, algo.salt2.Length, null, 0);
|
||||
sha256.TransformBlock(pbkdf2, 0, 64, null, 0);
|
||||
sha256.TransformFinalBlock(algo.salt2, 0, algo.salt2.Length);
|
||||
var x = BigEndianInteger(sha256.Hash);
|
||||
|
||||
Sha256.Initialize();
|
||||
Sha256.TransformBlock(algo.p, 0, 256, null, 0);
|
||||
Sha256.TransformFinalBlock(g_256, 0, 256);
|
||||
var k = BigEndianInteger(Sha256.Hash);
|
||||
sha256.Initialize();
|
||||
sha256.TransformBlock(algo.p, 0, 256, null, 0);
|
||||
sha256.TransformFinalBlock(g_256, 0, 256);
|
||||
var k = BigEndianInteger(sha256.Hash);
|
||||
|
||||
var v = BigInteger.ModPow(g, x, p);
|
||||
var k_v = (k * v) % p;
|
||||
|
|
@ -405,29 +407,29 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
|||
var g_a = BigInteger.ModPow(g, a, p);
|
||||
var g_a_256 = g_a.To256Bytes();
|
||||
|
||||
Sha256.Initialize();
|
||||
Sha256.TransformBlock(g_a_256, 0, 256, null, 0);
|
||||
Sha256.TransformFinalBlock(g_b_256, 0, 256);
|
||||
var u = BigEndianInteger(Sha256.Hash);
|
||||
sha256.Initialize();
|
||||
sha256.TransformBlock(g_a_256, 0, 256, null, 0);
|
||||
sha256.TransformFinalBlock(g_b_256, 0, 256);
|
||||
var u = BigEndianInteger(sha256.Hash);
|
||||
|
||||
var t = (g_b - k_v) % p; //(positive modulo, if the result is negative increment by p)
|
||||
if (t.Sign < 0) t += p;
|
||||
var s_a = BigInteger.ModPow(t, a + u * x, p);
|
||||
var k_a = Sha256.ComputeHash(s_a.To256Bytes());
|
||||
var k_a = sha256.ComputeHash(s_a.To256Bytes());
|
||||
|
||||
hash = Sha256.ComputeHash(algo.p);
|
||||
var h2 = Sha256.ComputeHash(g_256);
|
||||
hash = sha256.ComputeHash(algo.p);
|
||||
var h2 = sha256.ComputeHash(g_256);
|
||||
for (int i = 0; i < 32; i++) hash[i] ^= h2[i];
|
||||
var hs1 = Sha256.ComputeHash(algo.salt1);
|
||||
var hs2 = Sha256.ComputeHash(algo.salt2);
|
||||
Sha256.Initialize();
|
||||
Sha256.TransformBlock(hash, 0, 32, null, 0);
|
||||
Sha256.TransformBlock(hs1, 0, 32, null, 0);
|
||||
Sha256.TransformBlock(hs2, 0, 32, null, 0);
|
||||
Sha256.TransformBlock(g_a_256, 0, 256, null, 0);
|
||||
Sha256.TransformBlock(g_b_256, 0, 256, null, 0);
|
||||
Sha256.TransformFinalBlock(k_a, 0, 32);
|
||||
var m1 = Sha256.Hash;
|
||||
var hs1 = sha256.ComputeHash(algo.salt1);
|
||||
var hs2 = sha256.ComputeHash(algo.salt2);
|
||||
sha256.Initialize();
|
||||
sha256.TransformBlock(hash, 0, 32, null, 0);
|
||||
sha256.TransformBlock(hs1, 0, 32, null, 0);
|
||||
sha256.TransformBlock(hs2, 0, 32, null, 0);
|
||||
sha256.TransformBlock(g_a_256, 0, 256, null, 0);
|
||||
sha256.TransformBlock(g_b_256, 0, 256, null, 0);
|
||||
sha256.TransformFinalBlock(k_a, 0, 32);
|
||||
var m1 = sha256.Hash;
|
||||
|
||||
return new InputCheckPasswordSRP { A = g_a_256, M1 = m1, srp_id = accountPassword.srp_id };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ namespace WTelegram
|
|||
public DateTime SessionStart => _sessionStart;
|
||||
public readonly SemaphoreSlim _sem = new(1);
|
||||
private readonly DateTime _sessionStart = DateTime.UtcNow;
|
||||
private readonly SHA256 _sha256 = SHA256.Create();
|
||||
private string _pathname;
|
||||
private byte[] _apiHash; // used as AES key for encryption of session file
|
||||
|
||||
|
|
@ -69,10 +70,11 @@ namespace WTelegram
|
|||
internal static Session Load(string pathname, byte[] apiHash)
|
||||
{
|
||||
var input = File.ReadAllBytes(pathname);
|
||||
using var sha256 = SHA256.Create();
|
||||
using var aes = Aes.Create();
|
||||
using var decryptor = aes.CreateDecryptor(apiHash, input[0..16]);
|
||||
var utf8Json = decryptor.TransformFinalBlock(input, 16, input.Length - 16);
|
||||
if (!Encryption.Sha256.ComputeHash(utf8Json, 32, utf8Json.Length - 32).SequenceEqual(utf8Json[0..32]))
|
||||
if (!sha256.ComputeHash(utf8Json, 32, utf8Json.Length - 32).SequenceEqual(utf8Json[0..32]))
|
||||
throw new ApplicationException("Integrity check failed in session loading");
|
||||
return JsonSerializer.Deserialize<Session>(utf8Json.AsSpan(32), JsonOptions);
|
||||
}
|
||||
|
|
@ -85,7 +87,7 @@ namespace WTelegram
|
|||
Encryption.RNG.GetBytes(output, 0, 16);
|
||||
using var aes = Aes.Create();
|
||||
using var encryptor = aes.CreateEncryptor(_apiHash, output[0..16]);
|
||||
encryptor.TransformBlock(Encryption.Sha256.ComputeHash(utf8Json), 0, 32, output, 16);
|
||||
encryptor.TransformBlock(_sha256.ComputeHash(utf8Json), 0, 32, output, 16);
|
||||
encryptor.TransformBlock(utf8Json, 0, utf8Json.Length & ~15, output, 48);
|
||||
utf8Json.AsSpan(utf8Json.Length & ~15).CopyTo(finalBlock);
|
||||
encryptor.TransformFinalBlock(finalBlock, 0, utf8Json.Length & 15).CopyTo(output.AsMemory(48 + utf8Json.Length & ~15));
|
||||
|
|
|
|||
Loading…
Reference in a new issue