Exemple #1
0
        private static void CheckWriteToStream(Action <TLStreamer> write, byte[] testBytesInBigEndian, bool streamAsLittleEndian)
        {
            int bytesCount = testBytesInBigEndian.Length;

            using (var streamer = new TLStreamer {
                StreamAsLittleEndian = streamAsLittleEndian
            })
            {
                write(streamer);
                streamer.Length.Should().Be(bytesCount);

                streamer.Position = 0;

                var bytes = new byte[bytesCount];
                streamer.Read(bytes, 0, bytesCount);

                if (streamAsLittleEndian)
                {
                    Array.Reverse(bytes);
                }

                for (byte i = 0; i < bytesCount; i++)
                {
                    bytes[i].Should().Be(testBytesInBigEndian[i]);
                }
            }
        }
Exemple #2
0
        protected override System.Threading.Tasks.Task HandleInternalAsync(IMessage responseMessage)
        {
            var gzipPacked = responseMessage.Body as GzipPacked;

            using (var uncompressedStream = new MemoryStream())
            {
                using (var compressedStream = new MemoryStream(gzipPacked.PackedData))
                {
                    using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress))
                    {
                        gzip.CopyTo(uncompressedStream);
                        var uncompressed = uncompressedStream.ToArray();
                        using (var streamer = new TLStreamer(uncompressed))
                        {
                            var newResult = _tlRig.Deserialize(streamer);
                            if (newResult is SharpTelegram.Schema.IUpdates)
                            {
                                return(_handler.HandleAsync(new Message {
                                    Body = newResult
                                }));
                            }
                        }
                    }
                }
            }

            return(TaskConstants.Completed);
        }
        public IMessage DecodeEncryptedMessage(byte[] messageBytes, byte[] authKey, Sender sender, out UInt64 salt, out UInt64 sessionId)
        {
            Argument.IsNotNull(() => authKey);
            Argument.IsNotNull(() => messageBytes);

            ulong providedAuthKeyId = ComputeAuthKeyId(authKey);

            var encryptedData = new byte[messageBytes.Length - EncryptedOuterHeaderLength];

            Int128 msgKey;

            using (var streamer = new TLStreamer(messageBytes))
            {
                // Reading header.
                ulong authKeyId = streamer.ReadUInt64();
                if (authKeyId != providedAuthKeyId)
                {
                    throw new InvalidAuthKey(string.Format("Message encrypted with auth key with id={0}, but auth key provided for decryption with id={1}.", authKeyId,
                                                           providedAuthKeyId));
                }
                msgKey = streamer.ReadInt128();

                // Reading encrypted data.
                streamer.Read(encryptedData, 0, encryptedData.Length);
            }

            // Decrypting.
            byte[] aesKey, aesIV;
            ComputeAesKeyAndIV(authKey, msgKey, out aesKey, out aesIV, sender);
            byte[] innerDataWithPadding = _encryptionServices.Aes256IgeDecrypt(encryptedData, aesKey, aesIV);

            Int32  msgDataLength;
            UInt64 msgId;
            UInt32 seqno;
            Object body;

            using (var streamer = new TLStreamer(innerDataWithPadding))
            {
                salt          = streamer.ReadUInt64();
                sessionId     = streamer.ReadUInt64();
                msgId         = streamer.ReadUInt64();
                seqno         = streamer.ReadUInt32();
                msgDataLength = streamer.ReadInt32();
                body          = _tlRig.Deserialize(streamer);
            }

            int innerDataLength = EncryptedInnerHeaderLength + msgDataLength;

            // When an encrypted message is received, it must be checked that
            // msg_key is in fact equal to the 128 lower-order bits
            // of the SHA1 hash of the previously encrypted portion.
            Int128 expectedMsgKey = ComputeMsgKey(new ArraySegment <byte>(innerDataWithPadding, 0, innerDataLength));

            if (msgKey != expectedMsgKey)
            {
                throw new InvalidMessageException(string.Format("Expected message key to be {0}, but actual is {1}.", expectedMsgKey, msgKey));
            }

            return(new Message(msgId, seqno, body));
        }
Exemple #4
0
        private ServerDHInnerData DecryptServerDHInnerData(byte[] encryptedAnswer, byte[] tmpAesKey, byte[] tmpAesIV)
        {
            /* encrypted_answer := AES256_ige_encrypt (answer_with_hash, tmp_aes_key, tmp_aes_iv);
             * here, tmp_aes_key is a 256-bit key, and tmp_aes_iv is a 256-bit initialization vector.
             * The same as in all the other instances that use AES encryption,
             * the encrypted data is padded with random bytes to a length divisible by 16 immediately prior to encryption.
             */

            // Decrypting.
            byte[] answerWithHash = _encryptionServices.Aes256IgeDecrypt(encryptedAnswer, tmpAesKey, tmpAesIV);
            if ((answerWithHash.Length % 16) != 0)
            {
                throw new InvalidResponseException("Decrypted ServerDHInnerData with hash has invalid length.");
            }

            var answerHash = new byte[HashLength];
            ServerDHInnerData serverDHInnerData;

            using (var streamer = new TLStreamer(answerWithHash))
            {
                streamer.Read(answerHash, 0, answerHash.Length);
                serverDHInnerData = _tlRig.Deserialize <ServerDHInnerData>(streamer);
            }

            // Checking the hash.
            byte[] serverDHInnerDataBytes     = _tlRig.Serialize(serverDHInnerData);
            byte[] serverDHInnerDataBytesHash = ComputeSHA1(serverDHInnerDataBytes);
            if (!serverDHInnerDataBytesHash.SequenceEqual(answerHash))
            {
                throw new InvalidResponseException("Decrypted ServerDHInnerData hash is invalid.");
            }

            return(serverDHInnerData);
        }
Exemple #5
0
 public void Dispose()
 {
     if (_nonceStream != null)
     {
         _nonceStream.Dispose();
         _nonceStream = null;
     }
 }
