Exemplo n.º 1
0
 /// <summary>
 /// Processes and stores the clients primary-stage Symmetric <see cref="KeyParams"/>, 
 /// decrypted with the servers <see cref="IAsymmetricKeyPair">Asymmetric KeyPair</see>.
 /// </summary>
 /// 
 /// <param name="PacketStream">A Stream containing the raw packet data</param>
 private void ProcessPrimary(MemoryStream PacketStream)
 {
     // get the header
     DtmPacket pktHdr = new DtmPacket(PacketStream);
     // read the data
     byte[] data = new byte[pktHdr.PayloadLength];
     PacketStream.Read(data, 0, data.Length);
     // decrypt using the auth stage symmetric key
     data = SymmetricTransform(_cltSymProcessor, data);
     // remove random padding
     data = UnwrapMessage(data);
     // decrypt the symmetric key using the primary asymmetric cipher
     byte[] dec = AsymmetricDecrypt(_srvAsmParams, _primKeyPair, data);
     // clear auth key
     _cltKeyParams.Dispose();
     // deserialize the primary session key
     _cltKeyParams = KeyParams.DeSerialize(new MemoryStream(dec));
 }
Exemplo n.º 2
0
 /// <summary>
 /// Processes the clients Primary-Stage <see cref="IAsymmetricKey">AsymmetricKey</see> Public key.
 /// </summary>
 /// 
 /// <param name="PacketStream">A Stream containing the raw packet data</param>
 private void ProcessPrimeEx(MemoryStream PacketStream)
 {
     // get the header
     DtmPacket pktHdr = new DtmPacket(PacketStream);
     // read the data
     byte[] data = new byte[pktHdr.PayloadLength];
     PacketStream.Read(data, 0, data.Length);
     // use clients symmetric key to decrypt data
     byte[] dec = SymmetricTransform(_cltSymProcessor, data);
     // remove padding
     dec = UnwrapMessage(dec);
     MemoryStream cltStream = new MemoryStream(dec);
     // store the clients public key
     _cltPublicKey = GetAsymmetricPublicKey(cltStream, _cltAsmParams);
 }
Exemplo n.º 3
0
        /// <summary>
        /// Process the clients private identity.
        /// <para>Decrypts and stores the clients private identity using the clients Auth-Stage Symmetric Key.</para>
        /// </summary>
        /// 
        /// <param name="PacketStream">A Stream containing the raw packet data</param>
        private void ProcessAuth(MemoryStream PacketStream)
        {
            // get the header
            DtmPacket pktHdr = new DtmPacket(PacketStream);
            byte[] data = new byte[pktHdr.PayloadLength];
            PacketStream.Read(data, 0, data.Length);
            // create the clients auth-stage symmetric cipher
            _cltSymProcessor = SymmetricInit(_cltIdentity.Session, _cltKeyParams);
            // decrypt the payload
            byte[] dec = SymmetricTransform(_cltSymProcessor, data);
            // remove random padding
            dec = UnwrapMessage(dec);
            // get the clients private id
            _cltIdentity = new DtmIdentity(new MemoryStream(dec));

            // notify user
            long resp = 0;
            if (IdentityReceived != null)
            {
                DtmIdentityEventArgs args = new DtmIdentityEventArgs(DtmExchangeFlags.Auth, resp, _cltIdentity);
                IdentityReceived(this, args);
                resp = args.Flag;
                if (args.Cancel)
                {
                    // back out of session
                    TearDown();
                }
            }
        }
Exemplo n.º 4
0
 /// <summary>
 /// Processes and stores the clients Auth-Stage Symmetric <see cref="KeyParams"/>, 
 /// decrypted with the servers <see cref="IAsymmetricKeyPair">Asymmetric KeyPair</see>.
 /// </summary>
 /// 
 /// <param name="PacketStream">A Stream containing the raw packet data</param>
 private void ProcessAuthEx(MemoryStream PacketStream)
 {
     // get the header
     DtmPacket pktHdr = new DtmPacket(PacketStream);
     // read the data
     byte[] data = new byte[pktHdr.PayloadLength];
     PacketStream.Read(data, 0, data.Length);
     // decrypt the symmetric key
     byte[] dec = AsymmetricDecrypt(_srvAsmParams, _authKeyPair, data);
     // deserialize the keyparams structure
     _cltKeyParams = KeyParams.DeSerialize(new MemoryStream(dec));
 }
