private static IKeyPair ExtractKeyPair(PrivateKeyFileDataReader privateKeySectionReader)
        {
            var      keyType = privateKeySectionReader.ReadString(Encoding.UTF8);
            IKeyPair keyPair = null;

            if (keyType == KeyTypes.ED25519)
            {
                var publicKey = privateKeySectionReader.ReadBytes(privateKeySectionReader.ReadInt32());
                privateKeySectionReader.ReadInt32();   //length of private + public key
                var privateKey = privateKeySectionReader.ReadBytes(32);
                privateKeySectionReader.ReadBytes(32); //public key (again)
                var comment = privateKeySectionReader.ReadString(Encoding.UTF8);
                keyPair = new Ed25519KeyPair(comment, publicKey, privateKey);
            }
            else if (keyType == KeyTypes.RSA)
            {
                var n       = privateKeySectionReader.ReadBigInteger(); //Modulus
                var e       = privateKeySectionReader.ReadBigInteger(); //Public Exponent
                var d       = privateKeySectionReader.ReadBigInteger(); //Private Exponent
                var iqmp    = privateKeySectionReader.ReadBigInteger(); //q^-1 mod p
                var p       = privateKeySectionReader.ReadBigInteger(); //Prime 1
                var q       = privateKeySectionReader.ReadBigInteger(); //Prime 2
                var comment = privateKeySectionReader.ReadString(Encoding.UTF8);
                keyPair = new RsaKeyPair(comment, n, e, d, iqmp, p, q);
            }
            else if (keyType == KeyTypes.ECDSA256 || keyType == KeyTypes.ECDSA384 || keyType == KeyTypes.ECDSA521)
            {
                int curveLength = privateKeySectionReader.ReadInt32();
                var curve       = Encoding.ASCII.GetString(privateKeySectionReader.ReadBytes(curveLength));
                var publicKey   = privateKeySectionReader.ReadBytes(privateKeySectionReader.ReadInt32());
                var privateKey  = privateKeySectionReader.ReadBytes(privateKeySectionReader.ReadInt32());
                var comment     = privateKeySectionReader.ReadString(Encoding.UTF8);
                keyPair = new EcdsaKeyPair(keyType, comment, curve, publicKey, privateKey);
            }
            else if (keyType == KeyTypes.DSA)
            {
                var p       = privateKeySectionReader.ReadBigInteger();
                var q       = privateKeySectionReader.ReadBigInteger();
                var g       = privateKeySectionReader.ReadBigInteger();
                var y       = privateKeySectionReader.ReadBigInteger();
                var x       = privateKeySectionReader.ReadBigInteger();
                var comment = privateKeySectionReader.ReadString(Encoding.UTF8);
                keyPair = new DsaKeyPair(comment, p, q, g, y, x);
            }
            else
            {
                throw new OpenSshKeyParseException($"key type '{keyType}' is not supported by this parser");
            }
            return(keyPair);
        }
        public static IKeyPair ParseOpenSshKeyFile(string privateKeyFileText, string passPhrase = null)
        {
            ValidPrivateKeyFileText(privateKeyFileText);
            try
            {
                IKeyPair keyPair = null;
                ValidateHeader(privateKeyFileText);
                using (var keyFileReader = GetPrivateKeyFileDataReader(privateKeyFileText))
                {
                    ValidateMagicHeader(keyFileReader.ReadBytes(AUTH_MAGIC.Length));

                    var    cipherName = keyFileReader.ReadString(Encoding.UTF8);
                    var    kdfName    = keyFileReader.ReadString(Encoding.UTF8);
                    byte[] salt       = null;
                    var    rounds     = 0;
                    if (keyFileReader.ReadInt32() > 0) //kdf options
                    {
                        salt   = keyFileReader.ReadBytes(keyFileReader.ReadInt32());
                        rounds = keyFileReader.ReadInt32();
                    }
                    ValidateEncryptionFields(cipherName, kdfName, passPhrase);

                    ValidateNumberOfKeys(keyFileReader.ReadInt32());

                    keyFileReader.ReadBytes(keyFileReader.ReadInt32()); //skip public key section

                    //we skipped the public key section but for reference, here is what parsing it would look like:

                    /*
                     * using (var publicKeySectionReader = new PrivateKeyFileDataReader(keyFileReader.ReadBytes(keyFileReader.ReadInt32())))
                     * {
                     *  publicKeySectionReader.ReadString(Encoding.UTF8); //key type
                     *  publicKeySectionReader.ReadBytes(); //public key, the parts of which will be dependant on the key type
                     * }
                     */

                    var privateKeySectionBytes = keyFileReader.ReadBytes(keyFileReader.ReadInt32());
                    if (cipherName != "none")
                    {
                        privateKeySectionBytes = DecryptPrivateKeySection(cipherName, privateKeySectionBytes, salt, rounds, passPhrase);
                    }
                    ValidatePrivateKeySectionLength(privateKeySectionBytes.Length);

                    using (var privateKeySectionReader = new PrivateKeyFileDataReader(privateKeySectionBytes))
                    {
                        ValidateCheckInts(privateKeySectionReader.ReadInt32(), privateKeySectionReader.ReadInt32());
                        keyPair = ExtractKeyPair(privateKeySectionReader);
                        ValidatePrivateKeyPadding(privateKeySectionReader.ReadBytes());
                    }
                }
                return(keyPair);
            }
            catch (Exception e)
            {
                if (e is OpenSshKeyParseException)
                {
                    throw e;
                }
                throw new OpenSshKeyParseException($"unexpected failure parsing key: {e.Message}");
            }
        }