Prechádzať zdrojové kódy

OPENSSH KeyReader for more keys (#614)

* OPENSSH KeyReader for more keys

Add support to parse OpenSSH Keys with ECDSA 256/384/521 and RSA.

https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key

Change-Id: Iaa9cce0f2522e5fee377a82cb252f81f0b7cc563

* Fix ED25519Key KeyLength

* Fix ED25519 PubKey-auth

LeadingZeros of BigInteger-Conversion have to be removed
before sending the Key.
Stefan Rinkes 4 rokov pred
rodič
commit
f072c5f1a1

+ 1 - 1
README.md

@@ -80,7 +80,7 @@ the missing test once you figure things out.  🤓
 * RSA in OpenSSL PEM and ssh.com format
 * DSA in OpenSSL PEM and ssh.com format
 * ECDSA 256/384/521 in OpenSSL PEM format
-* ED25519 in OpenSSH key format
+* ECDSA 256/384/521, ED25519 and RSA in OpenSSH key format
 
 Private keys can be encrypted using one of the following cipher methods:
 * DES-EDE3-CBC

+ 90 - 8
src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs

@@ -545,13 +545,10 @@ namespace Renci.SshNet.Tests.Classes
             }
         }
 
-        /// <summary>
-        /// A test for opening an openssh v1 keyfile where there is no passphrase.
-        ///</summary>
         [TestMethod()]
         [Owner("bhalbright")]
         [TestCategory("PrivateKey")]
-        public void TestOpenSshV1KeyFileNoPassphrase()
+        public void Test_PrivateKey_OPENSSH_ED25519()
         {
             using (var stream = GetData("Key.OPENSSH.ED25519.txt"))
             {
@@ -559,13 +556,10 @@ namespace Renci.SshNet.Tests.Classes
             }
         }
 
-        /// <summary>
-        /// A test for opening an openssh v1 keyfile where there is a passphrase.
-        ///</summary>
         [TestMethod()]
         [Owner("bhalbright")]
         [TestCategory("PrivateKey")]
-        public void TestOpenSshV1KeyFileWithPassphrase()
+        public void Test_PrivateKey_OPENSSH_ED25519_ENCRYPTED()
         {
             using (var stream = GetData("Key.OPENSSH.ED25519.Encrypted.txt"))
             {
@@ -573,6 +567,94 @@ namespace Renci.SshNet.Tests.Classes
             }
         }
 
