Ejemplo n.º 1
0
        public override byte[] SendMessage(byte[] aMessage)
        {
            var hwnd = FindWindow(cPageantWindowClass, cPageantWindowClass);

            if (hwnd == IntPtr.Zero)
            {
                throw new AgentNotRunningException();
            }
            var threadId = Thread.CurrentThread.ManagedThreadId;
            var mapName  = String.Format("{0}{1:x8}", cMapNamePrefix, threadId);

            using (var mappedFile = MemoryMappedFile.CreateNew(mapName, 8192)) {
                if (mappedFile.SafeMemoryMappedFileHandle.IsInvalid)
                {
                    throw new Exception("Invalid mapped file handle");
                }
                using (var stream = mappedFile.CreateViewStream()) {
                    stream.Write(aMessage, 0, aMessage.Length);
                    var copyData = new COPYDATASTRUCT();
                    if (IntPtr.Size == 4)
                    {
                        copyData.dwData = new IntPtr(unchecked ((int)AGENT_COPYDATA_ID));
                    }
                    else
                    {
                        copyData.dwData = new IntPtr(AGENT_COPYDATA_ID);
                    }
                    copyData.cbData = mapName.Length + 1;
                    copyData.lpData = Marshal.StringToCoTaskMemAnsi(mapName);
                    IntPtr copyDataPtr = Marshal.AllocHGlobal(Marshal.SizeOf(copyData));
                    Marshal.StructureToPtr(copyData, copyDataPtr, false);
                    var resultPtr =
                        SendMessage(hwnd, WM_COPYDATA, IntPtr.Zero, copyDataPtr);
                    Marshal.FreeHGlobal(copyData.lpData);
                    Marshal.FreeHGlobal(copyDataPtr);
                    if (resultPtr == IntPtr.Zero)
                    {
                        throw new Exception("send message failed");
                    }
                    stream.Position = 0;
                    var parser      = new BlobParser(stream);
                    var replyLength = parser.ReadUInt32();
                    stream.Position = 0;
                    var reply = new byte[replyLength + 4];
                    stream.Read(reply, 0, reply.Length);
                    return(reply);
                }
            }
        }
        public override object Deserialize(Stream stream)
        {
            /* check for required parameters */
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            try {
                var reader    = new StreamReader(stream);
                var firstLine = reader.ReadLine();
                if (firstLine != MARK_BEGIN)
                {
                    throw new KeyFormatterException("Bad file format - does not have expected header.");
                }
                var base64String = new StringBuilder();
                while (true)
                {
                    var line = reader.ReadLine();
                    if (line == MARK_END)
                    {
                        break;
                    }
                    base64String.Append(line);
                }

                /* reading unencrypted part */
                BlobParser parser = new BlobParser(Util.FromBase64(base64String.ToString()));

                var magicBytes = parser.ReadBytes((uint)AUTH_MAGIC.Length);
                if (Encoding.UTF8.GetString(magicBytes) != AUTH_MAGIC)
                {
                    throw new KeyFormatterException("Bad data - missing AUTH_MAGIC.");
                }

                var ciphername = parser.ReadString();
                if (!IsSupportCipher(ciphername))
                {
                    throw new KeyFormatterException("Unsupported cyphername: " + ciphername);
                }

                var kdfname = parser.ReadString();
                if (kdfname != KDFNAME_BCRYPT && kdfname != KDFNAME_NONE)
                {
                    throw new KeyFormatterException("Unsupported kdfname: " + ciphername);
                }
                if (kdfname == KDFNAME_NONE && ciphername != CIPHERNAME_NONE)
                {
                    throw new KeyFormatterException("Invalid format.");
                }

                var kdfoptions = parser.ReadBlob();
                var keyCount   = parser.ReadUInt32();
                if (keyCount != 1)
                {
                    throw new KeyFormatterException("Only one key allowed.");
                }

                var publicKeys = new List <byte[]>();
                for (int i = 0; i < keyCount; i++)
                {
                    publicKeys.Add(parser.ReadBlob());
                }
                var privateKeys = parser.ReadBlob();

                var keyAndIV = new byte[32 + 16];
                if (kdfname == KDFNAME_BCRYPT)
                {
                    var kdfOptionsParser = new BlobParser(kdfoptions);
                    var salt             = kdfOptionsParser.ReadBlob();
                    var rounds           = kdfOptionsParser.ReadUInt32();

                    var passphrase      = GetPassphraseCallbackMethod(null);
                    var passphraseChars = new char[passphrase.Length];
                    var passphrasePtr   = Marshal.SecureStringToGlobalAllocUnicode(passphrase);
                    for (int i = 0; i < passphrase.Length; i++)
                    {
                        passphraseChars[i] = (char)Marshal.ReadInt16(passphrasePtr, i * 2);
                    }
                    Marshal.ZeroFreeGlobalAllocUnicode(passphrasePtr);
                    BCrypt.HashUsingOpensshBCryptPbkdf(passphraseChars, salt, ref keyAndIV, rounds);
                    Array.Clear(passphraseChars, 0, passphraseChars.Length);
                }

                var key = new byte[32];
                Array.Copy(keyAndIV, key, key.Length);
                var iv = new byte[16];
                Array.Copy(keyAndIV, key.Length, iv, 0, iv.Length);

                switch (ciphername)
                {
                case CIPHERNAME_AES256_CBC:
                    var aes = Aes.Create();
                    aes.KeySize = 256;
                    aes.Mode    = CipherMode.CBC;
                    aes.Padding = PaddingMode.None;
                    aes.Key     = key;
                    aes.IV      = iv;

                    if (privateKeys.Length < aes.BlockSize / 8 || privateKeys.Length % (aes.BlockSize / 8) != 0)
                    {
                        throw new KeyFormatterException("Bad private key encrypted length.");
                    }

                    using (ICryptoTransform decryptor = aes.CreateDecryptor()) {
                        privateKeys = Util.GenericTransform(decryptor, privateKeys);
                    }
                    aes.Clear();
                    break;

                case CIPHERNAME_AES256_CTR:
                    var ctrCipher = CipherUtilities.GetCipher("AES/CTR/NoPadding");
                    ctrCipher.Init(false, new ParametersWithIV(new KeyParameter(key), iv));
                    privateKeys = ctrCipher.DoFinal(privateKeys);
                    break;
                }

                parser = new BlobParser(privateKeys);

                var checkint1 = parser.ReadUInt32();
                var checkint2 = parser.ReadUInt32();
                if (checkint1 != checkint2)
                {
                    throw new KeyFormatterException("checkint does not match in private key.");
                }
                var keys = new List <SshKey>();
                for (int i = 0; i < keyCount; i++)
                {
                    OpensshCertificate cert;
                    var publicKey = parser.ReadSsh2PublicKeyData(out cert);
                    var keyPair   = parser.ReadSsh2KeyData(publicKey);
                    var comment   = parser.ReadString();
                    var sshKey    = new SshKey(SshVersion.SSH2, keyPair, comment, cert);
                    keys.Add(sshKey);
                }
                return(keys[0]);
            } catch (KeyFormatterException) {
                throw;
            } catch (Exception ex) {
                throw new KeyFormatterException("see inner exception", ex);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Answers the message.
        /// </summary>
        /// <param name='messageStream'>Message stream.</param>
        /// <param name="process">The calling process or <c>null</c> if the process
        /// could not be obtained.</param>
        /// <remarks>code based on winpgnt.c from PuTTY source code</remarks>
        public void AnswerMessage(Stream messageStream, Process process = null)
        {
            if (messageStream.CanTimeout)
            {
                messageStream.ReadTimeout = 5000;
            }
            var        messageParser   = new BlobParser(messageStream);
            var        responseBuilder = new BlobBuilder();
            BlobHeader header;

            try {
                header = messageParser.ReadHeader();

                if (MessageReceived != null)
                {
                    var eventArgs = new MessageReceivedEventArgs(header);
                    MessageReceived(this, eventArgs);
                    if (eventArgs.Fail)
                    {
                        throw new Exception();
                    }
                }
            } catch (Exception) {
                header         = new BlobHeader();
                header.Message = Message.UNKNOWN;
                // this will cause the switch statement below to use the default case
                // which returns an error to the stream.
            }

            switch (header.Message)
            {
            case Message.SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
                /*
                 * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
                 */
                try {
                    if (header.BlobLength > 1)
                    {
                        // ruby net-ssh tries to send a SSH2_AGENT_REQUEST_VERSION message
                        // which has the same id number as SSH1_AGENTC_REQUEST_RSA_IDENTITIES
                        // with a string tacked on. We need to read the string from the
                        // stream, but it is not used for anything.
                        messageParser.ReadString();
                    }
                    var keyList = ListKeys(SshVersion.SSH1);
                    if (FilterKeyListCallback != null)
                    {
                        keyList = FilterKeyListCallback(keyList);
                    }
                    foreach (SshKey key in keyList)
                    {
                        responseBuilder.AddBytes(key.GetPublicKeyBlob());
                        responseBuilder.AddStringBlob(key.Comment);
                    }
                    responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_IDENTITIES_ANSWER,
                                                 keyList.Count);
                    // TODO may want to check that there is enough room in the message stream
                    break; // succeeded
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH2_AGENTC_REQUEST_IDENTITIES:
                /*
                 * Reply with SSH2_AGENT_IDENTITIES_ANSWER.
                 */
                try {
                    var keyList = ListKeys(SshVersion.SSH2);
                    if (FilterKeyListCallback != null)
                    {
                        keyList = FilterKeyListCallback(keyList);
                    }
                    foreach (SshKey key in keyList)
                    {
                        responseBuilder.AddBlob(key.GetPublicKeyBlob());
                        responseBuilder.AddStringBlob(key.Comment);
                    }
                    responseBuilder.InsertHeader(Message.SSH2_AGENT_IDENTITIES_ANSWER,
                                                 keyList.Count);
                    // TODO may want to check that there is enough room in the message stream
                    break; // succeeded
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH1_AGENTC_RSA_CHALLENGE:
                /*
                 * Reply with either SSH1_AGENT_RSA_RESPONSE or
                 * SSH_AGENT_FAILURE, depending on whether we have that key
                 * or not.
                 */

                try {
                    //Reading publicKey information
                    var publicKeyParams = messageParser.ReadSsh1PublicKeyData(true);

                    //Searching for Key here
                    var matchingKey = mKeyList.Where(key => key.Version == SshVersion.SSH1 &&
                                                     (key.GetPublicKeyParameters().Equals(publicKeyParams))).Single();

                    //Reading challenge
                    var encryptedChallenge = messageParser.ReadSsh1BigIntBlob();
                    var sessionId          = messageParser.ReadBytes(16);

                    //Checking responseType field
                    if (messageParser.ReadUInt32() != 1)
                    {
                        goto default; //responseType !=1  is not longer supported
                    }

                    //Answering to the challenge
                    var engine = new Pkcs1Encoding(new RsaEngine());
                    engine.Init(false /* decrypt */, matchingKey.GetPrivateKeyParameters());

                    var decryptedChallenge = engine.ProcessBlock(encryptedChallenge,
                                                                 0, encryptedChallenge.Length);

                    using (MD5 md5 = MD5.Create()) {
                        var md5Buffer = new byte[48];
                        decryptedChallenge.CopyTo(md5Buffer, 0);
                        sessionId.CopyTo(md5Buffer, 32);

                        responseBuilder.AddBytes(md5.ComputeHash(md5Buffer));
                        responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_RESPONSE);
                        break;
                    }
                } catch (InvalidOperationException) {
                    // this is expected if there is not a matching key
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }

                goto default; // failed

            case Message.SSH2_AGENTC_SIGN_REQUEST:
                /*
                 * Reply with either SSH2_AGENT_SIGN_RESPONSE or SSH_AGENT_FAILURE,
                 * depending on whether we have that key or not.
                 */
                try {
                    var keyBlob = messageParser.ReadBlob();
                    var reqData = messageParser.ReadBlob();
                    var flags   = new SignRequestFlags();
                    try {
                        // usually, there are no flags, so parser will throw
                        flags = (SignRequestFlags)messageParser.ReadUInt32();
                    } catch { }

                    var matchingKey =
                        mKeyList.Where(key => key.Version == SshVersion.SSH2 &&
                                       key.GetPublicKeyBlob().SequenceEqual(keyBlob)).First();
                    var confirmConstraints = matchingKey.Constraints
                                             .Where(constraint => constraint.Type ==
                                                    KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM);
                    if (confirmConstraints.Count() > 0)
                    {
                        if (!ConfirmUserPermissionCallback.Invoke(matchingKey, process))
                        {
                            goto default;
                        }
                    }

                    /* create signature */
                    var signKey = matchingKey;
                    var signer  = signKey.GetSigner();
                    var algName = signKey.Algorithm.GetIdentifierString();
                    signer.Init(true, signKey.GetPrivateKeyParameters());
                    signer.BlockUpdate(reqData, 0, reqData.Length);
                    byte[] signature = signer.GenerateSignature();
                    signature = signKey.FormatSignature(signature);
                    BlobBuilder signatureBuilder = new BlobBuilder();
                    if (!flags.HasFlag(SignRequestFlags.SSH_AGENT_OLD_SIGNATURE))
                    {
                        signatureBuilder.AddStringBlob(algName);
                    }
                    signatureBuilder.AddBlob(signature);
                    responseBuilder.AddBlob(signatureBuilder.GetBlob());
                    responseBuilder.InsertHeader(Message.SSH2_AGENT_SIGN_RESPONSE);
                    try {
                        KeyUsed(this, new KeyUsedEventArgs(signKey, process));
                    } catch { }
                    break; // succeeded
                } catch (InvalidOperationException) {
                    // this is expected if there is not a matching key
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failure

            case Message.SSH1_AGENTC_ADD_RSA_IDENTITY:
            case Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED:
                /*
                 * Add to the list and return SSH_AGENT_SUCCESS, or
                 * SSH_AGENT_FAILURE if the key was malformed.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                bool ssh1constrained = (header.Message == Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED);

                try {
                    var publicKeyParams = messageParser.ReadSsh1PublicKeyData(false);
                    var keyPair         = messageParser.ReadSsh1KeyData(publicKeyParams);

                    SshKey key = new SshKey(SshVersion.SSH1, keyPair);
                    key.Comment = messageParser.ReadString();
                    key.Source  = "External client";

                    if (ssh1constrained)
                    {
                        while (messageStream.Position < header.BlobLength + 4)
                        {
                            KeyConstraint constraint = new KeyConstraint();
                            constraint.Type = (KeyConstraintType)messageParser.ReadUInt8();
                            if (constraint.Type ==
                                KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME)
                            {
                                constraint.Data = messageParser.ReadUInt32();
                            }
                            key.AddConstraint(constraint);
                        }
                    }
                    AddKey(key);
                    responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                    break;
                } catch (CallbackNullException) {
                    // this is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }

                goto default; // failed

            case Message.SSH2_AGENTC_ADD_IDENTITY:
            case Message.SSH2_AGENTC_ADD_ID_CONSTRAINED:
                /*
                 * Add to the list and return SSH_AGENT_SUCCESS, or
                 * SSH_AGENT_FAILURE if the key was malformed.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                bool constrained = (header.Message ==
                                    Message.SSH2_AGENTC_ADD_ID_CONSTRAINED);

                try {
                    OpensshCertificate cert;
                    var    publicKeyParams = messageParser.ReadSsh2PublicKeyData(out cert);
                    var    keyPair         = messageParser.ReadSsh2KeyData(publicKeyParams);
                    SshKey key             = new SshKey(SshVersion.SSH2, keyPair, null, cert);
                    key.Comment = messageParser.ReadString();
                    key.Source  = "External client";

                    if (constrained)
                    {
                        while (messageStream.Position < header.BlobLength + 4)
                        {
                            KeyConstraint constraint = new KeyConstraint();
                            constraint.Type =
                                (KeyConstraintType)messageParser.ReadUInt8();
                            if (constraint.Type ==
                                KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME)
                            {
                                constraint.Data = messageParser.ReadUInt32();
                            }
                            key.AddConstraint(constraint);
                        }
                    }
                    AddKey(key);
                    responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                    break; // success!
                } catch (CallbackNullException) {
                    // this is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY:
            case Message.SSH2_AGENTC_REMOVE_IDENTITY:
                /*
                 * Remove from the list and return SSH_AGENT_SUCCESS, or
                 * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
                 * start with.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                SshVersion removeVersion;
                byte[]     rKeyBlob;
                if (header.Message == Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY)
                {
                    removeVersion = SshVersion.SSH1;
                    rKeyBlob      = messageParser.ReadBytes(header.BlobLength - 1);
                }
                else if (header.Message == Message.SSH2_AGENTC_REMOVE_IDENTITY)
                {
                    removeVersion = SshVersion.SSH2;
                    rKeyBlob      = messageParser.ReadBlob();
                }
                else
                {
                    Debug.Fail("Should not get here.");
                    goto default;
                }

                try {
                    var matchingKey        = mKeyList.Get(removeVersion, rKeyBlob);
                    var startKeyListLength = mKeyList.Count;
                    RemoveKey(matchingKey);
                    // only succeed if key was removed
                    if (mKeyList.Count == startKeyListLength - 1)
                    {
                        responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                        break; //success!
                    }
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
            case Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
                /*
                 * Remove all SSH-1 or SSH-2 keys.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                SshVersion removeAllVersion;
                if (header.Message == Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES)
                {
                    removeAllVersion = SshVersion.SSH1;
                }
                else if (header.Message == Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES)
                {
                    removeAllVersion = SshVersion.SSH2;
                }
                else
                {
                    Debug.Fail("Should not get here.");
                    goto default;
                }

                try {
                    RemoveAllKeys(removeAllVersion);
                    responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                    break; //success!
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH_AGENTC_LOCK:
                try {
                    var passphrase = new PinnedArray <byte>(messageParser.ReadBlob());
                    try {
                        Lock(passphrase.Data);
                    } finally {
                        passphrase.Clear();
                    }
                    if (IsLocked)
                    {
                        responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                        break;
                    }
                } catch (AgentLockedException) {
                    // This is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default;

            case Message.SSH_AGENTC_UNLOCK:
                try {
                    var passphrase = new PinnedArray <byte>(messageParser.ReadBlob());
                    try {
                        Unlock(passphrase.Data);
                    } finally {
                        passphrase.Clear();
                    }
                    if (!IsLocked)
                    {
                        responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                        break;
                    }
                } catch (AgentLockedException) {
                    // This is expected
                } catch (PassphraseException) {
                    // This is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default;

            default:
                responseBuilder.Clear();
                responseBuilder.InsertHeader(Message.SSH_AGENT_FAILURE);
                break;
            }
            /* write response to stream */
            if (messageStream.CanSeek)
            {
                messageStream.Position = 0;
            }
            messageStream.Write(responseBuilder.GetBlob(), 0, responseBuilder.Length);
            messageStream.Flush();
        }
Ejemplo n.º 4
0
        public ICollection <ISshKey> ListKeys(SshVersion aVersion)
        {
            BlobBuilder builder = new BlobBuilder();

            switch (aVersion)
            {
            case SshVersion.SSH1:
                builder.InsertHeader(Agent.Message.SSH1_AGENTC_REQUEST_RSA_IDENTITIES);
                break;

            case SshVersion.SSH2:
                builder.InsertHeader(Agent.Message.SSH2_AGENTC_REQUEST_IDENTITIES);
                break;

            default:
                throw new Exception(cUnsupportedSshVersion);
            }
            BlobParser replyParser   = SendMessage(builder);
            var        keyCollection = new List <ISshKey>();
            var        header        = replyParser.ReadHeader();

            switch (aVersion)
            {
            case SshVersion.SSH1:
                if (header.Message != Agent.Message.SSH1_AGENT_RSA_IDENTITIES_ANSWER)
                {
                    throw new AgentFailureException();
                }
                var ssh1KeyCount = replyParser.ReadUInt32();
                for (var i = 0; i < ssh1KeyCount; i++)
                {
                    var publicKeyParams = replyParser.ReadSsh1PublicKeyData(true);
                    var comment         = replyParser.ReadString();
                    keyCollection.Add(
                        new SshKey(SshVersion.SSH1, publicKeyParams, null, comment));
                }
                break;

            case SshVersion.SSH2:
                if (header.Message != Agent.Message.SSH2_AGENT_IDENTITIES_ANSWER)
                {
                    throw new AgentFailureException();
                }
                var ssh2KeyCount = replyParser.ReadUInt32();
                for (var i = 0; i < ssh2KeyCount; i++)
                {
                    var publicKeyBlob   = replyParser.ReadBlob();
                    var publicKeyParser = new BlobParser(publicKeyBlob);
                    OpensshCertificate cert;
                    var publicKeyParams = publicKeyParser.ReadSsh2PublicKeyData(out cert);
                    var comment         = replyParser.ReadString();
                    keyCollection.Add(
                        new SshKey(SshVersion.SSH2, publicKeyParams, null, comment, cert));
                }
                break;

            default:
                throw new Exception(cUnsupportedSshVersion);
            }
            return(keyCollection);
        }
Ejemplo n.º 5
0
        public override object Deserialize(Stream aStream)
        {
            /* check for required parameters */
            if (aStream == null)
            {
                throw new ArgumentNullException("aStream");
            }

            /* reading unencrypted part */
            BlobParser parser = new BlobParser(aStream);

            parser.ReadBytes((uint)FILE_HEADER_LINE.Length + 2); //Skipping header line

            byte cipherType = parser.ReadUInt8();

            if (cipherType != SSH_CIPHER_3DES && cipherType != SSH_CIPHER_NONE)
            {
                //TripleDes is the only encryption supported
                throw new KeyFormatterException("Unsupported cypherType: " + cipherType);
            }

            parser.ReadUInt32(); //reserved

            /* reading public key */
            AsymmetricKeyParameter aPublicKeyParameter =
                parser.ReadSsh1PublicKeyData(false);
            String keyComment = parser.ReadString();

            /* reading private key */
            byte[] inputBuffer = new byte[aStream.Length];
            aStream.Read(inputBuffer, 0, inputBuffer.Length);
            byte[] ouputBuffer;

            try {
                if (cipherType == 3)
                {
                    /* private key is 3DES encrypted */
                    PasswordFinder pwFinder = null;
                    if (GetPassphraseCallbackMethod != null)
                    {
                        pwFinder = new PasswordFinder(GetPassphraseCallbackMethod);
                    }

                    byte[] keydata;
                    try {
                        using (MD5 md5 = MD5.Create()) {
                            char[] md5Buffer = pwFinder.GetPassword();
                            keydata = md5.ComputeHash(Encoding.ASCII.GetBytes(md5Buffer));
                        }
                    } catch (PasswordException ex) {
                        if (GetPassphraseCallbackMethod == null)
                        {
                            throw new CallbackNullException();
                        }
                        throw new KeyFormatterException("see inner exception", ex);
                    }

                    /* decryption */
                    DesSsh1Engine desEngine = new DesSsh1Engine();
                    desEngine.Init(false, new KeyParameter(keydata));

                    BufferedBlockCipher bufferedBlockCipher = new BufferedBlockCipher(desEngine);
                    ouputBuffer = bufferedBlockCipher.ProcessBytes(inputBuffer);
                }
                else
                {
                    /* private key is stored in plain text */
                    ouputBuffer = inputBuffer;
                }

                var privateKeyParser = new BlobParser(ouputBuffer);

                /* checking result of decryption */
                byte[] resultCheck = privateKeyParser.ReadBytes(4);
                if (resultCheck[0] != resultCheck[2] || resultCheck[1] != resultCheck[3])
                {
                    throw new KeyFormatterException("bad passphrase");
                }

                /* reading private key */
                var    keyPair = privateKeyParser.ReadSsh1KeyData(aPublicKeyParameter);
                SshKey key     = new SshKey(SshVersion.SSH1, keyPair);
                key.Comment = keyComment;
                return(key);
            } catch (KeyFormatterException) {
                throw;
            } catch (Exception ex) {
                throw new KeyFormatterException("see inner exception", ex);
            }
        }