Ejemplo n.º 1
0
        private void OpenShellOrSubsystem(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader reader, string scheme) {
            if (_negotiationStatus == NegotiationStatus.WaitingChannelConfirmation) {
                if (pt != PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
                    if (pt != PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE)
                        receiver.OnChannelError(new SSHException("opening channel failed; packet type=" + pt));
                    else {
                        int errcode = reader.ReadInt32();
                        string msg = Encoding.ASCII.GetString(reader.ReadString());
                        receiver.OnChannelError(new SSHException(msg));
                    }
                    // Close() shouldn't be called because remote channel number is not given yet.
                    // We just remove an event receiver from the collection of channels.
                    // FIXME: _negotiationStatus sould be set an error status ?
                    _connection.ChannelCollection.UnregisterChannelEventReceiver(_localID);
                }
                else {
                    _remoteID = reader.ReadInt32();
                    _allowedDataSize = reader.ReadInt32();
                    _serverMaxPacketSize = reader.ReadInt32();

                    if (_type == ChannelType.Subsystem) {
                        OpenScheme(scheme);
                        _negotiationStatus = NegotiationStatus.WaitingSubsystemConfirmation;
                    }
                    else {
                        //open pty
                        SSH2DataWriter wr = new SSH2DataWriter();
                        SSHConnectionParameter param = _connection.Param;
                        wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_REQUEST);
                        wr.WriteInt32(_remoteID);
                        wr.WriteString("pty-req");
                        wr.WriteBool(true);
                        wr.WriteString(param.TerminalName);
                        wr.WriteInt32(param.TerminalWidth);
                        wr.WriteInt32(param.TerminalHeight);
                        wr.WriteInt32(param.TerminalPixelWidth);
                        wr.WriteInt32(param.TerminalPixelHeight);
                        wr.WriteAsString(new byte[0]);
                        if (_connection.IsEventTracerAvailable)
                            _connection.TraceTransmissionEvent(PacketType.SSH_MSG_CHANNEL_REQUEST, "pty-req", "terminal={0} width={1} height={2}", param.TerminalName, param.TerminalWidth, param.TerminalHeight);
                        TransmitPayload(wr.ToByteArray());

                        _negotiationStatus = NegotiationStatus.WaitingPtyReqConfirmation;
                    }
                }
            }
            else if (_negotiationStatus == NegotiationStatus.WaitingPtyReqConfirmation) {
                if (pt != PacketType.SSH_MSG_CHANNEL_SUCCESS) {
                    receiver.OnChannelError(new SSHException("opening pty failed"));
                    Close();
                }
                else {
                    //agent request (optional)
                    if (_connection.Param.AgentForward != null) {
                        SSH2DataWriter wr = new SSH2DataWriter();
                        wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_REQUEST);
                        wr.WriteInt32(_remoteID);
                        wr.WriteString("*****@*****.**");
                        wr.WriteBool(true);
                        _connection.TraceTransmissionEvent(PacketType.SSH_MSG_CHANNEL_REQUEST, "auth-agent-req", "");
                        TransmitPayload(wr.ToByteArray());
                        _negotiationStatus = NegotiationStatus.WaitingAuthAgentReqConfirmation;
                    }
                    else {
                        OpenScheme(scheme);
                        _negotiationStatus = NegotiationStatus.WaitingShellConfirmation;
                    }
                }
            }
            else if (_negotiationStatus == NegotiationStatus.WaitingAuthAgentReqConfirmation) {
                if (pt != PacketType.SSH_MSG_CHANNEL_SUCCESS && pt != PacketType.SSH_MSG_CHANNEL_FAILURE) {
                    receiver.OnChannelError(new SSHException("auth-agent-req error"));
                    Close();
                }
                else { //auth-agent-req is optional
                    _connection.SetAgentForwardConfirmed(pt == PacketType.SSH_MSG_CHANNEL_SUCCESS);
                    _connection.TraceReceptionEvent(pt, "auth-agent-req");

                    OpenScheme(scheme);
                    _negotiationStatus = NegotiationStatus.WaitingShellConfirmation;
                }
            }
            else if (_negotiationStatus == NegotiationStatus.WaitingShellConfirmation) {
                if (pt != PacketType.SSH_MSG_CHANNEL_SUCCESS) {
                    receiver.OnChannelError(new SSHException("Opening shell failed: packet type=" + pt.ToString()));
                    Close();
                }
                else {
                    receiver.OnChannelReady();
                    _negotiationStatus = NegotiationStatus.Ready; //goal!
                }
            }
            else if (_negotiationStatus == NegotiationStatus.WaitingSubsystemConfirmation) {
                if (pt != PacketType.SSH_MSG_CHANNEL_SUCCESS) {
                    receiver.OnChannelError(new SSHException("Opening subsystem failed: packet type=" + pt.ToString()));
                    Close();
                }
                else {
                    receiver.OnChannelReady();
                    _negotiationStatus = NegotiationStatus.Ready; //goal!
                }
            }
        }
