Provides utility methods.
예제 #1
0
        /// <summary>
        /// Decodes a <see cref="VncPixelFormat"/> from a <see cref="byte"/> array.
        /// </summary>
        /// <param name="buffer">
        /// The <see cref="byte"/> array which contains the <see cref="VncPixelFormat"/> data.
        /// </param>
        /// <param name="offset">
        /// The first index in the <paramref name="buffer"/> which contains the <see cref="VncPixelFormat"/>
        /// data.
        /// </param>
        /// <returns>
        /// A <see cref="VncPixelFormat"/> object.
        /// </returns>
        internal static VncPixelFormat Decode(byte[] buffer, int offset)
        {
            var bitsPerPixel   = buffer[offset + 0];
            var depth          = buffer[offset + 1];
            var isLittleEndian = buffer[offset + 2] == 0;
            var isPalettized   = buffer[offset + 3] == 0;
            var redBits        = BitsFromMax(VncUtility.DecodeUInt16BE(buffer, offset + 4));
            var greenBits      = BitsFromMax(VncUtility.DecodeUInt16BE(buffer, offset + 6));
            var blueBits       = BitsFromMax(VncUtility.DecodeUInt16BE(buffer, offset + 8));
            var redShift       = buffer[offset + 10];
            var greenShift     = buffer[offset + 11];
            var blueShift      = buffer[offset + 12];

            return(new VncPixelFormat(
                       bitsPerPixel,
                       depth,
                       redBits,
                       redShift,
                       greenBits,
                       greenShift,
                       blueBits,
                       blueShift,
                       isLittleEndian,
                       isPalettized));
        }
예제 #2
0
        /// <summary>
        /// Writes a <see cref="VncRectangle"/> to the current position in the stream and advances the position within the stream by 8 bytes.
        /// </summary>
        /// <param name="region">
        /// The <see cref="VncRectangle"/> to write to the stream.
        /// </param>
        public void SendRectangle(VncRectangle region)
        {
            var buffer = new byte[8];

            VncUtility.EncodeUInt16BE(buffer, 0, (ushort)region.X);
            VncUtility.EncodeUInt16BE(buffer, 2, (ushort)region.Y);
            VncUtility.EncodeUInt16BE(buffer, 4, (ushort)region.Width);
            VncUtility.EncodeUInt16BE(buffer, 6, (ushort)region.Height);
            this.Send(buffer);
        }
예제 #3
0
        void SendFramebufferUpdateRequest(bool incremental)
        {
            var p = new byte[10];

            p[0] = (byte)3; p[1] = (byte)(incremental ? 1 : 0);
            VncUtility.EncodeUInt16BE(p, 2, (ushort)0);
            VncUtility.EncodeUInt16BE(p, 4, (ushort)0);
            VncUtility.EncodeUInt16BE(p, 6, (ushort)Framebuffer.Width);
            VncUtility.EncodeUInt16BE(p, 8, (ushort)Framebuffer.Height);

            _c.Send(p);
        }
예제 #4
0
        /// <summary>
        /// 发送一个按键事件到VNC服务器,以指示已按下或释放了键。
        /// </summary>
        /// <param name="keysym">The X11 keysym of the key. 按键对应的 ASCII。</param>
        /// <param name="pressed"><c>true</c> for a key press event, or <c>false</c> for a key release event.</param>
        public void SendKeyEvent(int keysym, bool pressed)
        {
            var p = new byte[8];

            p[0] = (byte)4; p[1] = (byte)(pressed ? 1 : 0);
            VncUtility.EncodeUInt32BE(p, 4, (uint)keysym);

            if (IsConnected)
            {
                _c.Send(p);
            }
        }
예제 #5
0
        private void SendFramebufferUpdateRequest(bool incremental, int x, int y, int width, int height)
        {
            var p = new byte[10];

            p[0] = (byte)3;
            p[1] = (byte)(incremental ? 1 : 0);
            VncUtility.EncodeUInt16BE(p, 2, (ushort)x);
            VncUtility.EncodeUInt16BE(p, 4, (ushort)y);
            VncUtility.EncodeUInt16BE(p, 6, (ushort)width);
            VncUtility.EncodeUInt16BE(p, 8, (ushort)height);

            this.c.Send(p);
        }
