فهرست منبع

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 <rh@johnstreetcapital.com>
Rikard Johansson 11 ماه پیش
والد
کامیت
bdaa16463a
2فایلهای تغییر یافته به همراه49 افزوده شده و 1 حذف شده
  1. 1 1
      src/Renci.SshNet/PrivateKeyFile.cs
  2. 48 0
      test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs

+ 1 - 1
src/Renci.SshNet/PrivateKeyFile.cs

@@ -119,7 +119,7 @@ namespace Renci.SshNet
     /// </remarks>
     public partial class PrivateKeyFile : IPrivateKeySource, IDisposable
     {
-        private const string PrivateKeyPattern = @"^-+ *BEGIN (?<keyName>\w+( \w+)*) *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?<cipherName>[A-Z0-9-]+),(?<salt>[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?<data>([a-zA-Z0-9/+=]{1,80}\r?\n)+)(\r?\n)?-+ *END \k<keyName> *-+";
+        private const string PrivateKeyPattern = @"^-+ *BEGIN (?<keyName>\w+( \w+)*) *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?<cipherName>[A-Z0-9-]+),(?<salt>[a-fA-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?<data>([a-zA-Z0-9/+=]{1,80}\r?\n)+)(\r?\n)?-+ *END \k<keyName> *-+";
         private const string CertificatePattern = @"(?<type>[-\w]+@openssh\.com)\s(?<data>[a-zA-Z0-9\/+=]*)(\s+(?<comment>.*))?";
 
 #if NET7_0_OR_GREATER

+ 48 - 0
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<RsaKey>(rsaPrivateKeyFile.Key);
             Assert.IsNotNull(rsaPrivateKeyFile.HostKeyAlgorithms);
             Assert.AreEqual(3, rsaPrivateKeyFile.HostKeyAlgorithms.Count);