Exemple #6
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="EncryptedMessage" /> class from a plain inner message data.
        /// </summary>
        /// <param name="authKey">
        ///     Authorization Key a 2048-bit key shared by the client device and the server, created upon user
        ///     registration directly on the client device be exchanging Diffie-Hellman keys, and never transmitted over a network.
        ///     Each authorization key is user-specific. There is nothing that prevents a user from having several keys (that
        ///     correspond to “permanent sessions” on different devices), and some of these may be locked forever in the event the
        ///     device is lost.
        /// </param>
        /// <param name="salt">
        ///     Server Salt is a (random) 64-bit number periodically (say, every 24 hours) changed (separately for
        ///     each session) at the request of the server. All subsequent messages must contain the new salt (although, messages
        ///     with the old salt are still accepted for a further 300 seconds). Required to protect against replay attacks and
        ///     certain tricks associated with adjusting the client clock to a moment in the distant future.
        /// </param>
        /// <param name="sessionId">
        ///     Session is a (random) 64-bit number generated by the client to distinguish between individual sessions (for
        ///     example, between different instances of the application, created with the same authorization key). The session in
        ///     conjunction with the key identifier corresponds to an application instance. The server can maintain session state.
        ///     Under no circumstances can a message meant for one session be sent into a different session. The server may
        ///     unilaterally forget any client sessions; clients should be able to handle this.
        /// </param>
        /// <param name="messageId">
        ///     Message Identifier is a (time-dependent) 64-bit number used uniquely to identify a message within a session. Client
        ///     message identifiers are divisible by 4, server message identifiers modulo 4 yield 1 if the message is a response to
        ///     a client message, and 3 otherwise. Client message identifiers must increase monotonically (within a single
        ///     session), the same as server message identifiers, and must approximately equal unixtime*2^32. This way, a message
        ///     identifier points to the approximate moment in time the message was created. A message is rejected over 300 seconds
        ///     after it is created or 30 seconds before it is created (this is needed to protect from replay attacks). In this
        ///     situation, it must be re-sent with a different identifier (or placed in a container with a higher identifier). The
        ///     identifier of a message container must be strictly greater than those of its nested messages.
        /// </param>
        /// <param name="seqNumber">
        ///     Message Sequence Number is a 32-bit number equal to twice the number of “content-related” messages (those requiring
        ///     acknowledgment, and in particular those that are not containers) created by the sender prior to this message and
        ///     subsequently incremented by one if the current message is a content-related message. A container is always
        ///     generated after its entire contents; therefore, its sequence number is greater than or equal to the sequence
        ///     numbers of the messages contained in it.
        /// </param>
        /// <param name="messageData">Plain inner message data.</param>
        /// <param name="sender">Sender of the message.</param>
        /// <param name="hashServices">Hash services.</param>
        /// <param name="encryptionServices">Encryption services.</param>
        public EncryptedMessage([NotNull] byte[] authKey, ulong salt, ulong sessionId, ulong messageId, uint seqNumber, [NotNull] byte[] messageData, Sender sender,
                                [NotNull] IHashServices hashServices, [NotNull] IEncryptionServices encryptionServices)
        {
            Argument.IsNotNull(() => authKey);
            Argument.IsNotNull(() => messageData);
            Argument.IsNotNull(() => hashServices);
            Argument.IsNotNull(() => encryptionServices);

            _authKeyId   = ComputeAuthKeyId(authKey, hashServices);
            _salt        = salt;
            _sessionId   = sessionId;
            _messageId   = messageId;
            _seqNumber   = seqNumber;
            _messageData = (byte[])messageData.Clone();

            _messageDataLength = _messageData.Length;
            int innerDataLength            = InnerHeaderLength + _messageDataLength;
            int mod                        = innerDataLength % Alignment;
            int paddingLength              = mod > 0 ? Alignment - mod : 0;
            int innerDataWithPaddingLength = innerDataLength + paddingLength;

            _length = OuterHeaderLength + innerDataWithPaddingLength;

            // Writing inner data.
            var innerDataWithPadding = new byte[innerDataWithPaddingLength];

            using (var streamer = new TLStreamer(innerDataWithPadding))
            {
                streamer.WriteUInt64(_salt);
                streamer.WriteUInt64(_sessionId);
                streamer.WriteUInt64(_messageId);
                streamer.WriteUInt32(_seqNumber);
                streamer.WriteInt32(_messageDataLength);
                streamer.Write(_messageData);
                streamer.WriteRandomData(paddingLength);
            }

            _msgKey = ComputeMsgKey(new ArraySegment <byte>(innerDataWithPadding, 0, innerDataLength), hashServices);

            // Encrypting.
            byte[] aesKey, aesIV;
            ComputeAesKeyAndIV(authKey, _msgKey, out aesKey, out aesIV, hashServices, sender);
            byte[] encryptedData = encryptionServices.Aes256IgeEncrypt(innerDataWithPadding, aesKey, aesIV);

            Debug.Assert(encryptedData.Length == innerDataWithPaddingLength, "Wrong encrypted data length.");

            _messageBytes = new byte[_length];
            using (var streamer = new TLStreamer(_messageBytes))
            {
                // Writing header.
                streamer.WriteUInt64(_authKeyId);
                streamer.WriteInt128(_msgKey);

                // Writing encrypted data.
                streamer.Write(encryptedData, 0, innerDataWithPaddingLength);
            }
        }
        protected override void WriteBody(object obj, TLSerializationContext context)
        {
            var        str      = (string)obj;
            TLStreamer streamer = context.Streamer;

            byte[] bytes = Encoding.GetBytes(str);

            streamer.WriteTLBytes(bytes);
        }