Ejemplo n.º 2
0
        // sending "exec" service for SCP protocol.
        private void ExecCommand(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader reader) {
            if (_negotiationStatus == NegotiationStatus.WaitingChannelConfirmation) {
                if (pt != PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
                    if (pt != PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE)
                        receiver.OnChannelError(new SSHException("opening channel failed; packet type=" + pt));
                    else {
                        int errcode = reader.ReadInt32();
                        string msg = Encoding.ASCII.GetString(reader.ReadString());
                        receiver.OnChannelError(new SSHException(msg));
                    }
                    Close();
                }
                else {
                    _remoteID = reader.ReadInt32();
                    _allowedDataSize = reader.ReadInt32();
                    _serverMaxPacketSize = reader.ReadInt32();

                    // exec command
                    SSH2DataWriter wr = new SSH2DataWriter();
                    SSHConnectionParameter param = _connection.Param;
                    wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_REQUEST);
                    wr.WriteInt32(_remoteID);
                    wr.WriteString("exec");  // "exec"
                    wr.WriteBool(false);   // want confirm is disabled. (*)
                    wr.WriteString(_command);

                    if (_connection.IsEventTracerAvailable)
                        _connection.TraceTransmissionEvent("exec command", "cmd={0}", _command);
                    TransmitPayload(wr.ToByteArray());

                    //confirmation is omitted
                    receiver.OnChannelReady();
                    _negotiationStatus = NegotiationStatus.Ready; //goal!
                }
            }
            else if (_negotiationStatus == NegotiationStatus.WaitingExecCmdConfirmation) {
                if (pt != PacketType.SSH_MSG_CHANNEL_DATA) {
                    receiver.OnChannelError(new SSHException("exec command failed"));
                    Close();
                }
                else {
                    receiver.OnChannelReady();
                    _negotiationStatus = NegotiationStatus.Ready; //goal!
                }
            }
            else
                throw new SSHException("internal state error");
        }
Ejemplo n.º 3
0
        internal void ProcessPacket(ISSHChannelEventReceiver receiver, PacketType pt, int data_length, SSH2DataReader re) {
            //NOTE: the offset of 're' is next to 'receipiant channel' field

            AdjustWindowSize(pt, data_length);

            //SSH_MSG_CHANNEL_WINDOW_ADJUST comes before the complete of channel establishment
            if (pt == PacketType.SSH_MSG_CHANNEL_WINDOW_ADJUST) {
                int w = re.ReadInt32();
                //some servers may not send SSH_MSG_CHANNEL_WINDOW_ADJUST. 
                //it is dangerous to wait this message in send procedure
                _allowedDataSize += w;
                if (_connection.IsEventTracerAvailable)
                    _connection.TraceReceptionEvent("SSH_MSG_CHANNEL_WINDOW_ADJUST", "adjusted to {0} by increasing {1}", _allowedDataSize, w);
                return;
            }

            // check closing sequence
            if (_waitingChannelClose && pt == PacketType.SSH_MSG_CHANNEL_CLOSE) {
                _waitingChannelClose = false;
                return; // ignore it
            }

            if (_negotiationStatus != NegotiationStatus.Ready) //when the negotiation is not completed
                ProgressChannelNegotiation(receiver, pt, re);
            else
                ProcessChannelLocalData(receiver, pt, re);
        }