+        [TestMethod()]
+        [Owner("darinkes")]
+        [TestCategory("PrivateKey")]
+        public void Test_PrivateKey_OPENSSH_RSA()
+        {
+            using (var stream = GetData("Key.OPENSSH.RSA.txt"))
+            {
+                new PrivateKeyFile(stream);
+            }
+        }
+
+        [TestMethod()]
+        [Owner("darinkes")]
+        [TestCategory("PrivateKey")]
+        public void Test_PrivateKey_OPENSSH_RSA_ENCRYPTED()
+        {
+            using (var stream = GetData("Key.OPENSSH.RSA.Encrypted.txt"))
+            {
+                new PrivateKeyFile(stream, "12345");
+            }
+        }
+
+        [TestMethod()]
+        [Owner("darinkes")]
+        [TestCategory("PrivateKey")]
+        public void Test_PrivateKey_OPENSSH_ECDSA()
+        {
+            using (var stream = GetData("Key.OPENSSH.ECDSA.txt"))
+            {
+                new PrivateKeyFile(stream);
+            }
+        }
+
+        [TestMethod()]
+        [Owner("darinkes")]
+        [TestCategory("PrivateKey")]
+        public void Test_PrivateKey_OPENSSH_ECDSA_ENCRYPTED()
+        {
+            using (var stream = GetData("Key.OPENSSH.ECDSA.Encrypted.txt"))
+            {
+                new PrivateKeyFile(stream, "12345");
+            }
+        }
+
+        [TestMethod()]
+        [Owner("darinkes")]
+        [TestCategory("PrivateKey")]
+        public void Test_PrivateKey_OPENSSH_ECDSA384()
+        {
+            using (var stream = GetData("Key.OPENSSH.ECDSA384.txt"))
+            {
+                new PrivateKeyFile(stream);
+            }
+        }
+
+        [TestMethod()]
+        [Owner("darinkes")]
+        [TestCategory("PrivateKey")]
+        public void Test_PrivateKey_OPENSSH_ECDSA384_ENCRYPTED()
+        {
+            using (var stream = GetData("Key.OPENSSH.ECDSA384.Encrypted.txt"))
+            {
+                new PrivateKeyFile(stream, "12345");
+            }
+        }
+
+        [TestMethod()]
+        [Owner("darinkes")]
+        [TestCategory("PrivateKey")]
+        public void Test_PrivateKey_OPENSSH_ECDSA521()
+        {
+            using (var stream = GetData("Key.OPENSSH.ECDSA521.txt"))
+            {
+                new PrivateKeyFile(stream);
+            }
+        }
+
+        [TestMethod()]
+        [Owner("darinkes")]
+        [TestCategory("PrivateKey")]
+        public void Test_PrivateKey_OPENSSH_ECDSA521_ENCRYPTED()
+        {
+            using (var stream = GetData("Key.OPENSSH.ECDSA521.Encrypted.txt"))
+            {
+                new PrivateKeyFile(stream, "12345");
+            }
+        }
+
         private void SaveStreamToFile(Stream stream, string fileName)
         {
             var buffer = new byte[4000];

+ 9 - 0
src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.Encrypted.txt

@@ -0,0 +1,9 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCPSPglZ3
+w/7DmCJxYohONLAAAAEAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz
+dHAyNTYAAABBBK6YY2NwwLDSMnJTD+a4OfitCDuG/MnY/AstPgh54xMrZF6Qr0U1H6kRMK
+Y6JJsj31CI97qDYrnTA00Sx5Jy6ywAAACwq4qisorVCP6yvrmf/fcPacX4+FVEmrHNn3fW
+TiYsat7oKoItqTiDaHkIloSX93ue3fzcKXpGPR/qnpu4SezkhL9Uk6ntiwO4coB/kbEnjk
+IFY6ZK0HENRXkdIuDG9qmoB0wjVPJ6L9e5RWZwiCPvNI2O60bpKOUs+tUSah1W7eTWy5Ss
+ttdTgmwqS84c5+uitK1DJh2jsDqfdGm7h1XpDJsRmIEXxTVu/EdtD0hZ/x4=
+-----END OPENSSH PRIVATE KEY-----

+ 9 - 0
src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.txt

@@ -0,0 +1,9 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
+1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSP3ZTb37LFvSmKweu03A5s/cwcw3+3
+jL1LqQK6D929xY1J2J6S91LXOBpBfz4l+8Ng7sWhu9P/hF/wmB2QRygrAAAAqMq583bKuf
+N2AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBI/dlNvfssW9KYrB
+67TcDmz9zBzDf7eMvUupAroP3b3FjUnYnpL3Utc4GkF/PiX7w2DuxaG70/+EX/CYHZBHKC
+sAAAAhALVqID3K/N7IazKNbhrg09r7rLLtjy81RLV+VDxloQnxAAAAC3NyaW5rZXNATkVP
+AQIDBA==
+-----END OPENSSH PRIVATE KEY-----

+ 11 - 0
src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.Encrypted.txt

@@ -0,0 +1,11 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAMZphcrt
+UKJMlSabtzt2GdAAAAEAAAAAEAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlz
+dHAzODQAAABhBFL5NEL9uRhgkF2q+8m58EvtZq4mDGgcVEzafPRuNIn1018m9KuqNpOQ6d
++435n+MRYThe4MUdijSIDuopX2i14Z35oKZ9x2LsV+RxQczjmbnoWZdvgcvdOo6jiJdY7X
+JwAAAOBvXOaTq8vPRy7y5BBzr26QAYouJfGprYOqpywiIAZaICu0FJ8EXmmen6310CTG6Z
+CZ4VhC5MWCWRYTaOnPNn8FvGqo2bxEqWZmyZfVvv1Z35MtSAZEfwgfXaOZKJ/lPKsRndg5
+okpqNU1aG2u+4J7eZ7QyCD/1RCCEL5wwVcrDeuMkTDPpnJc1NEGz8HbfcZ5xZavrz6Wa9t
+tX7pFICqK9IIeOGMJ2WRXR6sQGyag+jNn9KmsIya7hkNJVeZeY2GKAk2s/0vxfYx9RFD55
+ewB34oHyTdxAQT3L+FZT6XfRHw==
+-----END OPENSSH PRIVATE KEY-----

+ 10 - 0
src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.txt

@@ -0,0 +1,10 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS
+1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRTP1DMXoHgW+RX+S/NxUEElou1cmLD
+6CEiR+zpzaGG6mzl6LhUY+Z3f2M3u4u7tcM8TgB/jiHbnI9TaeN5QK4HX1D9DXkH5RhfnL
+frm3kCTNoCFKd0Wa/QAvKrlNKiRi8AAADYlABjHJQAYxwAAAATZWNkc2Etc2hhMi1uaXN0
+cDM4NAAAAAhuaXN0cDM4NAAAAGEEUz9QzF6B4FvkV/kvzcVBBJaLtXJiw+ghIkfs6c2hhu
+ps5ei4VGPmd39jN7uLu7XDPE4Af44h25yPU2njeUCuB19Q/Q15B+UYX5y365t5AkzaAhSn
+dFmv0ALyq5TSokYvAAAAMAXLUgK32yWzUrpeLzpdFB2/eiNnkxQlu5OneTPukKcZYclfgo
+jv0YHK5LCvAtF8lwAAAAtzcmlua2VzQE5FTwECAwQF
+-----END OPENSSH PRIVATE KEY-----

+ 12 - 0
src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.Encrypted.txt

@@ -0,0 +1,12 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBWjIyzbM
+MQ3UPE8BiQ0n4LAAAAEAAAAAEAAACsAAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlz
+dHA1MjEAAACFBAH9BVM6bRhbELtgdMGsin5lM42R2EWoT+6Akakl5rQy2tHHLIYGLEfaqI
++0iUo2V6MxEf9w0hVz6SEsF+yDgyrYPQCIieaB1oBvIl+PZmL1XsuAXs2uMRsNJb4myGU/
+DiekxqzIPa0LMrBZ4xmErcn5Gazkw1EA0B3HoaW5wj+geI/efQAAARDi+GGTYH1T+5Dd8N
+EVCiL+J7fm8uP8yAcvQNh3JBYIf1g/GZ0hJDuA47fcTzXEfTGZLGWdgaE8cxIUICpjBoak
+EpNS1HyhqYZAt2J8o/14t2GbXczJfoQLOIQl2S1zXQ9shof12odu9DGcBhSAz9hswlndBE
+d99uCz/ymzwQ0i2Pp+urUXo7+YXB6HMh9YTMeGQAiDJFO3NPDqDczfUECtTUkQMhy8r06m
+hAp/oZ6K1KBbZzdc0xyqDePKAqqyHnN4FD7Wfv11SWoOhlUcEVg2ZvNj/O+CsoWzMpN+dt
+DPKZHmH/kegWKBsdtAC9f5Hg3b2oQAK0pKghms1+/J9iilnIMwv80CPzGdv0YAG9Vx5w==
+-----END OPENSSH PRIVATE KEY-----

+ 12 - 0
src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.txt

@@ -0,0 +1,12 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS
+1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAa7p4WVga+08qu160BrdzKyRNJMQC
+eGhFluNdq73/uaW3qlqoEiaNtc5uB7HHyjCWQTmfzrSRLRZ7YBwUancwyh4Aq6gBgGsXVz
+wNvY3kxRDlGrSfMmsHlXz41dgw9wm1fBcf97niexRQ/xGlhkyf7IYlQ/s5BpXF2lS9l0H5
+hBippRgAAAEI/9prf//aa38AAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ
+AAAIUEAGu6eFlYGvtPKrtetAa3cyskTSTEAnhoRZbjXau9/7mlt6paqBImjbXObgexx8ow
+lkE5n860kS0We2AcFGp3MMoeAKuoAYBrF1c8Db2N5MUQ5Rq0nzJrB5V8+NXYMPcJtXwXH/
+e54nsUUP8RpYZMn+yGJUP7OQaVxdpUvZdB+YQYqaUYAAAAQXwQnI20tNxwLKHPMDmumblD
+b0sBqW5Y9248L//x4sWFrkjk6k1LcZno9KLqz8+tIFMJ5sji+axRoUZCXb3cIPzPAAAAC3
+NyaW5rZXNATkVP
+-----END OPENSSH PRIVATE KEY-----

+ 28 - 0
src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.Encrypted.txt

@@ -0,0 +1,28 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCoWhCSaG
+psKT80oPIOAlqJAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCxOfnmxC1g
+mmX18LCBG/X73BoCXQEBEAJz3V9w0FMTgUBebK3fkfOMLNzWn5aMR608wQHOEPYhHffCJf
+dJR6lUWLHZz5+EZRfM9oHpysMtToYQoGtb9xM7D5J3lnWZgSea2R7xSeqpClN5nQUMGu8y
+2d2S3g9o1vrTdeu71u09QFOx2AXBPUmCjpCuBlNyYEEQMfRMtQ6PDbPdvLM1uylbQqB+/6
+jMsCyEFvlLit9GcZ7ItKQN+jsZNmP+f7ytVXLsZTjPLd5mWWrf6T1T1Xt9DBoLXnMrmDiC
+f/EXiTYonIO6B0FHvNUCrDzZ7rxIebqePLes1Q2yoUqmC8g+cww3AAADwNRNGSnB7cRpgU
+BxdyC0ofj0hUONXjmoT+OGPph9lgZMUnzcon9Z1bpsJuMoRXL14Cdbds7YPmw1YB94Uc+S
+8QexLJG0wGel2yvzJhU+QFsLeVRS4tayERFXGCoVpu7RunEYy+hvaiX5CD+luEkiarfj9I
+N8+9QUMhDYkELwWBV4rde18Vr8m1P1FuFgqikY0TfSKUGCkvjl4FvDxrxqsewaEkkzwRTI
+PhOFCCM5jBPWE+uWVcwKoidvAqcNbmwIzDNZGwXtrAvYYzZa62C/MNLHuFU1weuJiM8sYa
+6iKrk681BrrpGcSEZEXd41CFY3BWlIDTozrWn03xFlIpeLG2YMPcuYqFhR/41BJfa+fW5B
+Ei0SuUx2xjdRiamqpPku4H6ulkjl0KlFCr976Y2V1JZMQh7bd0huubmf4P4poBk6ZgGpSf
+snhcv1HjCVkvfA2yhOcXogzK2HOZgDS5sdSb/kUGURdjlj6ccSzc3OYaHAy9gZXj8Q58pA
+4KrXTDlCJ9BTR8PIND54j6gMKu5ijX0TP9nJf/hG9GXx+Xss8T3xdPxdNBapPCcuxGZGJN
+H+KFqrpmZYHm0evqFPS7BCUp2VvID6SMgrTYiH0IIbMHLStfdNchtn3EudMbW9vRhxg3Do
+npT7Px2JYp87PNoHg2eOx0yGy9r81n2+Wi7SpGCWD8MFfxqd4JIQ8+zjrIRAA1q53uuSUh
+m/hlmJWEjQWmcBw5bKrOU0CfGGoT3o6HWYRQ9d5+kKeoS+dOINxxf80G5b7vOrE3PbFxT3
+W8zwRd90Msr3LXgPaN0V4RJeBX38e0EvVbArL2MgSs/BC5aID0N0Sqiu+13AqqNYxj6RH2
+FA7FN+BBa16fvdi5h5kNnZUrQUKOAImjEE494O8uGKQImviGqB5PY6DJqHPTtn7RSwFx9E
+rR7nbAZPTucIN/OIfURxTedhROk0PXjWnwpjuz+UpaMRWqgWTv3bLOuqorqMLibAFLRQEQ
+6pR0wbmTpTfEW1jNmAohxB4N14YdSfhThzkCAgpQW6UCLc83y3EDzQFi5862a+2ixULKhK
+220tZRk2GU7OFAPRpgQ/sxptGqZbNdOV80wk1MgykoFkoptRkm7bfJcdLHZnP7E6yU0ssP
+rCbQlfD0/dD2QE/7HqxHsipNNuEagULjK6WUYXkpx1Siq2vecjZw8dNp7EBh+KlujEm+Dr
+R7KFdFCw8DUwrzXwfMIogeRVbW8H0/fQEqsX5oPLTEOnNBjzf8pHush7CCrprbo0ZK3xFp
+Vr3LUCoA==
+-----END OPENSSH PRIVATE KEY-----

+ 27 - 0
src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.txt

@@ -0,0 +1,27 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAQEA7W7Oigi7Hj1msa2l8HimLPzagVmE/CseMKCRxPMTtWTvoZdMt7hf
+kthWA7h20a7oSSeH2t7FqeOpVNGFYvRV3BVWsKZJMRcdJiTCZAjH38rYk90XvZ3mKrKN/3
+fcQsh4OiPnWqT6HSqg14oiV8UPtUwnE65skWSxvxt+ELlVpCqG5vE2O/GNDKQE7FzYt6vQ
+ihMFSABBqjvau0mjX002KYiCMr6vgl8XYkDA4n5+JyQSQxznnfrL93ZoaqujRP2bT5UhXg
+bzr8HFwuqQGvURECZTTI8Biv/6tOIn9x2hEaN6vxDLtXc99E2d6NW6cdriwaGFJ4jgVWDE
+5mU006XdPQAAA8jzN6zf8zes3wAAAAdzc2gtcnNhAAABAQDtbs6KCLsePWaxraXweKYs/N
+qBWYT8Kx4woJHE8xO1ZO+hl0y3uF+S2FYDuHbRruhJJ4fa3sWp46lU0YVi9FXcFVawpkkx
+Fx0mJMJkCMffytiT3Re9neYqso3/d9xCyHg6I+dapPodKqDXiiJXxQ+1TCcTrmyRZLG/G3
+4QuVWkKobm8TY78Y0MpATsXNi3q9CKEwVIAEGqO9q7SaNfTTYpiIIyvq+CXxdiQMDifn4n
+JBJDHOed+sv3dmhqq6NE/ZtPlSFeBvOvwcXC6pAa9REQJlNMjwGK//q04if3HaERo3q/EM
+u1dz30TZ3o1bpx2uLBoYUniOBVYMTmZTTTpd09AAAAAwEAAQAAAQEA6Xgq+gppzOt9nrts
+z5Ajf1tHlSesn7XaYuCRVgPb3mOZSuEW3BUdTa0Sr2fk1nzSBpUrfqnN3idyK2g3bD1sbB
+RDgUKR+AaNcCN3TpxfxgyVeJhQLvEkEdovzQRUfwrXRfxmE3jkRGfVbvxylrG8p35xcmXy
+del46r2i8dj8gIY3tKp0RMvZ4ZlNbhWHPd5OxyHWL9e3gbOSyIyjQgTKZezhzErS/X/KJ/
+XYqzyBAqNqZ2Rg1kKiHRlHS6KEI2tyFwYfh+Rb6L9xch1SqOtQhTWirmxS25dpGD2jgalX
+eyiw8PmuqTiWCqUmUMx6MdF3tFsirr54K4QA9kqMeaRLtQAAAIEAsUQT0Uhq7l0ugTd4Y9
+89bH6eW0fol21/m7B5zkJQepNadUPTs188uvv4inW8n2O3RCanXWHZfCJ1AsR/MEEW2C6Q
+DtvqKXHbzfWQlCYSVxB17CjURKa8fNaIAk98zgmNNwO53NBleyrUhPgvm3xt7ACgpzXY5R
+wNJL8/a0WOmgwAAACBAP508Op6wWPAwn1JfBZuqQtjcfnJeN4NkYQBdybn0vVu5UdyqSQL
+a8hlAzROhA+qJvrlsZgM9h8CyLTyuim8likZHocwO13zBTdVaQ8c2lJvf2uXTIXNZHseS7
+ITkfBiO1hSB4z8RDkOr35mGfdbyJIFAwFZF4Xs8WnQF+vHEadrAAAAgQDu329eCwVFf9g0
+zNHfZu31p0WtErcsRv57fq+UoPtov8nxUF71oOWe5KSGnGtMICI31kBtPhUbvfOmuqNrgJ
+BjgjbPQmi0xSAE5L3QuEKRNjlaE3/WadKBwzhJDtauuYk1ifkrdAVp67XyQ5puyuGgVaQB
+NPbrxA9g1IbyeL4/9wAAAAtzcmlua2VzQE5FTwECAwQFBg==
+-----END OPENSSH PRIVATE KEY-----

+ 8 - 0
src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj

@@ -35,6 +35,14 @@
     <EmbeddedResource Include="Data\Key.ECDSA521.txt" />
     <EmbeddedResource Include="Data\Key.OPENSSH.ED25519.Encrypted.txt" />
     <EmbeddedResource Include="Data\Key.OPENSSH.ED25519.txt" />
+    <EmbeddedResource Include="Data\Key.OPENSSH.RSA.Encrypted.txt" />
+    <EmbeddedResource Include="Data\Key.OPENSSH.RSA.txt" />
+    <EmbeddedResource Include="Data\Key.OPENSSH.ECDSA.txt" />
+    <EmbeddedResource Include="Data\Key.OPENSSH.ECDSA.Encrypted.txt" />
+    <EmbeddedResource Include="Data\Key.OPENSSH.ECDSA384.Encrypted.txt" />
+    <EmbeddedResource Include="Data\Key.OPENSSH.ECDSA521.Encrypted.txt" />
+    <EmbeddedResource Include="Data\Key.OPENSSH.ECDSA384.txt" />
+    <EmbeddedResource Include="Data\Key.OPENSSH.ECDSA521.txt" />
     <EmbeddedResource Include="Data\Key.RSA.Encrypted.Aes.128.CBC.12345.txt" />
     <EmbeddedResource Include="Data\Key.RSA.Encrypted.Aes.192.CBC.12345.txt" />
     <EmbeddedResource Include="Data\Key.RSA.Encrypted.Aes.256.CBC.12345.txt" />

+ 75 - 36
src/Renci.SshNet/PrivateKeyFile.cs

@@ -26,13 +26,13 @@ namespace Renci.SshNet
     /// The following private keys are supported:
     /// <list type="bullet">
     ///     <item>
-    ///         <description>RSA in OpenSSL PEM and ssh.com format</description>
+    ///         <description>RSA in OpenSSL PEM, ssh.com and OpenSSH key format</description>
     ///     </item>
     ///     <item>
     ///         <description>DSA in OpenSSL PEM and ssh.com format</description>
     ///     </item>
     ///     <item>
-    ///         <description>ECDSA 256/384/521 in OpenSSL PEM format</description>
+    ///         <description>ECDSA 256/384/521 in OpenSSL PEM and OpenSSH key format</description>
     ///     </item>
     ///     <item>
     ///         <description>ED25519 in OpenSSH key format</description>
@@ -373,7 +373,7 @@ namespace Renci.SshNet
         /// <param name="keyFileData">the key file data (i.e. base64 encoded data between the header/footer)</param>
         /// <param name="passPhrase">passphrase or null if there isn't one</param>
         /// <returns></returns>
-        private ED25519Key ParseOpenSshV1Key(byte [] keyFileData, string passPhrase)
+        private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase)
         {
             var keyReader = new SshDataReader(keyFileData);
 
@@ -387,8 +387,10 @@ namespace Renci.SshNet
 
             //cipher will be "aes256-cbc" if using a passphrase, "none" otherwise
             var cipherName = keyReader.ReadString(Encoding.UTF8);
+
             //key derivation function (kdf): bcrypt or nothing
             var kdfName = keyReader.ReadString(Encoding.UTF8);
+
             //kdf options length: 24 if passphrase, 0 if no passphrase
             var kdfOptionsLen = (int)keyReader.ReadUInt32();
             byte[] salt = null;
@@ -407,29 +409,21 @@ namespace Renci.SshNet
                 throw new SshException("At this time only one public key in the openssh key is supported.");
             }
 
