diff --git a/src/Renci.SshNet/Common/SshData.cs b/src/Renci.SshNet/Common/SshData.cs
index 54b77c6d9..578edb8c5 100644
--- a/src/Renci.SshNet/Common/SshData.cs
+++ b/src/Renci.SshNet/Common/SshData.cs
@@ -231,7 +231,7 @@ protected ulong ReadUInt64()
///
/// The that was read.
///
- protected string ReadString(Encoding encoding)
+ protected string ReadString(Encoding encoding = null)
{
return _stream.ReadString(encoding);
}
diff --git a/src/Renci.SshNet/Common/SshDataStream.cs b/src/Renci.SshNet/Common/SshDataStream.cs
index 9b64bed3a..9e2a28051 100644
--- a/src/Renci.SshNet/Common/SshDataStream.cs
+++ b/src/Renci.SshNet/Common/SshDataStream.cs
@@ -249,12 +249,14 @@ public ulong ReadUInt64()
///
/// Reads the next data type from the SSH data stream.
///
- /// The character encoding to use.
+ /// The character encoding to use. Defaults to .
///
/// The read from the SSH data stream.
///
- public string ReadString(Encoding encoding)
+ public string ReadString(Encoding encoding = null)
{
+ encoding ??= Encoding.UTF8;
+
var length = ReadUInt32();
if (length > int.MaxValue)
diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs
index 4a24e78a9..7eccb8dff 100644
--- a/src/Renci.SshNet/ConnectionInfo.cs
+++ b/src/Renci.SshNet/ConnectionInfo.cs
@@ -396,16 +396,16 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy
HostKeyAlgorithms = new Dictionary>
{
- { "ssh-ed25519", data => new KeyHostAlgorithm("ssh-ed25519", new ED25519Key(), data) },
- { "ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(), data) },
- { "ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(), data) },
- { "ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(), data) },
+ { "ssh-ed25519", data => new KeyHostAlgorithm("ssh-ed25519", new ED25519Key(new SshKeyData(data))) },
+ { "ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(new SshKeyData(data))) },
+ { "ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(new SshKeyData(data))) },
+ { "ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(new SshKeyData(data))) },
#pragma warning disable SA1107 // Code should not contain multiple statements on one line
- { "rsa-sha2-512", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-512", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); } },
- { "rsa-sha2-256", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-256", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); } },
+ { "rsa-sha2-512", data => { var key = new RsaKey(new SshKeyData(data)); return new KeyHostAlgorithm("rsa-sha2-512", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); } },
+ { "rsa-sha2-256", data => { var key = new RsaKey(new SshKeyData(data)); return new KeyHostAlgorithm("rsa-sha2-256", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); } },
#pragma warning restore SA1107 // Code should not contain multiple statements on one line
- { "ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data) },
- { "ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data) },
+ { "ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(new SshKeyData(data))) },
+ { "ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(new SshKeyData(data))) },
};
CompressionAlgorithms = new Dictionary
diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs
index 1373630cd..a93ffb195 100644
--- a/src/Renci.SshNet/PrivateKeyFile.cs
+++ b/src/Renci.SshNet/PrivateKeyFile.cs
@@ -573,12 +573,14 @@ private static Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase)
switch (keyType)
{
case "ssh-ed25519":
- // public key
- publicKey = privateKeyReader.ReadBignum2();
+ // https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-11#section-3.2.3
- // private key
+ // ENC(A)
+ _ = privateKeyReader.ReadBignum2();
+
+ // k || ENC(A)
unencryptedPrivateKey = privateKeyReader.ReadBignum2();
- parsedKey = new ED25519Key(publicKey.Reverse(), unencryptedPrivateKey);
+ parsedKey = new ED25519Key(unencryptedPrivateKey);
break;
case "ecdsa-sha2-nistp256":
case "ecdsa-sha2-nistp384":
diff --git a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs
index 65c6fceec..b0f915cc0 100644
--- a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs
+++ b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs
@@ -1,4 +1,5 @@
using System;
+
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography;
@@ -15,57 +16,27 @@ public class DsaKey : Key, IDisposable
///
/// Gets the P.
///
- public BigInteger P
- {
- get
- {
- return _privateKey[0];
- }
- }
+ public BigInteger P { get; }
///
/// Gets the Q.
///
- public BigInteger Q
- {
- get
- {
- return _privateKey[1];
- }
- }
+ public BigInteger Q { get; }
///
/// Gets the G.
///
- public BigInteger G
- {
- get
- {
- return _privateKey[2];
- }
- }
+ public BigInteger G { get; }
///
/// Gets public key Y.
///
- public BigInteger Y
- {
- get
- {
- return _privateKey[3];
- }
- }
+ public BigInteger Y { get; }
///
/// Gets private key X.
///
- public BigInteger X
- {
- get
- {
- return _privateKey[4];
- }
- }
+ public BigInteger X { get; }
///
/// Gets the length of the key.
@@ -94,10 +65,16 @@ protected internal override DigitalSignature DigitalSignature
}
///
- /// Gets or sets the public.
+ /// Gets the DSA public key.
///
///
- /// The public.
+ /// An array whose values are:
+ ///
+ /// - 0
+ /// - 1
+ /// - 2
+ /// - 3
+ ///
///
public override BigInteger[] Public
{
@@ -105,35 +82,53 @@ public override BigInteger[] Public
{
return new[] { P, Q, G, Y };
}
- set
- {
- if (value.Length != 4)
- {
- throw new InvalidOperationException("Invalid public key.");
- }
-
- _privateKey = value;
- }
}
///
/// Initializes a new instance of the class.
///
- public DsaKey()
+ /// The encoded public key data.
+ public DsaKey(SshKeyData publicKeyData)
{
- _privateKey = new BigInteger[5];
+ if (publicKeyData is null)
+ {
+ throw new ArgumentNullException(nameof(publicKeyData));
+ }
+
+ if (publicKeyData.Name != "ssh-dss" || publicKeyData.Keys.Length != 4)
+ {
+ throw new ArgumentException($"Invalid DSA public key data. ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData));
+ }
+
+ P = publicKeyData.Keys[0];
+ Q = publicKeyData.Keys[1];
+ G = publicKeyData.Keys[2];
+ Y = publicKeyData.Keys[3];
}
///
/// Initializes a new instance of the class.
///
- /// DER encoded private key data.
- public DsaKey(byte[] data)
- : base(data)
+ /// DER encoded private key data.
+ public DsaKey(byte[] privateKeyData)
{
- if (_privateKey.Length != 5)
+ if (privateKeyData is null)
+ {
+ throw new ArgumentNullException(nameof(privateKeyData));
+ }
+
+ var der = new DerData(privateKeyData);
+ _ = der.ReadBigInteger(); // skip version
+
+ P = der.ReadBigInteger();
+ Q = der.ReadBigInteger();
+ G = der.ReadBigInteger();
+ Y = der.ReadBigInteger();
+ X = der.ReadBigInteger();
+
+ if (!der.IsEndOfData)
{
- throw new InvalidOperationException("Invalid private key.");
+ throw new InvalidOperationException("Invalid private key (expected EOF).");
}
}
@@ -147,7 +142,11 @@ public DsaKey(byte[] data)
/// The x.
public DsaKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y, BigInteger x)
{
- _privateKey = new BigInteger[5] { p, q, g, y, x };
+ P = p;
+ Q = q;
+ G = g;
+ Y = y;
+ X = x;
}
///
diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs
index bb0037945..5ee2332c0 100644
--- a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs
+++ b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs
@@ -11,13 +11,7 @@ namespace Renci.SshNet.Security
///
public class ED25519Key : Key, IDisposable
{
-#pragma warning disable IDE1006 // Naming Styles
-#pragma warning disable SX1309 // Field names should begin with underscore
- private readonly byte[] privateKey = new byte[Ed25519.ExpandedPrivateKeySizeInBytes];
-#pragma warning restore SX1309 // Field names should begin with underscore
-#pragma warning restore IDE1006 // Naming Styles
private ED25519DigitalSignature _digitalSignature;
- private byte[] _publicKey = new byte[Ed25519.PublicKeySizeInBytes];
private bool _isDisposed;
///
@@ -32,20 +26,16 @@ public override string ToString()
}
///
- /// Gets or sets the public.
+ /// Gets the Ed25519 public key.
///
///
- /// The public.
+ /// An array with encoded at index 0.
///
public override BigInteger[] Public
{
get
{
- return new BigInteger[] { _publicKey.ToBigInteger2() };
- }
- set
- {
- _publicKey = value[0].ToByteArray().Reverse().TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes);
+ return new BigInteger[] { PublicKey.ToBigInteger2() };
}
}
@@ -78,52 +68,46 @@ protected internal override DigitalSignature DigitalSignature
///
/// Gets the PublicKey Bytes.
///
- public byte[] PublicKey
- {
- get
- {
- return _publicKey;
- }
- }
+ public byte[] PublicKey { get; }
///
/// Gets the PrivateKey Bytes.
///
- public byte[] PrivateKey
- {
- get
- {
- return privateKey;
- }
- }
+ public byte[] PrivateKey { get; }
///
/// Initializes a new instance of the class.
///
- public ED25519Key()
+ /// The encoded public key data.
+ public ED25519Key(SshKeyData publicKeyData)
{
- }
+ if (publicKeyData is null)
+ {
+ throw new ArgumentNullException(nameof(publicKeyData));
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// pk data.
- public ED25519Key(byte[] pk)
- {
- _publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes);
+ if (publicKeyData.Name != "ssh-ed25519" || publicKeyData.Keys.Length != 1)
+ {
+ throw new ArgumentException($"Invalid Ed25519 public key data ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData));
+ }
+
+ PublicKey = publicKeyData.Keys[0].ToByteArray().Reverse().TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes);
+ PrivateKey = new byte[Ed25519.ExpandedPrivateKeySizeInBytes];
}
///
/// Initializes a new instance of the class.
///
- /// pk data.
- /// sk data.
- public ED25519Key(byte[] pk, byte[] sk)
+ ///
+ /// The private key data k || ENC(A) as described in RFC 8032.
+ ///
+ public ED25519Key(byte[] privateKeyData)
{
- _publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes);
var seed = new byte[Ed25519.PrivateKeySeedSizeInBytes];
- Buffer.BlockCopy(sk, 0, seed, 0, seed.Length);
- Ed25519.KeyPairFromSeed(out _publicKey, out privateKey, seed);
+ Buffer.BlockCopy(privateKeyData, 0, seed, 0, seed.Length);
+ Ed25519.KeyPairFromSeed(out var publicKey, out var privateKey, seed);
+ PublicKey = publicKey;
+ PrivateKey = privateKey;
}
///
diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs
index 455bb1363..7898a92c9 100644
--- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs
+++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs
@@ -140,10 +140,11 @@ protected internal override DigitalSignature DigitalSignature
}
///
- /// Gets or sets the public.
+ /// Gets the ECDSA public key.
///
///
- /// The public.
+ /// An array with the ASCII-encoded curve identifier (e.g. "nistp256")
+ /// at index 0, and the public curve point Q at index 1.
///
public override BigInteger[] Public
{
@@ -213,14 +214,6 @@ public override BigInteger[] Public
// returns Curve-Name and x/y as ECPoint
return new[] { new BigInteger(curve.Reverse()), new BigInteger(q.Reverse()) };
}
- set
- {
- var curve_s = Encoding.ASCII.GetString(value[0].ToByteArray().Reverse());
- var curve_oid = GetCurveOid(curve_s);
-
- var publickey = value[1].ToByteArray().Reverse();
- Import(curve_oid, publickey, privatekey: null);
- }
}
///
@@ -236,8 +229,24 @@ public override BigInteger[] Public
///
/// Initializes a new instance of the class.
///
- public EcdsaKey()
+ /// The encoded public key data.
+ public EcdsaKey(SshKeyData publicKeyData)
{
+ if (publicKeyData is null)
+ {
+ throw new ArgumentNullException(nameof(publicKeyData));
+ }
+
+ if (!publicKeyData.Name.StartsWith("ecdsa-sha2-", StringComparison.Ordinal) || publicKeyData.Keys.Length != 2)
+ {
+ throw new ArgumentException($"Invalid ECDSA public key data. ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData));
+ }
+
+ var curve_s = Encoding.ASCII.GetString(publicKeyData.Keys[0].ToByteArray().Reverse());
+ var curve_oid = GetCurveOid(curve_s);
+
+ var publickey = publicKeyData.Keys[1].ToByteArray().Reverse();
+ Import(curve_oid, publickey, privatekey: null);
}
///
diff --git a/src/Renci.SshNet/Security/Cryptography/Key.cs b/src/Renci.SshNet/Security/Cryptography/Key.cs
index 81580a1ab..54ecac7e4 100644
--- a/src/Renci.SshNet/Security/Cryptography/Key.cs
+++ b/src/Renci.SshNet/Security/Cryptography/Key.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-
-using Renci.SshNet.Common;
+using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography;
namespace Renci.SshNet.Security
@@ -11,25 +8,18 @@ namespace Renci.SshNet.Security
///
public abstract class Key
{
- ///
- /// Specifies array of big integers that represent private key.
- ///
-#pragma warning disable SA1401 // Fields should be private
- protected BigInteger[] _privateKey;
-#pragma warning restore SA1401 // Fields should be private
-
///
/// Gets the default digital signature implementation for this key.
///
protected internal abstract DigitalSignature DigitalSignature { get; }
///
- /// Gets or sets the public key.
+ /// Gets the public key.
///
///
/// The public.
///
- public abstract BigInteger[] Public { get; set; }
+ public abstract BigInteger[] Public { get; }
///
/// Gets the length of the key.
@@ -44,36 +34,6 @@ public abstract class Key
///
public string Comment { get; set; }
- ///
- /// Initializes a new instance of the class.
- ///
- /// DER encoded private key data.
- protected Key(byte[] data)
- {
- if (data is null)
- {
- throw new ArgumentNullException(nameof(data));
- }
-
- var der = new DerData(data);
- _ = der.ReadBigInteger(); // skip version
-
- var keys = new List();
- while (!der.IsEndOfData)
- {
- keys.Add(der.ReadBigInteger());
- }
-
- _privateKey = keys.ToArray();
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- protected Key()
- {
- }
-
///
/// Signs the specified data with the key.
///
diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs
index 19c8bedc7..f342db6c1 100644
--- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs
+++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs
@@ -1,4 +1,5 @@
using System;
+
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography;
@@ -29,13 +30,7 @@ public override string ToString()
///
/// The modulus.
///
- public BigInteger Modulus
- {
- get
- {
- return _privateKey[0];
- }
- }
+ public BigInteger Modulus { get; }
///
/// Gets the exponent.
@@ -43,13 +38,7 @@ public BigInteger Modulus
///
/// The exponent.
///
- public BigInteger Exponent
- {
- get
- {
- return _privateKey[1];
- }
- }
+ public BigInteger Exponent { get; }
///
/// Gets the D.
@@ -57,18 +46,7 @@ public BigInteger Exponent
///
/// The D.
///
- public BigInteger D
- {
- get
- {
- if (_privateKey.Length > 2)
- {
- return _privateKey[2];
- }
-
- return BigInteger.Zero;
- }
- }
+ public BigInteger D { get; }
///
/// Gets the P.
@@ -76,18 +54,7 @@ public BigInteger D
///
/// The P.
///
- public BigInteger P
- {
- get
- {
- if (_privateKey.Length > 3)
- {
- return _privateKey[3];
- }
-
- return BigInteger.Zero;
- }
- }
+ public BigInteger P { get; }
///
/// Gets the Q.
@@ -95,18 +62,7 @@ public BigInteger P
///
/// The Q.
///
- public BigInteger Q
- {
- get
- {
- if (_privateKey.Length > 4)
- {
- return _privateKey[4];
- }
-
- return BigInteger.Zero;
- }
- }
+ public BigInteger Q { get; }
///
/// Gets the DP.
@@ -114,18 +70,7 @@ public BigInteger Q
///
/// The DP.
///
- public BigInteger DP
- {
- get
- {
- if (_privateKey.Length > 5)
- {
- return _privateKey[5];
- }
-
- return BigInteger.Zero;
- }
- }
+ public BigInteger DP { get; }
///
/// Gets the DQ.
@@ -133,18 +78,7 @@ public BigInteger DP
///
/// The DQ.
///
- public BigInteger DQ
- {
- get
- {
- if (_privateKey.Length > 6)
- {
- return _privateKey[6];
- }
-
- return BigInteger.Zero;
- }
- }
+ public BigInteger DQ { get; }
///
/// Gets the inverse Q.
@@ -152,18 +86,7 @@ public BigInteger DQ
///
/// The inverse Q.
///
- public BigInteger InverseQ
- {
- get
- {
- if (_privateKey.Length > 7)
- {
- return _privateKey[7];
- }
-
- return BigInteger.Zero;
- }
- }
+ public BigInteger InverseQ { get; }
///
/// Gets the length of the key.
@@ -196,10 +119,11 @@ protected internal override DigitalSignature DigitalSignature
}
///
- /// Gets or sets the public.
+ /// Gets the RSA public key.
///
///
- /// The public.
+ /// An array with at index 0, and
+ /// at index 1.
///
public override BigInteger[] Public
{
@@ -207,34 +131,54 @@ public override BigInteger[] Public
{
return new[] { Exponent, Modulus };
}
- set
- {
- if (value.Length != 2)
- {
- throw new InvalidOperationException("Invalid private key.");
- }
-
- _privateKey = new[] { value[1], value[0] };
- }
}
///
/// Initializes a new instance of the class.
///
- public RsaKey()
+ /// The encoded public key data.
+ public RsaKey(SshKeyData publicKeyData)
{
+ if (publicKeyData is null)
+ {
+ throw new ArgumentNullException(nameof(publicKeyData));
+ }
+
+ if (publicKeyData.Name != "ssh-rsa" || publicKeyData.Keys.Length != 2)
+ {
+ throw new ArgumentException($"Invalid RSA public key data. ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData));
+ }
+
+ Exponent = publicKeyData.Keys[0];
+ Modulus = publicKeyData.Keys[1];
}
///
/// Initializes a new instance of the class.
///
- /// DER encoded private key data.
- public RsaKey(byte[] data)
- : base(data)
+ /// DER encoded private key data.
+ public RsaKey(byte[] privateKeyData)
{
- if (_privateKey.Length != 8)
+ if (privateKeyData is null)
{
- throw new InvalidOperationException("Invalid private key.");
+ throw new ArgumentNullException(nameof(privateKeyData));
+ }
+
+ var der = new DerData(privateKeyData);
+ _ = der.ReadBigInteger(); // skip version
+
+ Modulus = der.ReadBigInteger();
+ Exponent = der.ReadBigInteger();
+ D = der.ReadBigInteger();
+ P = der.ReadBigInteger();
+ Q = der.ReadBigInteger();
+ DP = der.ReadBigInteger();
+ DQ = der.ReadBigInteger();
+ InverseQ = der.ReadBigInteger();
+
+ if (!der.IsEndOfData)
+ {
+ throw new InvalidOperationException("Invalid private key (expected EOF).");
}
}
@@ -249,22 +193,19 @@ public RsaKey(byte[] data)
/// The inverse Q.
public RsaKey(BigInteger modulus, BigInteger exponent, BigInteger d, BigInteger p, BigInteger q, BigInteger inverseQ)
{
- _privateKey = new BigInteger[8]
- {
- modulus,
- exponent,
- d,
- p,
- q,
- PrimeExponent(d, p),
- PrimeExponent(d, q),
- inverseQ
- };
+ Modulus = modulus;
+ Exponent = exponent;
+ D = d;
+ P = p;
+ Q = q;
+ DP = PrimeExponent(d, p);
+ DQ = PrimeExponent(d, q);
+ InverseQ = inverseQ;
}
private static BigInteger PrimeExponent(BigInteger privateExponent, BigInteger prime)
{
- var pe = prime - new BigInteger(1);
+ var pe = prime - BigInteger.One;
return privateExponent % pe;
}
diff --git a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs
index 0a0232a58..5611c9713 100644
--- a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs
+++ b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs
@@ -1,8 +1,6 @@
-using System.Collections.Generic;
-using System.Text;
+using System.Text;
using Renci.SshNet.Common;
-using Renci.SshNet.Security.Chaos.NaCl;
using Renci.SshNet.Security.Cryptography;
namespace Renci.SshNet.Security
@@ -15,17 +13,11 @@ public class KeyHostAlgorithm : HostAlgorithm
///
/// Gets the key used in this host key algorithm.
///
- ///
- /// The key used in this host key algorithm.
- ///
public Key Key { get; private set; }
///
/// Gets the signature implementation used in this host key algorithm.
///
- ///
- /// The signature implementation used in this host key algorithm.
- ///
public DigitalSignature DigitalSignature { get; private set; }
///
@@ -47,11 +39,7 @@ public override byte[] Data
/// Initializes a new instance of the class.
///
/// The signature format identifier.
- ///
- ///
- /// This constructor is typically passed a private key in order to create an encoded signature for later
- /// verification by the host.
- ///
+ /// The key used in this host key algorithm.
public KeyHostAlgorithm(string name, Key key)
: base(name)
{
@@ -63,13 +51,9 @@ public KeyHostAlgorithm(string name, Key key)
/// Initializes a new instance of the class.
///
/// The signature format identifier.
- ///
- ///
+ /// The key used in this host key algorithm.
+ /// The signature implementation used in this host key algorithm.
///
- ///
- /// This constructor is typically passed a private key in order to create an encoded signature for later
- /// verification by the host.
- ///
/// The key used by is intended to be equal to .
/// This is not verified.
///
@@ -80,59 +64,6 @@ public KeyHostAlgorithm(string name, Key key, DigitalSignature digitalSignature)
DigitalSignature = digitalSignature;
}
- ///
- /// Initializes a new instance of the class
- /// with the given encoded public key data. The data will be decoded into .
- ///
- /// The signature format identifier.
- ///
- /// Host key encoded data.
- ///
- /// This constructor is typically passed a new or reusable instance in
- /// order to verify an encoded signature sent by the host, created by the private counterpart
- /// to the host's public key, which is encoded in .
- ///
- public KeyHostAlgorithm(string name, Key key, byte[] data)
- : base(name)
- {
- Key = key;
-
- var sshKey = new SshKeyData();
- sshKey.Load(data);
- Key.Public = sshKey.Keys;
-
- DigitalSignature = key.DigitalSignature;
- }
-
- ///
- /// Initializes a new instance of the class
- /// with the given encoded public key data. The data will be decoded into .
- ///
- /// The signature format identifier.
- ///
- /// Host key encoded data.
- ///
- ///
- ///
- /// This constructor is typically passed a new or reusable instance in
- /// order to verify an encoded signature sent by the host, created by the private counterpart
- /// to the host's public key, which is encoded in .
- ///
- /// The key used by is intended to be equal to .
- /// This is not verified.
- ///
- public KeyHostAlgorithm(string name, Key key, byte[] data, DigitalSignature digitalSignature)
- : base(name)
- {
- Key = key;
-
- var sshKey = new SshKeyData();
- sshKey.Load(data);
- Key.Public = sshKey.Keys;
-
- DigitalSignature = digitalSignature;
- }
-
///
/// Signs and encodes the specified data.
///
@@ -162,98 +93,6 @@ public override bool VerifySignature(byte[] data, byte[] signature)
return DigitalSignature.Verify(data, signatureData.Signature);
}
- private sealed class SshKeyData : SshData
- {
- private byte[] _name;
- private List _keys;
-
- public BigInteger[] Keys
- {
- get
- {
- var keys = new BigInteger[_keys.Count];
-
- for (var i = 0; i < _keys.Count; i++)
- {
- var key = _keys[i];
- keys[i] = key.ToBigInteger2();
- }
-
- return keys;
- }
- private set
- {
- _keys = new List(value.Length);
-
- foreach (var key in value)
- {
- var keyData = key.ToByteArray().Reverse();
- if (Name == "ssh-ed25519")
- {
- keyData = keyData.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes);
- }
-
- _keys.Add(keyData);
- }
- }
- }
-
- private string Name
- {
- get { return Utf8.GetString(_name, 0, _name.Length); }
- set { _name = Utf8.GetBytes(value); }
- }
-
- protected override int BufferCapacity
- {
- get
- {
- var capacity = base.BufferCapacity;
- capacity += 4; // Name length
- capacity += _name.Length; // Name
-
- foreach (var key in _keys)
- {
- capacity += 4; // Key length
- capacity += key.Length; // Key
- }
-
- return capacity;
- }
- }
-
- public SshKeyData()
- {
- }
-
- public SshKeyData(string name, params BigInteger[] keys)
- {
- Name = name;
- Keys = keys;
- }
-
- protected override void LoadData()
- {
- _name = ReadBinary();
- _keys = new List();
-
- while (!IsEndOfData)
- {
- _keys.Add(ReadBinary());
- }
- }
-
- protected override void SaveData()
- {
- WriteBinaryString(_name);
-
- foreach (var key in _keys)
- {
- WriteBinaryString(key);
- }
- }
- }
-
internal sealed class SignatureKeyData : SshData
{
///
@@ -306,7 +145,7 @@ public SignatureKeyData(string name, byte[] signature)
///
protected override void LoadData()
{
- AlgorithmName = Encoding.UTF8.GetString(ReadBinary());
+ AlgorithmName = ReadString();
Signature = ReadBinary();
}
@@ -315,7 +154,7 @@ protected override void LoadData()
///
protected override void SaveData()
{
- WriteBinaryString(Encoding.UTF8.GetBytes(AlgorithmName));
+ Write(AlgorithmName);
WriteBinaryString(Signature);
}
}
diff --git a/src/Renci.SshNet/Security/SshKeyData.cs b/src/Renci.SshNet/Security/SshKeyData.cs
new file mode 100644
index 000000000..6a3af835a
--- /dev/null
+++ b/src/Renci.SshNet/Security/SshKeyData.cs
@@ -0,0 +1,98 @@
+using System.Collections.Generic;
+using System.Text;
+
+using Renci.SshNet.Common;
+using Renci.SshNet.Security.Chaos.NaCl;
+
+namespace Renci.SshNet.Security
+{
+ ///
+ /// Facilitates (de)serializing encoded public key data in the format
+ /// specified by RFC 4253 section 6.6.
+ ///
+ ///
+ /// See https://datatracker.ietf.org/doc/html/rfc4253#section-6.6.
+ ///
+ public sealed class SshKeyData : SshData
+ {
+ ///
+ /// Gets the public key format identifier.
+ ///
+ public string Name { get; private set; }
+
+ ///
+ /// Gets the public key constituents.
+ ///
+ public BigInteger[] Keys { get; private set; }
+
+ ///
+ protected override int BufferCapacity
+ {
+ get
+ {
+ var capacity = base.BufferCapacity;
+ capacity += 4; // Name length
+ capacity += Encoding.UTF8.GetByteCount(Name); // Name
+
+ foreach (var key in Keys)
+ {
+ capacity += 4; // Key length
+ capacity += key.BitLength / 8; // Key
+ }
+
+ return capacity;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The encoded public key data.
+ public SshKeyData(byte[] data)
+ {
+ Load(data);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The public key format identifer.
+ /// The public key constituents.
+ public SshKeyData(string name, BigInteger[] keys)
+ {
+ Name = name;
+ Keys = keys;
+ }
+
+ ///
+ protected override void LoadData()
+ {
+ Name = ReadString();
+ var keys = new List();
+
+ while (!IsEndOfData)
+ {
+ keys.Add(ReadBinary().ToBigInteger2());
+ }
+
+ Keys = keys.ToArray();
+ }
+
+ ///
+ protected override void SaveData()
+ {
+ Write(Name);
+
+ foreach (var key in Keys)
+ {
+ var keyData = key.ToByteArray().Reverse();
+ if (Name == "ssh-ed25519")
+ {
+ keyData = keyData.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes);
+ }
+
+ WriteBinaryString(keyData);
+ }
+ }
+ }
+}
diff --git a/test/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs
index 54900d046..c3b070884 100644
--- a/test/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs
+++ b/test/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs
@@ -1,6 +1,5 @@
using BenchmarkDotNet.Attributes;
-using Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers;
using Renci.SshNet.Common;
using Renci.SshNet.Security;
@@ -18,7 +17,7 @@ public HostKeyEventArgsBenchmarks()
}
private static KeyHostAlgorithm GetKeyHostAlgorithm()
{
- using (var s = typeof(RsaCipherBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.RSA.txt"))
+ using (var s = typeof(HostKeyEventArgsBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.RSA.txt"))
{
var privateKey = new PrivateKeyFile(s);
return (KeyHostAlgorithm) privateKey.HostKeyAlgorithms.First();
diff --git a/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs
deleted file mode 100644
index 13c08edb1..000000000
--- a/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-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)new PrivateKeyFile(s).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);
- // }
- }
-}
diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs
index d7558c2c4..acfc16382 100644
--- a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs
+++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs
@@ -57,10 +57,7 @@ public void Sha1_SignAndVerify()
//Assert.IsTrue(digitalSignature.Verify(data, signedBytes));
// 'Workaround': use a key with no private key information
- var digitalSignaturePublic = new RsaDigitalSignature(new RsaKey()
- {
- Public = rsaKey.Public
- });
+ var digitalSignaturePublic = new RsaDigitalSignature(new RsaKey(rsaKey.Modulus, rsaKey.Exponent, default, default, default, default));
Assert.IsTrue(digitalSignaturePublic.Verify(data, signedBytes));
}
@@ -101,10 +98,9 @@ public void Sha256_SignAndVerify()
//Assert.IsTrue(digitalSignature.Verify(data, signedBytes));
// 'Workaround': use a key with no private key information
- var digitalSignaturePublic = new RsaDigitalSignature(new RsaKey()
- {
- Public = rsaKey.Public
- }, HashAlgorithmName.SHA256);
+ var digitalSignaturePublic = new RsaDigitalSignature(
+ new RsaKey(rsaKey.Modulus, rsaKey.Exponent, default, default, default, default),
+ HashAlgorithmName.SHA256);
Assert.IsTrue(digitalSignaturePublic.Verify(data, signedBytes));
}
@@ -144,10 +140,9 @@ public void Sha512_SignAndVerify()
//Assert.IsTrue(digitalSignature.Verify(data, signedBytes));
// 'Workaround': use a key with no private key information
- var digitalSignaturePublic = new RsaDigitalSignature(new RsaKey()
- {
- Public = rsaKey.Public
- }, HashAlgorithmName.SHA512);
+ var digitalSignaturePublic = new RsaDigitalSignature(
+ new RsaKey(rsaKey.Modulus, rsaKey.Exponent, default, default, default, default),
+ HashAlgorithmName.SHA512);
Assert.IsTrue(digitalSignaturePublic.Verify(data, signedBytes));
}
@@ -155,7 +150,7 @@ public void Sha512_SignAndVerify()
public void Constructor_InvalidHashAlgorithm_ThrowsArgumentException()
{
ArgumentException exception = Assert.ThrowsException(
- () => new RsaDigitalSignature(new RsaKey(), new HashAlgorithmName("invalid")));
+ () => new RsaDigitalSignature(GetRsaKey(), new HashAlgorithmName("invalid")));
Assert.AreEqual("hashAlgorithmName", exception.ParamName);
}
diff --git a/test/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs
index d024c05a6..d41199817 100644
--- a/test/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs
+++ b/test/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs
@@ -86,7 +86,7 @@ public void SshRsa_SignAndVerify()
CollectionAssert.AreEqual(expectedEncodedSignatureBytes, keyAlgorithm.Sign(data));
- keyAlgorithm = new KeyHostAlgorithm("ssh-rsa", new RsaKey(), GetRsaPublicKeyBytes());
+ keyAlgorithm = new KeyHostAlgorithm("ssh-rsa", new RsaKey(new SshKeyData(GetRsaPublicKeyBytes())));
Assert.IsTrue(keyAlgorithm.VerifySignature(data, expectedEncodedSignatureBytes));
}
@@ -126,8 +126,8 @@ public void RsaSha256_SignAndVerify()
CollectionAssert.AreEqual(expectedEncodedSignatureBytes, keyAlgorithm.Sign(data));
- key = new RsaKey();
- keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-256", key, GetRsaPublicKeyBytes(), new RsaDigitalSignature(key, HashAlgorithmName.SHA256));
+ key = new RsaKey(new SshKeyData(GetRsaPublicKeyBytes()));
+ keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-256", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA256));
Assert.IsTrue(keyAlgorithm.VerifySignature(data, expectedEncodedSignatureBytes));
}
@@ -167,8 +167,8 @@ public void RsaSha512_SignAndVerify()
CollectionAssert.AreEqual(expectedEncodedSignatureBytes, keyAlgorithm.Sign(data));
- key = new RsaKey();
- keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-512", key, GetRsaPublicKeyBytes(), new RsaDigitalSignature(key, HashAlgorithmName.SHA512));
+ key = new RsaKey(new SshKeyData(GetRsaPublicKeyBytes()));
+ keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-512", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA512));
Assert.IsTrue(keyAlgorithm.VerifySignature(data, expectedEncodedSignatureBytes));
}