Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update SSH.NET #5

Merged
merged 3 commits into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 0 additions & 68 deletions .github/workflows/codeql-analysis.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/dotnet-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dotnet-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ SshNet.PuttyKeyFile
[![NuGet](https://img.shields.io/nuget/v/SshNet.PuttyKeyFile.svg?style=flat)](https://www.nuget.org/packages/SshNet.PuttyKeyFile)
![Nuget](https://img.shields.io/nuget/dt/SshNet.PuttyKeyFile)

![CodeQL](https://github.com/darinkes/SshNet.PuttyKeyFile/workflows/CodeQL/badge.svg)
![.NET-Ubuntu](https://github.com/darinkes/SshNet.PuttyKeyFile/workflows/.NET-Ubuntu/badge.svg)
![.NET-Windows](https://github.com/darinkes/SshNet.PuttyKeyFile/workflows/.NET-Windows/badge.svg)
![NuGet](https://github.com/darinkes/SshNet.PuttyKeyFile/workflows/NuGet/badge.svg)
Expand All @@ -16,7 +15,7 @@ WIP

## .NET Frameworks

* .NET 4.6
* .NET 4.8
* netstandard 2.0

## Keys
Expand All @@ -38,4 +37,4 @@ var key = new PuttyKeyFile("my-key.ppk");
using var client = new SshClient("ssh.foo.com", "root", key);
client.Connect();
Console.WriteLine(client.RunCommand("hostname").Result);
```
```
4 changes: 2 additions & 2 deletions SshNet.PuttyKeyFile.Sample/SshNet.PuttyKeyFile.Sample.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">net462;net7.0</TargetFrameworks>
<TargetFramework Condition="'$(OS)' != 'Windows_NT'">net7.0</TargetFramework>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">net48;net8.0</TargetFrameworks>
<TargetFramework Condition="'$(OS)' != 'Windows_NT'">net8.0</TargetFramework>
<OutputType>exe</OutputType>
<LangVersion>9</LangVersion>
<Nullable>enable</Nullable>
Expand Down
10 changes: 6 additions & 4 deletions SshNet.PuttyKeyFile.Tests/PuttyKeyFileTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Reflection;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using Renci.SshNet.Security;

namespace SshNet.PuttyKeyFile.Tests
Expand All @@ -14,17 +15,18 @@ public void Setup()
{
}

private void TestKey<TKey>(string keyName, string versionSuffix, string comment, int keyLength = 0, string? pass = null) where TKey : Key, new()
private void TestKey<TKey>(string keyName, string versionSuffix, string comment, int keyLength = 0, string? pass = null) where TKey : Key
{
var keyStream = GetKey($"{keyName}-v{versionSuffix}.ppk");
if (keyStream is null)
throw new NullReferenceException(nameof(keyStream));

var keyFile = new PuttyKeyFile(keyStream, pass);

Assert.IsInstanceOf<TKey>(((KeyHostAlgorithm) keyFile.HostKeyAlgorithms.First()).Key);
Assert.AreEqual(keyLength, ((KeyHostAlgorithm) keyFile.HostKeyAlgorithms.First()).Key.KeyLength);
Assert.AreEqual(comment, ((KeyHostAlgorithm) keyFile.HostKeyAlgorithms.First()).Key.Comment);
ClassicAssert.IsInstanceOf<TKey>(((KeyHostAlgorithm) keyFile.HostKeyAlgorithms.First()).Key);
ClassicAssert.AreEqual(keyLength, ((KeyHostAlgorithm) keyFile.HostKeyAlgorithms.First()).Key.KeyLength);
ClassicAssert.AreEqual(comment, ((KeyHostAlgorithm) keyFile.HostKeyAlgorithms.First()).Key.Comment);
ClassicAssert.AreEqual(keyFile.Key is RsaKey ? 3 : 1, keyFile.HostKeyAlgorithms.Count);
}

[Test]
Expand Down
10 changes: 5 additions & 5 deletions SshNet.PuttyKeyFile.Tests/SshNet.PuttyKeyFile.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">net462;net7.0</TargetFrameworks>
<TargetFramework Condition="'$(OS)' != 'Windows_NT'">net7.0</TargetFramework>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">net48;net8.0</TargetFrameworks>
<TargetFramework Condition="'$(OS)' != 'Windows_NT'">net8.0</TargetFramework>
<LangVersion>9</LangVersion>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="NUnit" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
</ItemGroup>

<ItemGroup>
Expand Down
1 change: 0 additions & 1 deletion SshNet.PuttyKeyFile/Extensions/ByteExtension.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using Renci.SshNet.Common;

namespace SshNet.PuttyKeyFile.Extensions
{
Expand Down
56 changes: 24 additions & 32 deletions SshNet.PuttyKeyFile/PuttyKeyFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
using Renci.SshNet.Common;
using Renci.SshNet.Security;
using Renci.SshNet.Security.Cryptography.Ciphers;
using Renci.SshNet.Security.Cryptography.Ciphers.Modes;
using Renci.SshNet.Security.Cryptography.Ciphers.Paddings;
using SshNet.PuttyKeyFile.Extensions;
using Konscious.Security.Cryptography;
using Renci.SshNet.Security.Cryptography;
using HMACSHA1 = System.Security.Cryptography.HMACSHA1;
using HMACSHA256 = System.Security.Cryptography.HMACSHA256;

namespace SshNet.PuttyKeyFile
{
Expand All @@ -33,14 +34,14 @@ public class PuttyKeyFile : IPrivateKeySource
@"(?>Argon2-Salt: *(?<argon2Salt>[^\r\n]+)(\r|\n)+)?" + // Putty3
@"Private-Lines: *([0-9]+)(\r|\n)+" +
@"(?<privateLines>([a-zA-Z0-9/+=]{1,80}(\r|\n)+)+)" +
@"Private-(?<macOrHash>(MAC|Hash)): *(?<hashData>[a-zA-Z0-9/+=]+)",
"Private-(?<macOrHash>(MAC|Hash)): *(?<hashData>[a-zA-Z0-9/+=]+)",
RegexOptions.Compiled | RegexOptions.Multiline);

private readonly List<HostAlgorithm> _hostAlgorithms = new();

public IReadOnlyCollection<HostAlgorithm> HostKeyAlgorithms => _hostAlgorithms;

public Key Key { get; private set; }
public Key? Key { get; private set; }

public PuttyKeyFile(Stream privateKey)
{
Expand Down Expand Up @@ -115,8 +116,7 @@ private void Open(Stream privateKey, string? passPhrase)
case 2:
{
var cipherKey = GetCipherKey(passPhrase, 32);
var cipher = new AesCipher(cipherKey, new CbcCipherMode(new byte[cipherKey.Length]),
new PKCS7Padding());
var cipher = new AesCipher(cipherKey, new byte[cipherKey.Length], AesCipherMode.CBC);

var privateKeyData = Convert.FromBase64String(privateLines);
if (privateKeyData.Length % cipher.BlockSize != 0)
Expand All @@ -129,20 +129,13 @@ private void Open(Stream privateKey, string? passPhrase)
{
Argon2 argon2;
var passphraseBytes = Encoding.UTF8.GetBytes(passPhrase);
switch (keyDerivation)
argon2 = keyDerivation switch
{
case "Argon2d":
argon2 = new Argon2d(passphraseBytes);
break;
case "Argon2i":
argon2 = new Argon2i(passphraseBytes);
break;
case "Argon2id":
argon2 = new Argon2id(passphraseBytes);
break;
default:
throw new SshException($"Encryption Key Derivation {keyDerivation} is not supported.");
}
"Argon2d" => new Argon2d(passphraseBytes),
"Argon2i" => new Argon2i(passphraseBytes),
"Argon2id" => new Argon2id(passphraseBytes),
_ => throw new SshException($"Encryption Key Derivation {keyDerivation} is not supported.")
};

argon2.DegreeOfParallelism = int.Parse(argon2Parallelism);
argon2.MemorySize = int.Parse(argon2Memory);
Expand All @@ -168,7 +161,7 @@ private void Open(Stream privateKey, string? passPhrase)
macKey3.Clear();
macKey3.AddRange(macKey);

var cipher = new AesCipher(cipherKey, new CbcCipherMode(crcIv), new PKCS7Padding());
var cipher = new AesCipher(cipherKey, crcIv, AesCipherMode.CBC);

var privateKeyData = Convert.FromBase64String(privateLines);
if (privateKeyData.Length % cipher.BlockSize != 0)
Expand Down Expand Up @@ -264,24 +257,23 @@ private void Open(Stream privateKey, string? passPhrase)
throw new SshException($"PuTTY Public Key Type '{pubKeyType}' and Private Key Type '{keyType}' differ");
}

Key parsedKey;
byte[] publicKey;
byte[] unencryptedPrivateKey;
switch (keyType)
{
case "ssh-ed25519":
publicKey = publicKeyReader.ReadBignum2();
unencryptedPrivateKey = privateKeyReader.ReadBignum2();
parsedKey = new ED25519Key(publicKey.Reverse(), unencryptedPrivateKey);
Key = new ED25519Key(unencryptedPrivateKey);
_hostAlgorithms.Add(new KeyHostAlgorithm(Key.ToString(), Key));
break;
case "ecdsa-sha2-nistp256":
case "ecdsa-sha2-nistp384":
case "ecdsa-sha2-nistp521":
var len = (int)publicKeyReader.ReadUInt32();
var curve = Encoding.ASCII.GetString(publicKeyReader.ReadBytes(len));
publicKey = publicKeyReader.ReadBignum2();
var publicKey = publicKeyReader.ReadBignum2();
unencryptedPrivateKey = privateKeyReader.ReadBignum2();
parsedKey = new EcdsaKey(curve, publicKey, unencryptedPrivateKey.TrimLeadingZeros());
Key = new EcdsaKey(curve, publicKey, unencryptedPrivateKey.TrimLeadingZeros());
_hostAlgorithms.Add(new KeyHostAlgorithm(Key.ToString(), Key));
break;
case "ssh-rsa":
var exponent = publicKeyReader.ReadBigIntWithBytes();
Expand All @@ -290,19 +282,19 @@ private void Open(Stream privateKey, string? passPhrase)
var p = privateKeyReader.ReadBigIntWithBytes();
var q = privateKeyReader.ReadBigIntWithBytes();
var inverseQ = privateKeyReader.ReadBigIntWithBytes();
parsedKey = new RsaKey(modulus, exponent, d, p, q, inverseQ);
var rsaKey = new RsaKey(modulus, exponent, d, p, q, inverseQ);
Key = rsaKey;
_hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", Key));
_hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", Key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA512)));
_hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", Key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA256)));
break;
default:
throw new SshException("PuTTY key type '" + keyType + "' is not supported.");
}

parsedKey.Comment = comment;

Key = parsedKey;
_hostAlgorithms.Add(new KeyHostAlgorithm(parsedKey.ToString(), parsedKey));
Key.Comment = comment;
}


private static byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
Expand Down
8 changes: 4 additions & 4 deletions SshNet.PuttyKeyFile/SshNet.PuttyKeyFile.csproj
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">net462;netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">net48;netstandard2.0</TargetFrameworks>
<TargetFramework Condition="'$(OS)' != 'Windows_NT'">netstandard2.0</TargetFramework>
<LangVersion>9</LangVersion>
<Nullable>enable</Nullable>
<PackageId>SshNet.PuttyKeyFile</PackageId>
<Version>0.2.0-beta</Version>
<Version>2024.0.0-beta</Version>
<PackageVersion>$(Version)</PackageVersion>
<PackageTags>ssh;scp;sftp</PackageTags>
<Description>Extension to read and use Authentication Keys in PuTTY-Format</Description>
<PackageReleaseNotes>https://github.com/darinkes/SshNet.PuttyKeyFile/releases/tag/$(PackageVersion)</PackageReleaseNotes>
<Copyright>Copyright (c) 2021 - 2023 Stefan Rinkes</Copyright>
<Copyright>Copyright (c) 2021 - 2024 Stefan Rinkes</Copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/darinkes/SshNet.PuttyKeyFile/</PackageProjectUrl>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
Expand All @@ -20,7 +20,7 @@

<ItemGroup>
<PackageReference Include="SshNet.Security.Cryptography" Version="[1.3.0]" />
<PackageReference Include="SSH.NET" Version="2023.0.0" />
<PackageReference Include="SSH.NET" Version="2024.0.0" />
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.0"/>
</ItemGroup>
</Project>
Loading