public void PackAuthData(byte[] outdata)
        {
            int outlength = 32;
            {
                byte[] randomdata = new byte[18];
                g_random.GetBytes(randomdata);
                randomdata.CopyTo(outdata, 4);
            }
            TlsAuthData authData = (TlsAuthData)this.Server.data;

            lock (authData)
            {
                if (authData.clientID == null)
                {
                    authData.clientID = new byte[32];
                    g_random.GetBytes(authData.clientID);
                }
            }
            UInt64 utc_time_second = (UInt64)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);
            UInt32 utc_time        = (UInt32)(utc_time_second);

            byte[] time_bytes = BitConverter.GetBytes(utc_time);
            Array.Reverse(time_bytes);
            Array.Copy(time_bytes, 0, outdata, 0, 4);

            hmac_sha1(outdata, outlength);
        }
        public override byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength)
        {
            if (handshake_status == -1)
            {
                SentLength += datalength;
                outlength   = datalength;
                return(encryptdata);
            }
            byte[] outdata = new byte[datalength + 4096];
            if (handshake_status == 8)
            {
                int start = 0;
                outlength = 0;
                while (send_id <= 4 && datalength - start > 256)
                {
                    int len = random.Next(512) + 64;
                    if (len > datalength - start)
                    {
                        len = datalength - start;
                    }
                    PackData(encryptdata, ref start, len, outdata, ref outlength);
                }
                while (datalength - start > 2048)
                {
                    int len = random.Next(4096) + 100;
                    if (len > datalength - start)
                    {
                        len = datalength - start;
                    }
                    PackData(encryptdata, ref start, len, outdata, ref outlength);
                }
                if (datalength - start > 0)
                {
                    PackData(encryptdata, ref start, datalength - start, outdata, ref outlength);
                }
            }
            else if (handshake_status == 1)
            {
                outlength = 0;
                if (datalength > 0)
                {
                    byte[] data = new byte[datalength + 5];
                    data[0] = 0x17;
                    data[1] = 0x3;
                    data[2] = 0x3;
                    data[3] = (byte)(datalength >> 8);
                    data[4] = (byte)(datalength);
                    Array.Copy(encryptdata, 0, data, 5, datalength);
                    data_sent_buffer.Add(data);
                }
                else
                {
                    {
                        byte[] hmac_data = new byte[43];
                        byte[] rnd       = new byte[22];
                        random.NextBytes(rnd);

                        byte[] handshake_finish = System.Text.Encoding.ASCII.GetBytes("\x14\x03\x03\x00\x01\x01" + "\x16\x03\x03\x00\x20");
                        handshake_finish.CopyTo(hmac_data, 0);
                        rnd.CopyTo(hmac_data, handshake_finish.Length);

                        hmac_sha1(hmac_data, hmac_data.Length);

                        data_sent_buffer.Insert(0, hmac_data);
                        SentLength -= hmac_data.Length;
                    }
                    foreach (byte[] data in data_sent_buffer)
                    {
                        Util.Utils.SetArrayMinSize2(ref outdata, outlength + data.Length);
                        Array.Copy(data, 0, outdata, outlength, data.Length);
                        SentLength += data.Length;
                        outlength  += data.Length;
                    }
                    data_sent_buffer.Clear();
                    handshake_status = 8;
                }
            }
            else
            {
                byte[] rnd = new byte[32];
                PackAuthData(rnd);
                List <byte> ssl_buf = new List <byte>();
                List <byte> ext_buf = new List <byte>();
                string      str_buf = "001cc02bc02fcca9cca8cc14cc13c00ac014c009c013009c0035002f000a0100";
                ssl_buf.AddRange(rnd);
                ssl_buf.Add(32);
                ssl_buf.AddRange(((TlsAuthData)this.Server.data).clientID);
                ssl_buf.AddRange(to_bin(str_buf));

                str_buf = "ff01000100";
                ext_buf.AddRange(to_bin(str_buf));
                string host = Server.host;
                if (Server.param.Length > 0)
                {
                    string[] hosts = Server.param.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    if (hosts != null && hosts.Length > 0)
                    {
                        host = hosts[random.Next(hosts.Length)];
                        host = host.Trim(' ');
                    }
                }
                if (host != null && host.Length > 0 && host[host.Length - 1] >= '0' && host[host.Length - 1] <= '9' && Server.param.Length == 0)
                {
                    host = "";
                }
                ext_buf.AddRange(sni(host));
                string str_buf2 = "001700000023";
                ext_buf.AddRange(to_bin(str_buf2));
                {
                    TlsAuthData authData = (TlsAuthData)this.Server.data;
                    byte[]      ticket   = null;
                    lock (authData)
                    {
                        if (authData.ticket_buf == null)
                        {
                            authData.ticket_buf = new Dictionary <string, byte[]>();
                        }
                        if (!authData.ticket_buf.ContainsKey(host))
                        {
                            int ticket_size = random.Next(8, 26) * 16;
                            ticket = new byte[ticket_size];
                            g_random.GetBytes(ticket);
                            authData.ticket_buf[host] = ticket;
                        }
                        else
                        {
                            ticket = authData.ticket_buf[host];
                        }
                    }
                    ext_buf.Add((byte)(ticket.Length >> 8));
                    ext_buf.Add((byte)(ticket.Length & 0xff));
                    ext_buf.AddRange(ticket);
                }
                string str_buf3 = "000d0016001406010603050105030401040303010303020102030005000501000000000012000075500000000b00020100000a0006000400170018";
                str_buf3 += "00150066000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
                ext_buf.AddRange(to_bin(str_buf3));
                ext_buf.Insert(0, (byte)(ext_buf.Count % 256));
                ext_buf.Insert(0, (byte)((ext_buf.Count - 1) / 256));

                ssl_buf.AddRange(ext_buf);
                // client version
                ssl_buf.Insert(0, (byte)3); // version
                ssl_buf.Insert(0, (byte)3);
                // length
                ssl_buf.Insert(0, (byte)(ssl_buf.Count % 256));
                ssl_buf.Insert(0, (byte)((ssl_buf.Count - 1) / 256));
                ssl_buf.Insert(0, (byte)0);
                ssl_buf.Insert(0, (byte)1); // client hello
                // length
                ssl_buf.Insert(0, (byte)(ssl_buf.Count % 256));
                ssl_buf.Insert(0, (byte)((ssl_buf.Count - 1) / 256));
                //
                ssl_buf.Insert(0, (byte)0x1); // version
                ssl_buf.Insert(0, (byte)0x3);
                ssl_buf.Insert(0, (byte)0x16);
                for (int i = 0; i < ssl_buf.Count; ++i)
                {
                    outdata[i] = (byte)ssl_buf[i];
                }
                outlength = ssl_buf.Count;

                byte[] data = new byte[datalength + 5];
                data[0] = 0x17;
                data[1] = 0x3;
                data[2] = 0x3;
                data[3] = (byte)(datalength >> 8);
                data[4] = (byte)(datalength);
                Array.Copy(encryptdata, 0, data, 5, datalength);
                data_sent_buffer.Add(data);

                handshake_status = 1;
            }
            return(outdata);
        }