Reads elements which are encoded by ASN.1 Basic Encoding Rules
Only SEQUENCE and INTEGER are supported.
예제 #1
0
 public void TestIncompleteIntegerTag()
 {
     using (MemoryStream mem = new MemoryStream(
                new byte[] { 0x02, 0x04, 0x12, 0x34, 0x56 }
                )) {
         BERReader  reader = new BERReader(mem);
         BigInteger n;
         Assert.False(reader.ReadInteger(out n));
     }
 }
예제 #2
0
 public void TestNonIntegerTag()
 {
     using (MemoryStream mem = new MemoryStream(
                new byte[] { 0x30, 0x03, 0x02, 0x01, 0x01 }
                )) {
         BERReader  reader = new BERReader(mem);
         BigInteger n;
         Assert.False(reader.ReadInteger(out n));
     }
 }
예제 #3
0
 public void TestIncompleteTag()
 {
     using (MemoryStream mem = new MemoryStream(
                new byte[] { 0x7f, 0x87, 0xef, 0xab, 0xb7, 0x6e }
                )) {
         BERReader            reader  = new BERReader(mem);
         BERReader.BERTagInfo tagInfo = new BERReader.BERTagInfo();
         Assert.False(reader.ReadTagInfo(ref tagInfo));
     }
 }
예제 #4
0
 public void TestIntegerTag4()
 {
     using (MemoryStream mem = new MemoryStream(
                new byte[] { 0x02, 0x09, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x01 }
                )) {
         BERReader  reader = new BERReader(mem);
         BigInteger n;
         Assert.True(reader.ReadInteger(out n));
         Assert.AreEqual("123456789ABCDEF001", n.ToString(16));
     }
 }
예제 #5
0
 public void TestIntegerTag3()
 {
     using (MemoryStream mem = new MemoryStream(
                new byte[] { 0x02, 0x01, 0x00 }
                )) {
         BERReader  reader = new BERReader(mem);
         BigInteger n;
         Assert.True(reader.ReadInteger(out n));
         Assert.AreEqual("0", n.ToString());
     }
 }
예제 #6
0
 public void TestLargeTag()
 {
     using (MemoryStream mem = new MemoryStream(
                new byte[] { 0x7f, 0x87, 0xef, 0xab, 0xb7, 0x6e, 0x03, 0x02, 0x01, 0x01 }
                )) {
         BERReader            reader  = new BERReader(mem);
         BERReader.BERTagInfo tagInfo = new BERReader.BERTagInfo();
         Assert.True(reader.ReadTagInfo(ref tagInfo));
         Assert.AreEqual(1, tagInfo.ClassBits);
         Assert.AreEqual(true, tagInfo.IsConstructed);
         Assert.AreEqual(0x7deadbee, tagInfo.TagNumber);
         Assert.AreEqual(3, tagInfo.Length);
     }
 }
예제 #7
0
 public void TestLargeTag()
 {
     using (MemoryStream mem = new MemoryStream(
         new byte[] { 0x7f, 0x87, 0xef, 0xab, 0xb7, 0x6e, 0x03, 0x02, 0x01, 0x01 }
     )) {
         BERReader reader = new BERReader(mem);
         BERReader.BERTagInfo tagInfo = new BERReader.BERTagInfo();
         Assert.True(reader.ReadTagInfo(ref tagInfo));
         Assert.AreEqual(1, tagInfo.ClassBits);
         Assert.AreEqual(true, tagInfo.IsConstructed);
         Assert.AreEqual(0x7deadbee, tagInfo.TagNumber);
         Assert.AreEqual(3, tagInfo.Length);
     }
 }
예제 #8
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.");
                }
            }
        }
        /// <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.");
                }
            }
        }
예제 #10
0
 public void TestNonSequenceTag()
 {
     using (MemoryStream mem = new MemoryStream(
         new byte[] { 0x02, 0x01, 0x01 }
     )) {
         BERReader reader = new BERReader(mem);
         Assert.False(reader.ReadSequence());
     }
 }
