Răsfoiți Sursa

Add a benchmarks project (#1151)

* Add a benchmarks project

* Small improvements

---------

Co-authored-by: Wojciech Nagórski <wojtpl2@gmail.com>
Rob Hague 2 ani în urmă
părinte
comite
60de8a41a4
35 a modificat fișierele cu 211 adăugiri și 27 ștergeri
  1. 3 0
      .gitignore
  2. 0 0
      src/Data/Key.ECDSA.Encrypted.txt
  3. 0 0
      src/Data/Key.ECDSA.txt
  4. 0 0
      src/Data/Key.ECDSA384.Encrypted.txt
  5. 0 0
      src/Data/Key.ECDSA384.txt
  6. 0 0
      src/Data/Key.ECDSA521.Encrypted.txt
  7. 0 0
      src/Data/Key.ECDSA521.txt
  8. 0 0
      src/Data/Key.OPENSSH.ECDSA.Encrypted.txt
  9. 0 0
      src/Data/Key.OPENSSH.ECDSA.txt
  10. 0 0
      src/Data/Key.OPENSSH.ECDSA384.Encrypted.txt
  11. 0 0
      src/Data/Key.OPENSSH.ECDSA384.txt
  12. 0 0
      src/Data/Key.OPENSSH.ECDSA521.Encrypted.txt
  13. 0 0
      src/Data/Key.OPENSSH.ECDSA521.txt
  14. 0 0
      src/Data/Key.OPENSSH.ED25519.Encrypted.txt
  15. 0 0
      src/Data/Key.OPENSSH.ED25519.txt
  16. 0 0
      src/Data/Key.OPENSSH.RSA.Encrypted.txt
  17. 0 0
      src/Data/Key.OPENSSH.RSA.txt
  18. 0 0
      src/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt
  19. 0 0
      src/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt
  20. 0 0
      src/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt
  21. 0 0
      src/Data/Key.RSA.Encrypted.Des.CBC.12345.txt
  22. 0 0
      src/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt
  23. 0 0
      src/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt
  24. 0 0
      src/Data/Key.RSA.txt
  25. 0 0
      src/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt
  26. 0 0
      src/Data/Key.SSH2.DSA.txt
  27. 0 0
      src/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt
  28. 0 0
      src/Data/Key.SSH2.RSA.txt
  29. 27 0
      src/Renci.SshNet.Benchmarks/Program.cs
  30. 31 0
      src/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj
  31. 38 0
      src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs
  32. 48 0
      src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs
  33. 41 0
      src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs
  34. 1 27
      src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj
  35. 22 0
      src/Renci.SshNet.sln

+ 3 - 0
.gitignore

@@ -22,3 +22,6 @@ project.lock.json
 
 # Build outputs
 build/target/
+
+# Benchmark results
+BenchmarkDotNet.Artifacts/

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


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


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


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


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


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


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


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


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


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


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


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


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.Encrypted.txt → src/Data/Key.OPENSSH.ED25519.Encrypted.txt


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.txt → src/Data/Key.OPENSSH.ED25519.txt


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


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


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt → src/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt → src/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt → src/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Des.CBC.12345.txt → src/Data/Key.RSA.Encrypted.Des.CBC.12345.txt


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt → src/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt → src/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt


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


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt → src/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.SSH2.DSA.txt → src/Data/Key.SSH2.DSA.txt


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt → src/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt


+ 0 - 0
src/Renci.SshNet.Tests/Data/Key.SSH2.RSA.txt → src/Data/Key.SSH2.RSA.txt


+ 27 - 0
src/Renci.SshNet.Benchmarks/Program.cs

@@ -0,0 +1,27 @@
+using BenchmarkDotNet.Running;
+
+namespace Renci.SshNet.Benchmarks
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            // Usage examples:
+            // 1. Run all benchmarks:
+            //     dotnet run -c Release -- --filter *
+            // 2. List all benchmarks:
+            //     dotnet run -c Release -- --list flat
+            // 3. Run a subset of benchmarks based on a filter (of a benchmark method's fully-qualified name,
+            //    e.g. "Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers.AesCipherBenchmarks.Encrypt_CBC"):
+            //     dotnet run -c Release -- --filter *Ciphers*
+            // 4. Run benchmarks and include memory usage statistics in the output:
+            //     dotnet run -c Release -- filter *Rsa* --memory
+            // 3. Print help:
+            //     dotnet run -c Release -- --help
+
+            // See also https://benchmarkdotnet.org/articles/guides/console-args.html
+
+            _ = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
+        }
+    }
+}

