using System;
using Renci.SshNet.Common;
namespace Renci.SshNet.Security.Cryptography
{
///
/// Implements ECDSA digital signature algorithm.
///
public class EcdsaDigitalSignature : DigitalSignature, IDisposable
{
private readonly EcdsaKey _key;
///
/// Initializes a new instance of the class.
///
/// The ECDSA key.
/// is .
public EcdsaDigitalSignature(EcdsaKey key)
{
if (key is null)
{
throw new ArgumentNullException(nameof(key));
}
_key = key;
}
///
/// Verifies the signature.
///
/// The input.
/// The signature.
///
/// if signature was successfully verified; otherwise .
///
public override bool Verify(byte[] input, byte[] signature)
{
// for 521 sig_size is 132
var sig_size = _key.KeyLength == 521 ? 132 : _key.KeyLength / 4;
var ssh_data = new SshDataSignature(signature, sig_size);
return _key._impl.Verify(input, ssh_data.Signature);
}
///
/// Creates the signature.
///
/// The input.
///
/// Signed input data.
///
public override byte[] Sign(byte[] input)
{
var signed = _key._impl.Sign(input);
var ssh_data = new SshDataSignature(signed.Length) { Signature = signed };
return ssh_data.GetBytes();
}
///
/// 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)
{
}
private sealed class SshDataSignature : SshData
{
private readonly int _signature_size;
private byte[] _signature_r;
private byte[] _signature_s;
public byte[] Signature
{
get
{
var signature = new byte[_signature_size];
Buffer.BlockCopy(_signature_r, 0, signature, 0, _signature_r.Length);
Buffer.BlockCopy(_signature_s, 0, signature, _signature_r.Length, _signature_s.Length);
return signature;
}
set
{
var signed_r = new byte[_signature_size / 2];
Buffer.BlockCopy(value, 0, signed_r, 0, signed_r.Length);
_signature_r = signed_r.ToBigInteger2().ToByteArray(isBigEndian: true);
var signed_s = new byte[_signature_size / 2];
Buffer.BlockCopy(value, signed_r.Length, signed_s, 0, signed_s.Length);
_signature_s = signed_s.ToBigInteger2().ToByteArray(isBigEndian: true);
}
}
public SshDataSignature(int sig_size)
{
_signature_size = sig_size;
}
public SshDataSignature(byte[] data, int sig_size)
{
_signature_size = sig_size;
Load(data);
}
protected override void LoadData()
{
_signature_r = ReadBinary().TrimLeadingZeros().Pad(_signature_size / 2);
_signature_s = ReadBinary().TrimLeadingZeros().Pad(_signature_size / 2);
}
protected override void SaveData()
{
WriteBinaryString(_signature_r.ToBigInteger2().ToByteArray(isBigEndian: true));
WriteBinaryString(_signature_s.ToBigInteger2().ToByteArray(isBigEndian: true));
}
protected override int BufferCapacity
{
get
{
var capacity = base.BufferCapacity;
capacity += 4; // r length
capacity += _signature_r.Length; // signature r
capacity += 4; // s length
capacity += _signature_s.Length; // signature s
return capacity;
}
}
}
}
}