mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 09:15:47 +00:00
Make keys immutable (#1264)
This makes it easier to reason about Key instances in e.g. DigitalSignature implementations, because we know that the Key is initialised with its data and will not change. Co-authored-by: Wojciech Nagórski <wojtpl2@gmail.com>
This commit is contained in:
@@ -231,7 +231,7 @@ namespace Renci.SshNet.Common
|
||||
/// <returns>
|
||||
/// The <see cref="string"/> that was read.
|
||||
/// </returns>
|
||||
protected string ReadString(Encoding encoding)
|
||||
protected string ReadString(Encoding encoding = null)
|
||||
{
|
||||
return _stream.ReadString(encoding);
|
||||
}
|
||||
|
||||
@@ -249,12 +249,14 @@ namespace Renci.SshNet.Common
|
||||
/// <summary>
|
||||
/// Reads the next <see cref="string"/> data type from the SSH data stream.
|
||||
/// </summary>
|
||||
/// <param name="encoding">The character encoding to use.</param>
|
||||
/// <param name="encoding">The character encoding to use. Defaults to <see cref="Encoding.UTF8"/>.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="string"/> read from the SSH data stream.
|
||||
/// </returns>
|
||||
public string ReadString(Encoding encoding)
|
||||
public string ReadString(Encoding encoding = null)
|
||||
{
|
||||
encoding ??= Encoding.UTF8;
|
||||
|
||||
var length = ReadUInt32();
|
||||
|
||||
if (length > int.MaxValue)
|
||||
|
||||
@@ -396,16 +396,16 @@ namespace Renci.SshNet
|
||||
|
||||
HostKeyAlgorithms = new Dictionary<string, Func<byte[], KeyHostAlgorithm>>
|
||||
{
|
||||
{ "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<string, Type>
|
||||
|
||||
@@ -573,12 +573,14 @@ namespace Renci.SshNet
|
||||
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":
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
|
||||
@@ -15,57 +16,27 @@ namespace Renci.SshNet.Security
|
||||
/// <summary>
|
||||
/// Gets the P.
|
||||
/// </summary>
|
||||
public BigInteger P
|
||||
{
|
||||
get
|
||||
{
|
||||
return _privateKey[0];
|
||||
}
|
||||
}
|
||||
public BigInteger P { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Q.
|
||||
/// </summary>
|
||||
public BigInteger Q
|
||||
{
|
||||
get
|
||||
{
|
||||
return _privateKey[1];
|
||||
}
|
||||
}
|
||||
public BigInteger Q { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the G.
|
||||
/// </summary>
|
||||
public BigInteger G
|
||||
{
|
||||
get
|
||||
{
|
||||
return _privateKey[2];
|
||||
}
|
||||
}
|
||||
public BigInteger G { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets public key Y.
|
||||
/// </summary>
|
||||
public BigInteger Y
|
||||
{
|
||||
get
|
||||
{
|
||||
return _privateKey[3];
|
||||
}
|
||||
}
|
||||
public BigInteger Y { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets private key X.
|
||||
/// </summary>
|
||||
public BigInteger X
|
||||
{
|
||||
get
|
||||
{
|
||||
return _privateKey[4];
|
||||
}
|
||||
}
|
||||
public BigInteger X { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the key.
|
||||
@@ -94,10 +65,16 @@ namespace Renci.SshNet.Security
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the public.
|
||||
/// Gets the DSA public key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The public.
|
||||
/// An array whose values are:
|
||||
/// <list>
|
||||
/// <item><term>0</term><description><see cref="P"/></description></item>
|
||||
/// <item><term>1</term><description><see cref="Q"/></description></item>
|
||||
/// <item><term>2</term><description><see cref="G"/></description></item>
|
||||
/// <item><term>3</term><description><see cref="Y"/></description></item>
|
||||
/// </list>
|
||||
/// </value>
|
||||
public override BigInteger[] Public
|
||||
{
|
||||
@@ -105,35 +82,53 @@ namespace Renci.SshNet.Security
|
||||
{
|
||||
return new[] { P, Q, G, Y };
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value.Length != 4)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid public key.");
|
||||
}
|
||||
}
|
||||
|
||||
_privateKey = value;
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DsaKey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="publicKeyData">The encoded public key data.</param>
|
||||
public DsaKey(SshKeyData publicKeyData)
|
||||
{
|
||||
if (publicKeyData is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(publicKeyData));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DsaKey"/> class.
|
||||
/// </summary>
|
||||
public DsaKey()
|
||||
{
|
||||
_privateKey = new BigInteger[5];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DsaKey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">DER encoded private key data.</param>
|
||||
public DsaKey(byte[] data)
|
||||
: base(data)
|
||||
{
|
||||
if (_privateKey.Length != 5)
|
||||
if (publicKeyData.Name != "ssh-dss" || publicKeyData.Keys.Length != 4)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid private key.");
|
||||
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];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DsaKey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="privateKeyData">DER encoded private key data.</param>
|
||||
public DsaKey(byte[] privateKeyData)
|
||||
{
|
||||
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 (expected EOF).");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +142,11 @@ namespace Renci.SshNet.Security
|
||||
/// <param name="x">The x.</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -11,13 +11,7 @@ namespace Renci.SshNet.Security
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
@@ -32,20 +26,16 @@ namespace Renci.SshNet.Security
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the public.
|
||||
/// Gets the Ed25519 public key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The public.
|
||||
/// An array with <see cref="PublicKey"/> encoded at index 0.
|
||||
/// </value>
|
||||
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 @@ namespace Renci.SshNet.Security
|
||||
/// <summary>
|
||||
/// Gets the PublicKey Bytes.
|
||||
/// </summary>
|
||||
public byte[] PublicKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return _publicKey;
|
||||
}
|
||||
}
|
||||
public byte[] PublicKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the PrivateKey Bytes.
|
||||
/// </summary>
|
||||
public byte[] PrivateKey
|
||||
public byte[] PrivateKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ED25519Key"/> class.
|
||||
/// </summary>
|
||||
/// <param name="publicKeyData">The encoded public key data.</param>
|
||||
public ED25519Key(SshKeyData publicKeyData)
|
||||
{
|
||||
get
|
||||
if (publicKeyData is null)
|
||||
{
|
||||
return privateKey;
|
||||
throw new ArgumentNullException(nameof(publicKeyData));
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ED25519Key"/> class.
|
||||
/// </summary>
|
||||
public ED25519Key()
|
||||
/// <param name="privateKeyData">
|
||||
/// The private key data <c>k || ENC(A)</c> as described in RFC 8032.
|
||||
/// </param>
|
||||
public ED25519Key(byte[] privateKeyData)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <param name="pk">pk data.</param>
|
||||
/// <param name="sk">sk data.</param>
|
||||
public ED25519Key(byte[] pk, byte[] sk)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -140,10 +140,11 @@ namespace Renci.SshNet.Security
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the public.
|
||||
/// Gets the ECDSA public key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// 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.
|
||||
/// </value>
|
||||
public override BigInteger[] Public
|
||||
{
|
||||
@@ -213,14 +214,6 @@ namespace Renci.SshNet.Security
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -236,8 +229,24 @@ namespace Renci.SshNet.Security
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EcdsaKey"/> class.
|
||||
/// </summary>
|
||||
public EcdsaKey()
|
||||
/// <param name="publicKeyData">The encoded public key data.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
public abstract class Key
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies array of big integers that represent private key.
|
||||
/// </summary>
|
||||
#pragma warning disable SA1401 // Fields should be private
|
||||
protected BigInteger[] _privateKey;
|
||||
#pragma warning restore SA1401 // Fields should be private
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default digital signature implementation for this key.
|
||||
/// </summary>
|
||||
protected internal abstract DigitalSignature DigitalSignature { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the public key.
|
||||
/// Gets the public key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The public.
|
||||
/// </value>
|
||||
public abstract BigInteger[] Public { get; set; }
|
||||
public abstract BigInteger[] Public { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the key.
|
||||
@@ -44,36 +34,6 @@ namespace Renci.SshNet.Security
|
||||
/// </summary>
|
||||
public string Comment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Key"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">DER encoded private key data.</param>
|
||||
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<BigInteger>();
|
||||
while (!der.IsEndOfData)
|
||||
{
|
||||
keys.Add(der.ReadBigInteger());
|
||||
}
|
||||
|
||||
_privateKey = keys.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Key"/> class.
|
||||
/// </summary>
|
||||
protected Key()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signs the specified data with the key.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
|
||||
@@ -29,13 +30,7 @@ namespace Renci.SshNet.Security
|
||||
/// <value>
|
||||
/// The modulus.
|
||||
/// </value>
|
||||
public BigInteger Modulus
|
||||
{
|
||||
get
|
||||
{
|
||||
return _privateKey[0];
|
||||
}
|
||||
}
|
||||
public BigInteger Modulus { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exponent.
|
||||
@@ -43,13 +38,7 @@ namespace Renci.SshNet.Security
|
||||
/// <value>
|
||||
/// The exponent.
|
||||
/// </value>
|
||||
public BigInteger Exponent
|
||||
{
|
||||
get
|
||||
{
|
||||
return _privateKey[1];
|
||||
}
|
||||
}
|
||||
public BigInteger Exponent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the D.
|
||||
@@ -57,18 +46,7 @@ namespace Renci.SshNet.Security
|
||||
/// <value>
|
||||
/// The D.
|
||||
/// </value>
|
||||
public BigInteger D
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_privateKey.Length > 2)
|
||||
{
|
||||
return _privateKey[2];
|
||||
}
|
||||
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
public BigInteger D { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the P.
|
||||
@@ -76,18 +54,7 @@ namespace Renci.SshNet.Security
|
||||
/// <value>
|
||||
/// The P.
|
||||
/// </value>
|
||||
public BigInteger P
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_privateKey.Length > 3)
|
||||
{
|
||||
return _privateKey[3];
|
||||
}
|
||||
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
public BigInteger P { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Q.
|
||||
@@ -95,18 +62,7 @@ namespace Renci.SshNet.Security
|
||||
/// <value>
|
||||
/// The Q.
|
||||
/// </value>
|
||||
public BigInteger Q
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_privateKey.Length > 4)
|
||||
{
|
||||
return _privateKey[4];
|
||||
}
|
||||
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
public BigInteger Q { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DP.
|
||||
@@ -114,18 +70,7 @@ namespace Renci.SshNet.Security
|
||||
/// <value>
|
||||
/// The DP.
|
||||
/// </value>
|
||||
public BigInteger DP
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_privateKey.Length > 5)
|
||||
{
|
||||
return _privateKey[5];
|
||||
}
|
||||
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
public BigInteger DP { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DQ.
|
||||
@@ -133,18 +78,7 @@ namespace Renci.SshNet.Security
|
||||
/// <value>
|
||||
/// The DQ.
|
||||
/// </value>
|
||||
public BigInteger DQ
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_privateKey.Length > 6)
|
||||
{
|
||||
return _privateKey[6];
|
||||
}
|
||||
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
public BigInteger DQ { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the inverse Q.
|
||||
@@ -152,18 +86,7 @@ namespace Renci.SshNet.Security
|
||||
/// <value>
|
||||
/// The inverse Q.
|
||||
/// </value>
|
||||
public BigInteger InverseQ
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_privateKey.Length > 7)
|
||||
{
|
||||
return _privateKey[7];
|
||||
}
|
||||
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
public BigInteger InverseQ { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the key.
|
||||
@@ -196,10 +119,11 @@ namespace Renci.SshNet.Security
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the public.
|
||||
/// Gets the RSA public key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The public.
|
||||
/// An array with <see cref="Exponent"/> at index 0, and <see cref="Modulus"/>
|
||||
/// at index 1.
|
||||
/// </value>
|
||||
public override BigInteger[] Public
|
||||
{
|
||||
@@ -207,34 +131,54 @@ namespace Renci.SshNet.Security
|
||||
{
|
||||
return new[] { Exponent, Modulus };
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value.Length != 2)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid private key.");
|
||||
}
|
||||
}
|
||||
|
||||
_privateKey = new[] { value[1], value[0] };
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaKey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="publicKeyData">The encoded public key data.</param>
|
||||
public RsaKey(SshKeyData publicKeyData)
|
||||
{
|
||||
if (publicKeyData is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(publicKeyData));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaKey"/> class.
|
||||
/// </summary>
|
||||
public RsaKey()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaKey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">DER encoded private key data.</param>
|
||||
public RsaKey(byte[] data)
|
||||
: base(data)
|
||||
{
|
||||
if (_privateKey.Length != 8)
|
||||
if (publicKeyData.Name != "ssh-rsa" || publicKeyData.Keys.Length != 2)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid private key.");
|
||||
throw new ArgumentException($"Invalid RSA public key data. ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData));
|
||||
}
|
||||
|
||||
Exponent = publicKeyData.Keys[0];
|
||||
Modulus = publicKeyData.Keys[1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaKey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="privateKeyData">DER encoded private key data.</param>
|
||||
public RsaKey(byte[] privateKeyData)
|
||||
{
|
||||
if (privateKeyData is null)
|
||||
{
|
||||
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 @@ namespace Renci.SshNet.Security
|
||||
/// <param name="inverseQ">The inverse Q.</param>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 @@ namespace Renci.SshNet.Security
|
||||
/// <summary>
|
||||
/// Gets the key used in this host key algorithm.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The key used in this host key algorithm.
|
||||
/// </value>
|
||||
public Key Key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the signature implementation used in this host key algorithm.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The signature implementation used in this host key algorithm.
|
||||
/// </value>
|
||||
public DigitalSignature DigitalSignature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -47,11 +39,7 @@ namespace Renci.SshNet.Security
|
||||
/// Initializes a new instance of the <see cref="KeyHostAlgorithm"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The signature format identifier.</param>
|
||||
/// <param name="key"><inheritdoc cref="Key" path="/summary"/></param>
|
||||
/// <remarks>
|
||||
/// This constructor is typically passed a private key in order to create an encoded signature for later
|
||||
/// verification by the host.
|
||||
/// </remarks>
|
||||
/// <param name="key">The key used in this host key algorithm.</param>
|
||||
public KeyHostAlgorithm(string name, Key key)
|
||||
: base(name)
|
||||
{
|
||||
@@ -63,13 +51,9 @@ namespace Renci.SshNet.Security
|
||||
/// Initializes a new instance of the <see cref="KeyHostAlgorithm"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The signature format identifier.</param>
|
||||
/// <param name="key"><inheritdoc cref="Key" path="/summary"/></param>
|
||||
/// <param name="digitalSignature"><inheritdoc cref="DigitalSignature" path="/summary"/></param>
|
||||
/// <param name="key">The key used in this host key algorithm.</param>
|
||||
/// <param name="digitalSignature">The signature implementation used in this host key algorithm.</param>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This constructor is typically passed a private key in order to create an encoded signature for later
|
||||
/// verification by the host.
|
||||
/// </para>
|
||||
/// The key used by <paramref name="digitalSignature"/> is intended to be equal to <paramref name="key"/>.
|
||||
/// This is not verified.
|
||||
/// </remarks>
|
||||
@@ -80,59 +64,6 @@ namespace Renci.SshNet.Security
|
||||
DigitalSignature = digitalSignature;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="KeyHostAlgorithm"/> class
|
||||
/// with the given encoded public key data. The data will be decoded into <paramref name="key"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The signature format identifier.</param>
|
||||
/// <param name="key"><inheritdoc cref="Key" path="/summary"/></param>
|
||||
/// <param name="data">Host key encoded data.</param>
|
||||
/// <remarks>
|
||||
/// This constructor is typically passed a new or reusable <see cref="Security.Key"/> 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 <paramref name="data"/>.
|
||||
/// </remarks>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="KeyHostAlgorithm"/> class
|
||||
/// with the given encoded public key data. The data will be decoded into <paramref name="key"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The signature format identifier.</param>
|
||||
/// <param name="key"><inheritdoc cref="Key" path="/summary"/></param>
|
||||
/// <param name="data">Host key encoded data.</param>
|
||||
/// <param name="digitalSignature"><inheritdoc cref="DigitalSignature" path="/summary"/></param>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This constructor is typically passed a new or reusable <see cref="Security.Key"/> 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 <paramref name="data"/>.
|
||||
/// </para>
|
||||
/// The key used by <paramref name="digitalSignature"/> is intended to be equal to <paramref name="key"/>.
|
||||
/// This is not verified.
|
||||
/// </remarks>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signs and encodes the specified data.
|
||||
/// </summary>
|
||||
@@ -162,98 +93,6 @@ namespace Renci.SshNet.Security
|
||||
return DigitalSignature.Verify(data, signatureData.Signature);
|
||||
}
|
||||
|
||||
private sealed class SshKeyData : SshData
|
||||
{
|
||||
private byte[] _name;
|
||||
private List<byte[]> _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<byte[]>(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<byte[]>();
|
||||
|
||||
while (!IsEndOfData)
|
||||
{
|
||||
_keys.Add(ReadBinary());
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SaveData()
|
||||
{
|
||||
WriteBinaryString(_name);
|
||||
|
||||
foreach (var key in _keys)
|
||||
{
|
||||
WriteBinaryString(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SignatureKeyData : SshData
|
||||
{
|
||||
/// <summary>
|
||||
@@ -306,7 +145,7 @@ namespace Renci.SshNet.Security
|
||||
/// </summary>
|
||||
protected override void LoadData()
|
||||
{
|
||||
AlgorithmName = Encoding.UTF8.GetString(ReadBinary());
|
||||
AlgorithmName = ReadString();
|
||||
Signature = ReadBinary();
|
||||
}
|
||||
|
||||
@@ -315,7 +154,7 @@ namespace Renci.SshNet.Security
|
||||
/// </summary>
|
||||
protected override void SaveData()
|
||||
{
|
||||
WriteBinaryString(Encoding.UTF8.GetBytes(AlgorithmName));
|
||||
Write(AlgorithmName);
|
||||
WriteBinaryString(Signature);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Facilitates (de)serializing encoded public key data in the format
|
||||
/// specified by RFC 4253 section 6.6.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://datatracker.ietf.org/doc/html/rfc4253#section-6.6.
|
||||
/// </remarks>
|
||||
public sealed class SshKeyData : SshData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the public key format identifier.
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the public key constituents.
|
||||
/// </summary>
|
||||
public BigInteger[] Keys { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SshKeyData"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">The encoded public key data.</param>
|
||||
public SshKeyData(byte[] data)
|
||||
{
|
||||
Load(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SshKeyData"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The public key format identifer.</param>
|
||||
/// <param name="keys">The public key constituents.</param>
|
||||
public SshKeyData(string name, BigInteger[] keys)
|
||||
{
|
||||
Name = name;
|
||||
Keys = keys;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadData()
|
||||
{
|
||||
Name = ReadString();
|
||||
var keys = new List<BigInteger>();
|
||||
|
||||
while (!IsEndOfData)
|
||||
{
|
||||
keys.Add(ReadBinary().ToBigInteger2());
|
||||
}
|
||||
|
||||
Keys = keys.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 @@ namespace Renci.SshNet.Benchmarks.Common
|
||||
}
|
||||
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();
|
||||
|
||||
@@ -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);
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -57,10 +57,7 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography
|
||||
//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 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography
|
||||
//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 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography
|
||||
//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 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography
|
||||
public void Constructor_InvalidHashAlgorithm_ThrowsArgumentException()
|
||||
{
|
||||
ArgumentException exception = Assert.ThrowsException<ArgumentException>(
|
||||
() => new RsaDigitalSignature(new RsaKey(), new HashAlgorithmName("invalid")));
|
||||
() => new RsaDigitalSignature(GetRsaKey(), new HashAlgorithmName("invalid")));
|
||||
|
||||
Assert.AreEqual("hashAlgorithmName", exception.ParamName);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace Renci.SshNet.Tests.Classes.Security
|
||||
|
||||
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 @@ namespace Renci.SshNet.Tests.Classes.Security
|
||||
|
||||
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 @@ namespace Renci.SshNet.Tests.Classes.Security
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user