public PqData SolvePq(UInt64 pq) { Random r = new Random(); UInt64 g = 0; for (int i = 0; i < 3; i++) { UInt64 q = (UInt64)((r.Next(128) & 15) + 17); UInt64 x = (UInt64)(r.Next(1000000000) + 1), y = x; Int32 lim = 1 << (i + 18); for (int j = 0; j < lim; j++) { UInt64 a = x, b = x, c = q; while (b != 0) { if ((b & 1) != 0) { c += a; if (c >= pq) { c -= pq; } } a += a; if (a >= pq) { a -= pq; } b >>= 1; } x = c; UInt64 z = x < y ? y - x : x - y; g = GreatestCommonDivisor(z, pq); if (g != 1) { break; } if ((j & (j - 1)) == 0) { y = x; } } } UInt64 f = pq / g; PqData data = new PqData { P = (UInt32)Math.Min(f, g), Q = (UInt32)Math.Max(f, g) }; return(data); }
public PqData SolvePq(UInt64 pq) { Random r = new Random(); UInt64 g = 0; for (int i = 0; i < 3; i++) { UInt64 q = (UInt64)((r.Next(128) & 15) + 17); UInt64 x = (UInt64)(r.Next(1000000000) + 1), y = x; Int32 lim = 1 << (i + 18); for (int j = 0; j < lim; j++) { UInt64 a = x, b = x, c = q; while (b != 0) { if ((b & 1) != 0) { c += a; if (c >= pq) c -= pq; } a += a; if (a >= pq) a -= pq; b >>= 1; } x = c; UInt64 z = x < y ? y - x : x - y; g = GreatestCommonDivisor(z, pq); if (g != 1) break; if ((j & (j - 1)) == 0) y = x; } } UInt64 f = pq / g; PqData data = new PqData { P = (UInt32)Math.Min(f, g), Q = (UInt32)Math.Max(f, g) }; return data; }
private async Task DoAuthenticationAsync(IConnectionInfo connectionInfo) { Random r = new Random(); IPlainConnection connection = new PlainConnection(connectionInfo); await connection.ConnectAsync().ConfigureAwait(false); TLReqPqMethod method = new TLReqPqMethod(); ReqPq reqPq = new ReqPq { Nonce = new byte[16] }; r.NextBytes(reqPq.Nonce); TLFrame <ReqPq> frame = new TLFrame <ReqPq> { AuthKey = 0, MessageId = DateTime.Now.ToUnixTime() * (Int64)Math.Pow(2, 32), MessageLength = 20, Content = reqPq }; method.SendObject = frame; TLFrame <ResPq> resPqFrame = await connection.ExecuteMethodAsync(method).ConfigureAwait(false); UInt64 pq = (UInt64)TLRootSerializer.Deserialize(resPqFrame.Content.Pq.Content.Reverse().ToList(), typeof(UInt64)); PqData pqData = _pqSolver.SolvePq(pq); PqInnerData innerData = new PqInnerData { Nonce = resPqFrame.Content.Nonce, ServerNonce = resPqFrame.Content.ServerNonce, NewNonce = new byte[32], Pq = resPqFrame.Content.Pq, P = new TLBytes(TLRootSerializer.Serialize(pqData.P).Reverse().ToArray()), Q = new TLBytes(TLRootSerializer.Serialize(pqData.Q).Reverse().ToArray()) }; r.NextBytes(innerData.NewNonce); byte[] data = TLRootSerializer.Serialize(innerData); UInt64 fingerprint = resPqFrame.Content.Vector.Content.First(); SHA1 shaAlgo = SHA1.Create(); byte[] sha1 = shaAlgo.ComputeHash(data); List <byte> dataWithHash = sha1.Concat(data).ToList(); while (dataWithHash.Count < 255) { dataWithHash.Add((byte)(r.Next() & 0xFF)); } byte[] encData = _rsaCrypter.EncryptBytes(dataWithHash.ToArray(), fingerprint); TLFrame <ReqDhParams> reqDhFrame = new TLFrame <ReqDhParams> { AuthKey = 0, MessageId = DateTime.Now.ToUnixTime() * (Int64)Math.Pow(2, 32), MessageLength = 320, Content = new ReqDhParams { Nonce = innerData.Nonce, ServerNonce = innerData.ServerNonce, P = innerData.P, Q = innerData.Q, Fingerprint = TLRootSerializer.Serialize(fingerprint), EncryptedData = new TLBytes(encData) } }; TLReqDhParamsMethod reqDhMethod = new TLReqDhParamsMethod { SendObject = reqDhFrame }; TLFrame <ServerDhParams> dhParamsFrame = await connection.ExecuteMethodAsync(reqDhMethod).ConfigureAwait(false); ServerDhParamsOk paramsOk = dhParamsFrame.Content as ServerDhParamsOk; if (paramsOk == null) { throw new ServerException("Didn't receive ServerDhParamsOk(0xd0e8075c)"); } // SHA1(new_nonce + server_nonce) byte[] tmpAesKey = shaAlgo.ComputeHash(ArrayUtils.Concat(innerData.NewNonce, innerData.ServerNonce)); // + substr (SHA1(server_nonce + new_nonce), 0, 12) tmpAesKey = tmpAesKey.Concat(shaAlgo.ComputeHash(ArrayUtils.Concat(innerData.ServerNonce, innerData.NewNonce)).Take(12).ToArray()).ToArray(); // substr (SHA1(server_nonce + new_nonce), 12, 8) byte[] tmpAesIv = shaAlgo.ComputeHash(ArrayUtils.Concat(innerData.ServerNonce, innerData.NewNonce)).Skip(12).Take(8).ToArray(); // + SHA1(new_nonce + new_nonce) tmpAesIv = tmpAesIv.Concat(shaAlgo.ComputeHash(ArrayUtils.Concat(innerData.NewNonce, innerData.NewNonce))).ToArray(); // + substr (new_nonce, 0, 4); tmpAesIv = tmpAesIv.Concat(innerData.NewNonce.Take(4)).ToArray(); byte[] decData = _aes256IgeCrypter.DecryptBytes(paramsOk.EncryptedAnswer.Content, tmpAesKey, tmpAesIv); byte[] hash = decData.Take(20).ToArray(); decData = decData.Skip(20).ToArray(); ServerDhInnerData dhInnerData = TLRootSerializer.Deserialize <ServerDhInnerData>(decData.ToList()); if (!ArrayUtils.Equal(hash, shaAlgo.ComputeHash(TLRootSerializer.Serialize(dhInnerData)))) { throw new SecurityException("SHA-1 hash not equal to ServerDhInnerData"); } }