Ejemplo n.º 4
0
 private void ProcessChannelLocalData(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader re) {
     switch (pt) {
         case PacketType.SSH_MSG_CHANNEL_DATA: {
                 int len = re.ReadInt32();
                 receiver.OnData(re.Image, re.Offset, len);
             }
             break;
         case PacketType.SSH_MSG_CHANNEL_EXTENDED_DATA: {
                 int t = re.ReadInt32();
                 byte[] data = re.ReadString();
                 receiver.OnExtendedData(t, data);
             }
             break;
         case PacketType.SSH_MSG_CHANNEL_REQUEST: {
                 string request = Encoding.ASCII.GetString(re.ReadString());
                 bool reply = re.ReadBool();
                 if (request == "exit-status") {
                     int status = re.ReadInt32();
                 }
                 else if (reply) { //we reject unknown requests including keep-alive check
                     SSH2DataWriter wr = new SSH2DataWriter();
                     wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_FAILURE);
                     wr.WriteInt32(_remoteID);
                     TransmitPayload(wr.ToByteArray());
                 }
             }
             break;
         case PacketType.SSH_MSG_CHANNEL_EOF:
             receiver.OnChannelEOF();
             break;
         case PacketType.SSH_MSG_CHANNEL_CLOSE:
             _connection.ChannelCollection.UnregisterChannelEventReceiver(_localID);
             receiver.OnChannelClosed();
             break;
         case PacketType.SSH_MSG_CHANNEL_FAILURE:
             receiver.OnMiscPacket((byte)pt, re.Image, re.Offset, re.Rest);
             break;
         default:
             receiver.OnMiscPacket((byte)pt, re.Image, re.Offset, re.Rest);
             //Debug.WriteLine("Unknown Packet " + pt);
             break;
     }
 }
Ejemplo n.º 5
0
        private void ProcessPortforwardingRequest(ISSHConnectionEventReceiver receiver, SSH2DataReader reader) {

            int remote_channel = reader.ReadInt32();
            int window_size = reader.ReadInt32(); //skip initial window size
            int servermaxpacketsize = reader.ReadInt32();
            string host = Encoding.ASCII.GetString(reader.ReadString());
            int port = reader.ReadInt32();
            string originator_ip = Encoding.ASCII.GetString(reader.ReadString());
            int originator_port = reader.ReadInt32();

            TraceReceptionEvent("port forwarding request", String.Format("host={0} port={1} originator-ip={2} originator-port={3}", host, port, originator_ip, originator_port));
            PortForwardingCheckResult r = receiver.CheckPortForwardingRequest(host, port, originator_ip, originator_port);
            SSH2DataWriter wr = new SSH2DataWriter();
            if (r.allowed) {
                //send OPEN_CONFIRMATION
                SSH2Channel channel = new SSH2Channel(this, ChannelType.ForwardedRemoteToLocal, this.ChannelCollection.RegisterChannelEventReceiver(null, r.channel).LocalID, remote_channel, servermaxpacketsize);
                wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
                wr.WriteInt32(remote_channel);
                wr.WriteInt32(channel.LocalChannelID);
                wr.WriteInt32(_param.WindowSize); //initial window size
                wr.WriteInt32(_param.MaxPacketSize); //max packet size
                receiver.EstablishPortforwarding(r.channel, channel);
                TraceTransmissionEvent("port-forwarding request is confirmed", "host={0} port={1} originator-ip={2} originator-port={3}", host, port, originator_ip, originator_port);
            }
            else {
                wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE);
                wr.WriteInt32(remote_channel);
                wr.WriteInt32(r.reason_code);
                wr.WriteString(r.reason_message);
                wr.WriteString(""); //lang tag
                TraceTransmissionEvent("port-forwarding request is rejected", "host={0} port={1} originator-ip={2} originator-port={3}", host, port, originator_ip, originator_port);
            }
            TransmitRawPayload(wr.ToByteArray());
        }
