Пример #1
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);
        }
Пример #2
0
        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));
        }
Пример #3
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]);
                }
            }
        }
Пример #4
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));
            }
        }