Example #1
0
        /// <summary>
        /// Extracts SSH packet from the internal buffer.
        /// </summary>
        /// <returns>
        /// true if one SSH packet has been extracted.
        /// in this case, _packetImage contains payload part of the SSH packet.
        /// </returns>
        private bool ConstructPacket()
        {
            const int SEQUENCE_NUMBER_FIELD_LEN = 4;
            const int PACKET_LENGTH_FIELD_LEN   = 4;
            const int PADDING_LENGTH_FIELD_LEN  = 1;

            lock (_cipherSync) {
                if (_packetLength < 0)
                {
                    int headLen = (_cipher != null) ? _cipher.BlockSize : 4;

                    if (_inputBuffer.Length < headLen)
                    {
                        return(false);
                    }

                    _packetImage.Clear();
                    _packetImage.WriteUInt32(_sequence);
                    _packetImage.Append(_inputBuffer, 0, headLen);
                    _inputBuffer.RemoveHead(headLen);

                    int headOffset = _packetImage.RawBufferOffset + SEQUENCE_NUMBER_FIELD_LEN;

                    if (_cipher != null)
                    {
                        // decrypt first block
                        _cipher.Decrypt(
                            _packetImage.RawBuffer, headOffset, headLen,
                            _packetImage.RawBuffer, headOffset);
                    }

                    uint packetLength = SSHUtil.ReadUInt32(_packetImage.RawBuffer, headOffset);

                    if (packetLength < MIN_PACKET_LENGTH || packetLength >= MAX_PACKET_LENGTH)
                    {
                        throw new SSHException(String.Format("invalid packet length : {0}", packetLength));
                    }

                    _packetLength = (int)packetLength;
                }

                int packetHeadLen  = _packetImage.Length;   // size already read in
                int requiredLength = SEQUENCE_NUMBER_FIELD_LEN + PACKET_LENGTH_FIELD_LEN + _packetLength + _macLength - packetHeadLen;

                if (_inputBuffer.Length < requiredLength)
                {
                    return(false);
                }

                _packetImage.Append(_inputBuffer, 0, requiredLength);
                _inputBuffer.RemoveHead(requiredLength);

                if (_cipher != null)
                {
                    // decrypt excluding MAC
                    int headOffset = _packetImage.RawBufferOffset + packetHeadLen;
                    _cipher.Decrypt(
                        _packetImage.RawBuffer, headOffset, requiredLength - _macLength,
                        _packetImage.RawBuffer, headOffset);
                }

                int paddingLength = _packetImage[SEQUENCE_NUMBER_FIELD_LEN + PACKET_LENGTH_FIELD_LEN];
                if (paddingLength < 4)
                {
                    throw new SSHException(String.Format("invalid padding length : {0}", paddingLength));
                }

                int payloadLength = _packetLength - PADDING_LENGTH_FIELD_LEN - paddingLength;

                if (_checkMAC && _mac != null)
                {
                    int    contentLen = SEQUENCE_NUMBER_FIELD_LEN + PACKET_LENGTH_FIELD_LEN + _packetLength;
                    byte[] result     = _mac.ComputeHash(_packetImage.RawBuffer, _packetImage.RawBufferOffset, contentLen);

                    if (result.Length != _macLength ||
                        !SSHUtil.ByteArrayEqual(result, 0, _packetImage.RawBuffer, _packetImage.RawBufferOffset + contentLen, _macLength))
                    {
                        throw new SSHException("MAC mismatch");
                    }
                }

                // retain only payload
                _packetImage.RemoveHead(SEQUENCE_NUMBER_FIELD_LEN + PACKET_LENGTH_FIELD_LEN + PADDING_LENGTH_FIELD_LEN);
                _packetImage.RemoveTail(_macLength + paddingLength);

                // sanity check
                if (_packetImage.Length != payloadLength)
                {
                    throw new InvalidOperationException();
                }

                // prepare for the next packet
                ++_sequence;
                _packetLength = -1;

                return(true);
            }
        }