+ 31 - 0
src/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj

@@ -0,0 +1,31 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net7.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+      <!--
+          Even though we're not interested in producing XML docs for test projects, we have to enable this in order to have the .NET Compiler
+          Platform analyzers produce the IDE0005 (Remove unnecessary import) diagnostic.
+            
+          To avoid warnings for missing XML docs, we add CS1591 (Missing XML comment for publicly visible type or member) to the NoWarn property.
+          We can stop producing XML docs for test projects (and remove the NoWarn for CS1591) once the following issue is fixed:
+          https://github.com/dotnet/roslyn/issues/41640.
+      -->
+      <NoWarn>$(NoWarn);CS1591</NoWarn>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="BenchmarkDotNet" Version="0.13.8" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Renci.SshNet\Renci.SshNet.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+      <EmbeddedResource Include="..\Data\*.txt" LinkBase="Data" />
+  </ItemGroup>
+
+</Project>

+ 38 - 0
src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs

@@ -0,0 +1,38 @@
+using BenchmarkDotNet.Attributes;
+using Renci.SshNet.Security.Cryptography.Ciphers;
+using Renci.SshNet.Security.Cryptography.Ciphers.Modes;
+
+namespace Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers
+{
+    [MemoryDiagnoser]
+    public class AesCipherBenchmarks
+    {
+        private readonly byte[] _key;
+        private readonly byte[] _iv;
+        private readonly byte[] _data;
+
+        public AesCipherBenchmarks()
+        {
+            _key = new byte[32];
+            _iv = new byte[16];
+            _data = new byte[256];
+
+            Random random = new(Seed: 12345);
+            random.NextBytes(_key);
+            random.NextBytes(_iv);
+            random.NextBytes(_data);
+        }
+
+        [Benchmark]
+        public byte[] Encrypt_CBC()
+        {
+            return new AesCipher(_key, new CbcCipherMode(_iv), null).Encrypt(_data);
+        }
+
+        [Benchmark]
+        public byte[] Decrypt_CBC()
+        {
+            return new AesCipher(_key, new CbcCipherMode(_iv), null).Decrypt(_data);
+        }
+    }
+}

+ 48 - 0
src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs

