mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-11 01:36:39 +00:00
[Private Key] Add support for PuTTY private key file format (V3 and V2) (#1543)
* [Private Key] Add support for PuTTY private key * add negative test for mac --------- Co-authored-by: Rob Hague <rob.hague00@gmail.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
|
||||
<PackageVersion Include="BouncyCastle.Cryptography" Version="2.4.0" />
|
||||
<PackageVersion Include="BouncyCastle.Cryptography" Version="2.5.0" />
|
||||
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
|
||||
<PackageVersion Include="coverlet.msbuild" Version="6.0.2" />
|
||||
<PackageVersion Include="GitHubActionsTestLogger" Version="2.4.1">
|
||||
|
||||
@@ -102,17 +102,21 @@ The main types provided by this library are:
|
||||
* OpenSSL PKCS#8 PEM format ("BEGIN PRIVATE KEY", "BEGIN ENCRYPTED PRIVATE KEY")
|
||||
* ssh.com format ("BEGIN SSH2 ENCRYPTED PRIVATE KEY")
|
||||
* OpenSSH key format ("BEGIN OPENSSH PRIVATE KEY")
|
||||
* PuTTY private key format ("PuTTY-User-Key-File-2", "PuTTY-User-Key-File-3")
|
||||
* DSA in
|
||||
* OpenSSL traditional PEM format ("BEGIN DSA PRIVATE KEY")
|
||||
* OpenSSL PKCS#8 PEM format ("BEGIN PRIVATE KEY", "BEGIN ENCRYPTED PRIVATE KEY")
|
||||
* ssh.com format ("BEGIN SSH2 ENCRYPTED PRIVATE KEY")
|
||||
* PuTTY private key format ("PuTTY-User-Key-File-2", "PuTTY-User-Key-File-3")
|
||||
* ECDSA 256/384/521 in
|
||||
* OpenSSL traditional PEM format ("BEGIN EC PRIVATE KEY")
|
||||
* OpenSSL PKCS#8 PEM format ("BEGIN PRIVATE KEY", "BEGIN ENCRYPTED PRIVATE KEY")
|
||||
* OpenSSH key format ("BEGIN OPENSSH PRIVATE KEY")
|
||||
* PuTTY private key format ("PuTTY-User-Key-File-2", "PuTTY-User-Key-File-3")
|
||||
* ED25519 in
|
||||
* OpenSSL PKCS#8 PEM format ("BEGIN PRIVATE KEY", "BEGIN ENCRYPTED PRIVATE KEY")
|
||||
* OpenSSH key format ("BEGIN OPENSSH PRIVATE KEY")
|
||||
* PuTTY private key format ("PuTTY-User-Key-File-2", "PuTTY-User-Key-File-3")
|
||||
|
||||
Private keys in OpenSSL traditional PEM format can be encrypted using one of the following cipher methods:
|
||||
* DES-EDE3-CBC
|
||||
@@ -124,7 +128,7 @@ Private keys in OpenSSL traditional PEM format can be encrypted using one of the
|
||||
|
||||
Private keys in OpenSSL PKCS#8 PEM format can be encrypted using any cipher method BouncyCastle supports.
|
||||
|
||||
Private keys in ssh.com format can be encrypted using one of the following cipher methods:
|
||||
Private keys in ssh.com format can be encrypted using the following cipher method:
|
||||
* 3des-cbc
|
||||
|
||||
Private keys in OpenSSH key format can be encrypted using one of the following cipher methods:
|
||||
@@ -139,6 +143,9 @@ Private keys in OpenSSH key format can be encrypted using one of the following c
|
||||
* aes256-gcm<span></span>@openssh.com
|
||||
* chacha20-poly1305<span></span>@openssh.com
|
||||
|
||||
Private keys in PuTTY private key format can be encrypted using the following cipher method:
|
||||
* aes256-cbc
|
||||
|
||||
## Host Key Algorithms
|
||||
|
||||
**SSH.NET** supports the following host key algorithms:
|
||||
|
||||
@@ -42,13 +42,11 @@ namespace Renci.SshNet
|
||||
{
|
||||
throw new SshPassPhraseNullOrEmptyException("Private key is encrypted but passphrase is empty.");
|
||||
}
|
||||
|
||||
var binarySalt = new byte[_salt.Length / 2];
|
||||
for (var i = 0; i < binarySalt.Length; i++)
|
||||
{
|
||||
binarySalt[i] = Convert.ToByte(_salt.Substring(i * 2, 2), 16);
|
||||
}
|
||||
|
||||
#if NET
|
||||
var binarySalt = Convert.FromHexString(_salt);
|
||||
#else
|
||||
var binarySalt = Org.BouncyCastle.Utilities.Encoders.Hex.Decode(_salt);
|
||||
#endif
|
||||
CipherInfo cipher;
|
||||
switch (_cipherName)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Generators;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
using Renci.SshNet.Abstractions;
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security;
|
||||
using Renci.SshNet.Security.Cryptography.Ciphers;
|
||||
|
||||
namespace Renci.SshNet
|
||||
{
|
||||
public partial class PrivateKeyFile
|
||||
{
|
||||
private sealed class PuTTY : IPrivateKeyParser
|
||||
{
|
||||
private readonly string _version;
|
||||
private readonly string _algorithmName;
|
||||
private readonly string _encryptionType;
|
||||
private readonly string _comment;
|
||||
private readonly byte[] _publicKey;
|
||||
private readonly string? _argon2Type;
|
||||
private readonly string? _argon2Salt;
|
||||
private readonly string? _argon2Iterations;
|
||||
private readonly string? _argon2Memory;
|
||||
private readonly string? _argon2Parallelism;
|
||||
private readonly byte[] _data;
|
||||
private readonly string _mac;
|
||||
private readonly string? _passPhrase;
|
||||
|
||||
public PuTTY(string version, string algorithmName, string encryptionType, string comment, byte[] publicKey, string? argon2Type, string? argon2Salt, string? argon2Iterations, string? argon2Memory, string? argon2Parallelism, byte[] data, string mac, string? passPhrase)
|
||||
{
|
||||
_version = version;
|
||||
_algorithmName = algorithmName;
|
||||
_encryptionType = encryptionType;
|
||||
_comment = comment;
|
||||
_publicKey = publicKey;
|
||||
_argon2Type = argon2Type;
|
||||
_argon2Salt = argon2Salt;
|
||||
_argon2Iterations = argon2Iterations;
|
||||
_argon2Memory = argon2Memory;
|
||||
_argon2Parallelism = argon2Parallelism;
|
||||
_data = data;
|
||||
_mac = mac;
|
||||
_passPhrase = passPhrase;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an PuTTY PPK key file.
|
||||
/// <see href="https://tartarus.org/~simon/putty-snapshots/htmldoc/AppendixC.html"/>.
|
||||
/// </summary>
|
||||
public Key Parse()
|
||||
{
|
||||
byte[] privateKey;
|
||||
HMAC hmac;
|
||||
switch (_encryptionType)
|
||||
{
|
||||
case "aes256-cbc":
|
||||
if (string.IsNullOrEmpty(_passPhrase))
|
||||
{
|
||||
throw new SshPassPhraseNullOrEmptyException("Private key is encrypted but passphrase is empty.");
|
||||
}
|
||||
|
||||
byte[] cipherKey;
|
||||
byte[] cipherIV;
|
||||
switch (_version)
|
||||
{
|
||||
case "3":
|
||||
ThrowHelper.ThrowIfNullOrEmpty(_argon2Type);
|
||||
ThrowHelper.ThrowIfNullOrEmpty(_argon2Iterations);
|
||||
ThrowHelper.ThrowIfNullOrEmpty(_argon2Memory);
|
||||
ThrowHelper.ThrowIfNullOrEmpty(_argon2Parallelism);
|
||||
ThrowHelper.ThrowIfNullOrEmpty(_argon2Salt);
|
||||
|
||||
var keyData = Argon2(
|
||||
_argon2Type,
|
||||
Convert.ToInt32(_argon2Iterations),
|
||||
Convert.ToInt32(_argon2Memory),
|
||||
Convert.ToInt32(_argon2Parallelism),
|
||||
#if NET
|
||||
Convert.FromHexString(_argon2Salt),
|
||||
#else
|
||||
Org.BouncyCastle.Utilities.Encoders.Hex.Decode(_argon2Salt),
|
||||
#endif
|
||||
_passPhrase);
|
||||
|
||||
cipherKey = keyData.Take(32);
|
||||
cipherIV = keyData.Take(32, 16);
|
||||
|
||||
var macKey = keyData.Take(48, 32);
|
||||
hmac = new HMACSHA256(macKey);
|
||||
|
||||
break;
|
||||
case "2":
|
||||
keyData = V2KDF(_passPhrase);
|
||||
|
||||
cipherKey = keyData.Take(32);
|
||||
cipherIV = new byte[16];
|
||||
|
||||
macKey = CryptoAbstraction.HashSHA1(Encoding.UTF8.GetBytes("putty-private-key-file-mac-key" + _passPhrase)).Take(20);
|
||||
hmac = new HMACSHA1(macKey);
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new SshException("PuTTY key file version " + _version + " is not supported");
|
||||
}
|
||||
|
||||
using (var cipher = new AesCipher(cipherKey, cipherIV, AesCipherMode.CBC, pkcs7Padding: false))
|
||||
{
|
||||
privateKey = cipher.Decrypt(_data);
|
||||
}
|
||||
|
||||
break;
|
||||
case "none":
|
||||
switch (_version)
|
||||
{
|
||||
case "3":
|
||||
hmac = new HMACSHA256(Array.Empty<byte>());
|
||||
break;
|
||||
case "2":
|
||||
var macKey = CryptoAbstraction.HashSHA1(Encoding.UTF8.GetBytes("putty-private-key-file-mac-key"));
|
||||
hmac = new HMACSHA1(macKey);
|
||||
break;
|
||||
default:
|
||||
throw new SshException("PuTTY key file version " + _version + " is not supported");
|
||||
}
|
||||
|
||||
privateKey = _data;
|
||||
break;
|
||||
default:
|
||||
throw new SshException("Encryption " + _encryptionType + " is not supported for PuTTY key file");
|
||||
}
|
||||
|
||||
byte[] macData;
|
||||
using (var macStream = new SshDataStream(256))
|
||||
{
|
||||
macStream.Write(_algorithmName, Encoding.UTF8);
|
||||
macStream.Write(_encryptionType, Encoding.UTF8);
|
||||
macStream.Write(_comment, Encoding.UTF8);
|
||||
macStream.WriteBinary(_publicKey);
|
||||
macStream.WriteBinary(privateKey);
|
||||
macData = macStream.ToArray();
|
||||
}
|
||||
|
||||
byte[] macValue;
|
||||
using (hmac)
|
||||
{
|
||||
macValue = hmac.ComputeHash(macData);
|
||||
}
|
||||
#if NET
|
||||
var reference = Convert.FromHexString(_mac);
|
||||
#else
|
||||
var reference = Org.BouncyCastle.Utilities.Encoders.Hex.Decode(_mac);
|
||||
#endif
|
||||
if (!macValue.SequenceEqual(reference))
|
||||
{
|
||||
throw new SshException("MAC verification failed for PuTTY key file");
|
||||
}
|
||||
|
||||
var publicKeyReader = new SshDataReader(_publicKey);
|
||||
var keyType = publicKeyReader.ReadString(Encoding.UTF8);
|
||||
Debug.Assert(keyType == _algorithmName, $"{nameof(keyType)} is not the same as {nameof(_algorithmName)}");
|
||||
|
||||
var privateKeyReader = new SshDataReader(privateKey);
|
||||
|
||||
Key parsedKey;
|
||||
|
||||
switch (keyType)
|
||||
{
|
||||
case "ssh-ed25519":
|
||||
parsedKey = new ED25519Key(privateKeyReader.ReadBignum2());
|
||||
break;
|
||||
case "ecdsa-sha2-nistp256":
|
||||
case "ecdsa-sha2-nistp384":
|
||||
case "ecdsa-sha2-nistp521":
|
||||
var curve = publicKeyReader.ReadString(Encoding.ASCII);
|
||||
var pub = publicKeyReader.ReadBignum2();
|
||||
var prv = privateKeyReader.ReadBignum2();
|
||||
parsedKey = new EcdsaKey(curve, pub, prv);
|
||||
break;
|
||||
case "ssh-dss":
|
||||
var p = publicKeyReader.ReadBignum();
|
||||
var q = publicKeyReader.ReadBignum();
|
||||
var g = publicKeyReader.ReadBignum();
|
||||
var y = publicKeyReader.ReadBignum();
|
||||
var x = privateKeyReader.ReadBignum();
|
||||
parsedKey = new DsaKey(p, q, g, y, x);
|
||||
break;
|
||||
case "ssh-rsa":
|
||||
var exponent = publicKeyReader.ReadBignum(); // e
|
||||
var modulus = publicKeyReader.ReadBignum(); // n
|
||||
var d = privateKeyReader.ReadBignum(); // d
|
||||
p = privateKeyReader.ReadBignum(); // p
|
||||
q = privateKeyReader.ReadBignum(); // q
|
||||
var inverseQ = privateKeyReader.ReadBignum(); // iqmp
|
||||
parsedKey = new RsaKey(modulus, exponent, d, p, q, inverseQ);
|
||||
break;
|
||||
default:
|
||||
throw new SshException("Key type " + keyType + " is not supported for PuTTY key file");
|
||||
}
|
||||
|
||||
parsedKey.Comment = _comment;
|
||||
return parsedKey;
|
||||
}
|
||||
|
||||
private static byte[] Argon2(string type, int iterations, int memory, int parallelism, byte[] salt, string passPhrase)
|
||||
{
|
||||
int param;
|
||||
switch (type)
|
||||
{
|
||||
case "Argon2i":
|
||||
param = Argon2Parameters.Argon2i;
|
||||
break;
|
||||
case "Argon2d":
|
||||
param = Argon2Parameters.Argon2d;
|
||||
break;
|
||||
case "Argon2id":
|
||||
param = Argon2Parameters.Argon2id;
|
||||
break;
|
||||
default:
|
||||
throw new SshException("KDF " + type + " is not supported for PuTTY key file");
|
||||
}
|
||||
|
||||
var a2p = new Argon2Parameters.Builder(param)
|
||||
.WithVersion(Argon2Parameters.Version13)
|
||||
.WithIterations(iterations)
|
||||
.WithMemoryAsKB(memory)
|
||||
.WithParallelism(parallelism)
|
||||
.WithSalt(salt).Build();
|
||||
|
||||
var generator = new Argon2BytesGenerator();
|
||||
|
||||
generator.Init(a2p);
|
||||
|
||||
var output = new byte[80];
|
||||
var bytes = generator.GenerateBytes(passPhrase.ToCharArray(), output);
|
||||
|
||||
if (bytes != output.Length)
|
||||
{
|
||||
throw new SshException("Failed to generate key via Argon2");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private static byte[] V2KDF(string passPhrase)
|
||||
{
|
||||
var cipherKey = new List<byte>();
|
||||
|
||||
var passPhraseBytes = Encoding.UTF8.GetBytes(passPhrase);
|
||||
for (var sequenceNumber = 0; sequenceNumber < 2; sequenceNumber++)
|
||||
{
|
||||
using (var sha1 = SHA1.Create())
|
||||
{
|
||||
var sequence = new byte[] { 0, 0, 0, (byte)sequenceNumber };
|
||||
_ = sha1.TransformBlock(sequence, 0, 4, outputBuffer: null, 0);
|
||||
_ = sha1.TransformFinalBlock(passPhraseBytes, 0, passPhraseBytes.Length);
|
||||
Debug.Assert(sha1.Hash != null, "Hash is null");
|
||||
cipherKey.AddRange(sha1.Hash);
|
||||
}
|
||||
}
|
||||
|
||||
return cipherKey.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,16 +25,16 @@ namespace Renci.SshNet
|
||||
/// The following private keys are supported:
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// <description>RSA in OpenSSL PEM, ssh.com and OpenSSH key format</description>
|
||||
/// <description>RSA in OpenSSL PEM, ssh.com, OpenSSH and PuTTY key format</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <description>DSA in OpenSSL PEM and ssh.com format</description>
|
||||
/// <description>DSA in OpenSSL PEM, ssh.com and PuTTY key format</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <description>ECDSA 256/384/521 in OpenSSL PEM and OpenSSH key format</description>
|
||||
/// <description>ECDSA 256/384/521 in OpenSSL PEM, OpenSSH and PuTTY key format</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <description>ED25519 in OpenSSL PEM and OpenSSH key format</description>
|
||||
/// <description>ED25519 in OpenSSL PEM, OpenSSH and PuTTY key format</description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
@@ -73,7 +73,7 @@ namespace Renci.SshNet
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The following encryption algorithms are supported for OpenSSH format:
|
||||
/// The following encryption algorithms are supported for OpenSSH key format:
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// <description>3des-cbc</description>
|
||||
@@ -107,23 +107,37 @@ namespace Renci.SshNet
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The following encryption algorithms are supported for PuTTY key format:
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// <description>aes256-cbc</description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// </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-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 PuTTYPrivateKeyPattern = @"^(?<keyName>PuTTY-User-Key-File)-(?<version>\d+): (?<algorithmName>[\w-]+)\r?\nEncryption: (?<encryptionType>[\w-]+)\r?\nComment: (?<comment>.*)\r?\nPublic-Lines: \d+\r?\n(?<publicKey>(([a-zA-Z0-9/+=]{1,64})\r?\n)+)(Key-Derivation: (?<argon2Type>\w+)\r?\nArgon2-Memory: (?<argon2Memory>\d+)\r?\nArgon2-Passes: (?<argon2Passes>\d+)\r?\nArgon2-Parallelism: (?<argon2Parallelism>\d+)\r?\nArgon2-Salt: (?<argon2Salt>[a-fA-F0-9]+)\r?\n)?Private-Lines: \d+\r?\n(?<data>(([a-zA-Z0-9/+=]{1,64})\r?\n)+)+Private-MAC: (?<mac>[a-fA-F0-9]+)";
|
||||
private const string CertificatePattern = @"(?<type>[-\w]+@openssh\.com)\s(?<data>[a-zA-Z0-9\/+=]*)(\s+(?<comment>.*))?";
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
private static readonly Regex PrivateKeyRegex = GetPrivateKeyRegex();
|
||||
private static readonly Regex PuTTYPrivateKeyRegex = GetPrivateKeyPuTTYRegex();
|
||||
private static readonly Regex CertificateRegex = GetCertificateRegex();
|
||||
|
||||
[GeneratedRegex(PrivateKeyPattern, RegexOptions.Multiline | RegexOptions.ExplicitCapture)]
|
||||
private static partial Regex GetPrivateKeyRegex();
|
||||
|
||||
[GeneratedRegex(PuTTYPrivateKeyPattern, RegexOptions.Multiline | RegexOptions.ExplicitCapture)]
|
||||
private static partial Regex GetPrivateKeyPuTTYRegex();
|
||||
|
||||
[GeneratedRegex(CertificatePattern, RegexOptions.ExplicitCapture)]
|
||||
private static partial Regex GetCertificateRegex();
|
||||
#else
|
||||
private static readonly Regex PrivateKeyRegex = new Regex(PrivateKeyPattern, RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.ExplicitCapture);
|
||||
private static readonly Regex PuTTYPrivateKeyRegex = new Regex(PuTTYPrivateKeyPattern, RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.ExplicitCapture);
|
||||
private static readonly Regex CertificateRegex = new Regex(CertificatePattern, RegexOptions.Compiled | RegexOptions.ExplicitCapture);
|
||||
#endif
|
||||
|
||||
@@ -287,7 +301,14 @@ namespace Renci.SshNet
|
||||
using (var sr = new StreamReader(privateKey))
|
||||
{
|
||||
var text = sr.ReadToEnd();
|
||||
privateKeyMatch = PrivateKeyRegex.Match(text);
|
||||
if (text.StartsWith("PuTTY-User-Key-File", StringComparison.Ordinal))
|
||||
{
|
||||
privateKeyMatch = PuTTYPrivateKeyRegex.Match(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
privateKeyMatch = PrivateKeyRegex.Match(text);
|
||||
}
|
||||
}
|
||||
|
||||
if (!privateKeyMatch.Success)
|
||||
@@ -321,6 +342,34 @@ namespace Renci.SshNet
|
||||
case "SSH2 ENCRYPTED PRIVATE KEY":
|
||||
parser = new SSHCOM(binaryData, passPhrase);
|
||||
break;
|
||||
case "PuTTY-User-Key-File":
|
||||
var version = privateKeyMatch.Result("${version}");
|
||||
var algorithmName = privateKeyMatch.Result("${algorithmName}");
|
||||
var encryptionType = privateKeyMatch.Result("${encryptionType}");
|
||||
var comment = privateKeyMatch.Result("${comment}");
|
||||
var publicKey = privateKeyMatch.Result("${publicKey}");
|
||||
var argon2Type = privateKeyMatch.Result("${argon2Type}");
|
||||
var argon2Memory = privateKeyMatch.Result("${argon2Memory}");
|
||||
var argon2Passes = privateKeyMatch.Result("${argon2Passes}");
|
||||
var argon2Parallelism = privateKeyMatch.Result("${argon2Parallelism}");
|
||||
var argon2Salt = privateKeyMatch.Result("${argon2Salt}");
|
||||
var mac = privateKeyMatch.Result("${mac}");
|
||||
|
||||
parser = new PuTTY(
|
||||
version,
|
||||
algorithmName,
|
||||
encryptionType,
|
||||
comment,
|
||||
Convert.FromBase64String(publicKey),
|
||||
argon2Type,
|
||||
argon2Salt,
|
||||
argon2Passes,
|
||||
argon2Memory,
|
||||
argon2Parallelism,
|
||||
binaryData,
|
||||
mac,
|
||||
passPhrase);
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Key '{0}' is not supported.", keyName));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
PuTTY-User-Key-File-2: ssh-ed25519
|
||||
Encryption: aes256-cbc
|
||||
Comment: Key.OPENSSH.ED25519
|
||||
Public-Lines: 2
|
||||
AAAAC3NzaC1lZDI1NTE5AAAAIA0JZnDQrxQZcNALfZYG7LPAW1MYEGvVW5nje7Ol
|
||||
MGMi
|
||||
Private-Lines: 1
|
||||
f3N2/AkwbgVeXdK155h+JCbWgBXyEk3qEyx+ChUqm4tOUQGiJ95/mTo4RbIjWn+2
|
||||
Private-MAC: 823817b8364ce7f52e278e252fd10e2f51ac8554
|
||||
@@ -0,0 +1,9 @@
|
||||
PuTTY-User-Key-File-2: ssh-ed25519
|
||||
Encryption: none
|
||||
Comment: Key.OPENSSH.ED25519
|
||||
Public-Lines: 2
|
||||
AAAAC3NzaC1lZDI1NTE5AAAAIA0JZnDQrxQZcNALfZYG7LPAW1MYEGvVW5nje7Ol
|
||||
MGMi
|
||||
Private-Lines: 1
|
||||
AAAAIADMEXUw9TGuz7JykmHbzPOj8XebpZwo76iuxJtHkvAp
|
||||
Private-MAC: 6a1329739932b5caaaf48d7fcd61392d498b8f5f
|
||||
@@ -0,0 +1,26 @@
|
||||
PuTTY-User-Key-File-2: ssh-rsa
|
||||
Encryption: aes256-cbc
|
||||
Comment: Key.OPENSSH.RSA
|
||||
Public-Lines: 6
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQDtbs6KCLsePWaxraXweKYs/NqBWYT8Kx4w
|
||||
oJHE8xO1ZO+hl0y3uF+S2FYDuHbRruhJJ4fa3sWp46lU0YVi9FXcFVawpkkxFx0m
|
||||
JMJkCMffytiT3Re9neYqso3/d9xCyHg6I+dapPodKqDXiiJXxQ+1TCcTrmyRZLG/
|
||||
G34QuVWkKobm8TY78Y0MpATsXNi3q9CKEwVIAEGqO9q7SaNfTTYpiIIyvq+CXxdi
|
||||
QMDifn4nJBJDHOed+sv3dmhqq6NE/ZtPlSFeBvOvwcXC6pAa9REQJlNMjwGK//q0
|
||||
4if3HaERo3q/EMu1dz30TZ3o1bpx2uLBoYUniOBVYMTmZTTTpd09
|
||||
Private-Lines: 14
|
||||
i38C+M7U/qOvzvOdtEC60v3cn354TMdDpAVk22UuNgQY7u6avW907mUuXjqU7Tjy
|
||||
G66uQ+6vOnaQR6xTYWn3uI1YMWGsRylLiNZ/O/dIpITv+9xuU5U8qB+nFIH3iD6U
|
||||
cBuumRKH2k2IxYVBO1nKTt3T3HejIIy3JlFifs9ylahgPD1m8jIfNARnYB09fOQr
|
||||
g+nV4YNRntOqpf+cUpc+TGnz35oa9O+6fzJY/2hdkOJ+fUBdlYmcKEZZ9PgYHAlM
|
||||
+aoQhL1vRoqZqzfHZYcMUBlmbRMgWiPfFB59nU0QbZ2uClbFxGGehBnCAsnd8Nni
|
||||
TafVYckp3kCNLmctrmorsRgM/IXWcdqmrGJO5sHEsutQqs9Dp3KM9xhRP23xoGnZ
|
||||
ssNw1qEAOP/k9JTCID/oeRE7RvAEMEdCs3l6FHKDvInR5xDuNrGehHdc3vGqklkC
|
||||
1kBER2vWRX+LANNXcfISRDNajC6XKsDo6aGJRPTMj/tbVJNbjP4Oi6fwcFizV9Z0
|
||||
yJiw1yV5AjUc8nG3cuTb1wNZ8DTPccq+W6ir8U+Vmdc67Mhxas6e2UKa5nXC+HqC
|
||||
jtM1oCPpxNyRoJSuxcWrwcs/yEhFfSOBU9PFsbJcX5i+ilZ2ZSipFc2fOcSx/6RC
|
||||
U36mELhmHPINoTDOc6qvL/fXRkqtoQGZm2UHoINVLkeMu3ERkxxDk9kFqRcSdFd+
|
||||
nSMJt9d3YRSsjhzvro65ugKiYBubugon24frB3nARI9zoe0BZB9H/RW3RPlMT8d9
|
||||
H+gElqyiYWZKKJs+Qht6NY0Hv1gp9erMIcTTts/w7ZRc5oS8pLCKOuB9wKYepJm7
|
||||
5I0x8qVotiHglDJ7PPbP+3UzrJvGp2nwPzj4qokCZKFhPYNYiCY16V0LaBRoE3mQ
|
||||
Private-MAC: 191817999553b67a7516223647e90e0b17db8918
|
||||
@@ -0,0 +1,26 @@
|
||||
PuTTY-User-Key-File-2: ssh-rsa
|
||||
Encryption: none
|
||||
Comment: Key.OPENSSH.RSA
|
||||
Public-Lines: 6
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQDtbs6KCLsePWaxraXweKYs/NqBWYT8Kx4w
|
||||
oJHE8xO1ZO+hl0y3uF+S2FYDuHbRruhJJ4fa3sWp46lU0YVi9FXcFVawpkkxFx0m
|
||||
JMJkCMffytiT3Re9neYqso3/d9xCyHg6I+dapPodKqDXiiJXxQ+1TCcTrmyRZLG/
|
||||
G34QuVWkKobm8TY78Y0MpATsXNi3q9CKEwVIAEGqO9q7SaNfTTYpiIIyvq+CXxdi
|
||||
QMDifn4nJBJDHOed+sv3dmhqq6NE/ZtPlSFeBvOvwcXC6pAa9REQJlNMjwGK//q0
|
||||
4if3HaERo3q/EMu1dz30TZ3o1bpx2uLBoYUniOBVYMTmZTTTpd09
|
||||
Private-Lines: 14
|
||||
AAABAQDpeCr6CmnM632eu2zPkCN/W0eVJ6yftdpi4JFWA9veY5lK4RbcFR1NrRKv
|
||||
Z+TWfNIGlSt+qc3eJ3IraDdsPWxsFEOBQpH4Bo1wI3dOnF/GDJV4mFAu8SQR2i/N
|
||||
BFR/CtdF/GYTeOREZ9Vu/HKWsbynfnFyZfJ16XjqvaLx2PyAhje0qnREy9nhmU1u
|
||||
FYc93k7HIdYv17eBs5LIjKNCBMpl7OHMStL9f8on9dirPIECo2pnZGDWQqIdGUdL
|
||||
ooQja3IXBh+H5Fvov3FyHVKo61CFNaKubFLbl2kYPaOBqVd7KLDw+a6pOJYKpSZQ
|
||||
zHox0Xe0WyKuvngrhAD2Sox5pEu1AAAAgQD+dPDqesFjwMJ9SXwWbqkLY3H5yXje
|
||||
DZGEAXcm59L1buVHcqkkC2vIZQM0ToQPqib65bGYDPYfAsi08ropvJYpGR6HMDtd
|
||||
8wU3VWkPHNpSb39rl0yFzWR7HkuyE5HwYjtYUgeM/EQ5Dq9+Zhn3W8iSBQMBWReF
|
||||
7PFp0BfrxxGnawAAAIEA7t9vXgsFRX/YNMzR32bt9adFrRK3LEb+e36vlKD7aL/J
|
||||
8VBe9aDlnuSkhpxrTCAiN9ZAbT4VG73zprqja4CQY4I2z0JotMUgBOS90LhCkTY5
|
||||
WhN/1mnSgcM4SQ7WrrmJNYn5K3QFaeu18kOabsrhoFWkATT268QPYNSG8ni+P/cA
|
||||
AACBALFEE9FIau5dLoE3eGPfPWx+nltH6Jdtf5uwec5CUHqTWnVD07NfPLr7+Ip1
|
||||
vJ9jt0Qmp11h2XwidQLEfzBBFtgukA7b6ilx2831kJQmElcQdewo1ESmvHzWiAJP
|
||||
fM4JjTcDudzQZXsq1IT4L5t8bewAoKc12OUcDSS/P2tFjpoM
|
||||
Private-MAC: 7f487d19cb5d03257c9b9a2e1c7192a5d2396af5
|
||||
@@ -0,0 +1,22 @@
|
||||
PuTTY-User-Key-File-3: ssh-dss
|
||||
Encryption: aes256-cbc
|
||||
Comment: imported-openssh-key
|
||||
Public-Lines: 10
|
||||
AAAAB3NzaC1kc3MAAACBALVl3fae2O4qwsAK95SUShX0KMUNP+yl/uT3lGH9T/Zp
|
||||
tnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u34qkmaNLy2LiAxiqd
|
||||
obZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyCr4zFZMrm0wtdyJQV
|
||||
AAAAFQCu+iNkqf/YOAYjYrHSCHFmWAfEYQAAAIAOVJ434UAR3Hn6lA5nWNfFOuUV
|
||||
H3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cvyXPrNQUYDHCF
|
||||
lS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5Ptyd7d3Kq5tE
|
||||
DM8KiVdIhwkXjUA3PQAAAIEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID
|
||||
7c/VQ4zdTZdG3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7W
|
||||
C29WOXW3t90ySTh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEu
|
||||
QxE=
|
||||
Key-Derivation: Argon2id
|
||||
Argon2-Memory: 8192
|
||||
Argon2-Passes: 8
|
||||
Argon2-Parallelism: 1
|
||||
Argon2-Salt: 310d916da49faba22ba8d2745777e5c5
|
||||
Private-Lines: 1
|
||||
xMm0Tg+o7Yq6lAs6L33y2fy3fiDPl6p71iKxm8OAgj4=
|
||||
Private-MAC: fc2aef48bf90b80b97d06c32c37491db614331c2551ab37865d8719ee6cb5f4f
|
||||
@@ -0,0 +1,17 @@
|
||||
PuTTY-User-Key-File-3: ssh-dss
|
||||
Encryption: none
|
||||
Comment: imported-openssh-key
|
||||
Public-Lines: 10
|
||||
AAAAB3NzaC1kc3MAAACBALVl3fae2O4qwsAK95SUShX0KMUNP+yl/uT3lGH9T/Zp
|
||||
tnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u34qkmaNLy2LiAxiqd
|
||||
obZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyCr4zFZMrm0wtdyJQV
|
||||
AAAAFQCu+iNkqf/YOAYjYrHSCHFmWAfEYQAAAIAOVJ434UAR3Hn6lA5nWNfFOuUV
|
||||
H3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cvyXPrNQUYDHCF
|
||||
lS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5Ptyd7d3Kq5tE
|
||||
DM8KiVdIhwkXjUA3PQAAAIEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID
|
||||
7c/VQ4zdTZdG3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7W
|
||||
C29WOXW3t90ySTh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEu
|
||||
QxE=
|
||||
Private-Lines: 1
|
||||
AAAAFBhGOzk+Aimeob964E8+HsQNlyde
|
||||
Private-MAC: 6c517ac5ede72c006b0115dd9d0830c8e699a1f4d72c708d41f68b6263d974ae
|
||||
@@ -0,0 +1,15 @@
|
||||
PuTTY-User-Key-File-3: ecdsa-sha2-nistp256
|
||||
Encryption: aes256-cbc
|
||||
Comment: imported-openssh-key
|
||||
Public-Lines: 3
|
||||
AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEA+TDv5/cqk
|
||||
g07M8M1aQKS8eUkBXnBOWXw5IMalXR0HnJtQQD6M2eHihjYSp+9oU+/Zi5afR11/
|
||||
qDRHLlU/Nx8=
|
||||
Key-Derivation: Argon2id
|
||||
Argon2-Memory: 8192
|
||||
Argon2-Passes: 8
|
||||
Argon2-Parallelism: 1
|
||||
Argon2-Salt: d496ed94c393d7c5df6ecd10440210ba
|
||||
Private-Lines: 1
|
||||
7gcJBC98J9hOJVkp0rUJrx8vlWIklCf+/7iQZT+1pCyhaWs+5jm/dIw8aCGMhM0a
|
||||
Private-MAC: 916979ee4696a5ee7674816259b2ac32c5258eaec94c554a9bc8d090dbc45b50
|
||||
@@ -0,0 +1,10 @@
|
||||
PuTTY-User-Key-File-3: ecdsa-sha2-nistp256
|
||||
Encryption: none
|
||||
Comment: imported-openssh-key
|
||||
Public-Lines: 3
|
||||
AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEA+TDv5/cqk
|
||||
g07M8M1aQKS8eUkBXnBOWXw5IMalXR0HnJtQQD6M2eHihjYSp+9oU+/Zi5afR11/
|
||||
qDRHLlU/Nx8=
|
||||
Private-Lines: 1
|
||||
AAAAIEdqaFKgJBIibVjyUh1v7Y35LwIQJrocdTaYFLwl7iB0
|
||||
Private-MAC: 3df7a232c8e3021a8f9809968b748c9db46ad3c668fa7d3f4d87ec8cbd838522
|
||||
@@ -0,0 +1,14 @@
|
||||
PuTTY-User-Key-File-3: ssh-ed25519
|
||||
Encryption: aes256-cbc
|
||||
Comment: Key.OPENSSH.ED25519
|
||||
Public-Lines: 2
|
||||
AAAAC3NzaC1lZDI1NTE5AAAAIA0JZnDQrxQZcNALfZYG7LPAW1MYEGvVW5nje7Ol
|
||||
MGMi
|
||||
Key-Derivation: Argon2d
|
||||
Argon2-Memory: 8192
|
||||
Argon2-Passes: 8
|
||||
Argon2-Parallelism: 1
|
||||
Argon2-Salt: a937df822b7304499c58f1795e90376a
|
||||
Private-Lines: 1
|
||||
EjcQkrXqEA3uJb/TfLt8MM+Gt1pM80S5fn5AlUWiUdhvrCG7pTTSVpaYYP8svW89
|
||||
Private-MAC: 673bd514209afa19d14506300f236a6049a915e7c7ec1a67d8df464e948f2654
|
||||
@@ -0,0 +1,14 @@
|
||||
PuTTY-User-Key-File-3: ssh-ed25519
|
||||
Encryption: aes256-cbc
|
||||
Comment: Key.OPENSSH.ED25519
|
||||
Public-Lines: 2
|
||||
AAAAC3NzaC1lZDI1NTE5AAAAIA0JZnDQrxQZcNALfZYG7LPAW1MYEGvVW5nje7Ol
|
||||
MGMi
|
||||
Key-Derivation: Argon2i
|
||||
Argon2-Memory: 8192
|
||||
Argon2-Passes: 8
|
||||
Argon2-Parallelism: 1
|
||||
Argon2-Salt: bf99b3e5c7d28d566c8c759d8a1a41d2
|
||||
Private-Lines: 1
|
||||
tbSkuSPLzdnnQuGYnC/L1fv9UnFzCBkwtk5aLDZYJFiD08h5EmpGCfJJHe0lJx9/
|
||||
Private-MAC: eee47ba955ba32fc85e3eb7a70d7e5f0359eacbf9f1abd5f02904fa98db513b7
|
||||
@@ -0,0 +1,14 @@
|
||||
PuTTY-User-Key-File-3: ssh-ed25519
|
||||
Encryption: aes256-cbc
|
||||
Comment: Key.OPENSSH.ED25519
|
||||
Public-Lines: 2
|
||||
AAAAC3NzaC1lZDI1NTE5AAAAIA0JZnDQrxQZcNALfZYG7LPAW1MYEGvVW5nje7Ol
|
||||
MGMi
|
||||
Key-Derivation: Argon2id
|
||||
Argon2-Memory: 8192
|
||||
Argon2-Passes: 21
|
||||
Argon2-Parallelism: 1
|
||||
Argon2-Salt: a8bb359d93fc58732e595da9c80b2e88
|
||||
Private-Lines: 1
|
||||
GHfMNhx9V3k/OKJxNb6QJ93Gwg9/slksETZ0Ns0edelE6hJfUc+XhXnQBLkUHZ6H
|
||||
Private-MAC: b07d3ddb544a7396637bc607bedd3d14ed28db929f2bdb5af4a94b410c3d9feb
|
||||
@@ -0,0 +1,9 @@
|
||||
PuTTY-User-Key-File-3: ssh-ed25519
|
||||
Encryption: none
|
||||
Comment: Key.OPENSSH.ED25519
|
||||
Public-Lines: 2
|
||||
AAAAC3NzaC1lZDI1NTE5AAAAIA0JZnDQrxQZcNALfZYG7LPAW1MYEGvVW5nje7Ol
|
||||
MGMi
|
||||
Private-Lines: 1
|
||||
AAAAIADMEXUw9TGuz7JykmHbzPOj8XebpZwo76iuxJtHkvAp
|
||||
Private-MAC: 273204de25dcb0fc8835d6d08b8045be34358bf64d009a7566d97851449fb9ab
|
||||
@@ -0,0 +1,31 @@
|
||||
PuTTY-User-Key-File-3: ssh-rsa
|
||||
Encryption: aes256-cbc
|
||||
Comment: Key.OPENSSH.RSA
|
||||
Public-Lines: 6
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQDtbs6KCLsePWaxraXweKYs/NqBWYT8Kx4w
|
||||
oJHE8xO1ZO+hl0y3uF+S2FYDuHbRruhJJ4fa3sWp46lU0YVi9FXcFVawpkkxFx0m
|
||||
JMJkCMffytiT3Re9neYqso3/d9xCyHg6I+dapPodKqDXiiJXxQ+1TCcTrmyRZLG/
|
||||
G34QuVWkKobm8TY78Y0MpATsXNi3q9CKEwVIAEGqO9q7SaNfTTYpiIIyvq+CXxdi
|
||||
QMDifn4nJBJDHOed+sv3dmhqq6NE/ZtPlSFeBvOvwcXC6pAa9REQJlNMjwGK//q0
|
||||
4if3HaERo3q/EMu1dz30TZ3o1bpx2uLBoYUniOBVYMTmZTTTpd09
|
||||
Key-Derivation: Argon2id
|
||||
Argon2-Memory: 8192
|
||||
Argon2-Passes: 13
|
||||
Argon2-Parallelism: 1
|
||||
Argon2-Salt: 433d83be99e63cd358ef5df037448734
|
||||
Private-Lines: 14
|
||||
q3I+FoI3y6nzGIi1lIXMIx4J/yOlIYIqoHQbpQxFiUwoDxYYm8zy4BYexEw/Ox6n
|
||||
LaKo4LKyvh36+5lrjqMluWsJ+PXrA+GBxSXsanzWG42RPRNbNF7RQCqTrxDRgTSv
|
||||
GztaXcS5URSIutOl5vePib/9lFC5FlYRp+dCM0CVRpkUezgbZdnOQ5901DhylceT
|
||||
fUXzpUcEHI4i1kp9awG+4ZpfJf057HuHFhmIvNECirt//LKBH9vrr7NQ7t1Sv8+r
|
||||
NdzkcUHpCyvPLqII/zaQurgFlrYTCIyqzKHphoVZGa2XrB6VHgt/pvh+a0fOw/lB
|
||||
c3t377cOr1PTht7AhYoeUPheFaYE9bPyZ5pV0Ai5IlOD94blp94BWU56e8GNx8Gp
|
||||
SB0zCqrW80Q39OXb3hweyIcVEbb8dfY6sJf3PhzEL1pehUzOFSRlwjGl7BsYZCe3
|
||||
uIUyNzczpbvk6OTReGRHM7DX5xz3t/esC7VXP7CpOnjhdr9dZ6dpqGz/vDciyxV9
|
||||
Jw/gaipPAQXUf6ls3atooxN1IpLnwtPE1FHAzofV9ixW4TqHmv1H9++94VJKFyA0
|
||||
nPUVBtKhM8gT/4ZxnPEDc/sl/EYb9DmuaUC8cTV2O10Wpnj3HhS1Qh43qAguyOu/
|
||||
qF7QGETSweXTYSgresMxeLRkX/tia6tz2Rfk1HnP8sRbMyIOyOvU4pNMDuTelGy9
|
||||
7OfsS54bcBIM1DTpMZ7HiKctZ6DvjL4VtgIJPlXmc+s4CD6cjbycOHo5iQfjsoS4
|
||||
Wh2dHGK3bYVJ+LTA/Z63nasR9CLW26oL76CI/+TXvheyFotzIjtn3iKpJUqS7Dc0
|
||||
vpZT3x5OWxmYlu1xZYbzMkLIedE8WaKYjeb3qE3Ox+rN0xIYXoNiCi6jxU+viuF4
|
||||
Private-MAC: 3bf7e6fe566fab36eba63d3129929b197f6b07e234ebcf22549d10b1d97e3e2f
|
||||
@@ -0,0 +1,26 @@
|
||||
PuTTY-User-Key-File-3: ssh-rsa
|
||||
Encryption: none
|
||||
Comment: Key.OPENSSH.RSA
|
||||
Public-Lines: 6
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQDtbs6KCLsePWaxraXweKYs/NqBWYT8Kx4w
|
||||
oJHE8xO1ZO+hl0y3uF+S2FYDuHbRruhJJ4fa3sWp46lU0YVi9FXcFVawpkkxFx0m
|
||||
JMJkCMffytiT3Re9neYqso3/d9xCyHg6I+dapPodKqDXiiJXxQ+1TCcTrmyRZLG/
|
||||
G34QuVWkKobm8TY78Y0MpATsXNi3q9CKEwVIAEGqO9q7SaNfTTYpiIIyvq+CXxdi
|
||||
QMDifn4nJBJDHOed+sv3dmhqq6NE/ZtPlSFeBvOvwcXC6pAa9REQJlNMjwGK//q0
|
||||
4if3HaERo3q/EMu1dz30TZ3o1bpx2uLBoYUniOBVYMTmZTTTpd09
|
||||
Private-Lines: 14
|
||||
AAABAQDpeCr6CmnM632eu2zPkCN/W0eVJ6yftdpi4JFWA9veY5lK4RbcFR1NrRKv
|
||||
Z+TWfNIGlSt+qc3eJ3IraDdsPWxsFEOBQpH4Bo1wI3dOnF/GDJV4mFAu8SQR2i/N
|
||||
BFR/CtdF/GYTeOREZ9Vu/HKWsbynfnFyZfJ16XjqvaLx2PyAhje0qnREy9nhmU1u
|
||||
FYc93k7HIdYv17eBs5LIjKNCBMpl7OHMStL9f8on9dirPIECo2pnZGDWQqIdGUdL
|
||||
ooQja3IXBh+H5Fvov3FyHVKo61CFNaKubFLbl2kYPaOBqVd7KLDw+a6pOJYKpSZQ
|
||||
zHox0Xe0WyKuvngrhAD2Sox5pEu1AAAAgQD+dPDqesFjwMJ9SXwWbqkLY3H5yXje
|
||||
DZGEAXcm59L1buVHcqkkC2vIZQM0ToQPqib65bGYDPYfAsi08ropvJYpGR6HMDtd
|
||||
8wU3VWkPHNpSb39rl0yFzWR7HkuyE5HwYjtYUgeM/EQ5Dq9+Zhn3W8iSBQMBWReF
|
||||
7PFp0BfrxxGnawAAAIEA7t9vXgsFRX/YNMzR32bt9adFrRK3LEb+e36vlKD7aL/J
|
||||
8VBe9aDlnuSkhpxrTCAiN9ZAbT4VG73zprqja4CQY4I2z0JotMUgBOS90LhCkTY5
|
||||
WhN/1mnSgcM4SQ7WrrmJNYn5K3QFaeu18kOabsrhoFWkATT268QPYNSG8ni+P/cA
|
||||
AACBALFEE9FIau5dLoE3eGPfPWx+nltH6Jdtf5uwec5CUHqTWnVD07NfPLr7+Ip1
|
||||
vJ9jt0Qmp11h2XwidQLEfzBBFtgukA7b6ilx2831kJQmElcQdewo1ESmvHzWiAJP
|
||||
fM4JjTcDudzQZXsq1IT4L5t8bewAoKc12OUcDSS/P2tFjpoM
|
||||
Private-MAC: ef76b1cf66a4a28d6fe08c70012c4bfa61771502e496d227dd77580650d20bfd
|
||||
@@ -344,6 +344,20 @@ namespace Renci.SshNet.Tests.Classes
|
||||
[DataRow("Key.OPENSSH.RSA.Encrypted.Aes.192.CTR.txt", "12345", typeof(RsaKey))]
|
||||
[DataRow("Key.OPENSSH.RSA.Encrypted.txt", "12345", typeof(RsaKey))]
|
||||
[DataRow("Key.OPENSSH.RSA.txt", null, typeof(RsaKey))]
|
||||
[DataRow("Key.PuTTY2.Ed25519.Encrypted.12345.ppk", "12345", typeof(ED25519Key))]
|
||||
[DataRow("Key.PuTTY2.Ed25519.ppk", null, typeof(ED25519Key))]
|
||||
[DataRow("Key.PuTTY2.RSA.Encrypted.12345.ppk", "12345", typeof(RsaKey))]
|
||||
[DataRow("Key.PuTTY2.RSA.ppk", null, typeof(RsaKey))]
|
||||
[DataRow("Key.PuTTY3.DSA.Encrypted.Argon2id.12345.ppk", "12345", typeof(DsaKey))]
|
||||
[DataRow("Key.PuTTY3.DSA.ppk", null, typeof(DsaKey))]
|
||||
[DataRow("Key.PuTTY3.ECDSA.Encrypted.Argon2id.12345.ppk", "12345", typeof(EcdsaKey))]
|
||||
[DataRow("Key.PuTTY3.ECDSA.ppk", null, typeof(EcdsaKey))]
|
||||
[DataRow("Key.PuTTY3.Ed25519.Encrypted.Argon2i.12345.ppk", "12345", typeof(ED25519Key))]
|
||||
[DataRow("Key.PuTTY3.Ed25519.Encrypted.Argon2d.12345.ppk", "12345", typeof(ED25519Key))]
|
||||
[DataRow("Key.PuTTY3.Ed25519.Encrypted.Argon2id.12345.ppk", "12345", typeof(ED25519Key))]
|
||||
[DataRow("Key.PuTTY3.Ed25519.ppk", null, typeof(ED25519Key))]
|
||||
[DataRow("Key.PuTTY3.RSA.Encrypted.Argon2id.12345.ppk", "12345", typeof(RsaKey))]
|
||||
[DataRow("Key.PuTTY3.RSA.ppk", null, typeof(RsaKey))]
|
||||
[DataRow("Key.RSA.Encrypted.Aes.128.CBC.12345.txt", "12345", typeof(RsaKey))]
|
||||
[DataRow("Key.RSA.Encrypted.Aes.192.CBC.12345.txt", "12345", typeof(RsaKey))]
|
||||
[DataRow("Key.RSA.Encrypted.Aes.256.CBC.12345.txt", "12345", typeof(RsaKey))]
|
||||
@@ -523,6 +537,86 @@ namespace Renci.SshNet.Tests.Classes
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void PuTTYv2_InvalidMac_ThrowsSshException()
|
||||
{
|
||||
string pk = """
|
||||
PuTTY-User-Key-File-2: ssh-rsa
|
||||
Encryption: none
|
||||
Comment: Key.OPENSSH.RSA
|
||||
Public-Lines: 6
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQDtbs6KCLsePWaxraXweKYs/NqBWYT8Kx4w
|
||||
oJHE8xO1ZO+hl0y3uF+S2FYDuHbRruhJJ4fa3sWp46lU0YVi9FXcFVawpkkxFx0m
|
||||
JMJkCMffytiT3Re9neYqso3/d9xCyHg6I+dapPodKqDXiiJXxQ+1TCcTrmyRZLG/
|
||||
G34QuVWkKobm8TY78Y0MpATsXNi3q9CKEwVIAEGqO9q7SaNfTTYpiIIyvq+CXxdi
|
||||
QMDifn4nJBJDHOed+sv3dmhqq6NE/ZtPlSFeBvOvwcXC6pAa9REQJlNMjwGK//q0
|
||||
4if3HaERo3q/EMu1dz30TZ3o1bpx2uLBoYUniOBVYMTmZTTTpd09
|
||||
Private-Lines: 14
|
||||
AAABAQDpeCr6CmnM632eu2zPkCN/W0eVJ6yftdpi4JFWA9veY5lK4RbcFR1NrRKv
|
||||
Z+TWfNIGlSt+qc3eJ3IraDdsPWxsFEOBQpH4Bo1wI3dOnF/GDJV4mFAu8SQR2i/N
|
||||
BFR/CtdF/GYTeOREZ9Vu/HKWsbynfnFyZfJ16XjqvaLx2PyAhje0qnREy9nhmU1u
|
||||
FYc93k7HIdYv17eBs5LIjKNCBMpl7OHMStL9f8on9dirPIECo2pnZGDWQqIdGUdL
|
||||
ooQja3IXBh+H5Fvov3FyHVKo61CFNaKubFLbl2kYPaOBqVd7KLDw+a6pOJYKpSZQ
|
||||
zHox0Xe0WyKuvngrhAD2Sox5pEu1AAAAgQD+dPDqesFjwMJ9SXwWbqkLY3H5yXje
|
||||
DZGEAXcm59L1buVHcqkkC2vIZQM0ToQPqib65bGYDPYfAsi08ropvJYpGR6HMDtd
|
||||
8wU3VWkPHNpSb39rl0yFzWR7HkuyE5HwYjtYUgeM/EQ5Dq9+Zhn3W8iSBQMBWReF
|
||||
7PFp0BfrxxGnawAAAIEA7t9vXgsFRX/YNMzR32bt9adFrRK3LEb+e36vlKD7aL/J
|
||||
8VBe9aDlnuSkhpxrTCAiN9ZAbT4VG73zprqja4CQY4I2z0JotMUgBOS90LhCkTY5
|
||||
WhN/1mnSgcM4SQ7WrrmJNYn5K3QFaeu18kOabsrhoFWkATT268QPYNSG8ni+P/cA
|
||||
AACBALFEE9FIau5dLoE3eGPfPWx+nltH6Jdtf5uwec5CUHqTWnVD07NfPLr7+Ip1
|
||||
vJ9jt0Qmp11h2XwidQLEfzBBFtgukA7b6ilx2831kJQmElcQdewo1ESmvHzWiAJP
|
||||
fM4JjTcDudzQZXsq1IT4L5t8bewAoKc12OUcDSS/P2tFjpoM
|
||||
Private-MAC: 7f487d19cb5d03257c9b9a2aaaaaaaaaaaaaaaaa
|
||||
""";
|
||||
|
||||
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(pk)))
|
||||
{
|
||||
var ex = Assert.ThrowsException<SshException>(() => new PrivateKeyFile(stream));
|
||||
|
||||
Assert.AreEqual("MAC verification failed for PuTTY key file", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void PuTTYv3_InvalidMac_ThrowsSshException()
|
||||
{
|
||||
string pk = """
|
||||
PuTTY-User-Key-File-3: ssh-rsa
|
||||
Encryption: none
|
||||
Comment: Key.OPENSSH.RSA
|
||||
Public-Lines: 6
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQDtbs6KCLsePWaxraXweKYs/NqBWYT8Kx4w
|
||||
oJHE8xO1ZO+hl0y3uF+S2FYDuHbRruhJJ4fa3sWp46lU0YVi9FXcFVawpkkxFx0m
|
||||
JMJkCMffytiT3Re9neYqso3/d9xCyHg6I+dapPodKqDXiiJXxQ+1TCcTrmyRZLG/
|
||||
G34QuVWkKobm8TY78Y0MpATsXNi3q9CKEwVIAEGqO9q7SaNfTTYpiIIyvq+CXxdi
|
||||
QMDifn4nJBJDHOed+sv3dmhqq6NE/ZtPlSFeBvOvwcXC6pAa9REQJlNMjwGK//q0
|
||||
4if3HaERo3q/EMu1dz30TZ3o1bpx2uLBoYUniOBVYMTmZTTTpd09
|
||||
Private-Lines: 14
|
||||
AAABAQDpeCr6CmnM632eu2zPkCN/W0eVJ6yftdpi4JFWA9veY5lK4RbcFR1NrRKv
|
||||
Z+TWfNIGlSt+qc3eJ3IraDdsPWxsFEOBQpH4Bo1wI3dOnF/GDJV4mFAu8SQR2i/N
|
||||
BFR/CtdF/GYTeOREZ9Vu/HKWsbynfnFyZfJ16XjqvaLx2PyAhje0qnREy9nhmU1u
|
||||
FYc93k7HIdYv17eBs5LIjKNCBMpl7OHMStL9f8on9dirPIECo2pnZGDWQqIdGUdL
|
||||
ooQja3IXBh+H5Fvov3FyHVKo61CFNaKubFLbl2kYPaOBqVd7KLDw+a6pOJYKpSZQ
|
||||
zHox0Xe0WyKuvngrhAD2Sox5pEu1AAAAgQD+dPDqesFjwMJ9SXwWbqkLY3H5yXje
|
||||
DZGEAXcm59L1buVHcqkkC2vIZQM0ToQPqib65bGYDPYfAsi08ropvJYpGR6HMDtd
|
||||
8wU3VWkPHNpSb39rl0yFzWR7HkuyE5HwYjtYUgeM/EQ5Dq9+Zhn3W8iSBQMBWReF
|
||||
7PFp0BfrxxGnawAAAIEA7t9vXgsFRX/YNMzR32bt9adFrRK3LEb+e36vlKD7aL/J
|
||||
8VBe9aDlnuSkhpxrTCAiN9ZAbT4VG73zprqja4CQY4I2z0JotMUgBOS90LhCkTY5
|
||||
WhN/1mnSgcM4SQ7WrrmJNYn5K3QFaeu18kOabsrhoFWkATT268QPYNSG8ni+P/cA
|
||||
AACBALFEE9FIau5dLoE3eGPfPWx+nltH6Jdtf5uwec5CUHqTWnVD07NfPLr7+Ip1
|
||||
vJ9jt0Qmp11h2XwidQLEfzBBFtgukA7b6ilx2831kJQmElcQdewo1ESmvHzWiAJP
|
||||
fM4JjTcDudzQZXsq1IT4L5t8bewAoKc12OUcDSS/P2tFjpoM
|
||||
Private-MAC: ef76b1cf66a4a28d6fe08c70012c4bfa61771502e496d227dddddddddddddddd
|
||||
""";
|
||||
|
||||
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(pk)))
|
||||
{
|
||||
var ex = Assert.ThrowsException<SshException>(() => new PrivateKeyFile(stream));
|
||||
|
||||
Assert.AreEqual("MAC verification failed for PuTTY key file", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveStreamToFile(Stream stream, string fileName)
|
||||
{
|
||||
var buffer = new byte[4000];
|
||||
|
||||
Reference in New Issue
Block a user