예제 #6
0
 /// <summary>
 /// Serializes this <see cref="VncPixelFormat"/> to a <see cref="byte"/> array.
 /// </summary>
 /// <param name="buffer">
 /// The <see cref="byte"/> array to which to encode the <see cref="VncPixelFormat"/> object.
 /// </param>
 /// <param name="offset">
 /// The first <see cref="byte"/> at which to store the <see cref="VncPixelFormat"/> data.
 /// </param>
 internal void Encode(byte[] buffer, int offset)
 {
     buffer[offset + 0] = (byte)this.BitsPerPixel;
     buffer[offset + 1] = (byte)this.BitDepth;
     buffer[offset + 2] = (byte)(this.IsLittleEndian ? 0 : 1);
     buffer[offset + 3] = (byte)(this.IsPalettized ? 0 : 1);
     VncUtility.EncodeUInt16BE(buffer, offset + 4, this.RedMax);
     VncUtility.EncodeUInt16BE(buffer, offset + 6, this.GreenMax);
     VncUtility.EncodeUInt16BE(buffer, offset + 8, this.BlueMax);
     buffer[offset + 10] = (byte)this.RedShift;
     buffer[offset + 11] = (byte)this.GreenShift;
     buffer[offset + 12] = (byte)this.BlueShift;
 }
예제 #7
0
 internal void Encode(byte[] buffer, int offset)
 {
     buffer[offset + 0] = (byte)BitsPerPixel;
     buffer[offset + 1] = (byte)BitDepth;
     buffer[offset + 2] = (byte)(IsLittleEndian ? 0 : 1);
     buffer[offset + 3] = (byte)(IsPalettized ? 0 : 1);
     VncUtility.EncodeUInt16BE(buffer, offset + 4, (ushort)((1 << RedBits) - 1));
     VncUtility.EncodeUInt16BE(buffer, offset + 6, (ushort)((1 << GreenBits) - 1));
     VncUtility.EncodeUInt16BE(buffer, offset + 8, (ushort)((1 << BlueBits) - 1));
     buffer[offset + 10] = (byte)RedShift;
     buffer[offset + 11] = (byte)GreenShift;
     buffer[offset + 12] = (byte)BlueShift;
 }
예제 #8
0
        /// <summary>
        /// 向VNC服务端发送一个鼠标动作,点击鼠标按钮等
        /// </summary>
        /// <param name="x">鼠标的X坐标。</param>
        /// <param name="y">鼠标的Y坐标。</param>
        /// <param name="pressedButtons">
        ///     A bit mask of pressed mouse buttons, in X11 convention: 1 is left, 2 is middle, and 4 is right.
        ///     Mouse wheel scrolling is treated as a button event: 8 for up and 16 for down.
        /// </param>
        public void SendPointerEvent(int x, int y, int pressedButtons)
        {
            var p = new byte[6];

            p[0] = (byte)5; p[1] = (byte)pressedButtons;
            VncUtility.EncodeUInt16BE(p, 2, (ushort)x);
            VncUtility.EncodeUInt16BE(p, 4, (ushort)y);

            if (IsConnected)
            {
                _c.Send(p);
            }
        }
예제 #9
0
        /// <summary>
        /// Notifies the server that the local clipboard has changed.
        /// If you are implementing clipboard integration, use this to set the remote clipboard.
        /// </summary>
        /// <param name="data">The contents of the local clipboard.</param>
        public void SendLocalClipboardChange(string data)
        {
            Throw.If.Null(data, "data");

            var bytes = VncStream.EncodeString(data);

            var p = new byte[8 + bytes.Length];

            p[0] = (byte)6;
            VncUtility.EncodeUInt32BE(p, 4, (uint)bytes.Length);
            Array.Copy(bytes, 0, p, 8, bytes.Length);

            if (this.IsConnected)
            {
                this.c.Send(p);
            }
        }
예제 #10
0
        /// <summary>
        /// Notifies the server that the local clipboard has changed.
        /// If you are implementing clipboard integration, use this to set the remote clipboard.
        /// </summary>
        /// <param name="data">The contents of the local clipboard.</param>
        public void SendLocalClipboardChange(string data)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            var bytes = VncStream.EncodeString(data);

            var p = new byte[8 + bytes.Length];

            p[0] = (byte)6;
            VncUtility.EncodeUInt32BE(p, 4, (uint)bytes.Length);
            Array.Copy(bytes, 0, p, 8, bytes.Length);

            if (this.IsConnected)
            {
                this.c.Send(p);
            }
        }
