From bdaa16463ae34aa695e2ec2db0259a883d8ecf36 Mon Sep 17 00:00:00 2001 From: Rikard Johansson Date: Tue, 19 Nov 2024 09:20:46 +0100 Subject: [PATCH] Handle lower-case hex in private key's salt field (#179) * 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. * add test --------- Co-authored-by: Robert Hague --- src/Renci.SshNet/PrivateKeyFile.cs | 2 +- .../Classes/PrivateKeyFileTest.cs | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 23a6157f..821d5bbf 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -119,7 +119,7 @@ namespace Renci.SshNet /// public partial class PrivateKeyFile : IPrivateKeySource, IDisposable { - private const string PrivateKeyPattern = @"^-+ *BEGIN (?\w+( \w+)*) *-+\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)+)(\r?\n)?-+ *END \k *-+"; + private const string PrivateKeyPattern = @"^-+ *BEGIN (?\w+( \w+)*) *-+\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)+)(\r?\n)?-+ *END \k *-+"; private const string CertificatePattern = @"(?[-\w]+@openssh\.com)\s(?[a-zA-Z0-9\/+=]*)(\s+(?.*))?"; #if NET7_0_OR_GREATER diff --git a/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index 32dba2cb..1e5b5f7f 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 @@ namespace Renci.SshNet.Tests.Classes 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 @@ namespace Renci.SshNet.Tests.Classes private static void TestRsaKeyFile(PrivateKeyFile rsaPrivateKeyFile) { + Assert.IsInstanceOfType(rsaPrivateKeyFile.Key); Assert.IsNotNull(rsaPrivateKeyFile.HostKeyAlgorithms); Assert.AreEqual(3, rsaPrivateKeyFile.HostKeyAlgorithms.Count);