Ejemplo n.º 6
0
        private void ProcessAgentForwardRequest(ISSHConnectionEventReceiver receiver, SSH2DataReader reader) {
            int remote_channel = reader.ReadInt32();
            int window_size = reader.ReadInt32(); //skip initial window size
            int servermaxpacketsize = reader.ReadInt32();
            TraceReceptionEvent("agent forward request", "");

            SSH2DataWriter wr = new SSH2DataWriter();
            IAgentForward af = _param.AgentForward;
            if (_agentForwardConfirmed && af != null && af.CanAcceptForwarding()) {
                //send OPEN_CONFIRMATION
                AgentForwardingChannel ch = new AgentForwardingChannel(af);
                SSH2Channel channel = new SSH2Channel(this, ChannelType.AgentForward, this.ChannelCollection.RegisterChannelEventReceiver(null, ch).LocalID, remote_channel, servermaxpacketsize);
                ch.SetChannel(channel);
                wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
                wr.WriteInt32(remote_channel);
                wr.WriteInt32(channel.LocalChannelID);
                wr.WriteInt32(_param.WindowSize); //initial window size
                wr.WriteInt32(_param.MaxPacketSize); //max packet size
                TraceTransmissionEvent("granados confirmed agent-forwarding request", "");
            }
            else {
                wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE);
                wr.WriteInt32(remote_channel);
                wr.WriteInt32(0);
                wr.WriteString("reject");
                wr.WriteString(""); //lang tag
                TraceTransmissionEvent("granados rejected agent-forwarding request", "");
            }
            TransmitRawPayload(wr.ToByteArray());
        }
Ejemplo n.º 7
0
 private AuthenticationResult ProcessAuthenticationResponse() {
     do {
         SSH2DataReader response = new SSH2DataReader(ReceivePacket());
         PacketType h = response.ReadPacketType();
         if (h == PacketType.SSH_MSG_USERAUTH_FAILURE) {
             string msg = Encoding.ASCII.GetString(response.ReadString());
             TraceReceptionEvent(h, "user authentication failed:" + msg);
             return AuthenticationResult.Failure;
         }
         else if (h == PacketType.SSH_MSG_USERAUTH_BANNER) {
             TraceReceptionEvent(h, "");
         }
         else if (h == PacketType.SSH_MSG_USERAUTH_SUCCESS) {
             TraceReceptionEvent(h, "user authentication succeeded");
             _packetBuilder.InnerHandler = new CallbackSSH2PacketHandler(this);
             return AuthenticationResult.Success; //successfully exit
         }
         else if (h == PacketType.SSH_MSG_USERAUTH_INFO_REQUEST) {
             string name = Encoding.ASCII.GetString(response.ReadString());
             string inst = Encoding.ASCII.GetString(response.ReadString());
             string lang = Encoding.ASCII.GetString(response.ReadString());
             int num = response.ReadInt32();
             string[] prompts = new string[num];
             for (int i = 0; i < num; i++) {
                 prompts[i] = Encoding.ASCII.GetString(response.ReadString());
                 bool echo = response.ReadBool();
             }
             _eventReceiver.OnAuthenticationPrompt(prompts);
             _requiredResponseCount = num;
             return AuthenticationResult.Prompt;
         }
         else
             throw new SSHException("protocol error: unexpected packet type " + h);
     } while (true);
 }