-            //length of first public key section
-            keyReader.ReadUInt32();
-            var keyType = keyReader.ReadString(Encoding.UTF8);
-            if(keyType != "ssh-ed25519")
-            {
-                throw new SshException("openssh key type: " + keyType + " is not supported");
-            }
-
-            //read public key
-            var publicKeyLength = (int)keyReader.ReadUInt32(); //32
-            var publicKey = keyReader.ReadBytes(publicKeyLength);
+            //read public key in ssh-format, but we dont need it
+            keyReader.ReadString(Encoding.UTF8);
 
             //possibly encrypted private key
             var privateKeyLength = (int)keyReader.ReadUInt32();
             var privateKeyBytes = keyReader.ReadBytes(privateKeyLength);
 
             //decrypt private key if necessary
-            if (cipherName == "aes256-cbc")
+            if (cipherName != "none")
             {
                 if (string.IsNullOrEmpty(passPhrase))
                 {
                     throw new SshPassPhraseNullOrEmptyException("Private key is encrypted but passphrase is empty.");
                 }
+
                 if (string.IsNullOrEmpty(kdfName) || kdfName != "bcrypt")
                 {
                     throw new SshException("kdf " + kdfName + " is not supported for openssh key file");
@@ -445,14 +439,21 @@ namespace Renci.SshNet
                 byte[] iv = new byte[16];
                 Array.Copy(keyiv, 32, iv, 0, 16);
 
-                //now that we have the key/iv, use a cipher to decrypt the bytes
-                var cipher = new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding());
+                AesCipher cipher;
+                switch (cipherName)
+                {
+                    case "aes256-cbc":
+                        cipher = new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding());
+                        break;
+                    case "aes256-ctr":
+                        cipher = new AesCipher(key, new CtrCipherMode(iv), new PKCS7Padding());
+                        break;
+                    default:
+                        throw new SshException("Cipher '" + cipherName + "' is not supported for an OpenSSH key.");
+                }
+
                 privateKeyBytes = cipher.Decrypt(privateKeyBytes);
             }
