using System;
using Renci.SshNet.Common;
using Renci.SshNet.Security.Chaos.NaCl;
using Renci.SshNet.Security.Cryptography;
namespace Renci.SshNet.Security
{
///
/// Contains ED25519 private and public key.
///
public class ED25519Key : Key, IDisposable
{
private ED25519DigitalSignature _digitalSignature;
private bool _isDisposed;
///
/// Gets the name of the key.
///
///
/// The name of the key.
///
public override string ToString()
{
return "ssh-ed25519";
}
///
/// Gets the Ed25519 public key.
///
///
/// An array with encoded at index 0.
///
public override BigInteger[] Public
{
get
{
return new BigInteger[] { PublicKey.ToBigInteger2() };
}
}
///
/// Gets the length of the key.
///
///
/// The length of the key.
///
public override int KeyLength
{
get
{
return PublicKey.Length * 8;
}
}
///
/// Gets the digital signature.
///
protected internal override DigitalSignature DigitalSignature
{
get
{
_digitalSignature ??= new ED25519DigitalSignature(this);
return _digitalSignature;
}
}
///
/// Gets the PublicKey Bytes.
///
public byte[] PublicKey { get; }
///
/// Gets the PrivateKey Bytes.
///
public byte[] PrivateKey { get; }
///
/// Initializes a new instance of the class.
///
/// The encoded public key data.
public ED25519Key(SshKeyData publicKeyData)
{
if (publicKeyData is null)
{
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];
}
///
/// Initializes a new instance of the class.
///
///
/// The private key data k || ENC(A) as described in RFC 8032.
///
public ED25519Key(byte[] privateKeyData)
{
var seed = new byte[Ed25519.PrivateKeySeedSizeInBytes];
Buffer.BlockCopy(privateKeyData, 0, seed, 0, seed.Length);
Ed25519.KeyPairFromSeed(out var publicKey, out var privateKey, seed);
PublicKey = publicKey;
PrivateKey = privateKey;
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
///
/// Releases unmanaged and - optionally - managed resources.
///
/// to release both managed and unmanaged resources; to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
if (_isDisposed)
{
return;
}
if (disposing)
{
_isDisposed = true;
}
}
///
/// Finalizes an instance of the class.
///
~ED25519Key()
{
Dispose(disposing: false);
}
}
}