コード例 #1
0
ファイル: PrivateKeyLoader.cs プロジェクト: yueker/poderosa
        /// <summary>
        /// Detect file format of a SSH private key file.
        /// </summary>
        /// <returns>format type</returns>
        /// <exception cref="IOException">File I/O error</exception>
        public PrivateKeyFileFormat ProbeFormat()
        {
            if (keyFile == null)
            {
                return(PrivateKeyFileFormat.UNKNOWN);
            }

            if (ByteArrayUtil.ByteArrayStartsWith(keyFile, Encoding.ASCII.GetBytes(PrivateKeyFileHeader.SSH1_HEADER)))
            {
                return(PrivateKeyFileFormat.SSH1);
            }

            if (ByteArrayUtil.ByteArrayStartsWith(keyFile, Encoding.ASCII.GetBytes(PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_RSA)) ||
                ByteArrayUtil.ByteArrayStartsWith(keyFile, Encoding.ASCII.GetBytes(PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_DSA)) ||
                ByteArrayUtil.ByteArrayStartsWith(keyFile, Encoding.ASCII.GetBytes(PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_ECDSA)) ||
                ByteArrayUtil.ByteArrayStartsWith(keyFile, Encoding.ASCII.GetBytes(PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_OPENSSH)))
            {
                return(PrivateKeyFileFormat.SSH2_OPENSSH);
            }

            if (ByteArrayUtil.ByteArrayStartsWith(keyFile, Encoding.ASCII.GetBytes(PrivateKeyFileHeader.SSH2_SSHCOM_HEADER)))
            {
                return(PrivateKeyFileFormat.SSH2_SSHCOM);
            }

            if (ByteArrayUtil.ByteArrayStartsWith(keyFile, Encoding.ASCII.GetBytes(PrivateKeyFileHeader.SSH2_PUTTY_HEADER_1)) ||
                ByteArrayUtil.ByteArrayStartsWith(keyFile, Encoding.ASCII.GetBytes(PrivateKeyFileHeader.SSH2_PUTTY_HEADER_2)))
            {
                return(PrivateKeyFileFormat.SSH2_PUTTY);
            }

            return(PrivateKeyFileFormat.UNKNOWN);
        }
コード例 #2
0
        /// <summary>
        /// Read SSH1 private key parameters.
        /// </summary>
        /// <param name="passphrase">passphrase for decrypt the key file</param>
        /// <param name="modulus">private key parameter</param>
        /// <param name="publicExponent">private key parameter</param>
        /// <param name="privateExponent">private key parameter</param>
        /// <param name="primeP">private key parameter</param>
        /// <param name="primeQ">private key parameter</param>
        /// <param name="crtCoefficient">private key parameter</param>
        /// <exception cref="SSHException">failed to parse</exception>
        public void Load(
            string passphrase,
            out BigInteger modulus,
            out BigInteger publicExponent,
            out BigInteger privateExponent,
            out BigInteger primeP,
            out BigInteger primeQ,
            out BigInteger crtCoefficient)
        {
            if (keyFile == null)
            {
                throw new SSHException("A key file is not loaded yet");
            }
            byte[] hdr = Encoding.ASCII.GetBytes(PrivateKeyFileHeader.SSH1_HEADER);
            if (!ByteArrayUtil.ByteArrayStartsWith(keyFile, hdr))
            {
                throw new SSHException(Strings.GetString("NotValidPrivateKeyFile"));
            }

            SSH1DataReader reader = new SSH1DataReader(keyFile);

            reader.Read(hdr.Length);

            byte[] cipher = reader.Read(2); //first 2 bytes indicates algorithm and next 8 bytes is space
            reader.Read(8);

            modulus        = reader.ReadMPInt();
            publicExponent = reader.ReadMPInt();
            byte[] comment = reader.ReadString();
            byte[] prvt    = reader.ReadAll();
            //必要なら復号
            CipherAlgorithm algo = (CipherAlgorithm)cipher[1];

            if (algo != 0)
            {
                Cipher c   = CipherFactory.CreateCipher(SSHProtocol.SSH1, algo, SSH1PassphraseToKey(passphrase));
                byte[] buf = new byte[prvt.Length];
                c.Decrypt(prvt, 0, prvt.Length, buf, 0);
                prvt = buf;
            }

            SSH1DataReader prvtreader = new SSH1DataReader(prvt);

            byte[] mark = prvtreader.Read(4);
            if (mark[0] != mark[2] || mark[1] != mark[3])
            {
                throw new SSHException(Strings.GetString("WrongPassphrase"));
            }

            privateExponent = prvtreader.ReadMPInt();
            crtCoefficient  = prvtreader.ReadMPInt();
            primeP          = prvtreader.ReadMPInt();
            primeQ          = prvtreader.ReadMPInt();
        }