예제 #11
0
 /// <summary>
 /// Writes a <see cref="uint"/> in big endian encoding to the current position in the stream and advances the position within the stream by four bytes.
 /// </summary>
 /// <param name="value">
 /// The <see cref="uint"/> to write to the stream.
 /// </param>
 public void SendUInt32BE(uint value)
 {
     this.Send(VncUtility.EncodeUInt32BE(value));
 }
예제 #12
0
 /// <summary>
 /// Writes a <see cref="ushort"/> in big endian encoding to the current position in the stream and advances the position within the stream by two bytes.
 /// </summary>
 /// <param name="value">
 /// The <see cref="ushort"/> to write to the stream.
 /// </param>
 public void SendUInt16BE(ushort value)
 {
     this.Send(VncUtility.EncodeUInt16BE(value));
 }
예제 #13
0
 /// <summary>
 /// Reads a <see cref="uint"/> in big-endian encoding from the stream and advances the
 /// position within the stream by two bytes.
 /// </summary>
 /// <returns>
 /// The <see cref="uint"/> which was read from the stream.
 /// </returns>
 public uint ReceiveUInt32BE()
 {
     return(VncUtility.DecodeUInt32BE(this.Receive(4), 0));
 }
예제 #14
0
 /// <summary>
 /// Reads a <see cref="ushort"/> in big-endian encoding from the stream and advances the
 /// position within the stream by two bytes.
 /// </summary>
 /// <returns>
 /// The <see cref="ushort"/> which was read from the stream.
 /// </returns>
 public ushort ReceiveUInt16BE()
 {
     return(VncUtility.DecodeUInt16BE(this.Receive(2), 0));
 }
