using System.Collections.Generic; using Renci.SshNet.Common; using Renci.SshNet.Security.Chaos.NaCl; namespace Renci.SshNet.Security { /// /// Implements key support for host algorithm. /// public class KeyHostAlgorithm : HostAlgorithm { /// /// Gets the key. /// public Key Key { get; private set; } /// /// Gets the public key data. /// public override byte[] Data { get { return new SshKeyData(Name, Key.Public).GetBytes(); } } /// /// Initializes a new instance of the class. /// /// Host key name. /// Host key. public KeyHostAlgorithm(string name, Key key) : base(name) { Key = key; } /// /// Initializes a new instance of the class. /// /// Host key name. /// Host key. /// Host key encoded data. public KeyHostAlgorithm(string name, Key key, byte[] data) : base(name) { Key = key; var sshKey = new SshKeyData(); sshKey.Load(data); Key.Public = sshKey.Keys; } /// /// Signs the specified data. /// /// The data. /// /// Signed data. /// public override byte[] Sign(byte[] data) { return new SignatureKeyData(Name, Key.Sign(data)).GetBytes(); } /// /// Verifies the signature. /// /// The data. /// The signature. /// /// True is signature was successfully verifies; otherwise false. /// public override bool VerifySignature(byte[] data, byte[] signature) { var signatureData = new SignatureKeyData(); signatureData.Load(signature); return Key.VerifySignature(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); } } } private sealed class SignatureKeyData : SshData { /// /// Gets or sets the name of the algorithm as UTF-8 encoded byte array. /// /// /// The name of the algorithm. /// private byte[] AlgorithmName { get; set; } /// /// Gets the signature. /// /// /// The signature. /// public byte[] Signature { get; private set; } /// /// Gets the size of the message in bytes. /// /// /// The size of the messages in bytes. /// protected override int BufferCapacity { get { var capacity = base.BufferCapacity; capacity += 4; // AlgorithmName length capacity += AlgorithmName.Length; // AlgorithmName capacity += 4; // Signature length capacity += Signature.Length; // Signature return capacity; } } public SignatureKeyData() { } public SignatureKeyData(string name, byte[] signature) { AlgorithmName = Utf8.GetBytes(name); Signature = signature; } /// /// Called when type specific data need to be loaded. /// protected override void LoadData() { AlgorithmName = ReadBinary(); Signature = ReadBinary(); } /// /// Called when type specific data need to be saved. /// protected override void SaveData() { WriteBinaryString(AlgorithmName); WriteBinaryString(Signature); } } } }