/// <summary> /// Read SSH2 private key parameters. /// </summary> /// <param name="passphrase">passphrase for decrypt the key file</param> /// <param name="keyPair">key pair is set</param> /// <param name="comment">comment is set. empty if it didn't exist</param> /// <exception cref="SSHException">failed to parse</exception> public void LoadSSH2PrivateKey( string passphrase, out KeyPair keyPair, out string comment) { PrivateKeyFileFormat format = ProbeFormat(); ISSH2PrivateKeyLoader loader; if (format == PrivateKeyFileFormat.SSH2_SSHCOM) loader = new SSHComPrivateKeyLoader(keyFile, keyFilePath); else if (format == PrivateKeyFileFormat.SSH2_OPENSSH) loader = new OpenSSHPrivateKeyLoader(keyFile, keyFilePath); else if (format == PrivateKeyFileFormat.SSH2_PUTTY) loader = new PuTTYPrivateKeyLoader(keyFile, keyFilePath); else throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat")); loader.Load(passphrase, out keyPair, out comment); }
/// <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."); } } }
/// <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(SecureString 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."); } }
/// <summary> /// Read SSH.com 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> /// <exception cref="SSHException">failed to parse</exception> public void Load(SecureString passphrase, out KeyPair keyPair, out string comment) { if (keyFile == null) throw new SSHException("A key file is not loaded yet"); string base64Text; using (StreamReader sreader = GetStreamReader()) { var line = sreader.ReadLine(); if (line == null || line != PrivateKeyFileHeader.SSH2_SSHCOM_HEADER) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing header)"); var buf = new StringBuilder(); comment = string.Empty; while (true) { line = sreader.ReadLine(); if (line == null) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)"); if (line == PrivateKeyFileHeader.SSH2_SSHCOM_FOOTER) break; if (line.IndexOf(':') >= 0) { if (line.StartsWith("Comment: ")) comment = line.Substring("Comment: ".Length); } else if (line[line.Length - 1] == '\\') buf.Append(line, 0, line.Length - 1); else buf.Append(line); } base64Text = buf.ToString(); } var keydata = Base64.Decode(Encoding.ASCII.GetBytes(base64Text)); //Debug.WriteLine(DebugUtil.DumpByteArray(keydata)); var reader = new SSH2DataReader(keydata); int magic = reader.ReadInt32(); if (magic != MAGIC) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (magic code unmatched)"); int privateKeyLen = reader.ReadInt32(); string type = Encoding.ASCII.GetString(reader.ReadString()); string ciphername = Encoding.ASCII.GetString(reader.ReadString()); int bufLen = reader.ReadInt32(); if (ciphername != "none") { var algo = CipherFactory.SSH2NameToAlgorithm(ciphername); var key = SSH2UserAuthKey.PassphraseToKey(passphrase, CipherFactory.GetKeySize(algo)); var c = CipherFactory.CreateCipher(SSHProtocol.SSH2, algo, key); var tmp = new Byte[reader.Image.Length - reader.Offset]; c.Decrypt(reader.Image, reader.Offset, reader.Image.Length - reader.Offset, tmp, 0); reader = new SSH2DataReader(tmp); } int parmLen = reader.ReadInt32(); if (parmLen < 0 || parmLen > reader.Rest) throw new SSHException(Strings.GetString("WrongPassphrase")); if (type.IndexOf("if-modn") != -1) { //mindterm mistaken this order of BigIntegers BigInteger e = reader.ReadBigIntWithBits(); BigInteger d = reader.ReadBigIntWithBits(); BigInteger n = reader.ReadBigIntWithBits(); BigInteger u = reader.ReadBigIntWithBits(); BigInteger p = reader.ReadBigIntWithBits(); BigInteger q = reader.ReadBigIntWithBits(); keyPair = new RSAKeyPair(e, d, n, u, p, q); } else if (type.IndexOf("dl-modp") != -1) { if (reader.ReadInt32() != 0) throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat") + " (" + Strings.GetString("Reason_UnsupportedDSAKeyFormat") + ")"); BigInteger p = reader.ReadBigIntWithBits(); BigInteger g = reader.ReadBigIntWithBits(); BigInteger q = reader.ReadBigIntWithBits(); BigInteger y = reader.ReadBigIntWithBits(); BigInteger x = reader.ReadBigIntWithBits(); keyPair = new DSAKeyPair(p, g, q, y, x); } else throw new SSHException(Strings.GetString("UnsupportedAuthenticationMethod")); }
public SSH2UserAuthKey(KeyPair kp, string comment) { _keypair = kp; _comment = comment; }
public SSH2UserAuthKey(KeyPair kp) { _keypair = kp; _comment = ""; }