EcdsaKey
Contains ECDSA (ecdsa-sha2-nistp{256,384,521}) private and public key.
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography;
using System;
using System.Security.Cryptography;
using System.Text;
namespace Renci.SshNet.Security
{
public class EcdsaKey : Key, IDisposable
{
internal const string ECDSA_P256_OID_VALUE = "1.2.840.10045.3.1.7";
internal const string ECDSA_P384_OID_VALUE = "1.3.132.0.34";
internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35";
private EcdsaDigitalSignature _digitalSignature;
private bool _isDisposed;
public HashAlgorithmName HashAlgorithm {
get {
switch (KeyLength) {
case 256:
return HashAlgorithmName.SHA256;
case 384:
return HashAlgorithmName.SHA384;
case 521:
return HashAlgorithmName.SHA512;
default:
return HashAlgorithmName.SHA256;
}
}
}
public override int KeyLength => Ecdsa.KeySize;
protected internal override DigitalSignature DigitalSignature {
get {
if (_digitalSignature == null)
_digitalSignature = new EcdsaDigitalSignature(this);
return _digitalSignature;
}
}
public override BigInteger[] Public {
get {
ECParameters eCParameters = Ecdsa.ExportParameters(false);
byte[] x = eCParameters.Q.X;
byte[] y = eCParameters.Q.Y;
byte[] bytes;
switch (eCParameters.Curve.Oid.FriendlyName) {
case "ECDSA_P256":
case "nistP256":
bytes = Encoding.ASCII.GetBytes("nistp256");
break;
case "ECDSA_P384":
case "nistP384":
bytes = Encoding.ASCII.GetBytes("nistp384");
break;
case "ECDSA_P521":
case "nistP521":
bytes = Encoding.ASCII.GetBytes("nistp521");
break;
default:
throw new SshException("Unexpected Curve Name: " + eCParameters.Curve.Oid.FriendlyName);
}
byte[] array = new byte[1 + x.Length + y.Length];
Buffer.SetByte(array, 0, 4);
Buffer.BlockCopy(x, 0, array, 1, x.Length);
Buffer.BlockCopy(y, 0, array, x.Length + 1, y.Length);
return new BigInteger[2] {
new BigInteger(bytes.Reverse()),
new BigInteger(array.Reverse())
};
}
set {
string curveOid = GetCurveOid(Encoding.ASCII.GetString(value[0].ToByteArray().Reverse()));
byte[] publickey = value[1].ToByteArray().Reverse();
Import(curveOid, publickey, null);
}
}
public byte[] PrivateKey { get; set; }
public ECDsa Ecdsa { get; set; }
public override string ToString()
{
return $"""{KeyLength}";
}
public EcdsaKey()
{
}
public EcdsaKey(string curve, byte[] publickey, byte[] privatekey)
{
Import(GetCurveOid(curve), publickey, privatekey);
}
public EcdsaKey(byte[] data)
{
DerData derData = new DerData(data, false);
derData.ReadBigInteger();
byte[] privatekey = derData.ReadOctetString().TrimLeadingZeros();
byte b = derData.ReadByte();
if ((b & 224) != 160)
throw new SshException($"""{b:""}");
int num = b & 31;
if (num != 0)
throw new SshException($"""{num}");
byte[] oid = new DerData(derData.ReadBytes(derData.ReadLength()), true).ReadObject();
b = derData.ReadByte();
if ((b & 224) != 160)
throw new SshException($"""{b:""}");
num = (b & 31);
if (num != 1)
throw new SshException($"""{num}");
byte[] publickey = new DerData(derData.ReadBytes(derData.ReadLength()), true).ReadBitString().TrimLeadingZeros();
Import(OidByteArrayToString(oid), publickey, privatekey);
}
private void Import(string curve_oid, byte[] publickey, byte[] privatekey)
{
ECCurve curve = ECCurve.CreateFromValue(curve_oid);
ECParameters eCParameters = default(ECParameters);
eCParameters.Curve = curve;
ECParameters eCParameters2 = eCParameters;
int num = (publickey.Length - 1) / 2;
byte[] array = new byte[num];
Buffer.BlockCopy(publickey, 1, array, 0, array.Length);
byte[] array2 = new byte[num];
Buffer.BlockCopy(publickey, num + 1, array2, 0, array2.Length);
eCParameters2.Q.X = array;
eCParameters2.Q.Y = array2;
if (privatekey != null) {
eCParameters2.D = privatekey.TrimLeadingZeros().Pad(num);
PrivateKey = eCParameters2.D;
}
Ecdsa = ECDsa.Create(eCParameters2);
}
private static string GetCurveOid(string curve_s)
{
switch (curve_s.ToLower()) {
case "nistp256":
return "1.2.840.10045.3.1.7";
case "nistp384":
return "1.3.132.0.34";
case "nistp521":
return "1.3.132.0.35";
default:
throw new SshException("Unexpected Curve Name: " + curve_s);
}
}
private static string OidByteArrayToString(byte[] oid)
{
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < oid.Length; i++) {
if (i == 0) {
int num = (int)oid[0] % 40;
int num2 = (oid[0] - num) / 40;
stringBuilder.AppendFormat("{0}.{1}", num2, num);
} else if (oid[i] < 128) {
stringBuilder.AppendFormat(".{0}", oid[i]);
} else {
stringBuilder.AppendFormat(".{0}", (oid[i] - 128) * 128 + oid[i + 1]);
i++;
}
}
return stringBuilder.ToString();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed && disposing)
_isDisposed = true;
}
~EcdsaKey()
{
Dispose(false);
}
}
}