Ejemplo n.º 8
0
        private void ProcessKEXINIT(DataFragment packet) {
            SSH2DataReader re = null;
            do {
                _serverKEXINITPayload = packet.ToNewArray();
                re = new SSH2DataReader(_serverKEXINITPayload);
                byte[] head = re.Read(17); //Type and cookie
                PacketType pt = (PacketType)head[0];

                if (pt == PacketType.SSH_MSG_KEXINIT)
                    break; //successfully exit
                else if (pt == PacketType.SSH_MSG_IGNORE || pt == PacketType.SSH_MSG_DEBUG) { //continue
                    packet = _connection.ReceivePacket();
                }
                else
                    throw new SSHException(String.Format("Server response is not SSH_MSG_KEXINIT but {0}", head[0]));
            } while (true);

            Encoding enc = Encoding.ASCII;

            string kex = enc.GetString(re.ReadString());
            _cInfo._supportedKEXAlgorithms = kex;
            _cInfo._kexAlgorithm = DecideKexAlgorithm(kex);

            string host_key = enc.GetString(re.ReadString());
            _cInfo._supportedHostKeyAlgorithms = host_key;
            _cInfo._algorithmForHostKeyVerification = DecideHostKeyAlgorithm(host_key);

            string enc_cs = enc.GetString(re.ReadString());
            _cInfo._supportedCipherAlgorithms = enc_cs;
            _cInfo._algorithmForTransmittion = DecideCipherAlgorithm(enc_cs);

            string enc_sc = enc.GetString(re.ReadString());
            _cInfo._algorithmForReception = DecideCipherAlgorithm(enc_sc);

            string mac_cs = enc.GetString(re.ReadString());
            CheckAlgorithmSupport("mac", mac_cs, "hmac-sha1");

            string mac_sc = enc.GetString(re.ReadString());
            CheckAlgorithmSupport("mac", mac_sc, "hmac-sha1");

            string comp_cs = enc.GetString(re.ReadString());
            CheckAlgorithmSupport("compression", comp_cs, "none");
            string comp_sc = enc.GetString(re.ReadString());
            CheckAlgorithmSupport("compression", comp_sc, "none");

            string lang_cs = enc.GetString(re.ReadString());
            string lang_sc = enc.GetString(re.ReadString());
            bool flag = re.ReadBool();
            int reserved = re.ReadInt32();
            Debug.Assert(re.Rest == 0);

            if (_connection.IsEventTracerAvailable) {
                StringBuilder bld = new StringBuilder();
                bld.Append("kex_algorithm=");
                bld.Append(kex);
                bld.Append("; server_host_key_algorithms=");
                bld.Append(host_key);
                bld.Append("; encryption_algorithms_client_to_server=");
                bld.Append(enc_cs);
                bld.Append("; encryption_algorithms_server_to_client=");
                bld.Append(enc_sc);
                bld.Append("; mac_algorithms_client_to_server=");
                bld.Append(mac_cs);
                bld.Append("; mac_algorithms_server_to_client=");
                bld.Append(mac_sc);
                bld.Append("; comression_algorithms_client_to_server=");
                bld.Append(comp_cs);
                bld.Append("; comression_algorithms_server_to_client=");
                bld.Append(comp_sc);
                TraceReceptionNegotiation(PacketType.SSH_MSG_KEXINIT, bld.ToString());
            }

            if (flag)
                throw new SSHException("Algorithm negotiation failed");
        }