Example #2
0
        // Derived class can override this method to modify the buffer.
        public virtual DataFragment Close(Cipher cipher, MAC mac, int sequence)
        {
            if (!_isOpen)
                throw new SSHException("internal state error");

            int blocksize = cipher == null ? 8 : cipher.BlockSize;
            int payloadLength = _writer.Length - (SEQUENCE_MARGIN + LENGTH_MARGIN + PADDING_MARGIN);
            int paddingLength = 11 - payloadLength % blocksize;
            while (paddingLength < 4)
                paddingLength += blocksize;
            int packetLength = PADDING_MARGIN + payloadLength + paddingLength;
            int imageLength = packetLength + LENGTH_MARGIN;

            //fill padding
            byte[] tmp = new byte[4];
            Rng rng = RngManager.GetSecureRng();
            for (int i = 0; i < paddingLength; i += 4) {
                rng.GetBytes(tmp);
                _writer.Write(tmp);
            }

            //manipulate stream
            byte[] rawbuf = _writer.UnderlyingBuffer;
            SSHUtil.WriteIntToByteArray(rawbuf, 0, sequence);
            SSHUtil.WriteIntToByteArray(rawbuf, SEQUENCE_MARGIN, packetLength);
            rawbuf[SEQUENCE_MARGIN + LENGTH_MARGIN] = (byte)paddingLength;

            //mac
            if (mac != null) {
                byte[] macCode = mac.ComputeHash(rawbuf, 0, packetLength + LENGTH_MARGIN + SEQUENCE_MARGIN);
                Array.Copy(macCode, 0, rawbuf, packetLength + LENGTH_MARGIN + SEQUENCE_MARGIN, macCode.Length);
                imageLength += macCode.Length;
            }

            //encrypt
            if (cipher != null)
                cipher.Encrypt(rawbuf, SEQUENCE_MARGIN, packetLength + LENGTH_MARGIN, rawbuf, SEQUENCE_MARGIN);

            _dataFragment.Init(rawbuf, SEQUENCE_MARGIN, imageLength);
            _isOpen = false;
            return _dataFragment;
        }
        public void Close(Cipher cipher, Random rnd, MAC mac, int sequence, DataFragment result)
        {
            if(!_is_open) throw new SSHException("internal state error");

            int blocksize = cipher==null? 8 : cipher.BlockSize;
            int payload_length = _writer.Length - (SEQUENCE_MARGIN + LENGTH_MARGIN + PADDING_MARGIN);
            int r = 11 - payload_length % blocksize;
            while(r < 4) r += blocksize;
            _paddingLength = r;
            _packetLength = PADDING_MARGIN + payload_length + _paddingLength;
            int image_length = _packetLength + LENGTH_MARGIN;

            //fill padding
            for(int i=0; i<_paddingLength; i+=4)
                _writer.Write(rnd.Next());

            //manipulate stream
            byte[] rawbuf = _writer.UnderlyingBuffer;
            SSHUtil.WriteIntToByteArray(rawbuf, 0, sequence);
            SSHUtil.WriteIntToByteArray(rawbuf, SEQUENCE_MARGIN, _packetLength);
            rawbuf[SEQUENCE_MARGIN + LENGTH_MARGIN] = (byte)_paddingLength;

            //mac
            if(mac!=null) {
                _mac = mac.ComputeHash(rawbuf, 0, _packetLength+LENGTH_MARGIN+SEQUENCE_MARGIN);
                Array.Copy(_mac, 0, rawbuf, _packetLength+LENGTH_MARGIN+SEQUENCE_MARGIN, _mac.Length);
                image_length += _mac.Length;
            }

            //encrypt
            if(cipher!=null)
                cipher.Encrypt(rawbuf, SEQUENCE_MARGIN, _packetLength+LENGTH_MARGIN, rawbuf, SEQUENCE_MARGIN);

            result.Init(rawbuf, SEQUENCE_MARGIN, image_length);
            _is_open = false;
        }