KeyExchangeECCurve25519
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Agreement;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math.EC.Rfc8032;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Security.Cryptography;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Numerics;
using Org.BouncyCastle.Math.EC.Rfc8032;
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Numerics;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Renci.SshNet
{
public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable
{
private bool _isDisposed;
public ICollection<IPrivateKeySource> KeyFiles { get; set; }
public PrivateKeyConnectionInfo(string host, string username, params IPrivateKeySource[] keyFiles)
: this(host, 22, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, 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)
{
}
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)
{
}
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)
{
}
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles)
: this(host, 22, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles)
{
}
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles)
: this(host, 22, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles)
{
}
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles)
: this(host, 22, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, 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<IPrivateKeySource>(keyFiles);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed && disposing) {
if (base.AuthenticationMethods != null) {
foreach (AuthenticationMethod authenticationMethod in base.AuthenticationMethods) {
authenticationMethod.Dispose();
}
}
_isDisposed = true;
}
}
}
}
namespace Renci.SshNet.Security
{
public class ED25519Key : Key, IDisposable
{
private ED25519DigitalSignature _digitalSignature;
private bool _isDisposed;
public override BigInteger[] Public => new BigInteger[1] {
Extensions.ToBigInteger2(PublicKey)
};
public override int KeyLength => Ed25519.PublicKeySize * 8;
protected internal override DigitalSignature DigitalSignature {
get {
if (_digitalSignature == null)
_digitalSignature = new ED25519DigitalSignature(this);
return _digitalSignature;
}
}
public byte[] PublicKey { get; }
public byte[] PrivateKey { get; }
public override string ToString()
{
return "ssh-ed25519";
}
public ED25519Key(SshKeyData publicKeyData)
{
ThrowHelper.ThrowIfNull(publicKeyData, "publicKeyData");
if (publicKeyData.Name != "ssh-ed25519" || publicKeyData.Keys.Length != 1)
throw new ArgumentException($"""{publicKeyData.Name}""{publicKeyData.Keys.Length}""", "publicKeyData");
PublicKey = Extensions.Pad(Extensions.TrimLeadingZeros(Extensions.ToByteArray(publicKeyData.Keys[0], false, true)), Ed25519.PublicKeySize);
PrivateKey = new byte[Ed25519.SecretKeySize];
}
public ED25519Key(byte[] privateKeyData)
{
PrivateKey = new byte[Ed25519.SecretKeySize];
PublicKey = new byte[Ed25519.PublicKeySize];
Buffer.BlockCopy(privateKeyData, 0, PrivateKey, 0, Ed25519.SecretKeySize);
Ed25519.GeneratePublicKey(privateKeyData, 0, PublicKey, 0);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed && disposing)
_isDisposed = true;
}
}
}
namespace Renci.SshNet.Security
{
internal class KeyExchangeECCurve25519 : KeyExchangeEC
{
protected sealed class BouncyCastleImpl : Impl
{
private X25519Agreement _keyAgreement;
public override byte[] GenerateClientPublicKey()
{
X25519KeyPairGenerator val = new X25519KeyPairGenerator();
val.Init(new X25519KeyGenerationParameters(CryptoAbstraction.SecureRandom));
AsymmetricCipherKeyPair val2 = val.GenerateKeyPair();
_keyAgreement = new X25519Agreement();
_keyAgreement.Init(val2.get_Private());
return val2.get_Public().GetEncoded();
}
public override byte[] CalculateAgreement(byte[] serverPublicKey)
{
X25519PublicKeyParameters val = new X25519PublicKeyParameters(serverPublicKey);
byte[] array = new byte[_keyAgreement.get_AgreementSize()];
_keyAgreement.CalculateAgreement(val, array, 0);
return array;
}
}
protected BouncyCastleImpl _impl;
public override string Name => "curve25519-sha256";
protected override int HashSize => 256;
public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage)
{
base.Start(session, message, sendClientInitMessage);
_impl = new BouncyCastleImpl();
StartImpl();
}
protected virtual void StartImpl()
{
base.Session.RegisterMessage("SSH_MSG_KEX_ECDH_REPLY");
base.Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived;
_clientExchangeValue = _impl.GenerateClientPublicKey();
SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue));
}
public override void Finish()
{
base.Finish();
FinishImpl();
}
protected virtual void FinishImpl()
{
base.Session.KeyExchangeEcdhReplyMessageReceived -= Session_KeyExchangeEcdhReplyMessageReceived;
}
protected override byte[] Hash(byte[] hashData)
{
return CryptoAbstraction.HashSHA256(hashData);
}
private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageEventArgs<KeyExchangeEcdhReplyMessage> e)
{
KeyExchangeEcdhReplyMessage message = e.Message;
base.Session.UnRegisterMessage("SSH_MSG_KEX_ECDH_REPLY");
HandleServerEcdhReply(message.KS, message.QS, message.Signature);
Finish();
}
private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature)
{
_serverExchangeValue = serverExchangeValue;
_hostKey = hostKey;
_signature = signature;
byte[] data = _impl.CalculateAgreement(serverExchangeValue);
base.SharedKey = Extensions.ToByteArray(Extensions.ToBigInteger2(data), false, true);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
_impl?.Dispose();
}
}
}