DoFinal() публичный Метод

public DoFinal ( byte output, int outOff ) : int
output byte
outOff int
Результат int
Пример #1
0
 private static byte[] DoFinal(CombinedHash ch)
 {
     byte[] bs = new byte[ch.GetDigestSize()];
     ch.DoFinal(bs, 0);
     return(bs);
 }
Пример #2
0
        private void processHandshake()
        {
            bool read;
            do
            {
                read = false;

                /*
                * We need the first 4 bytes, they contain type and length of
                * the message.
                */
                if (handshakeQueue.Available >= 4)
                {
                    byte[] beginning = new byte[4];
                    handshakeQueue.Read(beginning, 0, 4, 0);
                    MemoryStream bis = new MemoryStream(beginning, false);
                    short type = TlsUtilities.ReadUint8(bis);
                    int len = TlsUtilities.ReadUint24(bis);

                    /*
                    * Check if we have enough bytes in the buffer to read
                    * the full message.
                    */
                    if (handshakeQueue.Available >= (len + 4))
                    {
                        /*
                        * Read the message.
                        */
                        byte[] buf = new byte[len];
                        handshakeQueue.Read(buf, 0, len, 4);
                        handshakeQueue.RemoveData(len + 4);

                        /*
                        * If it is not a finished message, update our hashes
                        * we prepare for the finish message.
                        */
                        if (type != HP_FINISHED)
                        {
                            rs.hash1.BlockUpdate(beginning, 0, 4);
                            rs.hash2.BlockUpdate(beginning, 0, 4);
                            rs.hash1.BlockUpdate(buf, 0, len);
                            rs.hash2.BlockUpdate(buf, 0, len);
                        }

                        /*
                        * Now, parse the message.
                        */
                        MemoryStream inStr = new MemoryStream(buf, false);

                        /*
                        * Check the type.
                        */
                        switch (type)
                        {
                            case HP_CERTIFICATE:
                                switch (connection_state)
                                {
                                    case CS_SERVER_HELLO_RECEIVED:
                                        /*
                                        * Parse the certificates.
                                        */
                                        Certificate cert = Certificate.Parse(inStr);
                                        AssertEmpty(inStr);

                                        /*
                                        * Verify them.
                                        */
                                        if (!this.verifyer.IsValid(cert.GetCerts()))
                                        {
                                            this.FailWithError(AL_fatal, AP_user_canceled);
                                        }

                                        /*
                                        * We only support RSA certificates. Lets hope
                                        * this is one.
                                        */
                                        RsaPublicKeyStructure rsaKey = null;
                                        try
                                        {
                                            rsaKey = RsaPublicKeyStructure.GetInstance(
                                                cert.certs[0].TbsCertificate.SubjectPublicKeyInfo.GetPublicKey());
                                        }
                                        catch (Exception)
                                        {
                                            /*
                                            * Sorry, we have to fail ;-(
                                            */
                                            this.FailWithError(AL_fatal, AP_unsupported_certificate);
                                        }

                                        /*
                                        * Parse the servers public RSA key.
                                        */
                                        this.serverRsaKey = new RsaKeyParameters(
                                            false,
                                            rsaKey.Modulus,
                                            rsaKey.PublicExponent);

                                        connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
                                        read = true;
                                        break;
                                    default:
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                        break;
                                }
                                break;
                            case HP_FINISHED:
                                switch (connection_state)
                                {
                                    case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED:
                                        /*
                                        * Read the checksum from the finished message,
                                        * it has always 12 bytes.
                                        */
                                        byte[] receivedChecksum = new byte[12];
                                        TlsUtilities.ReadFully(receivedChecksum, inStr);
                                        AssertEmpty(inStr);

                                        /*
                                        * Calculate our owne checksum.
                                        */
                                        byte[] checksum = new byte[12];
                                        byte[] md5andsha1 = new byte[16 + 20];
                                        rs.hash2.DoFinal(md5andsha1, 0);
                                        TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum);

                                        /*
                                        * Compare both checksums.
                                        */
                                        for (int i = 0; i < receivedChecksum.Length; i++)
                                        {
                                            if (receivedChecksum[i] != checksum[i])
                                            {
                                                /*
                                                * Wrong checksum in the finished message.
                                                */
                                                this.FailWithError(AL_fatal, AP_handshake_failure);
                                            }
                                        }

                                        connection_state = CS_DONE;

                                        /*
                                        * We are now ready to receive application data.
                                        */
                                        this.appDataReady = true;
                                        read = true;
                                        break;
                                    default:
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                        break;
                                }
                                break;
                            case HP_SERVER_HELLO:
                                switch (connection_state)
                                {
                                    case CS_CLIENT_HELLO_SEND:
                                        /*
                                        * Read the server hello message
                                        */
                                        TlsUtilities.CheckVersion(inStr, this);

                                        /*
                                        * Read the server random
                                        */
                                        this.serverRandom = new byte[32];
                                        TlsUtilities.ReadFully(this.serverRandom, inStr);

                                        /*
                                        * Currenty, we don't support session ids
                                        */
                                        short sessionIdLength = TlsUtilities.ReadUint8(inStr);
                                        byte[] sessionId = new byte[sessionIdLength];
                                        TlsUtilities.ReadFully(sessionId, inStr);

                                        /*
                                        * Find out which ciphersuite the server has
                                        * choosen. If we don't support this ciphersuite,
                                        * the TlsCipherSuiteManager will throw an
                                        * exception.
                                        */
                                        this.choosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite(
                                            TlsUtilities.ReadUint16(inStr), this);

                                        /*
                                        * We support only the null compression which
                                        * means no compression.
                                        */
                                        short compressionMethod = TlsUtilities.ReadUint8(inStr);
                                        if (compressionMethod != 0)
                                        {
                                            this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter);
                                        }
                                        AssertEmpty(inStr);

                                        connection_state = CS_SERVER_HELLO_RECEIVED;
                                        read = true;
                                        break;
                                    default:
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                        break;
                                }
                                break;
                            case HP_SERVER_HELLO_DONE:
                                switch (connection_state)
                                {
                                    case CS_SERVER_CERTIFICATE_RECEIVED:
                                    case CS_SERVER_KEY_EXCHANGE_RECEIVED:

                                        // NB: Original code used case label fall-through
                                        if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
                                        {
                                            /*
                                            * There was no server key exchange message, check
                                            * that we are doing RSA key exchange.
                                            */
                                            if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA)
                                            {
                                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                            }
                                        }

                                        AssertEmpty(inStr);
                                        connection_state = CS_SERVER_HELLO_DONE_RECEIVED;

                                        /*
                                        * Send the client key exchange message, depending
                                        * on the key exchange we are using in our
                                        * ciphersuite.
                                        */
                                        short ke = this.choosenCipherSuite.KeyExchangeAlgorithm;

                                        switch (ke)
                                        {
                                            case TlsCipherSuite.KE_RSA:
                                                /*
                                                * We are doing RSA key exchange. We will
                                                * choose a pre master secret and send it
                                                * rsa encrypted to the server.
                                                *
                                                * Prepare pre master secret.
                                                */
                                                pms = new byte[48];
                                                pms[0] = 3;
                                                pms[1] = 1;
                                                random.NextBytes(pms, 2, 46);

                                                /*
                                                * Encode the pms and send it to the server.
                                                *
                                                * Prepare an Pkcs1Encoding with good random
                                                * padding.
                                                */
                                                RsaBlindedEngine rsa = new RsaBlindedEngine();
                                                Pkcs1Encoding encoding = new Pkcs1Encoding(rsa);
                                                encoding.Init(true, new ParametersWithRandom(this.serverRsaKey, this.random));
                                                byte[] encrypted = null;
                                                try
                                                {
                                                    encrypted = encoding.ProcessBlock(pms, 0, pms.Length);
                                                }
                                                catch (InvalidCipherTextException)
                                                {
                                                    /*
                                                    * This should never happen, only during decryption.
                                                    */
                                                    this.FailWithError(AL_fatal, AP_internal_error);
                                                }

                                                /*
                                                * Send the encrypted pms.
                                                */
                                                MemoryStream bos = new MemoryStream();
                                                TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, bos);
                                                TlsUtilities.WriteUint24(encrypted.Length + 2, bos);
                                                TlsUtilities.WriteUint16(encrypted.Length, bos);
                                                bos.Write(encrypted, 0, encrypted.Length);
                                                byte[] message = bos.ToArray();

                                                rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length);
                                                break;
                                            case TlsCipherSuite.KE_DHE_RSA:
                                                /*
                                                * Send the Client Key Exchange message for
                                                * DHE key exchange.
                                                */
                                                byte[] YcByte = this.Yc.ToByteArray();
                                                MemoryStream DHbos = new MemoryStream();
                                                TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, DHbos);
                                                TlsUtilities.WriteUint24(YcByte.Length + 2, DHbos);
                                                TlsUtilities.WriteUint16(YcByte.Length, DHbos);
                                                DHbos.Write(YcByte, 0, YcByte.Length);
                                                byte[] DHmessage = DHbos.ToArray();

                                                rs.WriteMessage((short)RL_HANDSHAKE, DHmessage, 0, DHmessage.Length);

                                                break;
                                            default:
                                                /*
                                                * Proble during handshake, we don't know
                                                * how to thandle this key exchange method.
                                                */
                                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                                break;

                                        }

                                        connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;

                                        /*
                                        * Now, we send change cipher state
                                        */
                                        byte[] cmessage = new byte[1];
                                        cmessage[0] = 1;
                                        rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length);

                                        connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;

                                        /*
                                        * Calculate the ms
                                        */
                                        this.ms = new byte[48];
                                        byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length];
                                        Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length);
                                        Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length);
                                        TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms);

                                        /*
                                        * Initialize our cipher suite
                                        */
                                        rs.writeSuite = this.choosenCipherSuite;
                                        rs.writeSuite.Init(this.ms, clientRandom, serverRandom);

                                        /*
                                        * Send our finished message.
                                        */
                                        byte[] checksum = new byte[12];
                                        byte[] md5andsha1 = new byte[16 + 20];
                                        rs.hash1.DoFinal(md5andsha1, 0);
                                        TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum);

                                        MemoryStream bos2 = new MemoryStream();
                                        TlsUtilities.WriteUint8(HP_FINISHED, bos2);
                                        TlsUtilities.WriteUint24(12, bos2);
                                        bos2.Write(checksum, 0, checksum.Length);
                                        byte[] message2 = bos2.ToArray();

                                        rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length);

                                        this.connection_state = CS_CLIENT_FINISHED_SEND;
                                        read = true;
                                        break;
                                    default:
                                        this.FailWithError(AL_fatal, AP_handshake_failure);
                                        break;
                                }
                                break;
                            case HP_SERVER_KEY_EXCHANGE:
                                switch (connection_state)
                                {
                                    case CS_SERVER_CERTIFICATE_RECEIVED:
                                        /*
                                        * Check that we are doing DHE key exchange
                                        */
                                        if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_DHE_RSA)
                                        {
                                            this.FailWithError(AL_fatal, AP_unexpected_message);
                                        }

                                        /*
                                        * Parse the Structure
                                        */
                                        int pLength = TlsUtilities.ReadUint16(inStr);
                                        byte[] pByte = new byte[pLength];
                                        TlsUtilities.ReadFully(pByte, inStr);

                                        int gLength = TlsUtilities.ReadUint16(inStr);
                                        byte[] gByte = new byte[gLength];
                                        TlsUtilities.ReadFully(gByte, inStr);

                                        int YsLength = TlsUtilities.ReadUint16(inStr);
                                        byte[] YsByte = new byte[YsLength];
                                        TlsUtilities.ReadFully(YsByte, inStr);

                                        int sigLength = TlsUtilities.ReadUint16(inStr);
                                        byte[] sigByte = new byte[sigLength];
                                        TlsUtilities.ReadFully(sigByte, inStr);

                                        this.AssertEmpty(inStr);

                                        /*
                                        * Verify the Signature.
                                        *
                                        * First, calculate the hash.
                                        */
                                        CombinedHash sigDigest = new CombinedHash();
                                        MemoryStream signedData = new MemoryStream();
                                        TlsUtilities.WriteUint16(pLength, signedData);
                                        signedData.Write(pByte, 0, pByte.Length);
                                        TlsUtilities.WriteUint16(gLength, signedData);
                                        signedData.Write(gByte, 0, gByte.Length);
                                        TlsUtilities.WriteUint16(YsLength, signedData);
                                        signedData.Write(YsByte, 0, YsByte.Length);
                                        byte[] signed = signedData.ToArray();

                                        sigDigest.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length);
                                        sigDigest.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length);
                                        sigDigest.BlockUpdate(signed, 0, signed.Length);
                                        byte[] hash = new byte[sigDigest.GetDigestSize()];
                                        sigDigest.DoFinal(hash, 0);

                                        /*
                                        * Now, do the RSA operation
                                        */
                                        RsaBlindedEngine rsa = new RsaBlindedEngine();
                                        Pkcs1Encoding encoding = new Pkcs1Encoding(rsa);
                                        encoding.Init(false, this.serverRsaKey);

                                        /*
                                        * The data which was signed
                                        */
                                        byte[] sigHash = null;

                                        try
                                        {
                                            sigHash = encoding.ProcessBlock(sigByte, 0, sigByte.Length);
                                        }
                                        catch (InvalidCipherTextException)
                                        {
                                            this.FailWithError(AL_fatal, AP_bad_certificate);
                                        }

                                        /*
                                        * Check if the data which was signed is equal to
                                        * the hash we calculated.
                                        */
                                        if (sigHash.Length != hash.Length)
                                        {
                                            this.FailWithError(AL_fatal, AP_bad_certificate);
                                        }

                                        for (int i = 0; i < sigHash.Length; i++)
                                        {
                                            if (sigHash[i] != hash[i])
                                            {
                                                this.FailWithError(AL_fatal, AP_bad_certificate);
                                            }
                                        }

                                        /*
                                        * OK, Signature was correct.
                                        *
                                        * Do the DH calculation.
                                        */
                                        BigInteger p = new BigInteger(1, pByte);
                                        BigInteger g = new BigInteger(1, gByte);
                                        BigInteger Ys = new BigInteger(1, YsByte);
                                        BigInteger x = new BigInteger(p.BitLength - 1, this.random);
                                        Yc = g.ModPow(x, p);
                                        this.pms = (Ys.ModPow(x, p)).ToByteArray();

                                        /*
                                        * Remove leading zero byte, if present.
                                        */
                                        if (this.pms[0] == 0)
                                        {
                                            byte[] tmp = new byte[this.pms.Length - 1];
                                            Array.Copy(this.pms, 1, tmp, 0, tmp.Length);
                                            this.pms = tmp;
                                        }

                                        this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;
                                        read = true;
                                        break;
                                    default:
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                        break;
                                }
                                break;
                            case HP_HELLO_REQUEST:
                            case HP_CLIENT_KEY_EXCHANGE:
                            case HP_CERTIFICATE_REQUEST:
                            case HP_CERTIFICATE_VERIFY:
                            case HP_CLIENT_HELLO:
                            default:
                                // We do not support this!
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;

                        }

                    }
                }
            }
            while (read);
        }