예제 #15
0
        void HandleFramebufferUpdate()
        {
            _c.ReceiveByte(); // padding

            var numRects = _c.ReceiveUInt16BE();
            var rects    = new List <VncRectangle>();

            for (int i = 0; i < numRects; i++)
            {
                var r = _c.ReceiveRectangle();
                int x = r.X, y = r.Y, w = r.Width, h = r.Height;
                VncStream.SanityCheck(w > 0 && w < 0x8000);
                VncStream.SanityCheck(h > 0 && h < 0x8000);

                int fbW = Framebuffer.Width, fbH = Framebuffer.Height, bpp = Framebuffer.PixelFormat.BytesPerPixel;
                var inRange = w <= fbW && h <= fbH && x <= fbW - w && y <= fbH - h; byte[] pixels;

                var encoding = (VncEncoding)_c.ReceiveUInt32BE();
                switch (encoding)
                {
                case VncEncoding.Hextile:     // KVM seems to avoid this now that I support Zlib.
                    var background = new byte[bpp];
                    var foreground = new byte[bpp];

                    for (int ty = 0; ty < h; ty += 16)
                    {
                        int th = Math.Min(16, h - ty);
                        for (int tx = 0; tx < w; tx += 16)
                        {
                            int tw = Math.Min(16, w - tx);

                            var subencoding = _c.ReceiveByte();
                            pixels = AllocateFramebufferScratch(tw * th * bpp);

                            if (0 != (subencoding & 1))     // raw
                            {
                                _c.Receive(pixels, 0, tw * th * bpp);

                                if (inRange)
                                {
                                    lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x + tx, y + ty, tw, th, pixels); }
                                }
                            }
                            else
                            {
                                pixels = AllocateFramebufferScratch(tw * th * bpp);
                                if (0 != (subencoding & 2))
                                {
                                    background = _c.Receive(bpp);
                                }
                                if (0 != (subencoding & 4))
                                {
                                    foreground = _c.Receive(bpp);
                                }

                                int ptr = 0;
                                for (int pp = 0; pp < tw * th; pp++)
                                {
                                    for (int pe = 0; pe < bpp; pe++)
                                    {
                                        pixels[ptr++] = background[pe];
                                    }
                                }

                                int nsubrects = 0 != (subencoding & 8) ? _c.ReceiveByte() : 0;
                                if (nsubrects > 0)
                                {
                                    var subrectsColored = 0 != (subencoding & 16);
                                    for (int subrect = 0; subrect < nsubrects; subrect++)
                                    {
                                        var color = subrectsColored ? _c.Receive(bpp) : foreground;
                                        var srxy = _c.ReceiveByte(); var srwh = _c.ReceiveByte();
                                        int srx = (srxy >> 4) & 0xf, srw = ((srwh >> 4) & 0xf) + 1;
                                        int sry = (srxy >> 0) & 0xf, srh = ((srwh >> 0) & 0xf) + 1;
                                        if (srx + srw > tw || sry + srh > th)
                                        {
                                            continue;
                                        }

                                        for (int py = 0; py < srh; py++)
                                        {
                                            for (int px = 0; px < srw; px++)
                                            {
                                                int off = bpp * ((py + sry) * tw + (px + srx));
                                                for (int pe = 0; pe < bpp; pe++)
                                                {
                                                    pixels[off + pe] = color[pe];
                                                }
                                            }
                                        }
                                    }
                                }

                                lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x + tx, y + ty, tw, th, pixels); }
                            }
                        }
                    }
                    break;

                case VncEncoding.CopyRect:
                    var srcx = (int)_c.ReceiveUInt16BE();
                    var srcy = (int)_c.ReceiveUInt16BE();
                    if (srcx + w > fbW)
                    {
                        w = fbW - srcx;
                    }
                    if (srcy + h > fbH)
                    {
                        h = fbH - srcy;
                    }
                    if (w < 1 || h < 1)
                    {
                        continue;
                    }

                    pixels = AllocateFramebufferScratch(w * h * bpp);
                    lock (Framebuffer.SyncRoot)
                    {
                        CopyToGeneral(0, 0, w, h, pixels, srcx, srcy, fbW, fbH, Framebuffer.GetBuffer(), w, h);
                        CopyToFramebuffer(x, y, w, h, pixels);
                    }
                    break;

                case VncEncoding.Raw:
                    pixels = AllocateFramebufferScratch(w * h * bpp);
                    _c.Receive(pixels, 0, w * h * bpp);

                    if (inRange)
                    {
                        lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x, y, w, h, pixels); }
                    }
                    break;

                case VncEncoding.Zlib:
                    int bytesDesired = w * h * bpp;

                    int size = (int)_c.ReceiveUInt32BE(); VncStream.SanityCheck(size >= 0 && size < 0x10000000);
                    VncUtility.AllocateScratch(size, ref _zlibScratch);
                    _c.Receive(_zlibScratch, 0, size);

                    _zlibMemoryStream.Position = 0;
                    _zlibMemoryStream.Write(_zlibScratch, 0, size);
                    _zlibMemoryStream.SetLength(size);
                    _zlibMemoryStream.Position = 0;

                    if (_zlibInflater == null)     // Zlib has a two-byte header.
                    {
                        VncStream.SanityCheck(size >= 2); _zlibMemoryStream.Position = 2;
                        _zlibInflater = new DeflateStream(_zlibMemoryStream, CompressionMode.Decompress, false);
                    }

                    pixels = AllocateFramebufferScratch(bytesDesired);
                    for (int j = 0; j < bytesDesired;)
                    {
                        int count = 0;

                        try
                        {
                            count = _zlibInflater.Read(pixels, j, bytesDesired - j);
                        }
                        catch (InvalidDataException)
                        {
                            VncStream.Require(false,
                                              "Bad data compressed.",
                                              VncFailureReason.UnrecognizedProtocolElement);
                        }

                        VncStream.Require(count > 0,
                                          "No data compressed.",
                                          VncFailureReason.UnrecognizedProtocolElement);
                        j += count;
                    }

                    if (inRange)
                    {
                        lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x, y, w, h, pixels); }
                    }
                    break;

                case VncEncoding.PseudoDesktopSize:
                    Framebuffer = new VncFramebuffer(Framebuffer.Name, w, h, Framebuffer.PixelFormat);
                    continue;     // Don't call OnFramebufferChanged for this one.

                default:
                    VncStream.Require(false,
                                      "Unsupported encoding.",
                                      VncFailureReason.UnrecognizedProtocolElement);
                    break;
                }

                rects.Add(new VncRectangle(x, y, w, h));
            }

            if (rects.Count > 0)
            {
                OnFramebufferChanged(new FramebufferChangedEventArgs(rects));
            }
        }
예제 #16
0
 private byte[] AllocateFramebufferScratch(int bytes)
 {
     return(VncUtility.AllocateScratch(bytes, ref this.framebufferScratch));
 }
