public static async Task <ResPq> Do(Int128 nonce, MtProtoPlainTransport transport) { var res = await transport.Call(new ReqPq(nonce)).ConfigureAwait(false); Helpers.Assert(res.Nonce == nonce, "auth step1: invalid nonce"); return(res); }
public static async Task <Step3Res> Do( ServerDhParams.OkTag dhParams, Int256 newNonce, MtProtoPlainTransport transport ) { var key = Aes.GenerateKeyDataFromNonces(dhParams.ServerNonce.ToBytes(true), newNonce.ToBytes(true)); var plaintextAnswer = Aes.DecryptAES(key, dhParams.EncryptedAnswer.ToArrayUnsafe()); var dh = plaintextAnswer.Apply(Deserialize(WithHashSumCheck(ServerDhInnerData.Deserialize))); Helpers.Assert(dh.Nonce == dhParams.Nonce, "auth step3: invalid nonce in encrypted answer"); Helpers.Assert(dh.ServerNonce == dhParams.ServerNonce, "auth step3: invalid server nonce in encrypted answer"); var currentEpochTime = Helpers.GetCurrentEpochTime(); var timeOffset = dh.ServerTime - currentEpochTime; var g = dh.G; var dhPrime = new BigInteger(1, dh.DhPrime.ToArrayUnsafe()); var ga = new BigInteger(1, dh.Ga.ToArrayUnsafe()); var b = new BigInteger(Rnd.NextBytes(2048)); var gb = BigInteger.ValueOf(g).ModPow(b, dhPrime); var gab = ga.ModPow(b, dhPrime); var dhInnerData = new ClientDhInnerData( nonce: dh.Nonce, serverNonce: dh.ServerNonce, retryId: 0, gb: gb.ToByteArrayUnsigned().ToBytesUnsafe() ); var dhInnerDataBts = Serialize(dhInnerData); var dhInnerDataHashedBts = WithHashAndPadding(dhInnerDataBts); var dhInnerDataHashedEncryptedBytes = Aes.EncryptAES(key, dhInnerDataHashedBts); var resp = await transport.Call(new SetClientDhParams( nonce : dh.Nonce, serverNonce : dh.ServerNonce, encryptedData : dhInnerDataHashedEncryptedBytes.ToBytesUnsafe() )).ConfigureAwait(false); var res = resp.Match( dhGenOkTag: x => x, dhGenFailTag: _ => throw Helpers.FailedAssertion("auth step3: dh_gen_fail"), dhGenRetryTag: _ => throw Helpers.FailedAssertion("auth step3: dh_gen_retry") ); var authKey = AuthKey.FromGab(gab); var newNonceHash = authKey.CalcNewNonceHash(newNonce.ToBytes(true), 1).ToInt128(); Helpers.Assert(res.Nonce == dh.Nonce, "auth step3: invalid nonce"); Helpers.Assert(res.ServerNonce == dh.ServerNonce, "auth step3: invalid server nonce"); Helpers.Assert(res.NewNonceHash1 == newNonceHash, "auth step3: invalid new nonce hash"); return(new Step3Res(authKey, timeOffset)); }
public static async Task <Step3Res> DoAuthentication(MtProtoPlainTransport transport) { var step1Res = await Step1.Do(BtHelpers.GenNonce16(), transport).ConfigureAwait(false); var step2Res = await Step2.Do(step1Res, BtHelpers.GenNonce32(), transport).ConfigureAwait(false); var step3Res = await Step3.Do(step2Res.ServerDhParams, step2Res.NewNonce, transport).ConfigureAwait(false); return(step3Res); }
public static async Task <TgConnection> EstablishConnection( ILogger logger, ConnectInfo connectInfo, TgCallMiddlewareChain callMiddlewareChain, TcpClientConnectionHandler?connHandler = null ) { var endpoint = connectInfo.Endpoint; Helpers.Assert(endpoint != null, "endpoint == null"); var tcpClient = await CreateTcpClient(endpoint !, connHandler).ConfigureAwait(false); var tcpTransport = new TcpTransport(tcpClient); if (connectInfo.NeedsInAuth) { var mtPlainTransport = new MtProtoPlainTransport(tcpTransport); var result = await Authenticator.DoAuthentication(mtPlainTransport).ConfigureAwait(false); connectInfo.SetAuth(result); } var session = connectInfo.ToSession().AsVar(); var mtCipherTransport = new MtProtoCipherTransport(tcpTransport, session); var transport = new TgCustomizedTransport(new TgTransport(logger, mtCipherTransport, session), callMiddlewareChain); // TODO: separate Config var config = new GetConfig(); var request = new InitConnection <GetConfig, Config>( apiId: session.Get().ApiId, appVersion: "1.0.0", deviceModel: "PC", langCode: "en", query: config, systemVersion: "Win 10.0", systemLangCode: "en", langPack: "tdesktop", proxy: null, @params: null ); var invokeWithLayer = new InvokeWithLayer <InitConnection <GetConfig, Config>, Config>( layer: SchemeInfo.LayerVersion, query: request ); var cfg = await transport.Call(invokeWithLayer).ConfigureAwait(false); DcInfoKeeper.Update(cfg); return(new TgConnection(session, transport, cfg)); }
public static async Task <Step2Result> Do(ResPq resPq, Int256 newNonce, MtProtoPlainTransport transport) { var pqBts = resPq.Pq.ToArrayUnsafe(); Helpers.Assert(pqBts.Length <= 8, "auth step2: pq is too big"); var pq = new BigInteger(1, pqBts); var(pLong, qLong) = Factorizer.Factorize((ulong)pq.LongValue); var p = new BigInteger(pLong); var q = new BigInteger(qLong); var pqInnerData = new PqInnerData.DefaultTag( pq: resPq.Pq, p: p.ToByteArrayUnsigned().ToBytesUnsafe(), q: q.ToByteArrayUnsigned().ToBytesUnsafe(), nonce: resPq.Nonce, serverNonce: resPq.ServerNonce, newNonce: newNonce ); var pqInnerDataBts = Serialize((PqInnerData)pqInnerData); var fingerprint = resPq.ServerPublicKeyFingerprints.TryFind(x => x == TgServerRsaKey.Fingerprint) ?? throw Helpers.FailedAssertion( $"auth step2: can not find a key for fingerprints: {string.Join(", ", resPq.ServerPublicKeyFingerprints.Select(x => x.ToString("x16")))}" ); var cipherText = Rsa.Encrypt(TgServerRsaKey.Key, pqInnerDataBts); var resp = await transport.Call(new ReqDhParams( nonce : pqInnerData.Nonce, serverNonce : pqInnerData.ServerNonce, p : pqInnerData.P, q : pqInnerData.Q, publicKeyFingerprint : fingerprint, encryptedData : cipherText.ToBytesUnsafe() )).ConfigureAwait(false); var res = resp.Match( okTag: x => x, failTag: _ => throw Helpers.FailedAssertion("auth step2: server_DH_params_fail") ); Helpers.Assert(res.Nonce == pqInnerData.Nonce, "auth step2: invalid nonce"); Helpers.Assert(res.ServerNonce == pqInnerData.ServerNonce, "auth step2: invalid server nonce"); return(new Step2Result(res, newNonce)); }