ReadTag() public method

Read tag. (only check the value type)
public ReadTag ( TagClass tagClass, bool isConstructed, int tagNumber, int &length ) : bool
tagClass TagClass expected tag class
isConstructed bool expected value of "constructed" flag
tagNumber int expected tag number
length int length of the value field will be stored
return bool
コード例 #1
0
        /// <summary>
        /// Read 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>
        public void Load(string passphrase, out KeyPair keyPair, out string comment)
        {
            PEMKeyType keyType;
            String base64Text;
            bool encrypted = false;
            CipherAlgorithm? encryption = null;
            byte[] iv = null;
            int keySize = 0;
            int ivSize = 0;

            using (StreamReader sreader = GetStreamReader()) {
                string line = sreader.ReadLine();
                if (line == null)
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)");

                if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_RSA)
                    keyType = PEMKeyType.RSA;
                else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_DSA)
                    keyType = PEMKeyType.DSA;
                else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_ECDSA)
                    keyType = PEMKeyType.ECDSA;
                else
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected key type)");

                string footer = line.Replace("BEGIN", "END");

                StringBuilder buf = new StringBuilder();
                comment = String.Empty;
                while (true) {
                    line = sreader.ReadLine();
                    if (line == null)
                        throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)");
                    if (line == footer)
                        break;
                    if (line.IndexOf(':') >= 0) {
                        if (line.StartsWith("Proc-Type:")) {
                            string[] w = line.Substring("Proc-Type:".Length).Trim().Split(',');
                            if (w.Length < 1)
                                throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid Proc-Type)");
                            if (w[0] != "4")
                                throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat")
                                            + " (" + Strings.GetString("Reason_UnsupportedProcType") + ")");
                            if (w.Length >= 2 && w[1] == "ENCRYPTED")
                                encrypted = true;
                        }
                        else if (line.StartsWith("DEK-Info:")) {
                            string[] w = line.Substring("DEK-Info:".Length).Trim().Split(',');
                            if (w.Length < 2)
                                throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid DEK-Info)");
                            switch (w[0]) {
                                case "DES-EDE3-CBC":
                                    encryption = CipherAlgorithm.TripleDES;
                                    ivSize = 8;
                                    keySize = 24;
                                    break;
                                case "AES-128-CBC":
                                    encryption = CipherAlgorithm.AES128;
                                    ivSize = 16;
                                    keySize = 16;
                                    break;
                                default:
                                    throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat")
                                            + " (" + Strings.GetString("Reason_UnsupportedEncryptionType") + ")");
                            }
                            iv = HexToByteArray(w[1]);
                            if (iv == null || iv.Length != ivSize)
                                throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid IV)");
                        }
                    }
                    else
                        buf.Append(line);
                }
                base64Text = buf.ToString();
            }

            byte[] keydata = Base64.Decode(Encoding.ASCII.GetBytes(base64Text));

            if (encrypted) {
                if (!encryption.HasValue || iv == null)
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing encryption type or IV)");
                byte[] key = PassphraseToKey(passphrase, iv, keySize);
                Cipher cipher = CipherFactory.CreateCipher(SSHProtocol.SSH2, encryption.Value, key, iv);
                if (keydata.Length % cipher.BlockSize != 0)
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid key data size)");
                cipher.Decrypt(keydata, 0, keydata.Length, keydata, 0);
            }

            using (MemoryStream keyDataStream = new MemoryStream(keydata, false)) {
                BERReader reader = new BERReader(keyDataStream);
                if (!reader.ReadSequence())
                    throw new SSHException(Strings.GetString("WrongPassphrase"));
                if (keyType == PEMKeyType.RSA) {
                    /* from OpenSSL rsa_asn1.c
                     *
                     * ASN1_SIMPLE(RSA, version, LONG),
                     * ASN1_SIMPLE(RSA, n, BIGNUM),
                     * ASN1_SIMPLE(RSA, e, BIGNUM),
                     * ASN1_SIMPLE(RSA, d, BIGNUM),
                     * ASN1_SIMPLE(RSA, p, BIGNUM),
                     * ASN1_SIMPLE(RSA, q, BIGNUM),
                     * ASN1_SIMPLE(RSA, dmp1, BIGNUM),
                     * ASN1_SIMPLE(RSA, dmq1, BIGNUM),
                     * ASN1_SIMPLE(RSA, iqmp, BIGNUM)
                     */
                    BigInteger v, n, e, d, p, q, dmp1, dmq1, iqmp;
                    if (!reader.ReadInteger(out v) ||
                        !reader.ReadInteger(out n) ||
                        !reader.ReadInteger(out e) ||
                        !reader.ReadInteger(out d) ||
                        !reader.ReadInteger(out p) ||
                        !reader.ReadInteger(out q) ||
                        !reader.ReadInteger(out dmp1) ||
                        !reader.ReadInteger(out dmq1) ||
                        !reader.ReadInteger(out iqmp)) {

                        throw new SSHException(Strings.GetString("WrongPassphrase"));
                    }

                    BigInteger u = p.ModInverse(q);	// inverse of p mod q
                    keyPair = new RSAKeyPair(e, d, n, u, p, q);
                }
                else if (keyType == PEMKeyType.DSA) {
                    /* from OpenSSL dsa_asn1.c
                     *
                     * ASN1_SIMPLE(DSA, version, LONG),
                     * ASN1_SIMPLE(DSA, p, BIGNUM),
                     * ASN1_SIMPLE(DSA, q, BIGNUM),
                     * ASN1_SIMPLE(DSA, g, BIGNUM),
                     * ASN1_SIMPLE(DSA, pub_key, BIGNUM),
                     * ASN1_SIMPLE(DSA, priv_key, BIGNUM)
                     */
                    BigInteger v, p, q, g, y, x;
                    if (!reader.ReadInteger(out v) ||
                        !reader.ReadInteger(out p) ||
                        !reader.ReadInteger(out q) ||
                        !reader.ReadInteger(out g) ||
                        !reader.ReadInteger(out y) ||
                        !reader.ReadInteger(out x)) {

                        throw new SSHException(Strings.GetString("WrongPassphrase"));
                    }
                    keyPair = new DSAKeyPair(p, g, q, y, x);
                }
                else if (keyType == PEMKeyType.ECDSA) {
                    /* from OpenSSL ec_asn1.c
                     *
                     * ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG),
                     * ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING),
                     * ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0),
                     *   ------
                     *   ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT),
                     *   ------
                     * ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1)
                     */
                    int len;
                    byte[] privateKey;
                    byte[] publicKey;
                    string namedCurve;
                    BigInteger v;
                    if (!reader.ReadInteger(out v) ||
                        !reader.ReadOctetString(out privateKey) ||
                        !reader.ReadTag(BERReader.TagClass.ContextSpecific, true, 0, out len) ||
                        !reader.ReadObjectIdentifier(out namedCurve) ||
                        !reader.ReadTag(BERReader.TagClass.ContextSpecific, true, 1, out len) ||
                        !reader.ReadBitString(out publicKey)) {

                        throw new SSHException(Strings.GetString("WrongPassphrase"));
                    }

                    EllipticCurve curve = EllipticCurve.FindByOID(namedCurve);
                    if (curve == null) {
                        throw new SSHException(Strings.GetString("UnsupportedEllipticCurveInKeyPair"));
                    }

                    ECPoint ecPublicKeyPoint;
                    if (!ECPoint.Parse(publicKey, curve, out ecPublicKeyPoint)) {
                        throw new SSHException(Strings.GetString("KeysAreBroken"));
                    }

                    var ecKeyPair = new ECDSAKeyPair(curve, new ECDSAPublicKey(curve, ecPublicKeyPoint), new BigInteger(privateKey));

                    if (!ecKeyPair.CheckKeyConsistency()) {
                        throw new SSHException(Strings.GetString("KeysAreBroken"));
                    }

                    keyPair = ecKeyPair;
                }
                else {
                    throw new SSHException("Unknown file type. This should not happen.");
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Read 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>
        public void Load(string passphrase, out KeyPair keyPair, out string comment)
        {
            PEMKeyType      keyType;
            String          base64Text;
            bool            encrypted  = false;
            CipherAlgorithm?encryption = null;

            byte[] iv      = null;
            int    keySize = 0;
            int    ivSize  = 0;

            using (StreamReader sreader = GetStreamReader()) {
                string line = sreader.ReadLine();
                if (line == null)
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)");
                }

                if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_RSA)
                {
                    keyType = PEMKeyType.RSA;
                }
                else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_DSA)
                {
                    keyType = PEMKeyType.DSA;
                }
                else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_ECDSA)
                {
                    keyType = PEMKeyType.ECDSA;
                }
                else
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected key type)");
                }

                string footer = line.Replace("BEGIN", "END");

                StringBuilder buf = new StringBuilder();
                comment = String.Empty;
                while (true)
                {
                    line = sreader.ReadLine();
                    if (line == null)
                    {
                        throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)");
                    }
                    if (line == footer)
                    {
                        break;
                    }
                    if (line.IndexOf(':') >= 0)
                    {
                        if (line.StartsWith("Proc-Type:"))
                        {
                            string[] w = line.Substring("Proc-Type:".Length).Trim().Split(',');
                            if (w.Length < 1)
                            {
                                throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid Proc-Type)");
                            }
                            if (w[0] != "4")
                            {
                                throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat")
                                                       + " (" + Strings.GetString("Reason_UnsupportedProcType") + ")");
                            }
                            if (w.Length >= 2 && w[1] == "ENCRYPTED")
                            {
                                encrypted = true;
                            }
                        }
                        else if (line.StartsWith("DEK-Info:"))
                        {
                            string[] w = line.Substring("DEK-Info:".Length).Trim().Split(',');
                            if (w.Length < 2)
                            {
                                throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid DEK-Info)");
                            }
                            switch (w[0])
                            {
                            case "DES-EDE3-CBC":
                                encryption = CipherAlgorithm.TripleDES;
                                ivSize     = 8;
                                keySize    = 24;
                                break;

                            case "AES-128-CBC":
                                encryption = CipherAlgorithm.AES128;
                                ivSize     = 16;
                                keySize    = 16;
                                break;

                            default:
                                throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat")
                                                       + " (" + Strings.GetString("Reason_UnsupportedEncryptionType") + ")");
                            }
                            iv = HexToByteArray(w[1]);
                            if (iv == null || iv.Length != ivSize)
                            {
                                throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid IV)");
                            }
                        }
                    }
                    else
                    {
                        buf.Append(line);
                    }
                }
                base64Text = buf.ToString();
            }

            byte[] keydata = Base64.Decode(Encoding.ASCII.GetBytes(base64Text));

            if (encrypted)
            {
                if (!encryption.HasValue || iv == null)
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing encryption type or IV)");
                }
                byte[] key    = PassphraseToKey(passphrase, iv, keySize);
                Cipher cipher = CipherFactory.CreateCipher(SSHProtocol.SSH2, encryption.Value, key, iv);
                if (keydata.Length % cipher.BlockSize != 0)
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid key data size)");
                }
                cipher.Decrypt(keydata, 0, keydata.Length, keydata, 0);
            }

            using (MemoryStream keyDataStream = new MemoryStream(keydata, false)) {
                BERReader reader = new BERReader(keyDataStream);
                if (!reader.ReadSequence())
                {
                    throw new SSHException(Strings.GetString("WrongPassphrase"));
                }
                if (keyType == PEMKeyType.RSA)
                {
                    /* from OpenSSL rsa_asn1.c
                     *
                     * ASN1_SIMPLE(RSA, version, LONG),
                     * ASN1_SIMPLE(RSA, n, BIGNUM),
                     * ASN1_SIMPLE(RSA, e, BIGNUM),
                     * ASN1_SIMPLE(RSA, d, BIGNUM),
                     * ASN1_SIMPLE(RSA, p, BIGNUM),
                     * ASN1_SIMPLE(RSA, q, BIGNUM),
                     * ASN1_SIMPLE(RSA, dmp1, BIGNUM),
                     * ASN1_SIMPLE(RSA, dmq1, BIGNUM),
                     * ASN1_SIMPLE(RSA, iqmp, BIGNUM)
                     */
                    BigInteger v, n, e, d, p, q, dmp1, dmq1, iqmp;
                    if (!reader.ReadInteger(out v) ||
                        !reader.ReadInteger(out n) ||
                        !reader.ReadInteger(out e) ||
                        !reader.ReadInteger(out d) ||
                        !reader.ReadInteger(out p) ||
                        !reader.ReadInteger(out q) ||
                        !reader.ReadInteger(out dmp1) ||
                        !reader.ReadInteger(out dmq1) ||
                        !reader.ReadInteger(out iqmp))
                    {
                        throw new SSHException(Strings.GetString("WrongPassphrase"));
                    }

                    BigInteger u = p.ModInverse(q);     // inverse of p mod q
                    keyPair = new RSAKeyPair(e, d, n, u, p, q);
                }
                else if (keyType == PEMKeyType.DSA)
                {
                    /* from OpenSSL dsa_asn1.c
                     *
                     * ASN1_SIMPLE(DSA, version, LONG),
                     * ASN1_SIMPLE(DSA, p, BIGNUM),
                     * ASN1_SIMPLE(DSA, q, BIGNUM),
                     * ASN1_SIMPLE(DSA, g, BIGNUM),
                     * ASN1_SIMPLE(DSA, pub_key, BIGNUM),
                     * ASN1_SIMPLE(DSA, priv_key, BIGNUM)
                     */
                    BigInteger v, p, q, g, y, x;
                    if (!reader.ReadInteger(out v) ||
                        !reader.ReadInteger(out p) ||
                        !reader.ReadInteger(out q) ||
                        !reader.ReadInteger(out g) ||
                        !reader.ReadInteger(out y) ||
                        !reader.ReadInteger(out x))
                    {
                        throw new SSHException(Strings.GetString("WrongPassphrase"));
                    }
                    keyPair = new DSAKeyPair(p, g, q, y, x);
                }
                else if (keyType == PEMKeyType.ECDSA)
                {
                    /* from OpenSSL ec_asn1.c
                     *
                     * ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG),
                     * ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING),
                     * ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0),
                     *   ------
                     *   ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT),
                     *   ------
                     * ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1)
                     */
                    int        len;
                    byte[]     privateKey;
                    byte[]     publicKey;
                    string     namedCurve;
                    BigInteger v;
                    if (!reader.ReadInteger(out v) ||
                        !reader.ReadOctetString(out privateKey) ||
                        !reader.ReadTag(BERReader.TagClass.ContextSpecific, true, 0, out len) ||
                        !reader.ReadObjectIdentifier(out namedCurve) ||
                        !reader.ReadTag(BERReader.TagClass.ContextSpecific, true, 1, out len) ||
                        !reader.ReadBitString(out publicKey))
                    {
                        throw new SSHException(Strings.GetString("WrongPassphrase"));
                    }

                    EllipticCurve curve = EllipticCurve.FindByOID(namedCurve);
                    if (curve == null)
                    {
                        throw new SSHException(Strings.GetString("UnsupportedEllipticCurveInKeyPair"));
                    }

                    ECPoint ecPublicKeyPoint;
                    if (!ECPoint.Parse(publicKey, curve, out ecPublicKeyPoint))
                    {
                        throw new SSHException(Strings.GetString("KeysAreBroken"));
                    }

                    var ecKeyPair = new ECDSAKeyPair(curve, new ECDSAPublicKey(curve, ecPublicKeyPoint), new BigInteger(privateKey));

                    if (!ecKeyPair.CheckKeyConsistency())
                    {
                        throw new SSHException(Strings.GetString("KeysAreBroken"));
                    }

                    keyPair = ecKeyPair;
                }
                else
                {
                    throw new SSHException("Unknown file type. This should not happen.");
                }
            }
        }