using System;
using Renci.SshNet.Common;
namespace Renci.SshNet.Security.Cryptography
{
///
/// Implements digital signature where where asymmetric cipher is used,
///
public abstract class CipherDigitalSignature : DigitalSignature
{
private readonly AsymmetricCipher _cipher;
private readonly ObjectIdentifier _oid;
///
/// Initializes a new instance of the class.
///
/// The object identifier.
/// The cipher.
protected CipherDigitalSignature(ObjectIdentifier oid, AsymmetricCipher cipher)
{
if (cipher is null)
{
throw new ArgumentNullException(nameof(cipher));
}
_cipher = cipher;
_oid = oid;
}
///
/// Verifies the signature.
///
/// The input.
/// The signature.
///
/// True if signature was successfully verified; otherwise false.
///
public override bool Verify(byte[] input, byte[] signature)
{
var encryptedSignature = _cipher.Decrypt(signature);
var hashData = Hash(input);
var expected = DerEncode(hashData);
return expected.IsEqualTo(encryptedSignature);
}
///
/// Creates the signature.
///
/// The input.
///
/// Signed input data.
///
public override byte[] Sign(byte[] input)
{
// Calculate hash value
var hashData = Hash(input);
// Calculate DER string
var derEncodedHash = DerEncode(hashData);
return _cipher.Encrypt(derEncodedHash).TrimLeadingZeros();
}
///
/// Hashes the specified input.
///
/// The input.
/// Hashed data.
protected abstract byte[] Hash(byte[] input);
///
/// Encodes hash using DER.
///
/// The hash data.
///
/// DER Encoded byte array.
///
protected byte[] DerEncode(byte[] hashData)
{
var alg = new DerData();
alg.Write(_oid);
alg.WriteNull();
var data = new DerData();
data.Write(alg);
data.Write(hashData);
return data.Encode();
}
}
}