예제 #11
0
 public void TestSequenceTag1()
 {
     using (MemoryStream mem = new MemoryStream(
         new byte[] { 0x30, 0x03, 0x02, 0x01, 0x01 }
     )) {
         BERReader reader = new BERReader(mem);
         Assert.True(reader.ReadSequence());
     }
 }
예제 #12
0
        /// <summary>
        /// Read OpenSSH 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>
        public void Load(string passphrase, out KeyPair keyPair, out string comment)
        {
            if (keyFile == null)
            {
                throw new SSHException("A key file is not loaded yet");
            }

            KeyType         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 = KeyType.RSA;
                }
                else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_DSA)
                {
                    keyType = KeyType.DSA;
                }
                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    = OpenSSHPassphraseToKey(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 == KeyType.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 == KeyType.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
                {
                    throw new SSHException("Unknown file type. This should not happen.");
                }
            }
        }
예제 #13
0
 public void TestIncompleteIntegerTag()
 {
     using (MemoryStream mem = new MemoryStream(
         new byte[] { 0x02, 0x04, 0x12, 0x34, 0x56 }
     )) {
         BERReader reader = new BERReader(mem);
         BigInteger n;
         Assert.False(reader.ReadInteger(out n));
     }
 }
예제 #14
0
 public void TestIntegerTag4()
 {
     using (MemoryStream mem = new MemoryStream(
         new byte[] { 0x02, 0x09, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x01 }
     )) {
         BERReader reader = new BERReader(mem);
         BigInteger n;
         Assert.True(reader.ReadInteger(out n));
         Assert.AreEqual("123456789ABCDEF001", n.ToString(16));
     }
 }
예제 #15
0
 public void TestIntegerTag3()
 {
     using (MemoryStream mem = new MemoryStream(
         new byte[] { 0x02, 0x01, 0x00 }
     )) {
         BERReader reader = new BERReader(mem);
         BigInteger n;
         Assert.True(reader.ReadInteger(out n));
         Assert.AreEqual("0", n.ToString());
     }
 }
예제 #16
0
 public void TestIndefiniteSequenceTag()
 {
     using (MemoryStream mem = new MemoryStream(
         new byte[] { 0x30, 0x80, 0x02, 0x01, 0x01, 0x00, 0x00 }
     )) {
         BERReader reader = new BERReader(mem);
         Assert.True(reader.ReadSequence());
     }
 }
예제 #17
0
 public void TestIncompleteTag()
 {
     using (MemoryStream mem = new MemoryStream(
         new byte[] { 0x7f, 0x87, 0xef, 0xab, 0xb7, 0x6e }
     )) {
         BERReader reader = new BERReader(mem);
         BERReader.BERTagInfo tagInfo = new BERReader.BERTagInfo();
         Assert.False(reader.ReadTagInfo(ref tagInfo));
     }
 }
예제 #18
0
 public void TestIncompleteSequenceTag()
 {
     using (MemoryStream mem = new MemoryStream(
         new byte[] { 0x30 }
     )) {
         BERReader reader = new BERReader(mem);
         Assert.False(reader.ReadSequence());
     }
 }
예제 #19
0
        /// <summary>
        /// Read OpenSSH 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>
        public void Load(string passphrase, out KeyPair keyPair, out string comment)
        {
            if (keyFile == null)
                throw new SSHException("A key file is not loaded yet");

            KeyType 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 = KeyType.RSA;
                else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_DSA)
                    keyType = KeyType.DSA;
                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 = OpenSSHPassphraseToKey(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 == KeyType.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 == KeyType.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 {
                    throw new SSHException("Unknown file type. This should not happen.");
                }
            }
        }
예제 #20
0
 public void TestNonIntegerTag()
 {
     using (MemoryStream mem = new MemoryStream(
         new byte[] { 0x30, 0x03, 0x02, 0x01, 0x01 }
     )) {
         BERReader reader = new BERReader(mem);
         BigInteger n;
         Assert.False(reader.ReadInteger(out n));
     }
 }