예제 #17
0
        private bool HandleFramebufferUpdate()
        {
            this.c.ReceiveByte(); // padding

            var numRects = this.c.ReceiveUInt16BE();
            var rects    = new List <VncRectangle>();
            var encoding = VncEncoding.DesktopSize;

            for (int i = 0; i < numRects; i++)
            {
                var r = this.c.ReceiveRectangle();
                int x = r.X, y = r.Y, w = r.Width, h = r.Height;
                VncStream.SanityCheck(w > 0 && w < 0x8000);
                VncStream.SanityCheck(h > 0 && h < 0x8000);

                int    fbW = this.Framebuffer.Width, fbH = this.Framebuffer.Height, bpp = this.Framebuffer.PixelFormat.BytesPerPixel;
                var    inRange = w <= fbW && h <= fbH && x <= fbW - w && y <= fbH - h;
                byte[] pixels;

                encoding = (VncEncoding)this.c.ReceiveUInt32BE();
                switch (encoding)
                {
                case VncEncoding.Hextile:     // KVM seems to avoid this now that I support Zlib.
                    var background = new byte[bpp];
                    var foreground = new byte[bpp];

                    for (int ty = 0; ty < h; ty += 16)
                    {
                        int th = Math.Min(16, h - ty);
                        for (int tx = 0; tx < w; tx += 16)
                        {
                            int tw = Math.Min(16, w - tx);

                            var subencoding = this.c.ReceiveByte();
                            pixels = this.AllocateFramebufferScratch(tw * th * bpp);

                            if ((subencoding & 1) != 0)
                            {
                                // raw
                                this.c.Receive(pixels, 0, tw * th * bpp);

                                if (inRange)
                                {
                                    lock (this.Framebuffer.SyncRoot)
                                    {
                                        this.CopyToFramebuffer(x + tx, y + ty, tw, th, pixels);
                                    }
                                }
                            }
                            else
                            {
                                pixels = this.AllocateFramebufferScratch(tw * th * bpp);
                                if ((subencoding & 2) != 0)
                                {
                                    background = this.c.Receive(bpp);
                                }

                                if ((subencoding & 4) != 0)
                                {
                                    foreground = this.c.Receive(bpp);
                                }

                                int ptr = 0;
                                for (int pp = 0; pp < tw * th; pp++)
                                {
                                    for (int pe = 0; pe < bpp; pe++)
                                    {
                                        pixels[ptr++] = background[pe];
                                    }
                                }

                                int nsubrects = (subencoding & 8) != 0 ? this.c.ReceiveByte() : 0;
                                if (nsubrects > 0)
                                {
                                    var subrectsColored = (subencoding & 16) != 0;
                                    for (int subrect = 0; subrect < nsubrects; subrect++)
                                    {
                                        var color = subrectsColored ? this.c.Receive(bpp) : foreground;
                                        var srxy = this.c.ReceiveByte();
                                        var srwh = this.c.ReceiveByte();
                                        int srx = (srxy >> 4) & 0xf, srw = ((srwh >> 4) & 0xf) + 1;
                                        int sry = (srxy >> 0) & 0xf, srh = ((srwh >> 0) & 0xf) + 1;
                                        if (srx + srw > tw || sry + srh > th)
                                        {
                                            continue;
                                        }

                                        for (int py = 0; py < srh; py++)
                                        {
                                            for (int px = 0; px < srw; px++)
                                            {
                                                int off = bpp * (((py + sry) * tw) + (px + srx));
                                                for (int pe = 0; pe < bpp; pe++)
                                                {
                                                    pixels[off + pe] = color[pe];
                                                }
                                            }
                                        }
                                    }
                                }

                                lock (this.Framebuffer.SyncRoot)
                                {
                                    this.CopyToFramebuffer(x + tx, y + ty, tw, th, pixels);
                                }
                            }
                        }
                    }

                    break;

                case VncEncoding.CopyRect:
                    var srcx = (int)this.c.ReceiveUInt16BE();
                    var srcy = (int)this.c.ReceiveUInt16BE();
                    if (srcx + w > fbW)
                    {
                        w = fbW - srcx;
                    }

                    if (srcy + h > fbH)
                    {
                        h = fbH - srcy;
                    }

                    if (w < 1 || h < 1)
                    {
                        continue;
                    }

                    pixels = this.AllocateFramebufferScratch(w * h * bpp);
                    lock (this.Framebuffer.SyncRoot)
                    {
                        this.CopyToGeneral(0, 0, w, h, pixels, srcx, srcy, fbW, fbH, this.Framebuffer.GetBuffer(), w, h);
                        this.CopyToFramebuffer(x, y, w, h, pixels);
                    }

                    break;

                case VncEncoding.Raw:
                    pixels = this.AllocateFramebufferScratch(w * h * bpp);
                    this.c.Receive(pixels, 0, w * h * bpp);

                    if (inRange)
                    {
                        lock (this.Framebuffer.SyncRoot)
                        {
                            this.CopyToFramebuffer(x, y, w, h, pixels);
                        }
                    }

                    break;

                case VncEncoding.Zlib:
                    int bytesDesired = w * h * bpp;

                    int size = (int)this.c.ReceiveUInt32BE();
                    VncStream.SanityCheck(size >= 0 && size < 0x10000000);
                    VncUtility.AllocateScratch(size, ref this.zlibScratch);
                    this.c.Receive(this.zlibScratch, 0, size);
                    pixels = Decompress(zlibScratch);


                    if (inRange)
                    {
                        lock (this.Framebuffer.SyncRoot)
                        {
                            this.CopyToFramebuffer(x, y, w, h, pixels);
                        }
                    }

                    break;

                case VncEncoding.PseudoDesktopSize:
                    this.Framebuffer = new VncFramebuffer(this.Framebuffer.Name, w, h, this.Framebuffer.PixelFormat);
                    continue;     // Don't call OnFramebufferChanged for this one.

                default:
                    VncStream.Require(
                        false,
                        "Unsupported encoding.",
                        VncFailureReason.UnrecognizedProtocolElement);
                    break;
                }

                rects.Add(new VncRectangle(x, y, w, h));
            }

            if (rects.Count > 0)
            {
                this.OnFramebufferChanged(new FramebufferChangedEventArgs(rects));
            }

            return(encoding != VncEncoding.DesktopSize);
        }
