mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 09:15:47 +00:00
Agent auth and Keygen (#794)
* Allow to set PrivateKeyFile Key directly So you can add your own Key-Classes to SSH.NET * Add ED25519 ctor for just pub key part. * Make ECDSA Key Bits accessible You cant export imported CngKeys. To be able to export them to agent or Key-Files make the private bits also accessible. * Better NETFRAMEWORK vs NETSTANDARD handling * Add Comment Property to Key * Add IPrivateKeySource So Extension can add own PrivateKeyFiles, e.g. PuttyKeyFile.
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
using Renci.SshNet.Security;
|
||||
|
||||
namespace Renci.SshNet
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents private key source interface.
|
||||
/// </summary>
|
||||
public interface IPrivateKeySource
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the host key.
|
||||
/// </summary>
|
||||
HostAlgorithm HostKey { get; }
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@ namespace Renci.SshNet
|
||||
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.MinPort"/> and <see cref="IPEndPoint.MaxPort"/>.</exception>
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
|
||||
public NetConfClient(string host, int port, string username, params PrivateKeyFile[] keyFiles)
|
||||
public NetConfClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
|
||||
: this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true)
|
||||
{
|
||||
}
|
||||
@@ -116,7 +116,7 @@ namespace Renci.SshNet
|
||||
/// <param name="keyFiles">Authentication private key file(s) .</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
|
||||
public NetConfClient(string host, string username, params PrivateKeyFile[] keyFiles)
|
||||
public NetConfClient(string host, string username, params IPrivateKeySource[] keyFiles)
|
||||
: this(host, ConnectionInfo.DefaultPort, username, keyFiles)
|
||||
{
|
||||
}
|
||||
@@ -163,7 +163,7 @@ namespace Renci.SshNet
|
||||
/// <value>
|
||||
/// The NetConf server capabilities.
|
||||
/// </value>
|
||||
public XmlDocument ServerCapabilities
|
||||
public XmlDocument ServerCapabilities
|
||||
{
|
||||
get { return _netConfSession.ServerCapabilities; }
|
||||
}
|
||||
@@ -277,4 +277,4 @@ namespace Renci.SshNet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace Renci.SshNet
|
||||
/// <summary>
|
||||
/// Gets the key files used for authentication.
|
||||
/// </summary>
|
||||
public ICollection<PrivateKeyFile> KeyFiles { get; private set; }
|
||||
public ICollection<IPrivateKeySource> KeyFiles { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PrivateKeyAuthenticationMethod"/> class.
|
||||
@@ -36,13 +36,13 @@ namespace Renci.SshNet
|
||||
/// <param name="username">The username.</param>
|
||||
/// <param name="keyFiles">The key files.</param>
|
||||
/// <exception cref="ArgumentException"><paramref name="username"/> is whitespace or <c>null</c>.</exception>
|
||||
public PrivateKeyAuthenticationMethod(string username, params PrivateKeyFile[] keyFiles)
|
||||
public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[] keyFiles)
|
||||
: base(username)
|
||||
{
|
||||
if (keyFiles == null)
|
||||
throw new ArgumentNullException("keyFiles");
|
||||
|
||||
KeyFiles = new Collection<PrivateKeyFile>(keyFiles);
|
||||
KeyFiles = new Collection<IPrivateKeySource>(keyFiles);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -250,4 +250,4 @@ namespace Renci.SshNet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace Renci.SshNet
|
||||
/// <summary>
|
||||
/// Gets the key files used for authentication.
|
||||
/// </summary>
|
||||
public ICollection<PrivateKeyFile> KeyFiles { get; private set; }
|
||||
public ICollection<IPrivateKeySource> KeyFiles { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PrivateKeyConnectionInfo"/> class.
|
||||
@@ -40,7 +40,7 @@ namespace Renci.SshNet
|
||||
/// <param name="port">Connection port.</param>
|
||||
/// <param name="username">Connection username.</param>
|
||||
/// <param name="keyFiles">Connection key files.</param>
|
||||
public PrivateKeyConnectionInfo(string host, int port, string username, params PrivateKeyFile[] keyFiles)
|
||||
public PrivateKeyConnectionInfo(string host, int port, string username, params IPrivateKeySource[] keyFiles)
|
||||
: this(host, port, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, keyFiles)
|
||||
{
|
||||
}
|
||||
@@ -55,7 +55,7 @@ namespace Renci.SshNet
|
||||
/// <param name="proxyHost">The proxy host.</param>
|
||||
/// <param name="proxyPort">The proxy port.</param>
|
||||
/// <param name="keyFiles">The key files.</param>
|
||||
public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params PrivateKeyFile[] keyFiles)
|
||||
public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles)
|
||||
: this(host, port, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles)
|
||||
{
|
||||
}
|
||||
@@ -71,7 +71,7 @@ namespace Renci.SshNet
|
||||
/// <param name="proxyPort">The proxy port.</param>
|
||||
/// <param name="proxyUsername">The proxy username.</param>
|
||||
/// <param name="keyFiles">The key files.</param>
|
||||
public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params PrivateKeyFile[] keyFiles)
|
||||
public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles)
|
||||
: this(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles)
|
||||
{
|
||||
}
|
||||
@@ -85,7 +85,7 @@ namespace Renci.SshNet
|
||||
/// <param name="proxyHost">The proxy host.</param>
|
||||
/// <param name="proxyPort">The proxy port.</param>
|
||||
/// <param name="keyFiles">The key files.</param>
|
||||
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params PrivateKeyFile[] keyFiles)
|
||||
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles)
|
||||
: this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles)
|
||||
{
|
||||
}
|
||||
@@ -100,7 +100,7 @@ namespace Renci.SshNet
|
||||
/// <param name="proxyPort">The proxy port.</param>
|
||||
/// <param name="proxyUsername">The proxy username.</param>
|
||||
/// <param name="keyFiles">The key files.</param>
|
||||
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params PrivateKeyFile[] keyFiles)
|
||||
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles)
|
||||
: this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles)
|
||||
{
|
||||
}
|
||||
@@ -116,7 +116,7 @@ namespace Renci.SshNet
|
||||
/// <param name="proxyUsername">The proxy username.</param>
|
||||
/// <param name="proxyPassword">The proxy password.</param>
|
||||
/// <param name="keyFiles">The key files.</param>
|
||||
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params PrivateKeyFile[] keyFiles)
|
||||
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles)
|
||||
: this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, keyFiles)
|
||||
{
|
||||
}
|
||||
@@ -133,10 +133,10 @@ namespace Renci.SshNet
|
||||
/// <param name="proxyUsername">The proxy username.</param>
|
||||
/// <param name="proxyPassword">The proxy password.</param>
|
||||
/// <param name="keyFiles">The key files.</param>
|
||||
public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params PrivateKeyFile[] keyFiles)
|
||||
public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles)
|
||||
: base(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, new PrivateKeyAuthenticationMethod(username, keyFiles))
|
||||
{
|
||||
KeyFiles = new Collection<PrivateKeyFile>(keyFiles);
|
||||
KeyFiles = new Collection<IPrivateKeySource>(keyFiles);
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
@@ -194,4 +194,4 @@ namespace Renci.SshNet
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ namespace Renci.SshNet
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class PrivateKeyFile : IDisposable
|
||||
public class PrivateKeyFile : IPrivateKeySource, IDisposable
|
||||
{
|
||||
private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?<keyName>\w+( \w+)*) PRIVATE KEY *-+\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)+)-+ *END \k<keyName> PRIVATE KEY *-+",
|
||||
#if FEATURE_REGEX_COMPILE
|
||||
@@ -79,6 +79,15 @@ namespace Renci.SshNet
|
||||
/// </summary>
|
||||
public HostAlgorithm HostKey { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PrivateKeyFile"/> class.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
public PrivateKeyFile(Key key)
|
||||
{
|
||||
HostKey = new KeyHostAlgorithm(key.ToString(), key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PrivateKeyFile"/> class.
|
||||
/// </summary>
|
||||
@@ -262,7 +271,7 @@ namespace Renci.SshNet
|
||||
|
||||
if (decryptedLength > blobSize - 4)
|
||||
throw new SshException("Invalid passphrase.");
|
||||
|
||||
|
||||
if (keyType == "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}")
|
||||
{
|
||||
var exponent = reader.ReadBigIntWithBits();//e
|
||||
@@ -515,8 +524,7 @@ namespace Renci.SshNet
|
||||
throw new SshException("OpenSSH key type '" + keyType + "' is not supported.");
|
||||
}
|
||||
|
||||
//comment, we don't need this but we could log it, not sure if necessary
|
||||
var comment = privateKeyReader.ReadString(Encoding.UTF8);
|
||||
parsedKey.Comment = privateKeyReader.ReadString(Encoding.UTF8);
|
||||
|
||||
//The list of privatekey/comment pairs is padded with the bytes 1, 2, 3, ...
|
||||
//until the total length is a multiple of the cipher block size.
|
||||
@@ -642,4 +650,4 @@ namespace Renci.SshNet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,7 @@ namespace Renci.SshNet
|
||||
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.MinPort"/> and <see cref="IPEndPoint.MaxPort"/>.</exception>
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
|
||||
public ScpClient(string host, int port, string username, params PrivateKeyFile[] keyFiles)
|
||||
public ScpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
|
||||
: this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true)
|
||||
{
|
||||
}
|
||||
@@ -155,7 +155,7 @@ namespace Renci.SshNet
|
||||
/// <param name="keyFiles">Authentication private key file(s) .</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
|
||||
public ScpClient(string host, string username, params PrivateKeyFile[] keyFiles)
|
||||
public ScpClient(string host, string username, params IPrivateKeySource[] keyFiles)
|
||||
: this(host, ConnectionInfo.DefaultPort, username, keyFiles)
|
||||
{
|
||||
}
|
||||
@@ -466,4 +466,4 @@ namespace Renci.SshNet
|
||||
throw new SshException("Secure copy execution request was rejected by the server. Please consult the server logs.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,6 +99,15 @@ namespace Renci.SshNet.Security
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ED25519Key"/> class.
|
||||
/// </summary>
|
||||
/// <param name="pk">pk data.</param>
|
||||
public ED25519Key(byte[] pk)
|
||||
{
|
||||
publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ED25519Key"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -39,12 +39,12 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
// for 521 sig_size is 132
|
||||
var sig_size = _key.KeyLength == 521 ? 132 : _key.KeyLength / 4;
|
||||
var ssh_data = new SshDataSignature(signature, sig_size);
|
||||
#if NETSTANDARD2_0
|
||||
return _key.Ecdsa.VerifyData(input, ssh_data.Signature, _key.HashAlgorithm);
|
||||
#else
|
||||
#if NETFRAMEWORK
|
||||
var ecdsa = (ECDsaCng)_key.Ecdsa;
|
||||
ecdsa.HashAlgorithm = _key.HashAlgorithm;
|
||||
return ecdsa.VerifyData(input, ssh_data.Signature);
|
||||
#else
|
||||
return _key.Ecdsa.VerifyData(input, ssh_data.Signature, _key.HashAlgorithm);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -57,12 +57,12 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// </returns>
|
||||
public override byte[] Sign(byte[] input)
|
||||
{
|
||||
#if NETSTANDARD2_0
|
||||
var signed = _key.Ecdsa.SignData(input, _key.HashAlgorithm);
|
||||
#else
|
||||
#if NETFRAMEWORK
|
||||
var ecdsa = (ECDsaCng)_key.Ecdsa;
|
||||
ecdsa.HashAlgorithm = _key.HashAlgorithm;
|
||||
var signed = ecdsa.SignData(input);
|
||||
#else
|
||||
var signed = _key.Ecdsa.SignData(input, _key.HashAlgorithm);
|
||||
#endif
|
||||
var ssh_data = new SshDataSignature(signed.Length);
|
||||
ssh_data.Signature = signed;
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Renci.SshNet.Security
|
||||
internal const string ECDSA_P384_OID_VALUE = "1.3.132.0.34"; // Also called nistP384 or secP384r1
|
||||
internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521or secP521r1
|
||||
|
||||
#if !NETSTANDARD2_0
|
||||
#if NETFRAMEWORK
|
||||
internal enum KeyBlobMagicNumber : int
|
||||
{
|
||||
BCRYPT_ECDSA_PUBLIC_P256_MAGIC = 0x31534345,
|
||||
@@ -57,27 +57,7 @@ namespace Renci.SshNet.Security
|
||||
return string.Format("ecdsa-sha2-nistp{0}", KeyLength);
|
||||
}
|
||||
|
||||
#if NETSTANDARD2_0
|
||||
/// <summary>
|
||||
/// Gets the HashAlgorithm to use
|
||||
/// </summary>
|
||||
public HashAlgorithmName HashAlgorithm
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (KeyLength)
|
||||
{
|
||||
case 256:
|
||||
return HashAlgorithmName.SHA256;
|
||||
case 384:
|
||||
return HashAlgorithmName.SHA384;
|
||||
case 521:
|
||||
return HashAlgorithmName.SHA512;
|
||||
}
|
||||
return HashAlgorithmName.SHA256;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#if NETFRAMEWORK
|
||||
/// <summary>
|
||||
/// Gets the HashAlgorithm to use
|
||||
/// </summary>
|
||||
@@ -98,6 +78,26 @@ namespace Renci.SshNet.Security
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
/// Gets the HashAlgorithm to use
|
||||
/// </summary>
|
||||
public HashAlgorithmName HashAlgorithm
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (KeyLength)
|
||||
{
|
||||
case 256:
|
||||
return HashAlgorithmName.SHA256;
|
||||
case 384:
|
||||
return HashAlgorithmName.SHA384;
|
||||
case 521:
|
||||
return HashAlgorithmName.SHA512;
|
||||
}
|
||||
return HashAlgorithmName.SHA256;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -144,28 +144,7 @@ namespace Renci.SshNet.Security
|
||||
byte[] curve;
|
||||
byte[] qx;
|
||||
byte[] qy;
|
||||
#if NETSTANDARD2_0
|
||||
var parameter = Ecdsa.ExportParameters(false);
|
||||
qx = parameter.Q.X;
|
||||
qy = parameter.Q.Y;
|
||||
switch (parameter.Curve.Oid.FriendlyName)
|
||||
{
|
||||
case "ECDSA_P256":
|
||||
case "nistP256":
|
||||
curve = Encoding.ASCII.GetBytes("nistp256");
|
||||
break;
|
||||
case "ECDSA_P384":
|
||||
case "nistP384":
|
||||
curve = Encoding.ASCII.GetBytes("nistp384");
|
||||
break;
|
||||
case "ECDSA_P521":
|
||||
case "nistP521":
|
||||
curve = Encoding.ASCII.GetBytes("nistp521");
|
||||
break;
|
||||
default:
|
||||
throw new SshException("Unexpected Curve Name: " + parameter.Curve.Oid.FriendlyName);
|
||||
}
|
||||
#else
|
||||
#if NETFRAMEWORK
|
||||
var blob = key.Export(CngKeyBlobFormat.EccPublicBlob);
|
||||
|
||||
KeyBlobMagicNumber magic;
|
||||
@@ -191,6 +170,27 @@ namespace Renci.SshNet.Security
|
||||
default:
|
||||
throw new SshException("Unexpected Curve Magic: " + magic);
|
||||
}
|
||||
#else
|
||||
var parameter = Ecdsa.ExportParameters(false);
|
||||
qx = parameter.Q.X;
|
||||
qy = parameter.Q.Y;
|
||||
switch (parameter.Curve.Oid.FriendlyName)
|
||||
{
|
||||
case "ECDSA_P256":
|
||||
case "nistP256":
|
||||
curve = Encoding.ASCII.GetBytes("nistp256");
|
||||
break;
|
||||
case "ECDSA_P384":
|
||||
case "nistP384":
|
||||
curve = Encoding.ASCII.GetBytes("nistp384");
|
||||
break;
|
||||
case "ECDSA_P521":
|
||||
case "nistP521":
|
||||
curve = Encoding.ASCII.GetBytes("nistp521");
|
||||
break;
|
||||
default:
|
||||
throw new SshException("Unexpected Curve Name: " + parameter.Curve.Oid.FriendlyName);
|
||||
}
|
||||
#endif
|
||||
// Make ECPoint from x and y
|
||||
// Prepend 04 (uncompressed format) + qx-bytes + qy-bytes
|
||||
@@ -212,6 +212,11 @@ namespace Renci.SshNet.Security
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the PrivateKey Bytes
|
||||
/// </summary>
|
||||
public byte[] PrivateKey { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets ECDsa Object
|
||||
/// </summary>
|
||||
@@ -278,29 +283,7 @@ namespace Renci.SshNet.Security
|
||||
|
||||
private void Import(string curve_oid, byte[] publickey, byte[] privatekey)
|
||||
{
|
||||
#if NETSTANDARD2_0
|
||||
var curve = ECCurve.CreateFromValue(curve_oid);
|
||||
var parameter = new ECParameters
|
||||
{
|
||||
Curve = curve
|
||||
};
|
||||
|
||||
// ECPoint as BigInteger(2)
|
||||
var cord_size = (publickey.Length - 1) / 2;
|
||||
var qx = new byte[cord_size];
|
||||
Buffer.BlockCopy(publickey, 1, qx, 0, qx.Length);
|
||||
|
||||
var qy = new byte[cord_size];
|
||||
Buffer.BlockCopy(publickey, cord_size + 1, qy, 0, qy.Length);
|
||||
|
||||
parameter.Q.X = qx;
|
||||
parameter.Q.Y = qy;
|
||||
|
||||
if (privatekey != null)
|
||||
parameter.D = privatekey.TrimLeadingZeros().Pad(cord_size);
|
||||
|
||||
Ecdsa = ECDsa.Create(parameter);
|
||||
#else
|
||||
#if NETFRAMEWORK
|
||||
var curve_magic = KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC;
|
||||
switch (GetCurveName(curve_oid))
|
||||
{
|
||||
@@ -335,7 +318,10 @@ namespace Renci.SshNet.Security
|
||||
Buffer.BlockCopy(publickey, cord_size + 1, qy, 0, qy.Length);
|
||||
|
||||
if (privatekey != null)
|
||||
{
|
||||
privatekey = privatekey.Pad(cord_size);
|
||||
PrivateKey = privatekey;
|
||||
}
|
||||
|
||||
int headerSize = Marshal.SizeOf(typeof(BCRYPT_ECCKEY_BLOB));
|
||||
int blobSize = headerSize + qx.Length + qy.Length;
|
||||
@@ -355,6 +341,31 @@ namespace Renci.SshNet.Security
|
||||
key = CngKey.Import(blob, privatekey == null ? CngKeyBlobFormat.EccPublicBlob : CngKeyBlobFormat.EccPrivateBlob);
|
||||
|
||||
Ecdsa = new ECDsaCng(key);
|
||||
#else
|
||||
var curve = ECCurve.CreateFromValue(curve_oid);
|
||||
var parameter = new ECParameters
|
||||
{
|
||||
Curve = curve
|
||||
};
|
||||
|
||||
// ECPoint as BigInteger(2)
|
||||
var cord_size = (publickey.Length - 1) / 2;
|
||||
var qx = new byte[cord_size];
|
||||
Buffer.BlockCopy(publickey, 1, qx, 0, qx.Length);
|
||||
|
||||
var qy = new byte[cord_size];
|
||||
Buffer.BlockCopy(publickey, cord_size + 1, qy, 0, qy.Length);
|
||||
|
||||
parameter.Q.X = qx;
|
||||
parameter.Q.Y = qy;
|
||||
|
||||
if (privatekey != null)
|
||||
{
|
||||
parameter.D = privatekey.TrimLeadingZeros().Pad(cord_size);
|
||||
PrivateKey = parameter.D;
|
||||
}
|
||||
|
||||
Ecdsa = ECDsa.Create(parameter);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@ namespace Renci.SshNet.Security
|
||||
/// </value>
|
||||
public abstract int KeyLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Key Comment
|
||||
/// </summary>
|
||||
public string Comment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Key"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -208,7 +208,7 @@ namespace Renci.SshNet
|
||||
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid. <para>-or-</para> <paramref name="username"/> is nu<b>null</b>ll or contains only whitespace characters.</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.MinPort"/> and <see cref="IPEndPoint.MaxPort"/>.</exception>
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
|
||||
public SftpClient(string host, int port, string username, params PrivateKeyFile[] keyFiles)
|
||||
public SftpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
|
||||
: this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true)
|
||||
{
|
||||
}
|
||||
@@ -221,7 +221,7 @@ namespace Renci.SshNet
|
||||
/// <param name="keyFiles">Authentication private key file(s) .</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <b>null</b>.</exception>
|
||||
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid. <para>-or-</para> <paramref name="username"/> is <b>null</b> or contains only whitespace characters.</exception>
|
||||
public SftpClient(string host, string username, params PrivateKeyFile[] keyFiles)
|
||||
public SftpClient(string host, string username, params IPrivateKeySource[] keyFiles)
|
||||
: this(host, ConnectionInfo.DefaultPort, username, keyFiles)
|
||||
{
|
||||
}
|
||||
@@ -712,13 +712,13 @@ namespace Renci.SshNet
|
||||
// using SSH_FXP_REALPATH is not an alternative as the SFTP specification has not always
|
||||
// been clear on how the server should respond when the specified path is not present on
|
||||
// the server:
|
||||
//
|
||||
//
|
||||
// SSH 1 to 4:
|
||||
// No mention of how the server should respond if the path is not present on the server.
|
||||
//
|
||||
// SSH 5:
|
||||
// The server SHOULD fail the request if the path is not present on the server.
|
||||
//
|
||||
//
|
||||
// SSH 6:
|
||||
// Draft 06: The server SHOULD fail the request if the path is not present on the server.
|
||||
// Draft 07 to 13: The server MUST NOT fail the request if the path does not exist.
|
||||
@@ -747,7 +747,7 @@ namespace Renci.SshNet
|
||||
/// <exception cref="ArgumentException"><paramref name="path" /> is <b>null</b> or contains only whitespace characters.</exception>
|
||||
/// <exception cref="SshConnectionException">Client is not connected.</exception>
|
||||
/// <exception cref="SftpPermissionDeniedException">Permission to perform the operation was denied by the remote host. <para>-or-</para> A SSH command was denied by the server.</exception>
|
||||
/// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</exception>///
|
||||
/// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</exception>///
|
||||
/// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the remote host.</exception>
|
||||
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
|
||||
/// <remarks>
|
||||
@@ -2400,4 +2400,4 @@ namespace Renci.SshNet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ namespace Renci.SshNet
|
||||
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.MinPort"/> and <see cref="IPEndPoint.MaxPort"/>.</exception>
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
|
||||
public SshClient(string host, int port, string username, params PrivateKeyFile[] keyFiles)
|
||||
public SshClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
|
||||
: this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true)
|
||||
{
|
||||
}
|
||||
@@ -121,7 +121,7 @@ namespace Renci.SshNet
|
||||
/// </example>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
|
||||
public SshClient(string host, string username, params PrivateKeyFile[] keyFiles)
|
||||
public SshClient(string host, string username, params IPrivateKeySource[] keyFiles)
|
||||
: this(host, ConnectionInfo.DefaultPort, username, keyFiles)
|
||||
{
|
||||
}
|
||||
@@ -507,4 +507,4 @@ namespace Renci.SshNet
|
||||
throw new SshConnectionException("Client not connected.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user