Exemple #8
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="EncryptedMessage" /> class from a whole message bytes, which contain
        ///     encrypted data.
        /// </summary>
        /// <param name="authKey">
        ///     Authorization Key a 2048-bit key shared by the client device and the server, created upon user
        ///     registration directly on the client device be exchanging Diffie-Hellman keys, and never transmitted over a network.
        ///     Each authorization key is user-specific. There is nothing that prevents a user from having several keys (that
        ///     correspond to “permanent sessions” on different devices), and some of these may be locked forever in the event the
        ///     device is lost.
        /// </param>
        /// <param name="messageBytes">Whole message bytes, which contain encrypted data.</param>
        /// <param name="sender">Sender of the message.</param>
        /// <param name="hashServices">Hash services.</param>
        /// <param name="encryptionServices">Encryption services.</param>
        public EncryptedMessage([NotNull] byte[] authKey, [NotNull] byte[] messageBytes, Sender sender, [NotNull] IHashServices hashServices,
                                [NotNull] IEncryptionServices encryptionServices)
        {
            Argument.IsNotNull(() => authKey);
            Argument.IsNotNull(() => messageBytes);
            Argument.IsNotNull(() => hashServices);
            Argument.IsNotNull(() => encryptionServices);

            ulong authKeyId = ComputeAuthKeyId(authKey, hashServices);

            _messageBytes = messageBytes;
            _length       = _messageBytes.Length;

            var encryptedData = new byte[_length - OuterHeaderLength];

            using (var streamer = new TLStreamer(_messageBytes))
            {
                // Reading header.
                _authKeyId = streamer.ReadUInt64();
                if (_authKeyId != authKeyId)
                {
                    throw new InvalidAuthKey(string.Format("Message encrypted with auth key with id={0}, but auth key provided for decryption with id={1}.", _authKeyId,
                                                           authKeyId));
                }
                _msgKey = streamer.ReadInt128();

                // Reading encrypted data.
                streamer.Read(encryptedData, 0, encryptedData.Length);
            }

            // Decrypting.
            byte[] aesKey, aesIV;
            ComputeAesKeyAndIV(authKey, _msgKey, out aesKey, out aesIV, hashServices, sender);
            byte[] innerDataWithPadding = encryptionServices.Aes256IgeDecrypt(encryptedData, aesKey, aesIV);

            using (var streamer = new TLStreamer(innerDataWithPadding))
            {
                _salt              = streamer.ReadUInt64();
                _sessionId         = streamer.ReadUInt64();
                _messageId         = streamer.ReadUInt64();
                _seqNumber         = streamer.ReadUInt32();
                _messageDataLength = streamer.ReadInt32();
                _messageData       = streamer.ReadBytes(_messageDataLength);
            }

            int innerDataLength = InnerHeaderLength + _messageDataLength;

            // When an encrypted message is received, it must be checked that
            // msg_key is in fact equal to the 128 lower-order bits
            // of the SHA1 hash of the previously encrypted portion.
            var msgKey = ComputeMsgKey(new ArraySegment <byte>(innerDataWithPadding, 0, innerDataLength), hashServices);

            if (_msgKey != msgKey)
            {
                throw new InvalidMessageException(string.Format("Expected message key to be {0}, but actual is {1}.", _msgKey, msgKey));
            }
        }
Exemple #9
0
        private ReqDHParamsArgs CreateReqDhParamsArgs(ResPQ resPQ, out PQInnerData pqInnerData)
        {
            Int256 pq = resPQ.Pq.ToInt256(asLittleEndian: false);
            Int256 p, q;

            pq.GetPrimeMultipliers(out p, out q);

            Int256 newNonce = _nonceGenerator.GetNonce(32).ToInt256();

            pqInnerData = new PQInnerData
            {
                Pq          = resPQ.Pq,
                P           = p.ToBytes(false, true),
                Q           = q.ToBytes(false, true),
                Nonce       = resPQ.Nonce,
                ServerNonce = resPQ.ServerNonce,
                NewNonce    = newNonce
            };

            byte[] data     = _tlRig.Serialize(pqInnerData);
            byte[] dataHash = ComputeSHA1(data);

            Debug.Assert((dataHash.Length + data.Length) <= 255);

            // data_with_hash := SHA1(data) + data + (any random bytes); such that the length equal 255 bytes;
            var dataWithHash = new byte[255];

            using (var streamer = new TLStreamer(dataWithHash))
            {
                streamer.Write(dataHash);
                streamer.Write(data);
                streamer.WriteRandomDataTillEnd();
            }

            PublicKey publicKey = _keyChain.GetFirst(resPQ.ServerPublicKeyFingerprints);

            if (publicKey == null)
            {
                throw new PublicKeyNotFoundException(resPQ.ServerPublicKeyFingerprints);
            }

            byte[] encryptedData = _encryptionServices.RSAEncrypt(dataWithHash, publicKey);

            var reqDhParamsArgs = new ReqDHParamsArgs
            {
                Nonce                = pqInnerData.Nonce,
                ServerNonce          = pqInnerData.ServerNonce,
                P                    = pqInnerData.P,
                Q                    = pqInnerData.Q,
                PublicKeyFingerprint = publicKey.Fingerprint,
                EncryptedData        = encryptedData
            };

            return(reqDhParamsArgs);
        }