Exemplo n.º 5
0
        /// <summary>
        /// Resend a packet to a host
        /// </summary>
        private void Resend(DtmPacket Packet)
        {
            if (_sndBuffer.Exists(Packet.Sequence))
            {
                _maxSendCounter++;

                // limit attack scope with session resend max
                if (_maxSendCounter > MaxResend)
                {
                    // let the app decide what to do next
                    DtmErrorEventArgs args = new DtmErrorEventArgs(new InvalidDataException("The stream has encountered data loss, attempting to resync.."), DtmErrorSeverity.DataLoss);
                    if (SessionError != null)
                        SessionError(this, args);

                    if (args.Cancel)
                    {
                        Disconnect();
                        return;
                    }
                }

                try
                {
                    MemoryStream pktStm = _sndBuffer.Peek(Packet.Sequence);
                    if (pktStm != null)
                    {
                        if (pktStm.Length > 0)
                            pktStm.WriteTo(_clientSocket.TcpStream);

                        _sndSequence++;
                    }
                }
                catch
                {
                    // packet lost, request a resync
                    Transmit(DtmPacketTypes.Service, (short)DtmServiceFlags.DataLost);
                }
            }
            else
            {
                // packet lost, request a resync
                Transmit(DtmPacketTypes.Service, (short)DtmServiceFlags.DataLost);
            }
        }
Exemplo n.º 6
0
 /// <summary>
 /// Creates a serialized request packet (DtmPacket)
 /// </summary>
 private MemoryStream CreateRequest(DtmPacketTypes Message, short State)
 {
     MemoryStream ret = new DtmPacket(Message, 0, 0, State).ToStream();
     ret.Seek(0, SeekOrigin.Begin);
     return ret;
 }
Exemplo n.º 7
0
        /// <summary>
        /// Used to read a blocking message response
        /// </summary>
        private MemoryStream BlockingReceive()
        {
            MemoryStream pktStm = null;

            try
            {
                // get the header
                pktStm = _clientSocket.GetStreamData(DtmPacket.GetHeaderSize(), EXCHTIMEOUT);
                DtmPacket pktHdr = new DtmPacket(pktStm);

                // add the payload
                if (pktHdr.PayloadLength > 0)
                    _clientSocket.GetStreamData((int)pktHdr.PayloadLength, EXCHTIMEOUT).WriteTo(pktStm);

                pktStm.Seek(0, SeekOrigin.Begin);
            }
            catch (ObjectDisposedException)
            {
                // host is disconnected, notify app
                DtmErrorEventArgs args = new DtmErrorEventArgs(new SocketException((int)SocketError.HostDown), DtmErrorSeverity.Connection);
                if (SessionError != null)
                    SessionError(this, args);

                if (args.Cancel == true)
                    Disconnect();
            }

            if (pktStm == null || pktStm.Length == 0)
            {
                // exchange failed

                if (SessionError != null)
                    SessionError(this, new DtmErrorEventArgs(new SocketException((int)SocketError.HostUnreachable), DtmErrorSeverity.Critical));

                Disconnect();
            }

            return pktStm;
        }
Exemplo n.º 8
0
        /// <summary>
        /// Used Post-Exchange to setup a file transfer from the remote host
        /// </summary>
        /// 
        /// <param name="PacketStream">The stream containing the file transfer request</param>
        private void ReceiveFile(Stream PacketStream)
        {
            // asynchronous transfer by sending a file key and info, and running the entire transfer on another socket..
            if (!_isEstablished)
                throw new CryptoProcessingException("DtmKex:ReceiveFile", "The VPN has not been established!", new InvalidOperationException());
            if (FileRequest == null)
                throw new CryptoProcessingException("DtmKex:ReceiveFile", "The FileRequest and FileReceived must be connected to perform a file transfer, read the documentation!", new InvalidOperationException());
            if (FileReceived == null)
                throw new CryptoProcessingException("DtmKex:ReceiveFile", "The FileRequest and FileReceived must be connected to perform a file transfer, read the documentation!", new InvalidOperationException());

            // get the header
            DtmPacket pktHdr = new DtmPacket(PacketStream);
            // read the packet
            byte[] enc = new byte[pktHdr.PayloadLength];
            // get the encrypted data
            PacketStream.Read(enc, 0, enc.Length);
            // decrypt it using client crypto processor
            byte[] dec = SymmetricTransform(_cltSymProcessor, enc);
            // remove padding
            dec = UnwrapMessage(dec);
            MemoryStream pktStm = new MemoryStream(dec);

            // get file info header
            DtmFileInfo pktFi = new DtmFileInfo(pktStm);
            // get the key
            KeyParams fileKey = KeyParams.DeSerialize(pktStm);

            // forward request to app
            DtmFileRequestEventArgs args = new DtmFileRequestEventArgs(pktFi.FileName);
            FileRequest(this, args);

            // accept file or refuse and exit; app must send back a valid path or cancel; if cancel, send a refuse notice which will signal the end of the transfer, otherwise store file path and port
            if (args.Cancel || string.IsNullOrEmpty(args.FilePath) || args.FilePath.Equals(pktFi.FileName) || !Directory.Exists(Path.GetDirectoryName(args.FilePath)))
            {
                // send refuse and exit
                Transmit(DtmPacketTypes.Transfer, (short)DtmTransferFlags.Refused, pktHdr.OptionFlag);
            }
            else
            {
                // create the files crypto processor
                ICipherMode fileSymProcessor = SymmetricInit(_cltIdentity.Session, fileKey);
                // enable parallel decryption
                int blockSize = ((int)MessageBufferSize - DtmPacket.GetHeaderSize()) - ((int)MessageBufferSize - DtmPacket.GetHeaderSize()) % ((CTR)fileSymProcessor).ParallelMinimumSize;
                ((CTR)fileSymProcessor).ParallelBlockSize = blockSize;

                // init the file transfer host
                DtmFileTransfer fileTransfer = new DtmFileTransfer(fileSymProcessor, pktHdr.OptionFlag, 1024, (int)FileBufferSize);
                fileTransfer.FileTransferred += new DtmFileTransfer.FileTransferredDelegate(OnFileReceived);
                fileTransfer.ProgressPercent += new DtmFileTransfer.ProgressDelegate(OnFileReceivedProgress);
                // add to dictionary
                _transQueue.TryAdd(pktHdr.OptionFlag, fileTransfer);

                try
                {
                    // start the transfer on a new thread
                    Task socketTask = Task.Factory.StartNew(() =>
                    {
                        fileTransfer.StartReceive(_clientSocket.RemoteAddress, (int)pktFi.OptionsFlag, args.FilePath);
                    });
                    socketTask.Wait(10);
                }
                catch (AggregateException ae)
                {
                    if (SessionError != null)
                        SessionError(this, new DtmErrorEventArgs(ae.GetBaseException(), DtmErrorSeverity.Warning));
                }
            }
        }
