Skip to content

Commit

Permalink
Add support for external Crypto
Browse files Browse the repository at this point in the history
So users can use their own RSA/ECDSA instance.
  • Loading branch information
darinkes committed Mar 21, 2024
1 parent 65b7f1e commit b535984
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 17 deletions.
42 changes: 42 additions & 0 deletions SshNet.Keygen.Tests/TestKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,5 +265,47 @@ public void TestED25519()
TestFormatKey<ED25519Key>("ED25519", 256);
TestFormatKey<ED25519Key>("ED25519", 256, "12345");
}

[Test]
public void TestOwnRSA()
{
RSA? rsa;
int keySize = 2048;
#if NET8_0_OR_GREATER
rsa = RSA.Create();
if (rsa is RSACryptoServiceProvider)
{
rsa.Dispose();
rsa = new RSACng(keySize);
}
rsa.KeySize = keySize;
#else
var rsa = new RSACryptoServiceProvider(keySize);

Check failure on line 283 in SshNet.Keygen.Tests/TestKey.cs

View workflow job for this annotation

GitHub Actions / build

A local variable or function named 'rsa' is already defined in this scope

Check failure on line 283 in SshNet.Keygen.Tests/TestKey.cs

View workflow job for this annotation

GitHub Actions / build

A local variable or function named 'rsa' is already defined in this scope
#endif
var keyInfo = new SshKeyGenerateInfo()
{
Rsa = rsa

Check failure on line 287 in SshNet.Keygen.Tests/TestKey.cs

View workflow job for this annotation

GitHub Actions / build

Use of unassigned local variable 'rsa'

Check failure on line 287 in SshNet.Keygen.Tests/TestKey.cs

View workflow job for this annotation

GitHub Actions / build

Use of unassigned local variable 'rsa'
};
_ = SshKey.Generate(keyInfo);
}

[Test]
public void TestOwnEcdsa()
{
ECDsa? ecdsa;
#if NET8_0_OR_GREATER
var curve = ECCurve.CreateFromFriendlyName("nistp256");
ecdsa = ECDsa.Create();
ecdsa.GenerateKey(curve);
#else
ecdsa = new ECDsaCng(256);
#endif
var keyInfo = new SshKeyGenerateInfo()
{
KeyType = SshKeyType.ECDSA,
Ecdsa = ecdsa

Check failure on line 306 in SshNet.Keygen.Tests/TestKey.cs

View workflow job for this annotation

GitHub Actions / build

Cannot implicitly convert type 'System.Security.Cryptography.ECDsa' to 'System.Security.Cryptography.ECDsaCng'. An explicit conversion exists (are you missing a cast?)

Check failure on line 306 in SshNet.Keygen.Tests/TestKey.cs

View workflow job for this annotation

GitHub Actions / build

Cannot implicitly convert type 'System.Security.Cryptography.ECDsa' to 'System.Security.Cryptography.ECDsaCng'. An explicit conversion exists (are you missing a cast?)
};
_ = SshKey.Generate(keyInfo);
}
}
}
65 changes: 48 additions & 17 deletions SshNet.Keygen/SshKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,16 @@ public static GeneratedPrivateKey Generate(SshKeyGenerateInfo info)
}
case SshKeyType.RSA:
{
using var rsa = CreateRSA(info.KeyLength);
var rsaParameters = rsa.ExportParameters(true);
RSAParameters rsaParameters;
if (info.Rsa is not null)
{
rsaParameters = info.Rsa.ExportParameters(true);
}
else
{
using var rsa = CreateRSA(info.KeyLength);
rsaParameters = rsa.ExportParameters(true);
}

key = new RsaKey(
rsaParameters.Modulus.ToBigInteger2().ToByteArray().Reverse().ToBigInteger(),
Expand All @@ -75,28 +83,49 @@ public static GeneratedPrivateKey Generate(SshKeyGenerateInfo info)
}
case SshKeyType.ECDSA:
{
var dispose = false;
#if NETSTANDARD
var curve = info.KeyLength switch
ECDsa? ecdsa;
if (info.Ecdsa is not null)
{
256 => ECCurve.CreateFromFriendlyName("nistp256"),
384 => ECCurve.CreateFromFriendlyName("nistp384"),
521 => ECCurve.CreateFromFriendlyName("nistp521"),
_ => throw new CryptographicException("Unsupported KeyLength")
};

using var ecdsa = ECDsa.Create();
if (ecdsa is null)
throw new CryptographicException("Unable to generate ECDSA");
ecdsa.GenerateKey(curve);
var ecdsaParameters = ecdsa.ExportParameters(true);
ecdsa = info.Ecdsa;
}
else
{
var curve = info.KeyLength switch
{
256 => ECCurve.CreateFromFriendlyName("nistp256"),
384 => ECCurve.CreateFromFriendlyName("nistp384"),
521 => ECCurve.CreateFromFriendlyName("nistp521"),
_ => throw new CryptographicException("Unsupported KeyLength")
};

ecdsa = ECDsa.Create();
if (ecdsa is null)
throw new CryptographicException("Unable to generate ECDSA");
dispose = true;
ecdsa.GenerateKey(curve);
}

var ecParameters = ecdsa.ExportParameters(true);

key = new EcdsaKey(
ecdsa.EcCurveNameSshCompat(),
ecdsaParameters.UncompressedCoords(),
ecdsaParameters.D
ecParameters.UncompressedCoords(),
ecParameters.D
);
#else
using var ecdsa = new ECDsaCng(info.KeyLength);
ECDsaCng ecdsa;
if (info.Ecdsa is not null)
{
ecdsa = info.Ecdsa;
}
else
{
ecdsa = new ECDsaCng(info.KeyLength);
dispose = true;
}

var keyBlob = ecdsa.Key.Export(CngKeyBlobFormat.EccPrivateBlob);
using var stream = new MemoryStream(keyBlob);
using var reader = new BinaryReader(stream);
Expand All @@ -112,6 +141,8 @@ public static GeneratedPrivateKey Generate(SshKeyGenerateInfo info)
d
);
#endif
if (dispose)
ecdsa.Dispose();
break;
}
default:
Expand Down
9 changes: 9 additions & 0 deletions SshNet.Keygen/SshKeyGenerateInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Security.Cryptography;
using SshNet.Keygen.SshKeyEncryption;

namespace SshNet.Keygen
Expand Down Expand Up @@ -31,6 +32,14 @@ public class SshKeyGenerateInfo

public SshKeyType KeyType { get; set; }

public RSA? Rsa { get; set; }

#if NETSTANDARD
public ECDsa? Ecdsa { get; set; }
#else
public ECDsaCng? Ecdsa { get; set; }
#endif

public SshKeyGenerateInfo(SshKeyType keyType = DefaultSshKeyType)
{
Encryption = DefaultSshKeyEncryption;
Expand Down

0 comments on commit b535984

Please sign in to comment.