Exemple #10
0
        public byte[] EncodeEncryptedMessage(IMessage message, byte[] authKey, ulong salt, ulong sessionId, Sender sender)
        {
            Argument.IsNotNull(() => authKey);
            Argument.IsNotNull(() => message);

            ulong authKeyId = ComputeAuthKeyId(authKey);

            byte[] serBody = _tlRig.Serialize(message.Body, TLSerializationMode.Boxed);

            int serBodyLength   = serBody.Length;
            int innerDataLength = EncryptedInnerHeaderLength + serBodyLength;
            int mod             = innerDataLength % Alignment;
            int paddingLength   = mod > 0 ? Alignment - mod : 0;

            _randomGenerator.FillWithRandom(_alignmentBuffer);
            int innerDataWithPaddingLength = innerDataLength + paddingLength;

            int length = EncryptedOuterHeaderLength + innerDataWithPaddingLength;

            // Writing inner data.
            var innerDataWithPadding = new byte[innerDataWithPaddingLength];

            using (var streamer = new TLStreamer(innerDataWithPadding))
            {
                streamer.WriteUInt64(salt);
                streamer.WriteUInt64(sessionId);
                streamer.WriteUInt64(message.MsgId);
                streamer.WriteUInt32(message.Seqno);
                streamer.WriteInt32(serBodyLength);
                streamer.Write(serBody);
                streamer.Write(_alignmentBuffer, 0, paddingLength);
            }

            Int128 msgKey = ComputeMsgKey(new ArraySegment <byte>(innerDataWithPadding, 0, innerDataLength));

            // Encrypting.
            byte[] aesKey, aesIV;
            ComputeAesKeyAndIV(authKey, msgKey, out aesKey, out aesIV, sender);
            byte[] encryptedData = _encryptionServices.Aes256IgeEncrypt(innerDataWithPadding, aesKey, aesIV);

            Debug.Assert(encryptedData.Length == innerDataWithPaddingLength, "Wrong encrypted data length.");

            var messageBytes = new byte[length];

            using (var streamer = new TLStreamer(messageBytes))
            {
                // Writing header.
                streamer.WriteUInt64(authKeyId);
                streamer.WriteInt128(msgKey);

                // Writing encrypted data.
                streamer.Write(encryptedData, 0, innerDataWithPaddingLength);
            }
            return(messageBytes);
        }
Exemple #11
0
 private static void CheckReadFromStream <T>(Func <TLStreamer, T> read, T testValue, byte[] streamBuffer, bool streamAsLittleEndian) where T : struct
 {
     using (var stream = new TLStreamer(streamBuffer)
     {
         StreamAsLittleEndian = streamAsLittleEndian
     })
     {
         T value = read(stream);
         value.ShouldBeEquivalentTo(testValue);
     }
 }
Exemple #12
0
 private static byte[] GetBytes(params object[] values)
 {
     using (var stream = new MemoryStream())
     {
         using (var streamer = new TLStreamer(stream))
         {
             for (int i = 0; i < values.Length; i++)
             {
                 object value = values[i];
                 Type   type  = value.GetType();
                 if (type == typeof(byte))
                 {
                     streamer.WriteByte((byte)value);
                 }
                 else if (type == typeof(int))
                 {
                     streamer.WriteInt32((int)value);
                 }
                 else if (type == typeof(uint))
                 {
                     streamer.WriteUInt32((uint)value);
                 }
                 else if (type == typeof(long))
                 {
                     streamer.WriteInt64((long)value);
                 }
                 else if (type == typeof(ulong))
                 {
                     streamer.WriteUInt64((ulong)value);
                 }
                 else if (type == typeof(double))
                 {
                     streamer.WriteDouble((double)value);
                 }
                 else if (type == typeof(Array))
                 {
                     byte[] v = GetBytes(value);
                     streamer.Write(v, 0, v.Length);
                 }
                 else
                 {
                     var enumerable = value as IEnumerable;
                     if (enumerable != null)
                     {
                         byte[] v = GetBytes(enumerable.Cast <object>().ToArray());
                         streamer.Write(v, 0, v.Length);
                     }
                 }
             }
             return(stream.ToArray());
         }
     }
 }
        protected override Task HandleInternalAsync(IMessage responseMessage)
        {
            var    rpcResult = (IRpcResult)responseMessage.Body;
            object result    = rpcResult.Result;

            IRequest request = _requestsManager.Get(rpcResult.ReqMsgId);

            if (request == null)
            {
                Console.WriteLine(
                    string.Format(
                        "Ignored response of type '{1}' for not existed request with MsgId: 0x{0:X8}.",
                        rpcResult.ReqMsgId,
                        result.GetType()));
                return(TaskConstants.Completed);
            }

            var rpcError   = result as IRpcError;
            var gzipPacked = result as GzipPacked;

            if (rpcError != null)
            {
                request.SetException(new RpcErrorException(rpcError));
            }
            else if (gzipPacked != null)
            {
                using (var uncompressedStream = new MemoryStream())
                {
                    using (var compressedStream = new MemoryStream(gzipPacked.PackedData))
                    {
                        using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress))
                        {
                            gzip.CopyTo(uncompressedStream);
                            var uncompressed = uncompressedStream.ToArray();
                            using (var streamer = new TLStreamer(uncompressed))
                            {
                                var newResult = _tlRig.Deserialize(streamer);
                                request.SetResponse(newResult);
                            }
                        }
                    }
                }
            }
            else
            {
                request.SetResponse(result);
            }
            return(TaskConstants.Completed);
        }
        /// <summary>
        ///     Initializes a new instance of the <see cref="TcpTransportPacket" /> class.
        /// </summary>
        /// <param name="number">Sequential packet number.</param>
        /// <param name="payload">Payload bytes.</param>
        public TcpTransportPacket(int number, byte[] payload)
        {
            Number = number;
            int length = payload.Length + PacketEmbracesLength;

            _data = new byte[length];
            using (var streamer = new TLStreamer(_data))
            {
                streamer.WriteInt32(length);
                streamer.WriteInt32(Number);
                streamer.Write(payload);
                Crc32 = ComputeCrc32();
                streamer.WriteUInt32(Crc32);
            }
        }
Exemple #15
0
        private Int128 ComputeNewNonceHash(Int256 newNonce, byte num, byte[] authKeyAuxHash)
        {
            var arr = new byte[33 + authKeyAuxHash.Length];

            using (var streamer = new TLStreamer(arr))
            {
                streamer.WriteInt256(newNonce);
                streamer.WriteByte(num);
                streamer.Write(authKeyAuxHash);
            }
            byte[] hash   = ComputeSHA1(arr);
            Int128 result = hash.ToInt128(HashLength - 16);

            return(result);
        }
        protected override Message ReadTypedBody(TLSerializationContext context)
        {
            TLStreamer streamer = context.Streamer;

            ulong msgId      = streamer.ReadUInt64();
            uint  seqNo      = streamer.ReadUInt32();
            int   bodyLength = streamer.ReadInt32();

            if (streamer.BytesTillEnd < bodyLength)
            {
                throw new TLSerializationException(String.Format("Body length ({0}) is greated than available to read bytes till end ({1}).", bodyLength,
                                                                 streamer.BytesTillEnd));
            }

            object body = TLRig.Deserialize(context);

            return(new Message(msgId, seqNo, body));
        }
