Esempio n. 1
0
 public SocketSshConnection(ILogger logger, SequencePool sequencePool, Socket socket) :
     base(sequencePool)
 {
     _logger        = logger;
     _socket        = socket;
     _receiveBuffer = sequencePool.RentSequence();
     _sendBuffer    = sequencePool.RentSequence();
     _decoder       = new PacketDecoder(SequencePool);
     _encoder       = new PacketEncoder();
 }
Esempio n. 2
0
        private byte[] CalculateExchangeHash(SequencePool sequencePool, SshConnectionInfo connectionInfo, Packet clientKexInitMsg, Packet serverKexInitMsg, ReadOnlySequence <byte> public_host_key, ECPoint q_c, ECPoint q_s, BigInteger sharedSecret)
        {
            /*
             *  string   V_C, client's identification string (CR and LF excluded)
             *  string   V_S, server's identification string (CR and LF excluded)
             *  string   I_C, payload of the client's SSH_MSG_KEXINIT
             *  string   I_S, payload of the server's SSH_MSG_KEXINIT
             *  string   K_S, server's public host key
             *  string   Q_C, client's ephemeral public key octet string
             *  string   Q_S, server's ephemeral public key octet string
             *  mpint    K,   shared secret
             */
            using Sequence sequence = sequencePool.RentSequence();
            var writer = new SequenceWriter(sequence);

            writer.WriteString(connectionInfo.ClientIdentificationString !);
            writer.WriteString(connectionInfo.ServerIdentificationString !);
            writer.WriteString(clientKexInitMsg.Payload);
            writer.WriteString(serverKexInitMsg.Payload);
            writer.WriteString(public_host_key);
            writer.WriteString(q_c);
            writer.WriteString(q_s);
            writer.WriteMPInt(sharedSecret);

            using IncrementalHash hash = IncrementalHash.CreateHash(_hashAlgorithmName);
            foreach (var segment in sequence.AsReadOnlySequence())
            {
                hash.AppendData(segment.Span);
            }
            return(hash.GetHashAndReset());
        }
Esempio n. 3
0
        private byte[] Hash(SequencePool sequencePool, BigInteger sharedSecret, byte[] exchangeHash, byte c, byte[] sessionId, int hashLength)
        {
            // https://tools.ietf.org/html/rfc4253#section-7.2

            byte[] hashRv     = new byte[hashLength];
            int    hashOffset = 0;

            // TODO: handle 'If the key length needed is longer than the output of the HASH'
            // HASH(K || H || c || session_id)
            using Sequence sequence = sequencePool.RentSequence();
            var writer = new SequenceWriter(sequence);

            writer.WriteMPInt(sharedSecret);
            writer.Write(exchangeHash);
            writer.WriteByte(c);
            writer.Write(sessionId);

            using IncrementalHash hash = IncrementalHash.CreateHash(_hashAlgorithmName);
            foreach (var segment in sequence.AsReadOnlySequence())
            {
                hash.AppendData(segment.Span);
            }
            byte[] K1 = hash.GetHashAndReset();
            Append(hashRv, K1, ref hashOffset);

            while (hashOffset != hashRv.Length)
            {
                // TODO: handle 'If the key length needed is longer than the output of the HASH'
                // K3 = HASH(K || H || K1 || K2)
                throw new NotSupportedException();
            }

            return(hashRv);
Esempio n. 4
0
        private static Packet CreatePublicKeyRequestMessage(SequencePool sequencePool, string userName, byte[] sessionId, PrivateKey privateKey)
        {
            /*
             *  byte      SSH_MSG_USERAUTH_REQUEST
             *  string    user name
             *  string    service name
             *  string    "publickey"
             *  boolean   TRUE
             *  string    public key algorithm name
             *  string    public key to be used for authentication
             *  string    signature
             */
            using var packet = sequencePool.RentPacket();
            var writer = packet.GetWriter();

            writer.WriteByte(MessageNumber.SSH_MSG_USERAUTH_REQUEST);
            writer.WriteString(userName);
            writer.WriteString("ssh-connection");
            writer.WriteString("publickey");
            writer.WriteBoolean(true);
            writer.WriteString(privateKey.Format);
            privateKey.AppendPublicKey(ref writer);
            {
                /*
                 *  string    session identifier
                 *  byte      SSH_MSG_USERAUTH_REQUEST
                 *  string    user name
                 *  string    service name
                 *  string    "publickey"
                 *  boolean   TRUE
                 *  string    public key algorithm name
                 *  string    public key to be used for authentication
                 */
                using var signatureData = sequencePool.RentSequence();
                var signatureWriter = new SequenceWriter(signatureData);
                signatureWriter.WriteString(sessionId);
                signatureWriter.WriteByte(MessageNumber.SSH_MSG_USERAUTH_REQUEST);
                signatureWriter.WriteString(userName);
                signatureWriter.WriteString("ssh-connection");
                signatureWriter.WriteString("publickey");
                signatureWriter.WriteBoolean(true);
                signatureWriter.WriteString(privateKey.Format);
                privateKey.AppendPublicKey(ref signatureWriter);
                privateKey.AppendSignature(ref writer, signatureData.AsReadOnlySequence());
            }

            return(packet.Move());
        }
Esempio n. 5
0
        public bool TryDecodePacket(Sequence receiveBuffer, int maxLength, out Packet packet)
        {
            // Binary Packet Protocol: https://tools.ietf.org/html/rfc4253#section-6.

            /*
             *  uint32    packet_length
             *  byte      padding_length
             *  byte[n1]  payload; n1 = packet_length - padding_length - 1
             *  byte[n2]  random padding; n2 = padding_length
             *  byte[m]   mac (Message Authentication Code - MAC); m = mac_length
             */

            if (_decodedPacket == null)
            {
                _decodedPacket = _sequencePool.RentSequence();
            }

            // We can't decode past the packet, because the mac is not encrypted.
            // We need to know the packet length to know how much we can decrypt.
            while (_decodedPacket.Length < 4 && receiveBuffer.Length >= _decode.BlockSize)
            {
                _decode.Transform(receiveBuffer.AsReadOnlySequence().Slice(0, _decode.BlockSize), _decodedPacket);
                receiveBuffer.Remove(_decode.BlockSize);
            }

            var decodedReader = new SequenceReader(_decodedPacket);

            if (decodedReader.Length >= 4)
            {
                // Read the packet length.
                uint packet_length = decodedReader.ReadUInt32();
                if (packet_length > maxLength)
                {
                    ThrowHelper.ThrowProtocolPacketTooLong();
                }

                // Decode the entire packet.
                uint concatenated_length = 4 + packet_length;
                // TODO: verify contatenated_length is a multiple of the cipher block size or 8, whichever is larger.
                long remaining = concatenated_length - decodedReader.Length;
                if (remaining > 0 && receiveBuffer.Length >= remaining)
                {
                    _decode.Transform(receiveBuffer.AsReadOnlySequence().Slice(0, remaining), _decodedPacket);
                    receiveBuffer.Remove(remaining);
                    remaining = 0;
                }

                if (remaining == 0)
                {
                    if (_decodedPacket.Length != concatenated_length)
                    {
                        ThrowHelper.ThrowInvalidOperation("Complete packet expected.");
                    }

                    // TODO: verify mac
                    receiveBuffer.Remove(_mac.HashSize);

                    packet         = new Packet(_decodedPacket);
                    _decodedPacket = null;
                    return(true);
                }
            }

            packet = new Packet(null);
            return(false);
        }
        public static Packet RentPacket(this SequencePool sequencePool)
        {
            Sequence sequence = sequencePool.RentSequence();

            return(new Packet(sequence));
        }