Пример #3
0
 private static byte[] DoFinal(CombinedHash ch)
 {
     byte[] bs = new byte[ch.GetDigestSize()];
     ch.DoFinal(bs, 0);
     return bs;
 }
Пример #4
0
        private void processHandshake()
        {
            bool read;

            do
            {
                read = false;

                /*
                 * We need the first 4 bytes, they contain type and length of
                 * the message.
                 */
                if (handshakeQueue.Available >= 4)
                {
                    byte[] beginning = new byte[4];
                    handshakeQueue.Read(beginning, 0, 4, 0);
                    MemoryStream bis  = new MemoryStream(beginning, false);
                    short        type = TlsUtilities.ReadUint8(bis);
                    int          len  = TlsUtilities.ReadUint24(bis);

                    /*
                     * Check if we have enough bytes in the buffer to read
                     * the full message.
                     */
                    if (handshakeQueue.Available >= (len + 4))
                    {
                        /*
                         * Read the message.
                         */
                        byte[] buf = new byte[len];
                        handshakeQueue.Read(buf, 0, len, 4);
                        handshakeQueue.RemoveData(len + 4);

                        /*
                         * If it is not a finished message, update our hashes
                         * we prepare for the finish message.
                         */
                        if (type != HP_FINISHED)
                        {
                            rs.hash1.BlockUpdate(beginning, 0, 4);
                            rs.hash2.BlockUpdate(beginning, 0, 4);
                            rs.hash1.BlockUpdate(buf, 0, len);
                            rs.hash2.BlockUpdate(buf, 0, len);
                        }

                        /*
                         * Now, parse the message.
                         */
                        MemoryStream inStr = new MemoryStream(buf, false);

                        /*
                         * Check the type.
                         */
                        switch (type)
                        {
                        case HP_CERTIFICATE:
                            switch (connection_state)
                            {
                            case CS_SERVER_HELLO_RECEIVED:
                                /*
                                 * Parse the certificates.
                                 */
                                Certificate cert = Certificate.Parse(inStr);
                                AssertEmpty(inStr);

                                /*
                                 * Verify them.
                                 */
                                if (!this.verifyer.IsValid(cert.GetCerts()))
                                {
                                    this.FailWithError(AL_fatal, AP_user_canceled);
                                }

                                /*
                                 * We only support RSA certificates. Lets hope
                                 * this is one.
                                 */
                                RsaPublicKeyStructure rsaKey = null;
                                try
                                {
                                    rsaKey = RsaPublicKeyStructure.GetInstance(
                                        cert.certs[0].TbsCertificate.SubjectPublicKeyInfo.GetPublicKey());
                                }
                                catch (Exception)
                                {
                                    /*
                                     * Sorry, we have to fail ;-(
                                     */
                                    this.FailWithError(AL_fatal, AP_unsupported_certificate);
                                }

                                /*
                                 * Parse the servers public RSA key.
                                 */
                                this.serverRsaKey = new RsaKeyParameters(
                                    false,
                                    rsaKey.Modulus,
                                    rsaKey.PublicExponent);

                                connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
                                read             = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_FINISHED:
                            switch (connection_state)
                            {
                            case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED:
                                /*
                                 * Read the checksum from the finished message,
                                 * it has always 12 bytes.
                                 */
                                byte[] receivedChecksum = new byte[12];
                                TlsUtilities.ReadFully(receivedChecksum, inStr);
                                AssertEmpty(inStr);

                                /*
                                 * Calculate our owne checksum.
                                 */
                                byte[] checksum   = new byte[12];
                                byte[] md5andsha1 = new byte[16 + 20];
                                rs.hash2.DoFinal(md5andsha1, 0);
                                TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum);

                                /*
                                 * Compare both checksums.
                                 */
                                for (int i = 0; i < receivedChecksum.Length; i++)
                                {
                                    if (receivedChecksum[i] != checksum[i])
                                    {
                                        /*
                                         * Wrong checksum in the finished message.
                                         */
                                        this.FailWithError(AL_fatal, AP_handshake_failure);
                                    }
                                }

                                connection_state = CS_DONE;

                                /*
                                 * We are now ready to receive application data.
                                 */
                                this.appDataReady = true;
                                read = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_SERVER_HELLO:
                            switch (connection_state)
                            {
                            case CS_CLIENT_HELLO_SEND:
                                /*
                                 * Read the server hello message
                                 */
                                TlsUtilities.CheckVersion(inStr, this);

                                /*
                                 * Read the server random
                                 */
                                this.serverRandom = new byte[32];
                                TlsUtilities.ReadFully(this.serverRandom, inStr);

                                /*
                                 * Currenty, we don't support session ids
                                 */
                                short  sessionIdLength = TlsUtilities.ReadUint8(inStr);
                                byte[] sessionId       = new byte[sessionIdLength];
                                TlsUtilities.ReadFully(sessionId, inStr);

                                /*
                                 * Find out which ciphersuite the server has
                                 * choosen. If we don't support this ciphersuite,
                                 * the TlsCipherSuiteManager will throw an
                                 * exception.
                                 */
                                this.choosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite(
                                    TlsUtilities.ReadUint16(inStr), this);

                                /*
                                 * We support only the null compression which
                                 * means no compression.
                                 */
                                short compressionMethod = TlsUtilities.ReadUint8(inStr);
                                if (compressionMethod != 0)
                                {
                                    this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter);
                                }
                                AssertEmpty(inStr);

                                connection_state = CS_SERVER_HELLO_RECEIVED;
                                read             = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_SERVER_HELLO_DONE:
                            switch (connection_state)
                            {
                            case CS_SERVER_CERTIFICATE_RECEIVED:
                            case CS_SERVER_KEY_EXCHANGE_RECEIVED:

                                // NB: Original code used case label fall-through
                                if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
                                {
                                    /*
                                     * There was no server key exchange message, check
                                     * that we are doing RSA key exchange.
                                     */
                                    if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA)
                                    {
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                    }
                                }

                                AssertEmpty(inStr);
                                connection_state = CS_SERVER_HELLO_DONE_RECEIVED;

                                /*
                                 * Send the client key exchange message, depending
                                 * on the key exchange we are using in our
                                 * ciphersuite.
                                 */
                                short ke = this.choosenCipherSuite.KeyExchangeAlgorithm;

                                switch (ke)
                                {
                                case TlsCipherSuite.KE_RSA:
                                    /*
                                     * We are doing RSA key exchange. We will
                                     * choose a pre master secret and send it
                                     * rsa encrypted to the server.
                                     *
                                     * Prepare pre master secret.
                                     */
                                    pms    = new byte[48];
                                    pms[0] = 3;
                                    pms[1] = 1;
                                    random.NextBytes(pms, 2, 46);

                                    /*
                                     * Encode the pms and send it to the server.
                                     *
                                     * Prepare an Pkcs1Encoding with good random
                                     * padding.
                                     */
                                    RsaBlindedEngine rsa      = new RsaBlindedEngine();
                                    Pkcs1Encoding    encoding = new Pkcs1Encoding(rsa);
                                    encoding.Init(true, new ParametersWithRandom(this.serverRsaKey, this.random));
                                    byte[] encrypted = null;
                                    try
                                    {
                                        encrypted = encoding.ProcessBlock(pms, 0, pms.Length);
                                    }
                                    catch (InvalidCipherTextException)
                                    {
                                        /*
                                         * This should never happen, only during decryption.
                                         */
                                        this.FailWithError(AL_fatal, AP_internal_error);
                                    }

                                    /*
                                     * Send the encrypted pms.
                                     */
                                    MemoryStream bos = new MemoryStream();
                                    TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, bos);
                                    TlsUtilities.WriteUint24(encrypted.Length + 2, bos);
                                    TlsUtilities.WriteUint16(encrypted.Length, bos);
                                    bos.Write(encrypted, 0, encrypted.Length);
                                    byte[] message = bos.ToArray();

                                    rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length);
                                    break;

                                case TlsCipherSuite.KE_DHE_RSA:
                                    /*
                                     * Send the Client Key Exchange message for
                                     * DHE key exchange.
                                     */
                                    byte[]       YcByte = this.Yc.ToByteArray();
                                    MemoryStream DHbos  = new MemoryStream();
                                    TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, DHbos);
                                    TlsUtilities.WriteUint24(YcByte.Length + 2, DHbos);
                                    TlsUtilities.WriteUint16(YcByte.Length, DHbos);
                                    DHbos.Write(YcByte, 0, YcByte.Length);
                                    byte[] DHmessage = DHbos.ToArray();

                                    rs.WriteMessage((short)RL_HANDSHAKE, DHmessage, 0, DHmessage.Length);

                                    break;

                                default:
                                    /*
                                     * Proble during handshake, we don't know
                                     * how to thandle this key exchange method.
                                     */
                                    this.FailWithError(AL_fatal, AP_unexpected_message);
                                    break;
                                }

                                connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;

                                /*
                                 * Now, we send change cipher state
                                 */
                                byte[] cmessage = new byte[1];
                                cmessage[0] = 1;
                                rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length);

                                connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;

                                /*
                                 * Calculate the ms
                                 */
                                this.ms = new byte[48];
                                byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length];
                                Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length);
                                Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length);
                                TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms);

                                /*
                                 * Initialize our cipher suite
                                 */
                                rs.writeSuite = this.choosenCipherSuite;
                                rs.writeSuite.Init(this.ms, clientRandom, serverRandom);

                                /*
                                 * Send our finished message.
                                 */
                                byte[] checksum   = new byte[12];
                                byte[] md5andsha1 = new byte[16 + 20];
                                rs.hash1.DoFinal(md5andsha1, 0);
                                TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum);

                                MemoryStream bos2 = new MemoryStream();
                                TlsUtilities.WriteUint8(HP_FINISHED, bos2);
                                TlsUtilities.WriteUint24(12, bos2);
                                bos2.Write(checksum, 0, checksum.Length);
                                byte[] message2 = bos2.ToArray();

                                rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length);

                                this.connection_state = CS_CLIENT_FINISHED_SEND;
                                read = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_handshake_failure);
                                break;
                            }
                            break;

                        case HP_SERVER_KEY_EXCHANGE:
                            switch (connection_state)
                            {
                            case CS_SERVER_CERTIFICATE_RECEIVED:
                                /*
                                 * Check that we are doing DHE key exchange
                                 */
                                if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_DHE_RSA)
                                {
                                    this.FailWithError(AL_fatal, AP_unexpected_message);
                                }

                                /*
                                 * Parse the Structure
                                 */
                                int    pLength = TlsUtilities.ReadUint16(inStr);
                                byte[] pByte   = new byte[pLength];
                                TlsUtilities.ReadFully(pByte, inStr);

                                int    gLength = TlsUtilities.ReadUint16(inStr);
                                byte[] gByte   = new byte[gLength];
                                TlsUtilities.ReadFully(gByte, inStr);

                                int    YsLength = TlsUtilities.ReadUint16(inStr);
                                byte[] YsByte   = new byte[YsLength];
                                TlsUtilities.ReadFully(YsByte, inStr);

                                int    sigLength = TlsUtilities.ReadUint16(inStr);
                                byte[] sigByte   = new byte[sigLength];
                                TlsUtilities.ReadFully(sigByte, inStr);

                                this.AssertEmpty(inStr);

                                /*
                                 * Verify the Signature.
                                 *
                                 * First, calculate the hash.
                                 */
                                CombinedHash sigDigest  = new CombinedHash();
                                MemoryStream signedData = new MemoryStream();
                                TlsUtilities.WriteUint16(pLength, signedData);
                                signedData.Write(pByte, 0, pByte.Length);
                                TlsUtilities.WriteUint16(gLength, signedData);
                                signedData.Write(gByte, 0, gByte.Length);
                                TlsUtilities.WriteUint16(YsLength, signedData);
                                signedData.Write(YsByte, 0, YsByte.Length);
                                byte[] signed = signedData.ToArray();

                                sigDigest.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length);
                                sigDigest.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length);
                                sigDigest.BlockUpdate(signed, 0, signed.Length);
                                byte[] hash = new byte[sigDigest.GetDigestSize()];
                                sigDigest.DoFinal(hash, 0);

                                /*
                                 * Now, do the RSA operation
                                 */
                                RsaBlindedEngine rsa      = new RsaBlindedEngine();
                                Pkcs1Encoding    encoding = new Pkcs1Encoding(rsa);
                                encoding.Init(false, this.serverRsaKey);

                                /*
                                 * The data which was signed
                                 */
                                byte[] sigHash = null;

                                try
                                {
                                    sigHash = encoding.ProcessBlock(sigByte, 0, sigByte.Length);
                                }
                                catch (InvalidCipherTextException)
                                {
                                    this.FailWithError(AL_fatal, AP_bad_certificate);
                                }

                                /*
                                 * Check if the data which was signed is equal to
                                 * the hash we calculated.
                                 */
                                if (sigHash.Length != hash.Length)
                                {
                                    this.FailWithError(AL_fatal, AP_bad_certificate);
                                }

                                for (int i = 0; i < sigHash.Length; i++)
                                {
                                    if (sigHash[i] != hash[i])
                                    {
                                        this.FailWithError(AL_fatal, AP_bad_certificate);
                                    }
                                }

                                /*
                                 * OK, Signature was correct.
                                 *
                                 * Do the DH calculation.
                                 */
                                BigInteger p  = new BigInteger(1, pByte);
                                BigInteger g  = new BigInteger(1, gByte);
                                BigInteger Ys = new BigInteger(1, YsByte);
                                BigInteger x  = new BigInteger(p.BitLength - 1, this.random);
                                Yc       = g.ModPow(x, p);
                                this.pms = (Ys.ModPow(x, p)).ToByteArray();

                                /*
                                 * Remove leading zero byte, if present.
                                 */
                                if (this.pms[0] == 0)
                                {
                                    byte[] tmp = new byte[this.pms.Length - 1];
                                    Array.Copy(this.pms, 1, tmp, 0, tmp.Length);
                                    this.pms = tmp;
                                }

                                this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;
                                read = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_HELLO_REQUEST:
                        case HP_CLIENT_KEY_EXCHANGE:
                        case HP_CERTIFICATE_REQUEST:
                        case HP_CERTIFICATE_VERIFY:
                        case HP_CLIENT_HELLO:
                        default:
                            // We do not support this!
                            this.FailWithError(AL_fatal, AP_unexpected_message);
                            break;
                        }
                    }
                }
            }while (read);
        }