Ejemplo n.º 9
0
 private void EstablishSession(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader reader) {
     if (_negotiationStatus == NegotiationStatus.WaitingChannelConfirmation) {
         if (pt != PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
             if (pt != PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE)
                 receiver.OnChannelError(new SSHException("opening channel failed; packet type=" + pt));
             else {
                 int remote_id = reader.ReadInt32();
                 int errcode = reader.ReadInt32();
                 string msg = Encoding.ASCII.GetString(reader.ReadString());
                 receiver.OnChannelError(new SSHException(msg));
             }
             Close();
         }
         else {
             _remoteID = reader.ReadInt32();
             _serverMaxPacketSize = reader.ReadInt32();
             _negotiationStatus = NegotiationStatus.Ready;
             receiver.OnChannelReady();
         }
     }
     else
         throw new SSHException("internal state error");
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Read SSH.com SSH2 private key parameters.
        /// </summary>
        /// <param name="passphrase">passphrase for decrypt the key file</param>
        /// <param name="keyPair">key pair</param>
        /// <param name="comment">comment or empty if it didn't exist</param>
        /// <exception cref="SSHException">failed to parse</exception>
        public void Load(SecureString passphrase, out KeyPair keyPair, out string comment) {
            if (keyFile == null)
                throw new SSHException("A key file is not loaded yet");

            string base64Text;
            using (StreamReader sreader = GetStreamReader()) {
                var line = sreader.ReadLine();
                if (line == null || line != PrivateKeyFileHeader.SSH2_SSHCOM_HEADER)
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing header)");

                var buf = new StringBuilder();
                comment = string.Empty;
                while (true) {
                    line = sreader.ReadLine();
                    if (line == null)
                        throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)");
                    if (line == PrivateKeyFileHeader.SSH2_SSHCOM_FOOTER)
                        break;
                    if (line.IndexOf(':') >= 0) {
                        if (line.StartsWith("Comment: "))
                            comment = line.Substring("Comment: ".Length);
                    }
                    else if (line[line.Length - 1] == '\\')
                        buf.Append(line, 0, line.Length - 1);
                    else
                        buf.Append(line);
                }
                base64Text = buf.ToString();
            }

            var keydata = Base64.Decode(Encoding.ASCII.GetBytes(base64Text));
            //Debug.WriteLine(DebugUtil.DumpByteArray(keydata));

            var reader = new SSH2DataReader(keydata);
            int magic = reader.ReadInt32();
            if (magic != MAGIC)
                throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (magic code unmatched)");
            int privateKeyLen = reader.ReadInt32();
            string type = Encoding.ASCII.GetString(reader.ReadString());

            string ciphername = Encoding.ASCII.GetString(reader.ReadString());
            int bufLen = reader.ReadInt32();
            if (ciphername != "none") {
                var algo = CipherFactory.SSH2NameToAlgorithm(ciphername);
                var key  = SSH2UserAuthKey.PassphraseToKey(passphrase, CipherFactory.GetKeySize(algo));
                var c    = CipherFactory.CreateCipher(SSHProtocol.SSH2, algo, key);
                var tmp  = new Byte[reader.Image.Length - reader.Offset];
                c.Decrypt(reader.Image, reader.Offset, reader.Image.Length - reader.Offset, tmp, 0);
                reader   = new SSH2DataReader(tmp);
            }

            int parmLen = reader.ReadInt32();
            if (parmLen < 0 || parmLen > reader.Rest)
                throw new SSHException(Strings.GetString("WrongPassphrase"));

            if (type.IndexOf("if-modn") != -1) {
                //mindterm mistaken this order of BigIntegers
                BigInteger e = reader.ReadBigIntWithBits();
                BigInteger d = reader.ReadBigIntWithBits();
                BigInteger n = reader.ReadBigIntWithBits();
                BigInteger u = reader.ReadBigIntWithBits();
                BigInteger p = reader.ReadBigIntWithBits();
                BigInteger q = reader.ReadBigIntWithBits();
                keyPair = new RSAKeyPair(e, d, n, u, p, q);
            }
            else if (type.IndexOf("dl-modp") != -1) {
                if (reader.ReadInt32() != 0)
                    throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat")
                            + " (" + Strings.GetString("Reason_UnsupportedDSAKeyFormat") + ")");
                BigInteger p = reader.ReadBigIntWithBits();
                BigInteger g = reader.ReadBigIntWithBits();
                BigInteger q = reader.ReadBigIntWithBits();
                BigInteger y = reader.ReadBigIntWithBits();
                BigInteger x = reader.ReadBigIntWithBits();
                keyPair = new DSAKeyPair(p, g, q, y, x);
            }
            else
                throw new SSHException(Strings.GetString("UnsupportedAuthenticationMethod"));
        }