예제 #18
0
        void NegotiateSecurity()
        {
            int count = ReceiveByte();

            if (count == 0)
            {
                string message = ReceiveString().Trim('\0');
                Require(false, message, VncFailureReason.ServerOfferedNoAuthenticationMethods);
            }

            var types = new List <VncSecurityType>();

            for (int i = 0; i < count; i++)
            {
                types.Add((VncSecurityType)ReceiveByte());
            }

            if (types.Contains(VncSecurityType.None))
            {
                Send(new[] { (byte)VncSecurityType.None });
            }
            else if (types.Contains(VncSecurityType.Vnc))
            {
                if (_options.Password == null)
                {
                    OnPasswordRequired(new PasswordRequiredEventArgs(_options));
                    Require(_options.Password != null, "Password required.",
                            VncFailureReason.PasswordRequired);
                }

                Send(new[] { (byte)VncSecurityType.Vnc });

                var challenge = Receive(16);
                var response  = new byte[16];
                var password  = _options.Password;

                var key   = new byte[8];
                var bytes = Encoding.GetEncoding("iso-8859-1").GetBytes(password);

                try
                {
                    Array.Copy(bytes, 0, key, 0, Math.Min(bytes.Length, key.Length));
                    for (int i = 0; i < key.Length; i++)
                    {
                        key[i] = ReverseBits(key[i]);
                    }

                    using (var des = new DESCryptoServiceProvider()
                    {
                        Key = key, Mode = CipherMode.ECB
                    })
                        using (var encryptor = des.CreateEncryptor())
                        {
                            encryptor.TransformBlock(challenge, 0, 16, response, 0);
                            Send(response);
                        }
                }
                finally
                {
                    Array.Clear(bytes, 0, bytes.Length);
                    Array.Clear(key, 0, key.Length);
                    Array.Clear(response, 0, response.Length);
                }
            }
            else
            {
                Require(false, "No supported authentication methods.",
                        VncFailureReason.NoSupportedAuthenticationMethods);
            }

            uint status = VncUtility.DecodeUInt32BE(Receive(4), 0);

            if (status != 0)
            {
                string message = ReceiveString().Trim('\0');
                Require(false, message, VncFailureReason.AuthenticationFailed);
            }
        }