-            else if (cipherName != "none")
-            {
-                throw new SshException("cipher name " + cipherName + " for openssh key file is not supported");
-            }
 
             //validate private key length
             privateKeyLength = privateKeyBytes.Length;
@@ -470,22 +471,49 @@ namespace Renci.SshNet
             int checkInt1 = (int)privateKeyReader.ReadUInt32();
             int checkInt2 = (int)privateKeyReader.ReadUInt32();
             if (checkInt1 != checkInt2)
-            {
-                throw new SshException("The checkints differed, the openssh key was not correctly decoded.");
-            }
+                throw new SshException("The random check bytes of the OpenSSH key do not match (" + checkInt1 + " <->" + checkInt2 + ").");
 
-            //key type, we already know it is ssh-ed25519
-            privateKeyReader.ReadString(Encoding.UTF8);
+            //key type
+            var keyType = privateKeyReader.ReadString(Encoding.UTF8);
 
-            //public key length/bytes (again)
-            var publicKeyLength2 = (int)privateKeyReader.ReadUInt32();
-            privateKeyReader.ReadBytes(publicKeyLength2);
-
-            //length of private and public key (64)
-            privateKeyReader.ReadUInt32();
-            var unencryptedPrivateKey = privateKeyReader.ReadBytes(32);
-            //public key (again)
-            privateKeyReader.ReadBytes(32);
+            Key parsedKey;
+            byte[] publicKey;
+            byte[] unencryptedPrivateKey;
+            switch (keyType)
+            {
+                case "ssh-ed25519":
+                    //public key
+                    publicKey = privateKeyReader.ReadBignum2();
+                    //private key
+                    unencryptedPrivateKey = privateKeyReader.ReadBignum2();
+                    parsedKey = new ED25519Key(publicKey.Reverse(), unencryptedPrivateKey);
+                    break;
+#if FEATURE_ECDSA
+                case "ecdsa-sha2-nistp256":
+                case "ecdsa-sha2-nistp384":
+                case "ecdsa-sha2-nistp521":
+                    // curve
+                    int len = (int)privateKeyReader.ReadUInt32();
+                    var curve = Encoding.ASCII.GetString(privateKeyReader.ReadBytes(len));
+                    //public key
+                    publicKey = privateKeyReader.ReadBignum2();
+                    //private key
+                    unencryptedPrivateKey = privateKeyReader.ReadBignum2();
+                    parsedKey = new EcdsaKey(curve, publicKey, unencryptedPrivateKey.TrimLeadingZeros());
+                    break;
+#endif
+                case "ssh-rsa":
+                    var modulus = privateKeyReader.ReadBignum(); //n
+                    var exponent = privateKeyReader.ReadBignum(); //e
+                    var d = privateKeyReader.ReadBignum(); //d
+                    var inverseQ = privateKeyReader.ReadBignum(); // iqmp
+                    var p = privateKeyReader.ReadBignum(); //p
+                    var q = privateKeyReader.ReadBignum(); //q
+                    parsedKey = new RsaKey(modulus, exponent, d, p, q, inverseQ);
+                    break;
+                default:
+                    throw new SshException("OpenSSH key type '" + keyType + "' is not supported.");
+            }
 
             //comment, we don't need this but we could log it, not sure if necessary
             var comment = privateKeyReader.ReadString(Encoding.UTF8);