コード例 #3
0
        /// <summary>
        /// Read PuTTY 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");
            }

            int             version;
            string          keyTypeName;
            KeyType         keyType;
            string          encryptionName;
            CipherAlgorithm?encryption;

            byte[] publicBlob;
            byte[] privateBlob;
            string privateMac;
            string privateHash;

            using (StreamReader sreader = GetStreamReader()) {
                //*** Read header and key type
                ReadHeaderLine(sreader, out version, out keyTypeName);

                if (keyTypeName == "ssh-rsa")
                {
                    keyType = KeyType.RSA;
                }
                else if (keyTypeName == "ssh-dss")
                {
                    keyType = KeyType.DSA;
                }
                else
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected key type)");
                }

                //*** Read encryption
                ReadItemLine(sreader, "Encryption", out encryptionName);

                if (encryptionName == "aes256-cbc")
                {
                    encryption = CipherAlgorithm.AES256;
                }
                else if (encryptionName == "none")
                {
                    encryption = null;
                }
                else
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected encryption)");
                }

                //*** Read comment
                ReadItemLine(sreader, "Comment", out comment);

                //*** Read public lines
                string publicLinesStr;
                ReadItemLine(sreader, "Public-Lines", out publicLinesStr);
                int publicLines;
                if (!Int32.TryParse(publicLinesStr, out publicLines) || publicLines < 0)
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid public lines)");
                }

                ReadBlob(sreader, publicLines, out publicBlob);

                //*** Read private lines
                string privateLinesStr;
                ReadItemLine(sreader, "Private-Lines", out privateLinesStr);
                int privateLines;
                if (!Int32.TryParse(privateLinesStr, out privateLines) || privateLines < 0)
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid private lines)");
                }

                ReadBlob(sreader, privateLines, out privateBlob);

                //*** Read private MAC
                ReadPrivateMACLine(sreader, version, out privateMac, out privateHash);
            }

            if (encryption.HasValue)
            {
                byte[] key    = PuTTYPassphraseToKey(passphrase);
                byte[] iv     = new byte[16];
                Cipher cipher = CipherFactory.CreateCipher(SSHProtocol.SSH2, encryption.Value, key, iv);
                if (privateBlob.Length % cipher.BlockSize != 0)
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid key data size)");
                }
                cipher.Decrypt(privateBlob, 0, privateBlob.Length, privateBlob, 0);
            }

            bool verified = Verify(version, privateMac, privateHash,
                                   passphrase, keyTypeName, encryptionName, comment, publicBlob, privateBlob);

            if (!verified)
            {
                if (encryption.HasValue)
                {
                    throw new SSHException(Strings.GetString("WrongPassphrase"));
                }
                else
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (HMAC verification failed)");
                }
            }

            if (keyType == KeyType.RSA)
            {
                SSH2DataReader reader = new SSH2DataReader(publicBlob);
                byte[]         magic  = reader.ReadString();
                if (!ByteArrayUtil.AreEqual(magic, Encoding.ASCII.GetBytes("ssh-rsa")))
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing magic)");
                }

                BigInteger e = reader.ReadMPInt();
                BigInteger n = reader.ReadMPInt();

                reader = new SSH2DataReader(privateBlob);
                BigInteger d    = reader.ReadMPInt();
                BigInteger p    = reader.ReadMPInt();
                BigInteger q    = reader.ReadMPInt();
                BigInteger iqmp = reader.ReadMPInt();

                BigInteger u = p.modInverse(q);

                keyPair = new RSAKeyPair(e, d, n, u, p, q);
            }
            else if (keyType == KeyType.DSA)
            {
                SSH2DataReader reader = new SSH2DataReader(publicBlob);
                byte[]         magic  = reader.ReadString();
                if (!ByteArrayUtil.AreEqual(magic, Encoding.ASCII.GetBytes("ssh-dss")))
                {
                    throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing magic)");
                }

                BigInteger p = reader.ReadMPInt();
                BigInteger q = reader.ReadMPInt();
                BigInteger g = reader.ReadMPInt();
                BigInteger y = reader.ReadMPInt();

                reader = new SSH2DataReader(privateBlob);
                BigInteger x = reader.ReadMPInt();

                keyPair = new DSAKeyPair(p, g, q, y, x);
            }
            else
            {
                throw new SSHException("Unknown file type. This should not happen.");
            }
        }