From 3f2b3318a27269815a4164589542bbe553ddebfb Mon Sep 17 00:00:00 2001 From: Rikard Johansson Date: Wed, 22 Feb 2017 09:29:39 +0100 Subject: [PATCH 1/2] Handle lower-case hex in private key's salt field I'm using BouncyCastle (http://bouncycastle.org/) to produce public/private key pairs. In later versions of SSH.NET an exception is thrown (SshException: "Invalid private key file.") while establishing connection using the private keys previously generated. It seems to be an issue with the regex matching the private key file data which this commit handles properly. Below is the private key data I've been using for debugging: `-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,00abc69aea079727973a76b231177bef FnaHUyvIU4pOvR7RkIQ35KlNDB1HsPmLmGzXBpNKF59ifFw1cxoMIZ1xLbDdHy63 RIGRZAQ2l+unxo7TPgRznHENvj3BzW8X71hu0B1Vkr2DETsNCI5vqI29/U20YzUw EUzb4UBi9IyAEbQZHEjXKl36Q/FvXTWp/IQxzSzW80rn6GSENj7qJOb4tj0aLCpG CZEF+lxESCZ+na7IPXrzTeW3sPwDBHjf6IUbPK5biurM+SU9MLYH83cf0IvESq6y uL7uPWpzQPn4wVjTha15/0qpDD9uXJnzVfz6HENMUSdXDXWYFLCkCJUcmyA7W4X2 UZE9D0mD2TA85/FG4xS/JlWbgJRB/8LHjHQh7IfyCW5EAVA2cGUM1uSZkgIBM7rW vh0R3GF+FK38Op97EIGvpMmIYAqYwwuNfZqJuoib8J8WhzCIHbWt7VKGMjdwGcsY ayg1tg0vl/z4A3GobJksrirtvTTymikSitIpBAuARt3GCxj3KRnwqWc1x9lx4s9h wW7QJnsyPDi4YY0u3XjfRzFhzkpjzNnJjSNyIhLSZSMy8Nn2rks8cXTpYUDkn8JT C/V9OqjIUT0EFh06ei/uqSyd5c7XoU7IoxURwzP3FQzby+1Ncd9nrJXyHz+rMvMs VpvwpyOq8ddkhsHrYc39zSe5wZVE9Q7FKJ5KE7Z4eKsmBZg/BDQojJKmkIZfqVK2 Mph+337cLOC78HBWTOIqCCp8pEQtHNjujgeNBsDxJIgbl+g4aGtnI9fMMfl4wzX/ ROnnCbbWQBf/oEAi/2sUcJwt9gh/WHqY8B/DNZ3N69Iw0itslUuidjaTYwWmmkfs gch9UiBCNMEh0L6Pht/AKMdvbbnokVK8KrMr4mVcyJeBbYanFCzmi8gCcT7xA+2t K1evV1IZ9r2GCpDM21cWowiy0nsflgqUHOawNLdzJkSL+T2sqHra9MC+pe+YYySS UTSufiNA/LV31vef0k0x+Jp78uhWsRddw8zY3Tw1KWUlUaBcK8pjLdoHAO3By4+G 5FqVQRFHqdA1B0Zk7NNEllrD31AY5lTpgJKu9w/sDMAuluyzmReVFm2zXEyhQpqb lxpI3oTIcdlp5T69pgstNp5f1FGryURy/4ABrqUgdvJEjT5JNODR36au5o6gtnbz n1HyOXBfb4DjOy9lM3OYUgNLPw2pY3kmX4nARJH+0/OCV23nWaO5uB6BzyJKMzCC fZQPPf3nAA42HtO18VXNXFZ3FX41t4TdKkY0bfCA/offZX1T7DpbJlugiwkio323 93jX/d6ShfrJI2Q6y2OmZhVIBNEWfkK6bWqE4ay012lAsaWKOCXgQlG3V8qcbYoZ InTJae7SyhWJDV91/KwSsUKAKsBWRR7se/jTTbQTx2j6Hr8UkktC3F8oJVGOIsrl D4jvNp3QZ/qRFMNAU6hMBrUZhGvxh54ZkcgFuqMg0OVrmu39ngPsifkey60UlH8L jXs8ZFUKwuAAzKDeCEP073pxq9LSqQkDFtnMOUfzOOowgvEETFRpvbBflit1dT02 nzKtbSerG+wD1U+E93DbrYSLsSKfPYtBj3HMPaYLVzBfPashhZV0/v1gylEN4y3W -----END RSA PRIVATE KEY-----` --- src/Renci.SshNet/PrivateKeyFile.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index f44672347..d63445a4e 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -50,7 +50,7 @@ namespace Renci.SshNet /// public class PrivateKeyFile : IDisposable { - private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k PRIVATE KEY *-+", + private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[a-fA-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k PRIVATE KEY *-+", #if FEATURE_REGEX_COMPILE RegexOptions.Compiled | RegexOptions.Multiline); #else From adc6645b7ca6bfeb8aadedf8964600a7206ac6e8 Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Mon, 18 Nov 2024 22:37:09 +0100 Subject: [PATCH 2/2] add test --- .../Classes/PrivateKeyFileTest.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index 32dba2cb0..1e5b5f7f9 100644 --- a/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -476,6 +477,52 @@ public void Test_Certificate_OPENSSH_ECDSA() Assert.AreEqual("ecdsa-sha2-nistp521", algorithms[1].Name); } + [TestMethod] + public void Test_LowercaseSalt() + { + // Occurs occasionally in keys generated from older BouncyCastle versions + + string pk = """ + -----BEGIN RSA PRIVATE KEY----- + Proc-Type: 4,ENCRYPTED + DEK-Info: AES-256-CBC,063de67ae11456c89bce9d4a21be3dfb + + 6mS1GhCjAg5mEwMFcKRJwg1uxCeY3ekJNCQewIN9NSI5A8prBOQ+JSyWAsn6c3Gw + OeRyur+5dxMFdt5Hz1CBi9EePvhVyMry7U5U86BWB0HgtDAD02b324sfc6Wk+kj5 + PZvuKyXDiqdwy0rsbBUT+bLtXjCI4Ws1k/KbbF0OqGhFJJvErNU5x8zMD9mqp92R + D8ZZ/F8Sks3V/JeUisAF86sgMfVCELJobn5Zq/IaUyzQwC6IEL+Sy5fSBB5NHiex + NDIJg2RW79uLbufCpuoMPS/GKydf4dq0L5MwvKeqtUgf9Wddc+ZAE4+q1Xz/T8iN + 3IMqsQfVbYjVK7uTaVGKH+Ew77Qryj01Vg+zyzdf4UwOV3XXQKLVCjNxpMCVtoq7 + S45M3Ad7598vb7ooa/BFCIcEM8TkuzPnuttLqjzXEzUcA5kqm3kV14IKtlexBfNT + tarbidlZcOinvJaoIT3baP4rVnEWDKcxpc+UzNU5RRty6l0zpRmw/9RQ5+FKreh8 + eXDHD8TT8ArdaREFM8J2OGpkmIK5sLhhYi9gnTopmKIHn8OAXusmQosEOzS6kGxk + aFtZezXSCBGgXp5RsrBGGx3oXWHGuWbEFXAq+M7PKXMQe5rLRv6sQdfTFSB5hgNK + 82P8UzV1wWtAX4JYAhRh2zA8agY2arbNvbjRyjSbp9HNVBgSbVQ60JInesOqLxEg + XURuCYp4F8AeHzyO805MTNpcX7PZT2kOxp9sKKABJ9BJ0RoSWa0LJqXzGCHvrExE + g7XY/ZfDFZlPLbQnrOgVlYh7pzyfyKB74/oXHkonAisRfsgnQ87yT2DmcHNP6Cek + eae2nrpx2yn9Bf8rYdpmJgNxduO8IZvpn84xEyPqK+FbQsdOefBvsg5TgfzETkh/ + SJjzbqCTDa3XHEUCInixo/wT7FxT8KR9vk43FGPNVRUvPB2GNxe9ZwLYIir64hcQ + CpdA3ipVx4/jVzWQH8KXG9UP9TDAKXEvbndLnr2taPnUdAnznwHN2EkfzS/PrFG4 + /j3l1+VY2AyRybbCTI2iuwJPnKdxOR5oWW6I2Ksfq93Oy+NQz/zasjyNpCZBZWds + 5gBmwiNk2Xzq7ikEVtVk3osOQRw/u9GbretfaT9jtClALL3DFbOzL4WxA+0NJqpd + NB2MohOJa1BJjdfh6x6EVhugH85Y9uYyz/MQj7piljAJY96190n3Q86b/7phfwuD + A/ixS42nqpyOPO+EjiWFerFVTJ3iBj7GXXOZGwCrZfpTbqE7OdTDnE3Vr4MO/Etq + kSDmJ/+4SFFh80YwYVERDNFdDxCYxx5AnxaBFwbqjzatTV/btgGVabIf6zm2L6aY + BJ5wnBZnRnsRaIMehDQmTjioMcyHBSMqId+LYQp+KFpBXqXQTEjJPnq+t4o2FF/N + 8yoKR8BX6HXSO5qUndI8emwec1JeveiRai6SDnEz1EFfetYXImR290mlqt0aRjQk + t/HXRv+fmDQk5hJbCPICydcVSRyrbzxKkppVceEf9NwkBT1MBsOZIFJ3s3A9I72n + XPIab5czlgSLYA/U9nEg2XU21hKD2kRH1OF0WSlpNhN2SJFViVqlC3v36MgHoWNh + -----END RSA PRIVATE KEY----- + """; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(pk))) + { + var pkFile = new PrivateKeyFile(stream, "12345"); + + TestRsaKeyFile(pkFile); + } + } + private void SaveStreamToFile(Stream stream, string fileName) { var buffer = new byte[4000]; @@ -500,6 +547,7 @@ private string GetTempFileName() private static void TestRsaKeyFile(PrivateKeyFile rsaPrivateKeyFile) { + Assert.IsInstanceOfType(rsaPrivateKeyFile.Key); Assert.IsNotNull(rsaPrivateKeyFile.HostKeyAlgorithms); Assert.AreEqual(3, rsaPrivateKeyFile.HostKeyAlgorithms.Count);