Exemple #17
0
 protected void Dispose(bool isDisposing)
 {
     if (!isDisposing)
     {
         return;
     }
     if (_connectionCancellationTokenSource != null)
     {
         _connectionCancellationTokenSource.Cancel();
         _connectionCancellationTokenSource = null;
     }
     if (_receiverTask != null)
     {
         _receiverTask.Dispose();
         _receiverTask = null;
     }
     if (_nextPacketStreamer != null)
     {
         _nextPacketStreamer.Dispose();
         _nextPacketStreamer = null;
     }
     if (_in != null)
     {
         _in.Dispose();
         _in = null;
     }
     if (_socket != null)
     {
         try
         {
             _socket.Shutdown(SocketShutdown.Both);
             _socket.Disconnect(false);
             _socket.Close();
         }
         catch (Exception e)
         {
             Log.Error(e);
         }
         finally
         {
             _socket = null;
         }
     }
 }
Exemple #18
0
        private byte[] PrependHashAndAlign(byte[] data, int alignment)
        {
            int dataLength = data.Length;

            byte[] dataHash = ComputeSHA1(data);
            int    length   = HashLength + dataLength;
            int    mod      = length % alignment;

            length += mod > 0 ? alignment - mod : 0;
            var dataWithHash = new byte[length];

            using (var streamer = new TLStreamer(dataWithHash))
            {
                streamer.Write(dataHash);
                streamer.Write(data);
                streamer.WriteRandomDataTillEnd();
            }
            return(dataWithHash);
        }
Exemple #19
0
        public IMessage DecodePlainMessage(byte[] messageBytes)
        {
            using (var streamer = new TLStreamer(messageBytes))
            {
                long authKey = streamer.ReadInt64();
                if (authKey != 0)
                {
                    throw new InvalidMessageException("Auth key must always be zero for a plain message.");
                }

                ulong msgId      = streamer.ReadUInt64();
                int   bodyLength = streamer.ReadInt32();
                if (bodyLength > streamer.BytesTillEnd)
                {
                    throw new InvalidMessageException("Wrong message body length.");
                }
                object body = _tlRig.Deserialize(streamer);
                return(new Message(msgId, 0, body));
            }
        }
Exemple #20
0
        public byte[] EncodePlainMessage(IMessage message)
        {
            byte[] serBody = _tlRig.Serialize(message.Body, TLSerializationMode.Boxed);

            int length       = PlainHeaderLength + serBody.Length;
            var messageBytes = new byte[length];

            using (var streamer = new TLStreamer(messageBytes))
            {
                // Writing header.
                streamer.WriteInt64(0);              // Plain unencrypted message must always have zero auth key id.
                streamer.WriteUInt64(message.MsgId); // MsgId.
                streamer.WriteInt32(serBody.Length); // Length.

                // Writing data.
                streamer.Write(serBody);
            }

            return(messageBytes);
        }
        private void InitAndCheckConsistency()
        {
            int length = _data.Length;

            using (var streamer = new TLStreamer(_data))
            {
                int expectedLength = streamer.ReadInt32();
                if (length != expectedLength)
                {
                    throw new TransportException(string.Format("Invalid packet length. Expected: {0}, actual: {1}.", expectedLength, length));
                }
                Number = streamer.ReadInt32();
                streamer.Seek(-4, SeekOrigin.End);
                Crc32 = streamer.ReadUInt32();
            }

            uint actualCrc32 = ComputeCrc32();

            if (Crc32 != actualCrc32)
            {
                throw new TransportException(string.Format("Invalid packet CRC32. Expected: {0}, actual: {1}.", actualCrc32, Crc32));
            }
        }
Exemple #22
0
        public PlainMessage(ulong messageId, [NotNull] byte[] messageData)
        {
            Argument.IsNotNull(() => messageData);

            int dataLength = messageData.Length;

            _messageId    = messageId;
            _messageData  = messageData;
            _dataLength   = dataLength;
            _length       = HeaderLength + dataLength;
            _messageBytes = new byte[_length];

            using (var streamer = new TLStreamer(_messageBytes))
            {
                // Writing header.
                streamer.WriteInt64(0); // Plain unencrypted message must always have zero auth key id.
                streamer.WriteUInt64(_messageId);
                streamer.WriteInt32(_dataLength);

                // Writing data.
                streamer.Write(messageData, 0, _dataLength);
            }
        }
        protected override void WriteTypedBody(Message message, TLSerializationContext context)
        {
            TLStreamer streamer = context.Streamer;

            streamer.WriteUInt64(message.MsgId);
            streamer.WriteUInt32(message.Seqno);

            // Skip 4 bytes for a body length.
            streamer.Position += 4;

            long bodyStartPosition = streamer.Position;

            TLRig.Serialize(message.Body, context, TLSerializationMode.Boxed);
            long bodyEndPosition = streamer.Position;

            long bodyLength = bodyEndPosition - bodyStartPosition;

            streamer.Position = bodyStartPosition - 4;

            // Write a body length.
            streamer.WriteInt32((int)bodyLength);

            streamer.Position = bodyEndPosition;
        }