@@ -0,0 +1,48 @@
+using BenchmarkDotNet.Attributes;
+
+using Renci.SshNet.Security;
+using Renci.SshNet.Security.Cryptography.Ciphers;
+
+namespace Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers
+{
+    [MemoryDiagnoser]
+    public class RsaCipherBenchmarks
+    {
+        private readonly RsaKey _privateKey;
+        private readonly RsaKey _publicKey;
+        private readonly byte[] _data;
+
+        public RsaCipherBenchmarks()
+        {
+            _data = new byte[128];
+
+            Random random = new(Seed: 12345);
+            random.NextBytes(_data);
+
+            using (var s = typeof(RsaCipherBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.RSA.txt"))
+            {
+                _privateKey = (RsaKey)((KeyHostAlgorithm) new PrivateKeyFile(s).HostKey).Key;
+                
+                // The implementations of RsaCipher.Encrypt/Decrypt differ based on whether the supplied RsaKey has private key information
+                // or only public. So we extract out the public key information to a separate variable.
+                _publicKey = new RsaKey()
+                {
+                    Public = _privateKey.Public
+                };
+            }
+        }
+
+        [Benchmark]
+        public byte[] Encrypt()
+        {
+            return new RsaCipher(_publicKey).Encrypt(_data);
+        }
+
+        // RSA Decrypt does not work
+        // [Benchmark]
+        // public byte[] Decrypt()
+        // {
+        //     return new RsaCipher(_privateKey).Decrypt(_data);
+        // }
+    }
+}

+ 41 - 0
src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs

@@ -0,0 +1,41 @@
+using BenchmarkDotNet.Attributes;
+
+using Renci.SshNet.Security;
+using Renci.SshNet.Security.Cryptography;
+
+namespace Renci.SshNet.Benchmarks.Security.Cryptography
+{
+    [MemoryDiagnoser]
+    public class ED25519DigitalSignatureBenchmarks
+    {
+        private readonly ED25519Key _key;
+        private readonly byte[] _data;
+        private readonly byte[] _signature;
+
+        public ED25519DigitalSignatureBenchmarks()
+        {
+            _data = new byte[128];
+
+            Random random = new(Seed: 12345);
+            random.NextBytes(_data);
+
+            using (var s = typeof(ED25519DigitalSignatureBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.OPENSSH.ED25519.txt"))
+            {
+                _key = (ED25519Key) ((KeyHostAlgorithm) new PrivateKeyFile(s).HostKey).Key;
+            }
+            _signature = new ED25519DigitalSignature(_key).Sign(_data);
+        }
+
+        [Benchmark]
+        public byte[] Sign()
+        {
+            return new ED25519DigitalSignature(_key).Sign(_data);
+        }
+
+        [Benchmark]
+        public bool Verify()
+        {
+            return new ED25519DigitalSignature(_key).Verify(_data, _signature);
+        }
+    }
+}

+ 1 - 27
src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj

@@ -14,33 +14,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <EmbeddedResource Include="Data\Key.ECDSA.Encrypted.txt" />
-    <EmbeddedResource Include="Data\Key.ECDSA.txt" />
-    <EmbeddedResource Include="Data\Key.ECDSA384.Encrypted.txt" />
-    <EmbeddedResource Include="Data\Key.ECDSA384.txt" />
-    <EmbeddedResource Include="Data\Key.ECDSA521.Encrypted.txt" />
-    <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" />
-    <EmbeddedResource Include="Data\Key.RSA.Encrypted.Des.CBC.12345.txt" />
-    <EmbeddedResource Include="Data\Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt" />
-    <EmbeddedResource Include="Data\Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt" />
-    <EmbeddedResource Include="Data\Key.RSA.txt" />
-    <EmbeddedResource Include="Data\Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt" />
-    <EmbeddedResource Include="Data\Key.SSH2.DSA.txt" />
-    <EmbeddedResource Include="Data\Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt" />
-    <EmbeddedResource Include="Data\Key.SSH2.RSA.txt" />
+      <EmbeddedResource Include="..\Data\*.txt" LinkBase="Data" />
   </ItemGroup>
 
   <ItemGroup>

+ 22 - 0
src/Renci.SshNet.sln

@@ -42,6 +42,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D21A4D03-0
 		..\test\Directory.Build.props = ..\test\Directory.Build.props
 	EndProjectSection
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.Benchmarks", "Renci.SshNet.Benchmarks\Renci.SshNet.Benchmarks.csproj", "{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}"
+EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.IntegrationTests", "Renci.SshNet.IntegrationTests\Renci.SshNet.IntegrationTests.csproj", "{EEF98046-729C-419E-932D-4E569073C8CC}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.TestTools.OpenSSH", "Renci.SshNet.TestTools.OpenSSH\Renci.SshNet.TestTools.OpenSSH.csproj", "{78239046-2019-494E-B6EC-240AF787E4D0}"
@@ -88,6 +90,26 @@ Global
 		{C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 		{C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x64.ActiveCfg = Release|Any CPU
 		{C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x86.ActiveCfg = Release|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|ARM.ActiveCfg = Debug|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|ARM.Build.0 = Debug|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x64.Build.0 = Debug|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x86.Build.0 = Debug|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|ARM.ActiveCfg = Release|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|ARM.Build.0 = Release|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x64.ActiveCfg = Release|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x64.Build.0 = Release|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x86.ActiveCfg = Release|Any CPU
+		{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x86.Build.0 = Release|Any CPU
 		{EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{EEF98046-729C-419E-932D-4E569073C8CC}.Debug|ARM.ActiveCfg = Debug|Any CPU