Ejemplo n.º 11
0
    /*
         * Format style note
         *  ---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----
         *  Comment: *******
         *  <base64-encoded body>
         *  ---- END SSH2 ENCRYPTED PRIVATE KEY ----
         * 
         *  body = MAGIC_VAL || body-length || type(string) || encryption-algorithm-name(string) || encrypted-body(string)
         *  encrypted-body = array of BigInteger(algorithm-specific)
         */
#if !PODEROSA_KEYFORMAT
        public static SSH2UserAuthKey FromSECSHStyleStream(Stream strm, string passphrase)
        {
            StreamReader r = new StreamReader(strm, Encoding.ASCII);
            string l = r.ReadLine();
            if (l == null || l != "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----")
                throw new SSHException("Wrong key format (expected SSH2 ENCRYPTED PRIVATE KEY)");

            string comment = "";
            l = r.ReadLine();
            StringBuilder buf = new StringBuilder();
            while (l != "---- END SSH2 ENCRYPTED PRIVATE KEY ----")
            {
                if (l.IndexOf(':') == -1)
                    buf.Append(l);
                else if (l[l.Length - 1] == '\\')
                    buf.Append(l, 0, l.Length - 1);
                else if (l.StartsWith("Comment: "))
                    comment = l.Substring("Comment: ".Length);

                l = r.ReadLine();
                if (l == null)
                    throw new SSHException("Key is broken");
            }
            r.Close();

            byte[] keydata = Base64.Decode(Encoding.ASCII.GetBytes(buf.ToString()));
            //Debug.WriteLine(DebugUtil.DumpByteArray(keydata));


            SSH2DataReader re = new SSH2DataReader(keydata);
            int magic = re.ReadInt32();
            /*if (magic != MAGIC_VAL)
                throw new SSHException("key file is broken");*/
            int privateKeyLen = re.ReadInt32();
            string type = Encoding.ASCII.GetString(re.ReadString());

            string ciphername = Encoding.ASCII.GetString(re.ReadString());
            int bufLen = re.ReadInt32();
            if (ciphername != "none") {
                CipherAlgorithm algo = CipherFactory.SSH2NameToAlgorithm(ciphername);
                byte[] key = PassphraseToKey(passphrase, CipherFactory.GetKeySize(algo));
                Cipher c = CipherFactory.CreateCipher(SSHProtocol.SSH2, algo, key);
                byte[] tmp = new Byte[re.Image.Length - re.Offset];
                c.Decrypt(re.Image, re.Offset, re.Image.Length - re.Offset, tmp, 0);
                re = new SSH2DataReader(tmp);
            }

            int parmLen = re.ReadInt32();
            if (parmLen < 0 || parmLen > re.Rest)
                throw new SSHException(Strings.GetString("WrongPassphrase"));

            if (type.IndexOf("if-modn") != -1) {
                //mindterm mistaken this order of BigIntegers
                BigInteger e = re.ReadBigIntWithBits();
                BigInteger d = re.ReadBigIntWithBits();
                BigInteger n = re.ReadBigIntWithBits();
                BigInteger u = re.ReadBigIntWithBits();
                BigInteger p = re.ReadBigIntWithBits();
                BigInteger q = re.ReadBigIntWithBits();
                return new SSH2UserAuthKey(new RSAKeyPair(e, d, n, u, p, q), comment);
            }
            else if (type.IndexOf("dl-modp") != -1) {
                if (re.ReadInt32() != 0)
                    throw new SSHException("DSS Private Key File is broken");
                BigInteger p = re.ReadBigIntWithBits();
                BigInteger g = re.ReadBigIntWithBits();
                BigInteger q = re.ReadBigIntWithBits();
                BigInteger y = re.ReadBigIntWithBits();
                BigInteger x = re.ReadBigIntWithBits();
                return new SSH2UserAuthKey(new DSAKeyPair(p, g, q, y, x), comment);
            }
            else
                throw new SSHException("unknown authentication method " + type);

        }