@@ -501,7 +529,7 @@ namespace Renci.SshNet
                 }
             }
 
-            return new ED25519Key(publicKey.Reverse(), unencryptedPrivateKey);
+            return parsedKey;
         }
 
         #region IDisposable Members
@@ -594,6 +622,17 @@ namespace Renci.SshNet
                 return new BigInteger(bytesArray.Reverse());
             }
 
+            public BigInteger ReadBignum()
+            {
+                return new BigInteger(ReadBignum2().Reverse());
+            }
+
+            public byte[] ReadBignum2()
+            {
+                var length = (int)base.ReadUInt32();
+                return base.ReadBytes(length);
+            }
+
             protected override void LoadData()
             {
             }

+ 2 - 2
src/Renci.SshNet/Security/Cryptography/ED25519Key.cs

@@ -33,7 +33,7 @@ namespace Renci.SshNet.Security
         {
             get
             {
-                return new BigInteger[] { publicKey.ToBigInteger() };
+                return new BigInteger[] { publicKey.ToBigInteger2() };
             }
             set
             {
@@ -51,7 +51,7 @@ namespace Renci.SshNet.Security
         {
             get
             {
-                return PublicKey.Length;
+                return PublicKey.Length * 8;
             }
         }
 

+ 9 - 0
src/Renci.SshNet/Security/Cryptography/RsaKey.cs

@@ -9,6 +9,15 @@ namespace Renci.SshNet.Security
     /// </summary>
     public class RsaKey : Key, IDisposable
     {
+
+        /// <summary>
+        /// Gets the Key String.
+        /// </summary>
+        public override string ToString()
+        {
+            return "ssh-rsa";
+        }
+
         /// <summary>
         /// Gets the modulus.
         /// </summary>

+ 6 - 1
src/Renci.SshNet/Security/KeyHostAlgorithm.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using Renci.SshNet.Common;
+using Renci.SshNet.Security.Chaos.NaCl;
 
 namespace Renci.SshNet.Security
 {
@@ -101,7 +102,11 @@ namespace Renci.SshNet.Security
                     _keys = new List<byte[]>(value.Length);
                     foreach (var key in value)
                     {
-                        _keys.Add(key.ToByteArray().Reverse());
+                        var keyData = key.ToByteArray().Reverse();
+                        if (Name == "ssh-ed25519")
+                            keyData = keyData.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes);
+
+                        _keys.Add(keyData);
                     }
                 }
             }