Exemple #24
0
        /// <summary>
        ///     Processes incoming message bytes.
        /// </summary>
        /// <param name="messageBytes">Incoming bytes.</param>
        private void ProcessIncomingMessageBytes(byte[] messageBytes)
        {
            ThrowIfDisposed();

            try
            {
                Console.WriteLine("Processing incoming message.");
                ulong authKeyId;
                using (var streamer = new TLStreamer(messageBytes))
                {
                    if (messageBytes.Length == 4)
                    {
                        int error = streamer.ReadInt32();
                        Console.WriteLine("Received error code: {0}.", error);
                        return;
                    }
                    if (messageBytes.Length < 20)
                    {
                        throw new InvalidMessageException(
                                  string.Format(
                                      "Invalid message length: {0} bytes. Expected to be at least 20 bytes for message or 4 bytes for error code.",
                                      messageBytes.Length));
                    }
                    authKeyId = streamer.ReadUInt64();
                }

                IMessage message;

                if (authKeyId == 0)
                {
                    // Assume the message bytes has a plain (unencrypted) message.
                    Console.WriteLine(string.Format("Auth key ID = 0x{0:X16}. Assume this is a plain (unencrypted) message.", authKeyId));

                    message = _messageCodec.DecodePlainMessage(messageBytes);

                    if (!IsIncomingMessageIdValid(message.MsgId))
                    {
                        throw new InvalidMessageException(string.Format("Message ID = 0x{0:X16} is invalid.", message.MsgId));
                    }
                }
                else
                {
                    // Assume the stream has an encrypted message.
                    Console.WriteLine(string.Format("Auth key ID = 0x{0:X16}. Assume this is encrypted message.", authKeyId));
                    if (!IsEncryptionSupported)
                    {
                        Console.WriteLine("Encryption is not supported by this connection.");
                        return;
                    }

                    ulong salt, sessionId;
                    message = _messageCodec.DecodeEncryptedMessage(messageBytes, _config.AuthKey, Sender.Server, out salt, out sessionId);
                    // TODO: check salt.
                    if (sessionId != _config.SessionId)
                    {
                        throw new InvalidMessageException(string.Format("Invalid session ID {0}. Expected {1}.", sessionId, _config.SessionId));
                    }
                    Console.WriteLine(string.Format("Received encrypted message. Message ID = 0x{0:X16}.", message.MsgId));
                }
                ProcessIncomingMessage(message);
            }
            catch (Exception e)
            {
                Console.WriteLine("Failed to receive a message: " + e);
            }
        }
        protected virtual void Dispose(bool isDisposing)
        {
            if (_isDisposed)
            {
                return;
            }
            _isDisposed = true;

            if (!isDisposing)
            {
                return;
            }

            if (_connectionCancellationTokenSource != null)
            {
                _connectionCancellationTokenSource.Cancel();
                _connectionCancellationTokenSource = null;
            }
            if (_receiverTask != null)
            {
                if (!_receiverTask.IsCompleted)
                {
                    _receiverTask.Wait(1000);
                }
                if (_receiverTask.IsCompleted)
                {
                    _receiverTask.Dispose();
                }
                else
                {
                    Log.Warning("Receiver task did not completed on transport disposing.");
                }
                _receiverTask = null;
            }
            if (_nextPacketStreamer != null)
            {
                _nextPacketStreamer.Dispose();
                _nextPacketStreamer = null;
            }
            if (_in != null)
            {
                _in.OnCompleted();
                _in.Dispose();
                _in = null;
            }
            if (_socket != null)
            {
                try
                {
                    _socket.Shutdown(SocketShutdown.Both);
                    _socket.Disconnect(false);
                    _socket.Close();
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
                finally
                {
                    _socket = null;
                }
            }
        }
        private async Task ProcessReceivedDataAsync(ArraySegment <byte> buffer)
        {
            try
            {
                int bytesRead = 0;
                while (bytesRead < buffer.Count)
                {
                    int startIndex  = buffer.Offset + bytesRead;
                    int bytesToRead = buffer.Count - bytesRead;

                    if (_nextPacketBytesCountLeft == 0)
                    {
                        int tempLengthBytesToRead = PacketLengthBytesCount - _tempLengthBufferFill;
                        tempLengthBytesToRead = (bytesToRead < tempLengthBytesToRead) ? bytesToRead : tempLengthBytesToRead;
                        Buffer.BlockCopy(buffer.Array, startIndex, _tempLengthBuffer, _tempLengthBufferFill, tempLengthBytesToRead);

                        _tempLengthBufferFill += tempLengthBytesToRead;
                        if (_tempLengthBufferFill < PacketLengthBytesCount)
                        {
                            break;
                        }

                        startIndex  += tempLengthBytesToRead;
                        bytesToRead -= tempLengthBytesToRead;

                        _tempLengthBufferFill     = 0;
                        _nextPacketBytesCountLeft = _tempLengthBuffer.ToInt32();

                        if (_nextPacketDataBuffer == null || _nextPacketDataBuffer.Length < _nextPacketBytesCountLeft || _nextPacketStreamer == null)
                        {
                            _nextPacketDataBuffer = new byte[_nextPacketBytesCountLeft];
                            _nextPacketStreamer   = new TLStreamer(_nextPacketDataBuffer);
                        }

                        // Writing packet length.
                        _nextPacketStreamer.Write(_tempLengthBuffer);
                        _nextPacketBytesCountLeft -= PacketLengthBytesCount;
                        bytesRead += PacketLengthBytesCount;
                    }

                    bytesToRead = bytesToRead > _nextPacketBytesCountLeft ? _nextPacketBytesCountLeft : bytesToRead;

                    _nextPacketStreamer.Write(buffer.Array, startIndex, bytesToRead);

                    bytesRead += bytesToRead;
                    _nextPacketBytesCountLeft -= bytesToRead;

                    if (_nextPacketBytesCountLeft > 0)
                    {
                        break;
                    }

                    var packet = new TcpTransportPacket(_nextPacketDataBuffer, 0, (int)_nextPacketStreamer.Position);

                    await ProcessReceivedPacket(packet);

                    _nextPacketBytesCountLeft    = 0;
                    _nextPacketStreamer.Position = 0;
                }
            }
            catch (Exception)
            {
                if (_nextPacketStreamer != null)
                {
                    _nextPacketStreamer.Dispose();
                    _nextPacketStreamer = null;
                }
                _nextPacketDataBuffer     = null;
                _nextPacketBytesCountLeft = 0;

                throw;
            }
        }
 /// <summary>
 ///     Initializes a new instance of the <see cref="TLSerializationContext" /> class.
 /// </summary>
 /// <param name="rig">TL rig.</param>
 /// <param name="streamer">TL streamer.</param>
 public TLSerializationContext(TLRig rig, TLStreamer streamer)
 {
     Rig = rig;
     Streamer = streamer;
 }
 /// <summary>
 ///     Initializes a new instance of the <see cref="TLSerializationContext" /> class.
 /// </summary>
 /// <param name="rig">TL rig.</param>
 /// <param name="streamer">TL streamer.</param>
 public TLSerializationContext(TLRig rig, TLStreamer streamer)
 {
     Rig      = rig;
     Streamer = streamer;
 }
Exemple #29
0
        /// <summary>
        ///     Processes incoming message bytes.
        /// </summary>
        /// <param name="messageBytes">Incoming bytes.</param>
        private async void ProcessIncomingMessageBytes(byte[] messageBytes)
        {
            TLStreamer streamer = null;

            try
            {
                Log.Debug("Processing incoming message.");
                streamer = new TLStreamer(messageBytes);
                if (messageBytes.Length == 4)
                {
                    int error = streamer.ReadInt32();
                    Log.Debug("Received error code: {0}.", error);
                    return;
                }
                else if (messageBytes.Length < 20)
                {
                    throw new InvalidMessageException(
                              string.Format("Invalid message length: {0} bytes. Expected to be at least 20 bytes for message or 4 bytes for error code.", messageBytes.Length));
                }

                ulong authKeyId = streamer.ReadUInt64();
                if (authKeyId == 0)
                {
                    // Assume the message bytes has a plain (unencrypted) message.
                    Log.Debug(string.Format("Auth key ID = 0x{0:X16}. Assume this is a plain (unencrypted) message.", authKeyId));

                    // Reading message ID.
                    ulong messageId = streamer.ReadUInt64();
                    if (!IsIncomingMessageIdValid(messageId))
                    {
                        throw new InvalidMessageException(string.Format("Message ID = 0x{0:X16} is invalid.", messageId));
                    }

                    // Reading message data length.
                    int messageDataLength = streamer.ReadInt32();
                    if (messageDataLength <= 0)
                    {
                        throw new InvalidMessageException("Message data length must be greater than zero.");
                    }

                    // Reading message data.
                    var messageData = new byte[messageDataLength]; // TODO: consider reusing of byte arrays.
                    int read        = await streamer.ReadAsync(messageData, 0, messageDataLength, _connectionCancellationToken);

                    if (read != messageDataLength)
                    {
                        throw new InvalidMessageException(string.Format("Actual message data length ({0}) is not as expected ({1}).", read, messageDataLength));
                        // TODO: read message data if read is less than expected.
                    }

                    // Notify in-messages subject.
                    var message = new PlainMessage(messageId, messageData);

                    Log.Debug(string.Format("Received plain message. Message ID = 0x{0:X16}. Message data length: {1} bytes.", messageId, messageDataLength));

                    _inMessages.OnNext(message);
                }
                else
                {
                    // Assume the stream has an encrypted message.
                    Log.Debug(string.Format("Auth key ID = 0x{0:X16}. Assume this is encrypted message.", authKeyId));
                    if (!IsEncryptionSupported)
                    {
                        Log.Debug("Encryption is not supported by this connection.");
                        return;
                    }

                    var message = new EncryptedMessage(_authKey, messageBytes, Sender.Server, _hashServices, _encryptionServices);

                    Log.Debug(string.Format("Received encrypted message. Message ID = 0x{0:X16}. Message data length: {1} bytes.", message.MessageId, message.MessageDataLength));

                    _inMessages.OnNext(message);
                }
            }
            catch (Exception e)
            {
                Log.Error(e, "Failed to receive a message.");
            }
            finally
            {
                if (streamer != null)
                {
                    streamer.Dispose();
                }
            }
        }
Exemple #30
0
        public async void DoCommand(string[] args)
        {
            var command = args[0].ToLower();

            switch (command)
            {
            case "decrypt":
            {
                try
                {
                    var bytes = Convert.FromBase64String("+MW7Btpz31b0gt9WN5d5vAEAAAAVxLUcCwAAAMzG2AUAAAAAAQAAAA4xNDkuMTU0LjE3NS41MAC7AQAAzMbYBQEAAAABAAAAJzIwMDE6MGIyODpmMjNkOmYwMDE6MDAwMDowMDAwOjAwMDA6MDAwYbsBAADMxtgFAAAAAAIAAAAOMTQ5LjE1NC4xNjcuNTEAuwEAAMzG2AUBAAAAAgAAACcyMDAxOjA2N2M6MDRlODpmMDAyOjAwMDA6MDAwMDowMDAwOjAwMGG7AQAAzMbYBQAAAAADAAAADzE0OS4xNTQuMTc1LjEwMLsBAADMxtgFAQAAAAMAAAAnMjAwMTowYjI4OmYyM2Q6ZjAwMzowMDAwOjAwMDA6MDAwMDowMDBhuwEAAMzG2AUAAAAABAAAAA4xNDkuMTU0LjE2Ny45MQC7AQAAzMbYBQEAAAAEAAAAJzIwMDE6MDY3YzowNGU4OmYwMDQ6MDAwMDowMDAwOjAwMDA6MDAwYbsBAADMxtgFAgAAAAQAAAAPMTQ5LjE1NC4xNjUuMTIwuwEAAMzG2AUAAAAABQAAAA05MS4xMDguNTYuMTgwAAC7AQAAzMbYBQEAAAAFAAAAJzIwMDE6MGIyODpmMjNmOmYwMDU6MDAwMDowMDAwOjAwMDA6MDAwYbsBAADIAAAA6AMAAGQAAADA1AEAiBMAADB1AADgkwQAMHUAANwFAAAKAAAAYOoAAAIAAADIAAAAFcS1HAAAAAA=");
                    TLRig.Default.PrepareSerializersForAllTLObjectsInAssembly(typeof(IMTProtoAsyncMethods).Assembly);
                    using (var streamer = new TLStreamer(bytes))
                    {
                        var newResult = TLRig.Default.Deserialize(streamer);
                        int hi        = 5;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
            break;


            case "setup":
            {
                DebugPrint("Fetching nearest DC...");
                var telegramSettings = new TelegramSettings();
                var authInfo         = await FetchNewAuthentication(DefaultTransportConfig);

                using (var client = new TelegramClient(DefaultTransportConfig,
                                                       new ConnectionConfig(authInfo.AuthKey, authInfo.Salt), AppInfo))
                {
                    await client.Connect();

                    var nearestDcId = (NearestDc)await(client.Methods.HelpGetNearestDcAsync(new HelpGetNearestDcArgs {
                        }));
                    var config      = (Config)await(client.Methods.HelpGetConfigAsync(new HelpGetConfigArgs {
                        }));
                    var dcOption    = config.DcOptions.OfType <DcOption>().FirstOrDefault(x => x.Id == nearestDcId.NearestDcProperty);
                    telegramSettings.NearestDcId   = nearestDcId.NearestDcProperty;
                    telegramSettings.NearestDcIp   = dcOption.IpAddress;
                    telegramSettings.NearestDcPort = (int)dcOption.Port;
                }
                DebugPrint("Generating authentication on nearest DC...");
                var authInfo2 = await FetchNewAuthentication(
                    new TcpClientTransportConfig(telegramSettings.NearestDcIp, telegramSettings.NearestDcPort));

                telegramSettings.AuthKey = authInfo2.AuthKey;
                telegramSettings.Salt    = authInfo2.Salt;
                SettingsManager.Save(this, telegramSettings);
                DebugPrint("Great! Ready for the service to start.");
            }
            break;

            case "sendcode":
            {
                var number          = args[1];
                var transportConfig =
                    new TcpClientTransportConfig(_settings.NearestDcIp, _settings.NearestDcPort);
                using (var client = new TelegramClient(transportConfig,
                                                       new ConnectionConfig(_settings.AuthKey, _settings.Salt), AppInfo))
                {
                    await client.Connect();

                    var result = await client.Methods.AuthSendCodeAsync(new AuthSendCodeArgs
                        {
                            PhoneNumber = number,
                            ApiId       = AppInfo.ApiId,
                            ApiHash     = "f8f2562579817ddcec76a8aae4cd86f6",
                        });

                    DebugPrint(ObjectDumper.Dump(result));
                }
            }
            break;

            case "signin":
            {
                var number          = args[1];
                var hash            = args[2];
                var code            = args[3];
                var transportConfig =
                    new TcpClientTransportConfig(_settings.NearestDcIp, _settings.NearestDcPort);
                using (var client = new TelegramClient(transportConfig,
                                                       new ConnectionConfig(_settings.AuthKey, _settings.Salt), AppInfo))
                {
                    await client.Connect();

                    var result = (AuthAuthorization)await client.Methods.AuthSignInAsync(new AuthSignInArgs
                        {
                            PhoneNumber   = number,
                            PhoneCodeHash = hash,
                            PhoneCode     = code,
                        });

                    DebugPrint(ObjectDumper.Dump(result));
                }
            }
            break;

            case "signup":
            {
                var number          = args[1];
                var hash            = args[2];
                var code            = args[3];
                var firstName       = args[4];
                var lastName        = args[5];
                var transportConfig =
                    new TcpClientTransportConfig(_settings.NearestDcIp, _settings.NearestDcPort);
                using (var client = new TelegramClient(transportConfig,
                                                       new ConnectionConfig(_settings.AuthKey, _settings.Salt), AppInfo))
                {
                    await client.Connect();

                    var result = (AuthAuthorization)await client.Methods.AuthSignUpAsync(new AuthSignUpArgs
                        {
                            PhoneNumber   = number,
                            PhoneCodeHash = hash,
                            PhoneCode     = code,
                            FirstName     = firstName,
                            LastName      = lastName,
                        });

                    DebugPrint(ObjectDumper.Dump(result));
                }
            }
            break;

            case "getcontacts":
            {
                var result = await _fullClient.Methods.ContactsGetContactsAsync(new ContactsGetContactsArgs
                    {
                        Hash = string.Empty
                    });

                DebugPrint(ObjectDumper.Dump(result));
            }
            break;
//                case "sendhello":
//                    {
//                        var contacts = (ContactsContacts)await _fullClient.Methods.ContactsGetContactsAsync(new ContactsGetContactsArgs
//                        {
//                            Hash = string.Empty
//                        });
//                        var counter = 0;
//                        Console.WriteLine("Pick a contact:");
//                        foreach (var icontact in contacts.Users)
//                        {
//                            var contact = icontact as UserContact;
//                            if (contact == null)
//                                continue;
//                            Console.WriteLine(counter++ + ") " + contact.FirstName + " " + contact.LastName);
//                        }
//                        var choice = int.Parse(Console.ReadLine());
//                        var chosenContact = (UserContact)contacts.Users[choice];
//                        var result = await _fullClient.Methods.MessagesSendMessageAsync(new MessagesSendMessageArgs
//                        {
//                            Peer = new InputPeerContact
//                            {
//                                UserId = chosenContact.Id,
//                            },
//                            Message = "Hello from Disa!",
//                            RandomId = (ulong)Time.GetNowUnixTimestamp(),
//                        });
//                        Console.WriteLine(ObjectDumper.Dump(result));
//                    }
//                    break;
            }
        }