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]); } } }
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)); }
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); }
public void Dispose() { if (_nonceStream != null) { _nonceStream.Dispose(); _nonceStream = null; } }
/// <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); }
/// <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)); } }
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); }
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); }
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); } }
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); } }
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)); }
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; } } }
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); }
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)); } }
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)); } }
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; }
/// <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> /// 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(); } } }
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; } }