Exemplo n.º 9
0
        private void Transmit(DtmPacketTypes PacketType, short PacketFlag, long OptionFlag = 0, MemoryStream Payload = null)
        {
            lock (_sndLock)
            {
                long pldLen = Payload == null ? 0 : Payload.Length;
                // create a new packet: packet flag, payload size, sequence, and state flag
                MemoryStream pktStm = new DtmPacket(PacketType, pldLen, _sndSequence, PacketFlag, OptionFlag).ToStream();

                // add payload
                if (Payload != null)
                {
                    // copy to output
                    pktStm.Seek(0, SeekOrigin.End);
                    Payload.WriteTo(pktStm);
                    pktStm.Seek(0, SeekOrigin.Begin);
                }

                // store in the file packet buffer
                _sndBuffer.Push(_sndSequence, pktStm);
                // increment file send counter
                _sndSequence++;

                // transmit to remote client
                if (_clientSocket.IsConnected)
                {
                    try
                    {
                        _clientSocket.SendAsync(pktStm);
                    }
                    catch (CryptoSocketException ce)
                    {
                        SocketException se = ce.InnerException as SocketException;

                        if (se.SocketErrorCode == SocketError.WouldBlock ||
                            se.SocketErrorCode == SocketError.IOPending ||
                            se.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                        {
                            // buffer is full, throttle down
                            Throttle(pktStm);
                        }
                        else
                        {
                            // possible connection dropped, alert app
                            if (SessionError != null)
                            {
                                DtmErrorEventArgs args = new DtmErrorEventArgs(ce, DtmErrorSeverity.Connection);
                                SessionError(this, args);
                            }
                        }
                    }
                    catch (Exception)
                    {

                    }

                    // notify app
                    if (PacketSent != null)
                        PacketSent(this, new DtmPacketEventArgs((short)DtmTransferFlags.DataChunk, pldLen));
                }
            }
        }
Exemplo n.º 10
0
        /// <summary>
        /// Blocking transceiver; sends a packet and waits for a response.
        /// <para>For use with time sensitive data, that requires fast synchronous processing.
        /// Sent and received packets are not queued or buffered.</para>
        /// </summary>
        /// 
        /// <param name="DataStream">The payload data to send to the remote host</param>
        /// <param name="TimeOut">The number of milliseconds to wait before timing out (default is infinite)</param>
        /// 
        /// <returns>The return streams decrypted payload data, or an empty stream on failure</returns>
        public MemoryStream SendReceive(MemoryStream DataStream, int TimeOut = Timeout.Infinite)
        {
            if (!_isEstablished)
                throw new CryptoProcessingException("DtmKex:SendReceive", "The VPN is not established!", new InvalidOperationException());

            byte[] data = DataStream.ToArray();
            // append/prepend random
            data = WrapMessage(data, _dtmParameters.MaxMessageAppend, _dtmParameters.MaxMessagePrePend);
            // encrypt the data with the clients symmetric processor
            byte[] enc = SymmetricTransform(_srvSymProcessor, data);
            // store total bytes sent
            _bytesSent += enc.Length;

            // optional delay before transmission
            if (_dtmParameters.MaxMessageDelayMS > 0)
                SendWait(_dtmParameters.MaxMessageDelayMS);

            // create the packet
            MemoryStream pktStm = new DtmPacket(DtmPacketTypes.Message, enc.Length, _sndSequence, (short)DtmMessageFlags.Transmission).ToStream();
            pktStm.Seek(0, SeekOrigin.End);
            pktStm.Write(enc, 0, enc.Length);
            pktStm.Seek(0, SeekOrigin.Begin);
            // transmit data
            _clientSocket.Send(pktStm);
            _sndSequence++;

            // wait for response
            pktStm = BlockingReceive();
            // get the header
            DtmPacket dtmHdr = new DtmPacket(pktStm);
            // payload buffer
            data = new byte[dtmHdr.PayloadLength];
            // copy data to buffer
            pktStm.Write(data, 0, data.Length);
            // decrypt response
            data = SymmetricTransform(_cltSymProcessor, data);
            // remove padding
            data = UnwrapMessage(data);
            // increment rcv counter
            _rcvSequence++;
            // record encrypted byte count for resync
            _bytesReceived += dtmHdr.PayloadLength;

            return new MemoryStream(data);
        }
Exemplo n.º 11
0
 private void Resend(DtmPacket PacketHeader)
 {
     if (_sndBuffer.Exists(PacketHeader.Sequence))
     {
         MemoryStream pktStm = _sndBuffer.Peek(PacketHeader.Sequence);
         if (pktStm != null)
         {
             if (pktStm.Length > 0)
                 pktStm.WriteTo(_clientSocket.TcpStream);
         }
     }
 }
Exemplo n.º 12
0
        private void Receive(Stream PacketStream)
        {
            // get the packet header
            DtmPacket prcPacket = new DtmPacket(PacketStream);
            // read the packet
            byte[] enc = new byte[prcPacket.PayloadLength];
            // get the encrypted data
            PacketStream.Read(enc, 0, enc.Length);
            // decrypt it using file crypto processor
            byte[] dec = SymmetricTransform(_fileSymProcessor, enc);
            // get file info header
            DtmFileInfo pktFi = new DtmFileInfo(dec);
            // store file name and size
            string fileName = pktFi.FileName;
            long fileSize = pktFi.FileSize;
            long streamLen = 0;

            try
            {
                using (FileStream outStream = new FileStream(_tempPath, FileMode.Append, FileAccess.Write, FileShare.Read))
                {
                    // calculate offsets
                    int hdrSize = pktFi.GetHeaderSize();
                    int len = dec.Length - hdrSize;
                    // write to file
                    outStream.Write(ArrayUtils.GetRange(dec, hdrSize, len), 0, len);
                    // store length
                    streamLen = outStream.Length;

                    // progress
                    if (ProgressPercent != null)
                    {
                        double progress = 100.0 * (double)pktFi.OptionsFlag / fileSize;
                        ProgressPercent(this, new System.ComponentModel.ProgressChangedEventArgs((int)progress, (object)fileSize));
                    }
                }

                // transfer completed
                if (streamLen == fileSize)
                {
                    // reset attributes
                    File.SetAttributes(_tempPath, File.GetAttributes(_tempPath) & ~FileAttributes.Hidden);
                    // rename the file
                    File.Move(_tempPath, VTDev.Libraries.CEXEngine.Tools.FileTools.GetUniqueName(_filePath));

                    // notify app
                    if (FileTransferred != null)
                        FileTransferred(this, new DtmPacketEventArgs((short)DtmTransferFlags.Received, prcPacket.OptionFlag));

                    // flush and close
                    ReceiveClose();
                }
            }
            catch (Exception ex)
            {
                throw new CryptoFileTransferException("DtmFileTransfer:Receive", "The file transfer did not complete!", ex);
            }
        }
Exemplo n.º 13
0
        private void Process(MemoryStream PacketStream)
        {
            // increment rcv sequence
            _rcvSequence++;
            // get the header
            DtmPacket pktHdr = new DtmPacket(PacketStream);
            PacketStream.Seek(0, SeekOrigin.Begin);

            switch (pktHdr.PacketType)
            {
                // file transfer
                case DtmPacketTypes.Transfer:
                    {
                        switch ((DtmTransferFlags)pktHdr.PacketFlag)
                        {
                            case DtmTransferFlags.DataChunk:
                                {
                                    try
                                    {
                                        lock (_rcvLock)
                                        {
                                            // received file data
                                            Receive(PacketStream);
                                        }
                                    }
                                    catch (Exception)
                                    {
                                        // packet corrupted, request a retransmission and exit
                                        Transmit(DtmPacketTypes.Service, (short)DtmServiceFlags.Resend, pktHdr.Sequence);
                                        return;
                                    }

                                    // echo the packet to remove it from remote buffer
                                    Transmit(DtmPacketTypes.Service, (short)DtmServiceFlags.Echo, pktHdr.Sequence);
                                    break;
                                }
                        }
                        break;
                    }
                // service messages
                case DtmPacketTypes.Service:
                    {
                        switch ((DtmServiceFlags)pktHdr.PacketFlag)
                        {
                            case DtmServiceFlags.Resend:
                                {
                                    // resend the packet
                                    Resend(pktHdr);
                                    break;
                                }
                            case DtmServiceFlags.Echo:
                                {
                                    // remove from local buffer
                                    if (_sndBuffer.Exists(pktHdr.OptionFlag))
                                        _sndBuffer.Destroy(pktHdr.OptionFlag);

                                    break;
                                }
                        }
                        break;
                    }
                default:
                    {
                        throw new CryptoKeyExchangeException("DtmFileTransfer:Process", "The packet type is unknown!", new InvalidDataException());
                    }
            }

            // notify parent
            if (PacketReceived != null)
                PacketReceived(this, new DtmPacketEventArgs(pktHdr.PacketFlag, pktHdr.PayloadLength));
        }
Exemplo n.º 14
0
        /// <summary>
        /// Used to process a resync response.
        /// <para>The remote host has sent the number of bytes encrypted as the OptionFlag in the DtmPacket.
        /// The resynchronization of the crypto stream involves first encrypting an equal sized array, 
        /// and then testing for validity by decrypting the payload and comparing it to the stored client id.
        /// If the Resync fails, the client Disconnects, notifies the application, and performs a teardown of the VPN.</para>
        /// </summary>
        /// 
        /// <param name="PacketStream">A resync packet</param>
        private void ProcessResync(MemoryStream PacketStream)
        {
            // get the header
            DtmPacket pktHdr = new DtmPacket(PacketStream);
            int len = (int)(pktHdr.OptionFlag - pktHdr.PayloadLength - _bytesReceived);

            if (len > 0)
            {
                byte[] pad = new byte[len];
                // sync the cipher stream
                SymmetricTransform(_cltSymProcessor, pad);
            }
            else if (len < 0)
            {
                // can't resync, alert user and disconnect
                DtmErrorEventArgs args = new DtmErrorEventArgs(new InvalidDataException("The data stream could not be resynced, connection aborted!"), DtmErrorSeverity.Critical);
                if (SessionError != null)
                    SessionError(this, args);

                Disconnect();
                return;
            }

            // read the packet
            byte[] data = new byte[pktHdr.PayloadLength];
            // get the encrypted data
            PacketStream.Read(data, 0, data.Length);
            // decrypt the payload
            byte[] id = SymmetricTransform(_cltSymProcessor, data);
            // remove random padding
            id = UnwrapMessage(id);

            // compare to stored id
            if (!ArrayUtils.AreEqual(id, _cltIdentity.Identity))
            {
                // resync failed, abort connection
                DtmErrorEventArgs args = new DtmErrorEventArgs(new InvalidDataException("The data stream could not be resynced, connection aborted!"), DtmErrorSeverity.Critical);
                if (SessionError != null)
                    SessionError(this, args);

                Disconnect();
                return;
            }
        }
Exemplo n.º 15
0
        /// <summary>
        /// Notify that the VPN is established
        /// </summary>
        /// 
        /// <returns>A Stream containing the raw packet data</returns>
        private MemoryStream CreateEstablish()
        {
            MemoryStream pktStm = new DtmPacket(DtmPacketTypes.Exchange, 0, _sndSequence, (short)DtmExchangeFlags.Established).ToStream();

            // notify
            if (PacketSent != null)
                PacketSent(this, new DtmPacketEventArgs((short)_exchangeState, pktStm.Length));

            // stage completed
            _exchangeState = DtmExchangeFlags.Established;

            return pktStm;
        }
Exemplo n.º 16
0
        /// <summary>
        /// Process the clients identity structure <see cref="DtmIdentity"/>.
        /// </summary>
        /// 
        /// <param name="PacketStream">A Stream containing the raw packet data</param>
        private void ProcessSync(MemoryStream PacketStream)
        {
            // get the header
            DtmPacket pktHdr = new DtmPacket(PacketStream);
            // read the data
            byte[] data = new byte[pktHdr.PayloadLength];
            PacketStream.Read(data, 0, data.Length);
            // use clients symmetric key to decrypt data
            byte[] dec = SymmetricTransform(_cltSymProcessor, data);
            // remove random padding
            dec = UnwrapMessage(dec);
            // get the identity
            _cltIdentity = new DtmIdentity(dec);

            // pass id to the client, include oid
            long resp = 0;
            if (IdentityReceived != null)
            {
                DtmIdentityEventArgs args = new DtmIdentityEventArgs(DtmExchangeFlags.Init, _cltIdentity.OptionFlag, _cltIdentity);
                IdentityReceived(this, args);
                resp = args.Flag;
                if (args.Cancel)
                {
                    // back out of session
                    TearDown();
                }
            }

            // get the params oid
            _cltAsmParams = GetAsymmetricParams(_cltIdentity.PkeId);
        }
Exemplo n.º 17
0
        /// <summary>
        /// Process a message.
        /// <para>Use this method to process <see cref="DtmPacket"/> data sent to the server</para>
        /// </summary>
        private void Process(MemoryStream PacketStream)
        {
            try
            {
                // increment rcv sequence
                _rcvSequence++;
                // get the header
                DtmPacket pktHdr = new DtmPacket(PacketStream);
                PacketStream.Seek(0, SeekOrigin.Begin);

                switch (pktHdr.PacketType)
                {
                    // message stream
                    case DtmPacketTypes.Message:
                        {
                            // process message
                            switch ((DtmMessageFlags)pktHdr.PacketFlag)
                            {
                                case DtmMessageFlags.Transmission:
                                    {
                                        try
                                        {
                                            // received stream data
                                            ReceiveMessage(PacketStream);
                                        }
                                        catch (Exception)
                                        {
                                            // packet corrupted, request a retransmission and exit
                                            Transmit(DtmPacketTypes.Service, (short)DtmServiceFlags.Resend, pktHdr.Sequence);
                                            return;
                                        }

                                        // echo the packet to remove it from remote buffer
                                        Transmit(DtmPacketTypes.Service, (short)DtmServiceFlags.Echo, pktHdr.Sequence);
                                        break;
                                    }
                            }
                            break;
                        }
                    // service messages
                    case DtmPacketTypes.Service:
                        {
                            switch ((DtmServiceFlags)pktHdr.PacketFlag)
                            {
                                case DtmServiceFlags.KeepAlive:
                                    {
                                        // reset the keep alive counter
                                        _pulseCounter = 0;
                                        break;
                                    }
                                // process echo
                                case DtmServiceFlags.Echo:
                                    {
                                        // remove from buffer
                                        if (_sndBuffer.Exists(pktHdr.OptionFlag))
                                            _sndBuffer.Destroy(pktHdr.OptionFlag);

                                        break;
                                    }
                                case DtmServiceFlags.Resend:
                                    {
                                        // attempt resend, if not in buffer transmission, attempts a resync
                                        Resend(pktHdr);
                                        break;
                                    }
                                case DtmServiceFlags.DataLost:
                                    {
                                        // remote packet lost, try resync. note: if this happens often, increase buffer size in ctor + tcp
                                        MemoryStream pktData = CreateResync();
                                        _bytesSent += pktData.Length;
                                        Transmit(DtmPacketTypes.Service, (short)DtmServiceFlags.Resync, _bytesSent, pktData);
                                        break;
                                    }
                                case DtmServiceFlags.Resync:
                                    {
                                        // attempt to resync the crypto stream
                                        ProcessResync(PacketStream);
                                        break;
                                    }
                                case DtmServiceFlags.Refusal:
                                    {
                                        DtmErrorEventArgs args = new DtmErrorEventArgs(new ApplicationException("The session was refused by the remote host."), DtmErrorSeverity.Connection);
                                        if (SessionError != null)
                                            SessionError(this, args);

                                        if (args.Cancel)
                                            Disconnect();

                                        break;
                                    }
                                case DtmServiceFlags.Terminate:
                                    {
                                        // reserved
                                        DtmErrorEventArgs args = new DtmErrorEventArgs(new ApplicationException("The session was terminated by the remote host."), DtmErrorSeverity.Critical);
                                        if (SessionError != null)
                                            SessionError(this, args);

                                        Disconnect();
                                        break;
                                    }
                            }

                            break;
                        }
                    // file transfer
                    case DtmPacketTypes.Transfer:
                        {
                            switch ((DtmTransferFlags)pktHdr.PacketFlag)
                            {
                                case DtmTransferFlags.Request:
                                    {
                                        // received file transfer request
                                        ReceiveFile(PacketStream);
                                        break;
                                    }
                                case DtmTransferFlags.Refused:
                                    {
                                        // refused by remote
                                        DtmErrorEventArgs args = new DtmErrorEventArgs(new ApplicationException("The session was refused by the remote host."), DtmErrorSeverity.Connection);
                                        if (SessionError != null)
                                            SessionError(this, args);

                                        CloseTransfer(pktHdr.OptionFlag);
                                        break;
                                    }
                                case DtmTransferFlags.Received:
                                    {
                                        // refused by remote
                                        CloseTransfer(pktHdr.OptionFlag);
                                        break;
                                    }
                            }
                            break;
                        }
                    // key exchange
                    case DtmPacketTypes.Exchange:
                    {
                        // process message
                        switch ((DtmExchangeFlags)pktHdr.PacketFlag)
                        {
                            case DtmExchangeFlags.Connect:
                                {
                                    // received public id
                                    ProcessConnect(PacketStream);
                                    break;
                                }
                            case DtmExchangeFlags.Init:
                                {
                                    // received auth-stage params
                                    ProcessInit(PacketStream);
                                    break;
                                }
                            case DtmExchangeFlags.PreAuth:
                                {
                                    // received public key
                                    ProcessPreAuth(PacketStream);
                                    break;
                                }
                            case DtmExchangeFlags.AuthEx:
                                {
                                    // received symmetric key
                                    ProcessAuthEx(PacketStream);
                                    break;
                                }
                            case DtmExchangeFlags.Auth:
                                {
                                    // received private id
                                    ProcessAuth(PacketStream);
                                    break;
                                }
                            case DtmExchangeFlags.Sync:
                                {
                                    // received primary public key params
                                    ProcessSync(PacketStream);
                                    break;
                                }
                            case DtmExchangeFlags.Primary:
                                {
                                    // received primary public key
                                    ProcessPrimary(PacketStream);
                                    break;
                                }
                            case DtmExchangeFlags.PrimeEx:
                                {
                                    // received primary session key
                                    ProcessPrimeEx(PacketStream);
                                    break;
                                }
                            case DtmExchangeFlags.Established:
                                {
                                    // received ack established
                                    ProcessEstablish(PacketStream);
                                    break;
                                }
                        }

                        break;
                    }
                    default:
                    {
                        if (SessionError != null)
                            SessionError(this, new DtmErrorEventArgs(new CryptoProcessingException("DtmKex:Process", "The data transmission encountered an error!", new InvalidDataException()), DtmErrorSeverity.Critical));

                        break;
                    }
                }

                // notify app
                if (PacketReceived != null)
                    PacketReceived(this, new DtmPacketEventArgs(pktHdr.PacketFlag, pktHdr.PayloadLength));
            }
            catch (Exception ex)
            {
                if (SessionError != null)
                    SessionError(this, new DtmErrorEventArgs(new CryptoProcessingException("DtmKex:Process", "The data transmission encountered an error!", ex), DtmErrorSeverity.Critical));
            }
        }
Exemplo n.º 18
0
        /// <summary>
        /// Used Post-Exchange to decrypt bytes received from the client
        /// </summary>
        /// 
        /// <param name="PacketStream">The stream containing the ciphertext</param>
        private void ReceiveMessage(Stream PacketStream)
        {
            if (!_isEstablished)
                throw new CryptoProcessingException("DtmKex:Receive", "The VPN has not been established!", new InvalidOperationException());

            // get the header
            DtmPacket pktHdr = new DtmPacket(PacketStream);
            // store total bytes received
            _bytesReceived += pktHdr.PayloadLength;
            byte[] enc = new byte[pktHdr.PayloadLength];
            // get the encrypted data
            PacketStream.Read(enc, 0, enc.Length);
            // decrypt it using servers processor
            byte[] dec = SymmetricTransform(_cltSymProcessor, enc);
            // remove padding
            dec = UnwrapMessage(dec);

            // return the data
            if (DataReceived != null)
            {
                DtmDataReceivedEventArgs args = new DtmDataReceivedEventArgs(new MemoryStream(dec), 0);
                DataReceived(this, args);
            }
        }
Exemplo n.º 19
0
        /// <summary>
        /// Processes and queues incoming packets
        /// </summary>
        private void ProcessAndPush(PacketBuffer Buffer, MemoryStream PacketStream)
        {
            int hdrLen = DtmPacket.GetHeaderSize();
            int pktLen = 0;
            // process the whole packet
            PacketStream.Seek(0, SeekOrigin.Begin);
            // get the header
            DtmPacket dtmPkt = new DtmPacket(PacketStream);
            PacketStream.Seek(0, SeekOrigin.Begin);

            // track high sequence number, filters corrupt packets
            if (dtmPkt.Sequence > _seqCounter && dtmPkt.PayloadLength < MAXRCVBUFFER && dtmPkt.OptionFlag < 1000)
                _seqCounter = dtmPkt.Sequence;

            // out of sync, possible packet loss
            if (_seqCounter - _rcvSequence > ResendThreshold)
            {
                // request a retransmission
                Transmit(DtmPacketTypes.Service, (short)DtmServiceFlags.Resend, _rcvSequence + 1);
            }

            if (dtmPkt.PayloadLength + hdrLen == PacketStream.Length)
            {
                // resend was already processed
                if (dtmPkt.Sequence < _rcvSequence)
                    return;

                // push onto buffer
                Buffer.Push(dtmPkt.Sequence, PacketStream);
            }
            // more than one packet
            else if (dtmPkt.PayloadLength + hdrLen < PacketStream.Length)
            {
                byte[] buffer;
                long pos = 0;

                do
                {
                    // get packet position and size
                    pos = PacketStream.Position;

                    if (PacketStream.Length - pos < DtmPacket.GetHeaderSize())
                    {
                        // next packet corrupted, request a retransmission and exit
                        Transmit(DtmPacketTypes.Service, (short)DtmServiceFlags.Resend, Buffer.GetHighKey() + 1);
                        return;
                    }

                    dtmPkt = new DtmPacket(PacketStream);
                    pktLen = (int)(hdrLen + dtmPkt.PayloadLength);

                    if (pktLen > MAXRCVBUFFER || pktLen < 0 || PacketStream.Length - pos < pktLen)
                    {
                        // packet corrupted, request a retransmission and exit
                        Transmit(DtmPacketTypes.Service, (short)DtmServiceFlags.Resend, Buffer.GetHighKey() + 1);
                        return;
                    }
                    else
                    {
                        // create the buffer
                        buffer = new byte[pktLen];
                        PacketStream.Seek(pos, SeekOrigin.Begin);
                        PacketStream.Read(buffer, 0, (int)pktLen);
                        // push onto buffer
                        Buffer.Push(dtmPkt.Sequence, new MemoryStream(buffer));
                    }

                } while (PacketStream.Position < PacketStream.Length);
            }
            // malformed packet, send retransmit request
            else if (dtmPkt.PayloadLength > MAXRCVBUFFER || dtmPkt.PayloadLength < 0 || dtmPkt.PayloadLength + hdrLen > PacketStream.Length)
            {
                // packet corrupted, request a retransmission of last in queue + 1
                Transmit(DtmPacketTypes.Service, (short)DtmServiceFlags.Resend, Buffer.GetHighKey() + 1);
            }
        }
Exemplo n.º 20
0
        /// <summary>
        /// Frame and Transmit the packet to the remote client
        /// </summary>
        /// 
        /// <param name="PacketType">The packet class</param>
        /// <param name="PacketFlag">The packet message type flag</param>
        /// <param name="OptionFlag">The option flag</param>
        /// <param name="Payload">The packet payload flag</param>
        /// <param name="Blocking">Blocking or Async transmit</param>
        private void Transmit(DtmPacketTypes PacketType, short PacketFlag, long OptionFlag = 0, MemoryStream Payload = null, bool Blocking = false)
        {
            lock (_sendLock)
            {
                long pldLen = Payload == null ? 0 : Payload.Length;
                // create a new packet: packet flag, payload size, sequence, and state flag
                MemoryStream pktStm = new DtmPacket(PacketType, pldLen, _sndSequence, PacketFlag, OptionFlag).ToStream();

                // add payload
                if (Payload != null)
                {
                    // store total encrypted bytes sent
                    if (_isEstablished)
                        _bytesSent += Payload.Length;

                    // copy to output
                    pktStm.Seek(0, SeekOrigin.End);
                    Payload.WriteTo(pktStm);
                    pktStm.Seek(0, SeekOrigin.Begin);
                }

                // service requests are not buffered
                if (PacketType != DtmPacketTypes.Service)
                {
                    // store in the packet buffer
                    _sndBuffer.Push(_sndSequence, pktStm);
                }

                // increment send counter
                _sndSequence++;

                // transmit to remote client
                if (_clientSocket.IsConnected)
                {
                    if (Blocking)
                    {
                        try
                        {
                            _clientSocket.SendAsync(pktStm);
                        }
                        catch (CryptoSocketException ce)
                        {
                            SocketException se = ce.InnerException as SocketException;

                            if (se.SocketErrorCode == SocketError.WouldBlock ||
                                se.SocketErrorCode == SocketError.IOPending ||
                                se.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                            {
                                // buffer is full, slow down
                                Throttle(pktStm);
                            }
                            else if (se.SocketErrorCode != SocketError.Success)
                            {
                                // possible connection dropped, alert app
                                if (SessionError != null)
                                {
                                    DtmErrorEventArgs args = new DtmErrorEventArgs(ce, DtmErrorSeverity.Connection);
                                    SessionError(this, args);

                                    if (args.Cancel == true)
                                        Disconnect();
                                }
                            }
                        }
                    }
                    else
                    {
                        try
                        {
                            pktStm.WriteTo(_clientSocket.TcpStream);
                        }
                        catch (Exception ex)
                        {
                            // internal error, alert app
                            if (SessionError != null)
                            {
                                DtmErrorEventArgs args = new DtmErrorEventArgs(ex, DtmErrorSeverity.Critical);
                                SessionError(this, args);

                                if (args.Cancel == true)
                                    Disconnect();
                            }
                        }
                    }

                    // notify app
                    if (PacketSent != null)
                        PacketSent(this, new DtmPacketEventArgs((short)_exchangeState, pldLen));
                }
                else
                {
                    // possible connection dropped, alert app
                    if (SessionError != null)
                    {
                        DtmErrorEventArgs args = new DtmErrorEventArgs(new SocketException((int)SocketError.ConnectionReset), DtmErrorSeverity.Connection);
                        SessionError(this, args);

                        if (args.Cancel == true)
                            Disconnect();
                    }
                }
            }
        }
Exemplo n.º 21
0
 /// <summary>
 /// Serialize a <see cref="DtmPacket"/> structure
 /// </summary>
 /// 
 /// <param name="Packet">A CTKEPacket structure</param>
 /// 
 /// <returns>A stream containing the CTKEPacket data</returns>
 public static Stream Serialize(DtmPacket Packet)
 {
     return Packet.ToStream();
 }