public async Task CreateChatRequest(InputUser user) { try { messages_DhConfig dhConfig = await session.Api.messages_getDhConfig(version, 256); byte[] randomSalt; if(dhConfig.Constructor == Constructor.messages_dhConfig) { var conf = (Messages_dhConfigConstructor) dhConfig; version = conf.version; g = conf.g; p = new BigInteger(1, conf.p); randomSalt = conf.random; } else if(dhConfig.Constructor == Constructor.messages_dhConfigNotModified) { var conf = (Messages_dhConfigNotModifiedConstructor) dhConfig; randomSalt = conf.random; } else { throw new InvalidDataException("invalid constructor"); } byte[] a = GetSaltedRandomBytes(256, randomSalt, 0); BigInteger ga = BigInteger.ValueOf(g).ModPow(new BigInteger(1, a), p); logger.info("generated a: {0}, ga: {1}", BitConverter.ToString(a).Replace("-","").ToLower(), ga); int randomId = random.Next(); // also chat id EncryptedChat chat = await session.Api.messages_requestEncryption(user, randomId, ga.ToByteArrayUnsigned()); UpdateChat(chat, a); } catch(Exception e) { logger.error("creating chat error: {0}", e); } }
public AuthKey(BigInteger gab) { key = gab.ToByteArrayUnsigned(); using(SHA1 hash = new SHA1Managed()) { using(MemoryStream hashStream = new MemoryStream(hash.ComputeHash(key), false)) { using(BinaryReader hashReader = new BinaryReader(hashStream)) { auxHash = hashReader.ReadUInt64(); hashReader.ReadBytes(4); keyId = hashReader.ReadUInt64(); } } } }
public byte[] Encrypt(byte[] data, int offset, int length) { logger.debug("rsa plaintext: {0}", BitConverter.ToString(data, offset, length)); using(MemoryStream buffer = new MemoryStream(255)) using(BinaryWriter writer = new BinaryWriter(buffer)) { using(SHA1 sha1 = new SHA1Managed()) { byte[] hashsum = sha1.ComputeHash(data, offset, length); logger.debug("hashsum: {0}", BitConverter.ToString(hashsum)); writer.Write(hashsum); } buffer.Write(data, offset, length); if(length < 235) { byte[] padding = new byte[235 - length]; new Random().NextBytes(padding); buffer.Write(padding, 0, padding.Length); } logger.debug("rsa plaintext with hashsum and padding: {0}", BitConverter.ToString(buffer.ToArray())); byte[] ciphertext = new BigInteger(1, buffer.ToArray()).ModPow(e, m).ToByteArrayUnsigned(); logger.debug("ciphertext length: {0}, ciphertext: {1}", ciphertext.Length, BitConverter.ToString(ciphertext)); if(ciphertext.Length == 256) { return ciphertext; } else { byte[] paddedCiphertext = new byte[256]; int padding = 256 - ciphertext.Length; for(int i = 0; i < padding; i++) { paddedCiphertext[i] = 0; } ciphertext.CopyTo(paddedCiphertext, padding); logger.debug("ciphertext with padding: {0}", BitConverter.ToString(paddedCiphertext)); return paddedCiphertext; } } }
public BigInteger ShiftLeft( int n) { if (sign == 0 || magnitude.Length == 0) return Zero; if (n == 0) return this; if (n < 0) return ShiftRight(-n); BigInteger result = new BigInteger(sign, ShiftLeft(magnitude, n), true); if (this.nBits != -1) { result.nBits = sign > 0 ? this.nBits : this.nBits + n; } if (this.nBitLength != -1) { result.nBitLength = this.nBitLength + n; } return result; }
public BigInteger Multiply( BigInteger val) { if (sign == 0 || val.sign == 0) return Zero; if (val.QuickPow2Check()) // val is power of two { BigInteger result = this.ShiftLeft(val.Abs().BitLength - 1); return val.sign > 0 ? result : result.Negate(); } if (this.QuickPow2Check()) // this is power of two { BigInteger result = val.ShiftLeft(this.Abs().BitLength - 1); return this.sign > 0 ? result : result.Negate(); } int resLength = (this.BitLength + val.BitLength) / BitsPerInt + 1; int[] res = new int[resLength]; if (val == this) { Square(res, this.magnitude); } else { Multiply(res, this.magnitude, val.magnitude); } return new BigInteger(sign * val.sign, res, true); }
public BigInteger Remainder( BigInteger n) { if (n.sign == 0) throw new ArithmeticException("Division by zero error"); if (this.sign == 0) return Zero; // For small values, use fast remainder method if (n.magnitude.Length == 1) { int val = n.magnitude[0]; if (val > 0) { if (val == 1) return Zero; // TODO Make this func work on uint, and handle val == 1? int rem = Remainder(val); return rem == 0 ? Zero : new BigInteger(sign, new int[] { rem }, false); } } if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0) return this; int[] result; if (n.QuickPow2Check()) // n is power of two { // TODO Move before small values branch above? result = LastNBits(n.Abs().BitLength - 1); } else { result = (int[])this.magnitude.Clone(); result = Remainder(result, n.magnitude); } return new BigInteger(sign, result, true); }
public BigInteger Divide( BigInteger val) { if (val.sign == 0) throw new ArithmeticException("Division by zero error"); if (sign == 0) return Zero; if (val.QuickPow2Check()) // val is power of two { BigInteger result = this.Abs().ShiftRight(val.Abs().BitLength - 1); return val.sign == this.sign ? result : result.Negate(); } int[] mag = (int[])this.magnitude.Clone(); return new BigInteger(this.sign * val.sign, Divide(mag, val.magnitude), true); }
private async Task CreateChatResponse(EncryptedChatRequestedConstructor chat) { try { messages_DhConfig dhConfig = await session.Api.messages_getDhConfig(version, 256); byte[] randomSalt; if(dhConfig.Constructor == Constructor.messages_dhConfig) { Messages_dhConfigConstructor conf = (Messages_dhConfigConstructor) dhConfig; version = conf.version; g = conf.g; p = new BigInteger(1, conf.p); randomSalt = conf.random; } else if(dhConfig.Constructor == Constructor.messages_dhConfigNotModified) { Messages_dhConfigNotModifiedConstructor conf = (Messages_dhConfigNotModifiedConstructor) dhConfig; randomSalt = conf.random; } else { throw new InvalidDataException("invalid constructor"); } byte[] b = GetSaltedRandomBytes(256, randomSalt, 0); BigInteger bInt = new BigInteger(1, b); byte[] gb = BigInteger.ValueOf(g).ModPow(bInt, p).ToByteArrayUnsigned(); byte[] key = new BigInteger(1, chat.g_a).ModPow(bInt, p).ToByteArrayUnsigned(); long fingerprint = CalculateKeyFingerprint(key); EncryptedChat acceptedChat = await session.Api.messages_acceptEncryption(TL.inputEncryptedChat(chat.id, chat.access_hash), gb, fingerprint); Deployment.Current.Dispatcher.BeginInvoke(() => { var echats = from dialog in session.Dialogs.Model.Dialogs where dialog is DialogModelEncrypted && ((DialogModelEncrypted) dialog).Id == chat.id select dialog; if(echats.Any()) { // ??? } else { session.Dialogs.Model.Dialogs.Insert(0, new DialogModelEncrypted(session, acceptedChat, key, fingerprint, b)); } }); } catch(Exception e) { logger.error("response create chat error: {0}", e); } }
public BigInteger Add( BigInteger value) { if (this.sign == 0) return value; if (this.sign != value.sign) { if (value.sign == 0) return this; if (value.sign < 0) return Subtract(value.Negate()); return value.Subtract(Negate()); } return AddToMagnitude(value.magnitude); }
public BigInteger AndNot( BigInteger val) { return And(val.Not()); }
public BigInteger Max( BigInteger value) { return CompareTo(value) > 0 ? this : value; }
public BigInteger Min( BigInteger value) { return CompareTo(value) < 0 ? this : value; }
public BigInteger Gcd( BigInteger value) { if (value.sign == 0) return Abs(); if (sign == 0) return value.Abs(); BigInteger r; BigInteger u = this; BigInteger v = value; while (v.sign != 0) { r = u.Mod(v); u = v; v = r; } return u; }
internal bool RabinMillerTest( int certainty, Random random) { Debug.Assert(certainty > 0); Debug.Assert(BitLength > 2); Debug.Assert(TestBit(0)); // let n = 1 + d . 2^s BigInteger n = this; BigInteger nMinusOne = n.Subtract(One); int s = nMinusOne.GetLowestSetBit(); BigInteger r = nMinusOne.ShiftRight(s); Debug.Assert(s >= 1); do { // TODO Make a method for random BigIntegers in range 0 < x < n) // - Method can be optimized by only replacing examined bits at each trial BigInteger a; do { a = new BigInteger(n.BitLength, random); } while (a.CompareTo(One) <= 0 || a.CompareTo(nMinusOne) >= 0); BigInteger y = a.ModPow(r, n); if (!y.Equals(One)) { int j = 0; while (!y.Equals(nMinusOne)) { if (++j == s) return false; y = y.ModPow(Two, n); if (y.Equals(One)) return false; } } certainty -= 2; // composites pass for only 1/4 possible 'a' } while (certainty > 0); return true; }
public BigInteger[] DivideAndRemainder( BigInteger val) { if (val.sign == 0) throw new ArithmeticException("Division by zero error"); BigInteger[] biggies = new BigInteger[2]; if (sign == 0) { biggies[0] = Zero; biggies[1] = Zero; } else if (val.QuickPow2Check()) // val is power of two { int e = val.Abs().BitLength - 1; BigInteger quotient = this.Abs().ShiftRight(e); int[] remainder = this.LastNBits(e); biggies[0] = val.sign == this.sign ? quotient : quotient.Negate(); biggies[1] = new BigInteger(this.sign, remainder, true); } else { int[] remainder = (int[])this.magnitude.Clone(); int[] quotient = Divide(remainder, val.magnitude); biggies[0] = new BigInteger(this.sign * val.sign, quotient, true); biggies[1] = new BigInteger(this.sign, remainder, true); } return biggies; }
public FactorizedPair(long p, long q) { this.p = BigInteger.ValueOf(p); this.q = BigInteger.ValueOf(q); }
private void Read(BinaryReader reader) { version = reader.ReadInt32(); g = reader.ReadInt32(); p = new BigInteger(1, Serializers.Bytes.read(reader)); }
public BigInteger Subtract( BigInteger n) { if (n.sign == 0) return this; if (this.sign == 0) return n.Negate(); if (this.sign != n.sign) return Add(n.Negate()); int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude); if (compare == 0) return Zero; BigInteger bigun, lilun; if (compare < 0) { bigun = n; lilun = this; } else { bigun = this; lilun = n; } return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true); }
public BigInteger Mod( BigInteger m) { if (m.sign < 1) throw new ArithmeticException("Modulus must be positive"); BigInteger biggie = Remainder(m); return (biggie.sign >= 0 ? biggie : biggie.Add(m)); }
private static BigInteger createUValueOf( ulong value) { int msw = (int)(value >> 32); int lsw = (int)value; if (msw != 0) return new BigInteger(1, new int[] { msw, lsw }, false); if (lsw != 0) { BigInteger n = new BigInteger(1, new int[] { lsw }, false); // Check for a power of two if ((lsw & -lsw) == lsw) { n.nBits = 1; } return n; } return Zero; }
public RSAServerKey(string fingerprint, BigInteger m, BigInteger e) { this.fingerprint = fingerprint; this.m = m; this.e = e; }
public BigInteger And( BigInteger value) { if (this.sign == 0 || value.sign == 0) { return Zero; } int[] aMag = this.sign > 0 ? this.magnitude : Add(One).magnitude; int[] bMag = value.sign > 0 ? value.magnitude : value.Add(One).magnitude; bool resultNeg = sign < 0 && value.sign < 0; int resultLength = System.Math.Max(aMag.Length, bMag.Length); int[] resultMag = new int[resultLength]; int aStart = resultMag.Length - aMag.Length; int bStart = resultMag.Length - bMag.Length; for (int i = 0; i < resultMag.Length; ++i) { int aWord = i >= aStart ? aMag[i - aStart] : 0; int bWord = i >= bStart ? bMag[i - bStart] : 0; if (this.sign < 0) { aWord = ~aWord; } if (value.sign < 0) { bWord = ~bWord; } resultMag[i] = aWord & bWord; if (resultNeg) { resultMag[i] = ~resultMag[i]; } } BigInteger result = new BigInteger(1, resultMag, true); // TODO Optimise this case if (resultNeg) { result = result.Not(); } return result; }
public FactorizedPair(BigInteger p, BigInteger q) { this.p = p; this.q = q; }
public int CompareTo( BigInteger value) { return sign < value.sign ? -1 : sign > value.sign ? 1 : sign == 0 ? 0 : sign * CompareNoLeadingZeroes(0, magnitude, 0, value.magnitude); }
public BigInteger ModPow( BigInteger exponent, BigInteger m) { if (m.sign < 1) throw new ArithmeticException("Modulus must be positive"); if (m.Equals(One)) return Zero; if (exponent.sign == 0) return One; if (sign == 0) return Zero; int[] zVal = null; int[] yAccum = null; int[] yVal; // Montgomery exponentiation is only possible if the modulus is odd, // but AFAIK, this is always the case for crypto algo's bool useMonty = ((m.magnitude[m.magnitude.Length - 1] & 1) == 1); long mQ = 0; if (useMonty) { mQ = m.GetMQuote(); // tmp = this * R mod m BigInteger tmp = ShiftLeft(32 * m.magnitude.Length).Mod(m); zVal = tmp.magnitude; useMonty = (zVal.Length <= m.magnitude.Length); if (useMonty) { yAccum = new int[m.magnitude.Length + 1]; if (zVal.Length < m.magnitude.Length) { int[] longZ = new int[m.magnitude.Length]; zVal.CopyTo(longZ, longZ.Length - zVal.Length); zVal = longZ; } } } if (!useMonty) { if (magnitude.Length <= m.magnitude.Length) { //zAccum = new int[m.magnitude.Length * 2]; zVal = new int[m.magnitude.Length]; magnitude.CopyTo(zVal, zVal.Length - magnitude.Length); } else { // // in normal practice we'll never see this... // BigInteger tmp = Remainder(m); //zAccum = new int[m.magnitude.Length * 2]; zVal = new int[m.magnitude.Length]; tmp.magnitude.CopyTo(zVal, zVal.Length - tmp.magnitude.Length); } yAccum = new int[m.magnitude.Length * 2]; } yVal = new int[m.magnitude.Length]; // // from LSW to MSW // for (int i = 0; i < exponent.magnitude.Length; i++) { int v = exponent.magnitude[i]; int bits = 0; if (i == 0) { while (v > 0) { v <<= 1; bits++; } // // first time in initialise y // zVal.CopyTo(yVal, 0); v <<= 1; bits++; } while (v != 0) { if (useMonty) { // Montgomery square algo doesn't exist, and a normal // square followed by a Montgomery reduction proved to // be almost as heavy as a Montgomery mulitply. MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); } else { Square(yAccum, yVal); Remainder(yAccum, m.magnitude); Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length); ZeroOut(yAccum); } bits++; if (v < 0) { if (useMonty) { MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); } else { Multiply(yAccum, yVal, zVal); Remainder(yAccum, m.magnitude); Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length); ZeroOut(yAccum); } } v <<= 1; } while (bits < 32) { if (useMonty) { MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); } else { Square(yAccum, yVal); Remainder(yAccum, m.magnitude); Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length); ZeroOut(yAccum); } bits++; } } if (useMonty) { // Return y * R^(-1) mod m by doing y * 1 * R^(-1) mod m ZeroOut(zVal); zVal[zVal.Length - 1] = 1; MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); } BigInteger result = new BigInteger(1, yVal, true); return exponent.sign > 0 ? result : result.ModInverse(m); }
public BigInteger ModInverse( BigInteger m) { if (m.sign < 1) throw new ArithmeticException("Modulus must be positive"); // TODO Too slow at the moment // // "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel // if (m.TestBit(0)) // { // //The Almost Inverse Algorithm // int k = 0; // BigInteger B = One, C = Zero, F = this, G = m, tmp; // // for (;;) // { // // While F is even, do F=F/u, C=C*u, k=k+1. // int zeroes = F.GetLowestSetBit(); // if (zeroes > 0) // { // F = F.ShiftRight(zeroes); // C = C.ShiftLeft(zeroes); // k += zeroes; // } // // // If F = 1, then return B,k. // if (F.Equals(One)) // { // BigInteger half = m.Add(One).ShiftRight(1); // BigInteger halfK = half.ModPow(BigInteger.ValueOf(k), m); // return B.Multiply(halfK).Mod(m); // } // // if (F.CompareTo(G) < 0) // { // tmp = G; G = F; F = tmp; // tmp = B; B = C; C = tmp; // } // // F = F.Add(G); // B = B.Add(C); // } // } BigInteger x = new BigInteger(); BigInteger gcd = ExtEuclid(this.Mod(m), m, x, null); if (!gcd.Equals(One)) throw new ArithmeticException("Numbers not relatively prime."); if (x.sign < 0) { x.sign = 1; //x = m.Subtract(x); x.magnitude = doSubBigLil(m.magnitude, x.magnitude); } return x; }
public async Task<AuthKey> Generate(TelegramDC dc, int maxRetries) { ConnectedEvent += delegate {}; await ConnectAsync(dc, maxRetries); random.NextBytes(nonce); using(MemoryStream memoryStream = new MemoryStream()) { using(BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) { binaryWriter.Write(0x60469778); binaryWriter.Write(nonce); Send(memoryStream.ToArray()); } } completionSource = new TaskCompletionSource<byte[]>(); byte[] response = await completionSource.Task; BigInteger pq; List<byte[]> fingerprints = new List<byte[]>(); using(var memoryStream = new MemoryStream(response, false)) { using(var binaryReader = new BinaryReader(memoryStream)) { int responseCode = binaryReader.ReadInt32(); if(responseCode != 0x05162463) { logger.error("invalid response code: {0}", responseCode); return null; } byte[] nonceFromServer = binaryReader.ReadBytes(16); if(!nonceFromServer.SequenceEqual(nonce)) { logger.debug("invalid nonce from server"); return null; } serverNonce = binaryReader.ReadBytes(16); byte[] pqbytes = Serializers.Bytes.read(binaryReader); pq = new BigInteger(1, pqbytes); int vectorId = binaryReader.ReadInt32(); if(vectorId != 0x1cb5c415) { logger.debug("invalid fingerprints vector id: {0}", vectorId); return null; } int fingerprintCount = binaryReader.ReadInt32(); for(int i = 0; i < fingerprintCount; i++) { byte[] fingerprint = binaryReader.ReadBytes(8); fingerprints.Add(fingerprint); } } } FactorizedPair pqPair = Factorizator.Factorize(pq); logger.debug("stage 1: ok"); random.NextBytes(newNonce); byte[] reqDhParamsBytes; using(MemoryStream pqInnerData = new MemoryStream(255)) { using(BinaryWriter pqInnerDataWriter = new BinaryWriter(pqInnerData)) { pqInnerDataWriter.Write(0x83c95aec); // pq_inner_data Serializers.Bytes.write(pqInnerDataWriter, pq.ToByteArrayUnsigned()); Serializers.Bytes.write(pqInnerDataWriter, pqPair.Min.ToByteArrayUnsigned()); Serializers.Bytes.write(pqInnerDataWriter, pqPair.Max.ToByteArrayUnsigned()); pqInnerDataWriter.Write(nonce); pqInnerDataWriter.Write(serverNonce); pqInnerDataWriter.Write(newNonce); logger.debug("pq_inner_data: {0}", BitConverter.ToString(pqInnerData.GetBuffer())); byte[] ciphertext = null; byte[] targetFingerprint = null; foreach(byte[] fingerprint in fingerprints) { ciphertext = RSA.Encrypt(BitConverter.ToString(fingerprint).Replace("-", string.Empty), pqInnerData.GetBuffer(), 0, (int) pqInnerData.Position); if(ciphertext != null) { targetFingerprint = fingerprint; break; } } if(ciphertext == null) { logger.error("not found valid key for fingerprints: {0}", String.Join(", ", fingerprints)); return null; } using(MemoryStream reqDHParams = new MemoryStream(1024)) { using(BinaryWriter reqDHParamsWriter = new BinaryWriter(reqDHParams)) { reqDHParamsWriter.Write(0xd712e4be); // req_dh_params reqDHParamsWriter.Write(nonce); reqDHParamsWriter.Write(serverNonce); Serializers.Bytes.write(reqDHParamsWriter, pqPair.Min.ToByteArrayUnsigned()); Serializers.Bytes.write(reqDHParamsWriter, pqPair.Max.ToByteArrayUnsigned()); reqDHParamsWriter.Write(targetFingerprint); Serializers.Bytes.write(reqDHParamsWriter, ciphertext); logger.debug("sending req_dh_paras: {0}", BitConverter.ToString(reqDHParams.ToArray())); reqDhParamsBytes = reqDHParams.ToArray(); } } } } completionSource = new TaskCompletionSource<byte[]>(); Send(reqDhParamsBytes); response = await completionSource.Task; logger.debug("dh response: {0}", BitConverter.ToString(response)); byte[] encryptedAnswer; using(MemoryStream responseStream = new MemoryStream(response, false)) { using(BinaryReader responseReader = new BinaryReader(responseStream)) { uint responseCode = responseReader.ReadUInt32(); if(responseCode == 0x79cb045d) { // server_DH_params_fail logger.error("server_DH_params_fail: TODO"); return null; } if(responseCode != 0xd0e8075c) { logger.error("invalid response code: {0}", responseCode); return null; } byte[] nonceFromServer = responseReader.ReadBytes(16); if(!nonceFromServer.SequenceEqual(nonce)) { logger.debug("invalid nonce from server"); return null; } byte[] serverNonceFromServer = responseReader.ReadBytes(16); if(!serverNonceFromServer.SequenceEqual(serverNonce)) { logger.error("invalid server nonce from server"); return null; } encryptedAnswer = Serializers.Bytes.read(responseReader); } } logger.debug("encrypted answer: {0}", BitConverter.ToString(encryptedAnswer)); AESKeyData key = AES.GenerateKeyDataFromNonces(serverNonce, newNonce); byte[] plaintextAnswer = AES.DecryptAES(key, encryptedAnswer); logger.debug("plaintext answer: {0}", BitConverter.ToString(plaintextAnswer)); int g; BigInteger dhPrime; BigInteger ga; using(MemoryStream dhInnerData = new MemoryStream(plaintextAnswer)) { using(BinaryReader dhInnerDataReader = new BinaryReader(dhInnerData)) { byte[] hashsum = dhInnerDataReader.ReadBytes(20); uint code = dhInnerDataReader.ReadUInt32(); if(code != 0xb5890dba) { logger.error("invalid dh_inner_data code: {0}", code); return null; } logger.debug("valid code"); byte[] nonceFromServer1 = dhInnerDataReader.ReadBytes(16); if(!nonceFromServer1.SequenceEqual(nonce)) { logger.error("invalid nonce in encrypted answer"); return null; } logger.debug("valid nonce"); byte[] serverNonceFromServer1 = dhInnerDataReader.ReadBytes(16); if(!serverNonceFromServer1.SequenceEqual(serverNonce)) { logger.error("invalid server nonce in encrypted answer"); return null; } logger.debug("valid server nonce"); g = dhInnerDataReader.ReadInt32(); dhPrime = new BigInteger(1, Serializers.Bytes.read(dhInnerDataReader)); ga = new BigInteger(1, Serializers.Bytes.read(dhInnerDataReader)); int serverTime = dhInnerDataReader.ReadInt32(); timeOffset = serverTime - (int)(Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds) / 1000); logger.debug("g: {0}, dhprime: {1}, ga: {2}", g, dhPrime, ga); } } BigInteger b = new BigInteger(2048, random); BigInteger gb = BigInteger.ValueOf(g).ModPow(b, dhPrime); BigInteger gab = ga.ModPow(b, dhPrime); logger.debug("gab: {0}", gab); // prepare client dh inner data byte[] clientDHInnerDataBytes; using(MemoryStream clientDhInnerData = new MemoryStream()) { using(BinaryWriter clientDhInnerDataWriter = new BinaryWriter(clientDhInnerData)) { clientDhInnerDataWriter.Write(0x6643b654); // client_dh_inner_data clientDhInnerDataWriter.Write(nonce); clientDhInnerDataWriter.Write(serverNonce); clientDhInnerDataWriter.Write((long) 0); // TODO: retry_id Serializers.Bytes.write(clientDhInnerDataWriter, gb.ToByteArrayUnsigned()); using(MemoryStream clientDhInnerDataWithHash = new MemoryStream()) { using(BinaryWriter clientDhInnerDataWithHashWriter = new BinaryWriter(clientDhInnerDataWithHash)) { using(SHA1 sha1 = new SHA1Managed()) { clientDhInnerDataWithHashWriter.Write(sha1.ComputeHash(clientDhInnerData.GetBuffer(), 0, (int)clientDhInnerData.Position)); clientDhInnerDataWithHashWriter.Write(clientDhInnerData.GetBuffer(), 0, (int)clientDhInnerData.Position); clientDHInnerDataBytes = clientDhInnerDataWithHash.ToArray(); } } } } } logger.debug("client dh inner data papared len {0}: {1}", clientDHInnerDataBytes.Length, BitConverter.ToString(clientDHInnerDataBytes).Replace("-","")); // encryption byte[] clientDhInnerDataEncryptedBytes = AES.EncryptAES(key, clientDHInnerDataBytes); logger.debug("inner data encrypted {0}: {1}", clientDhInnerDataEncryptedBytes.Length, BitConverter.ToString(clientDhInnerDataEncryptedBytes).Replace("-","")); // prepare set_client_dh_params byte[] setclientDhParamsBytes; using(MemoryStream setClientDhParams = new MemoryStream()) { using(BinaryWriter setClientDhParamsWriter = new BinaryWriter(setClientDhParams)) { setClientDhParamsWriter.Write(0xf5045f1f); setClientDhParamsWriter.Write(nonce); setClientDhParamsWriter.Write(serverNonce); Serializers.Bytes.write(setClientDhParamsWriter, clientDhInnerDataEncryptedBytes); setclientDhParamsBytes = setClientDhParams.ToArray(); } } logger.debug("set client dh params prepared: {0}", BitConverter.ToString(setclientDhParamsBytes)); completionSource = new TaskCompletionSource<byte[]>(); Send(setclientDhParamsBytes); response = await completionSource.Task; using(MemoryStream responseStream = new MemoryStream(response)) { using(BinaryReader responseReader = new BinaryReader(responseStream)) { uint code = responseReader.ReadUInt32(); if(code == 0x3bcbf734) { // dh_gen_ok logger.debug("dh_gen_ok"); byte[] nonceFromServer = responseReader.ReadBytes(16); if(!nonceFromServer.SequenceEqual(nonce)) { logger.error("invalid nonce"); return null; } byte[] serverNonceFromServer = responseReader.ReadBytes(16); if(!serverNonceFromServer.SequenceEqual(serverNonce)) { logger.error("invalid server nonce"); return null; } byte[] newNonceHash1 = responseReader.ReadBytes(16); logger.debug("new nonce hash 1: {0}", BitConverter.ToString(newNonceHash1)); AuthKey authKey = new AuthKey(gab); byte[] newNonceHashCalculated = authKey.CalcNewNonceHash(newNonce, 1); if(!newNonceHash1.SequenceEqual(newNonceHashCalculated)) { logger.error("invalid new nonce hash"); return null; } logger.info("generated new auth key: {0}", gab); logger.info("saving time offset: {0}", timeOffset); TelegramSession.Instance.TimeOffset = timeOffset; return authKey; } else if(code == 0x46dc1fb9) { // dh_gen_retry logger.debug("dh_gen_retry"); return null; } else if(code == 0xa69dae02) { // dh_gen_fail logger.debug("dh_gen_fail"); return null; } else { logger.debug("dh_gen unknown: {0}", code); return null; } } } }
/** * Calculate the numbers u1, u2, and u3 such that: * * u1 * a + u2 * b = u3 * * where u3 is the greatest common divider of a and b. * a and b using the extended Euclid algorithm (refer p. 323 * of The Art of Computer Programming vol 2, 2nd ed). * This also seems to have the side effect of calculating * some form of multiplicative inverse. * * @param a First number to calculate gcd for * @param b Second number to calculate gcd for * @param u1Out the return object for the u1 value * @param u2Out the return object for the u2 value * @return The greatest common divisor of a and b */ private static BigInteger ExtEuclid( BigInteger a, BigInteger b, BigInteger u1Out, BigInteger u2Out) { BigInteger u1 = One; BigInteger u3 = a; BigInteger v1 = Zero; BigInteger v3 = b; while (v3.sign > 0) { BigInteger[] q = u3.DivideAndRemainder(v3); BigInteger tmp = v1.Multiply(q[0]); BigInteger tn = u1.Subtract(tmp); u1 = v1; v1 = tn; u3 = v3; v3 = q[1]; } if (u1Out != null) { u1Out.sign = u1.sign; u1Out.magnitude = u1.magnitude; } if (u2Out != null) { BigInteger tmp = u1.Multiply(a); tmp = u3.Subtract(tmp); BigInteger res = tmp.Divide(b); u2Out.sign = res.sign; u2Out.magnitude = res.magnitude; } return u3; }
public static FactorizedPair Factorize(BigInteger pq) { if(pq.BitLength < 64) { long pqlong = pq.LongValue; long divisor = findSmallMultiplierLopatin(pqlong); return new FactorizedPair(BigInteger.ValueOf(divisor), BigInteger.ValueOf(pqlong/divisor)); } else { // TODO: port pollard factorization logger.error("pq too long; TODO: port the pollard algo"); return null; } }