-
-
Notifications
You must be signed in to change notification settings - Fork 939
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ECDsa] Falls back to use BouncyCastle if BCL (Mono) doesn't support (#…
…1461) * Use BouncyCastle ECDsa when runtime is Mono * Falls back to use BouncyCastle if CngKey.Import throws NotImplementedException (in Mono) * Take NETStandard into consideration * Adjust some comments * Change #if NETFRAEWORK to #if NET462 for CngKey * Separate implementations * Consolidate Ecdsa property and HashAlgorithm property * Rename Import_Cng and Import_Bcl to Import; Rename Export_Cng and Export_Bcl to Export; * Add comments * refactor * add host key tests --------- Co-authored-by: Robert Hague <[email protected]> Co-authored-by: Rob Hague <[email protected]>
- Loading branch information
1 parent
3dda5c9
commit fe827a5
Showing
16 changed files
with
494 additions
and
338 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
82 changes: 82 additions & 0 deletions
82
src/Renci.SshNet/Security/Cryptography/EcdsaKey.BclImpl.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
#if !NET462 | ||
#nullable enable | ||
using System; | ||
using System.Security.Cryptography; | ||
|
||
using Renci.SshNet.Common; | ||
|
||
namespace Renci.SshNet.Security | ||
{ | ||
public partial class EcdsaKey : Key, IDisposable | ||
{ | ||
private sealed class BclImpl : Impl | ||
{ | ||
private readonly HashAlgorithmName _hashAlgorithmName; | ||
|
||
public BclImpl(string curve_oid, int cord_size, byte[] qx, byte[] qy, byte[]? privatekey) | ||
{ | ||
var curve = ECCurve.CreateFromValue(curve_oid); | ||
var parameter = new ECParameters | ||
{ | ||
Curve = curve | ||
}; | ||
|
||
parameter.Q.X = qx; | ||
parameter.Q.Y = qy; | ||
|
||
if (privatekey != null) | ||
{ | ||
parameter.D = privatekey.TrimLeadingZeros().Pad(cord_size); | ||
PrivateKey = parameter.D; | ||
} | ||
|
||
Ecdsa = ECDsa.Create(parameter); | ||
|
||
_hashAlgorithmName = KeyLength switch | ||
{ | ||
<= 256 => HashAlgorithmName.SHA256, | ||
<= 384 => HashAlgorithmName.SHA384, | ||
_ => HashAlgorithmName.SHA512, | ||
}; | ||
} | ||
|
||
public override byte[]? PrivateKey { get; } | ||
|
||
public override ECDsa Ecdsa { get; } | ||
|
||
public override int KeyLength | ||
{ | ||
get | ||
{ | ||
return Ecdsa.KeySize; | ||
} | ||
} | ||
|
||
public override byte[] Sign(byte[] input) | ||
{ | ||
return Ecdsa.SignData(input, _hashAlgorithmName); | ||
} | ||
|
||
public override bool Verify(byte[] input, byte[] signature) | ||
{ | ||
return Ecdsa.VerifyData(input, signature, _hashAlgorithmName); | ||
} | ||
|
||
public override void Export(out byte[] qx, out byte[] qy) | ||
{ | ||
var parameter = Ecdsa.ExportParameters(includePrivateParameters: false); | ||
qx = parameter.Q.X!; | ||
qy = parameter.Q.Y!; | ||
} | ||
|
||
protected override void Dispose(bool disposing) | ||
{ | ||
if (disposing) | ||
{ | ||
Ecdsa.Dispose(); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
#endif |
108 changes: 108 additions & 0 deletions
108
src/Renci.SshNet/Security/Cryptography/EcdsaKey.BouncyCastleImpl.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
#if !NET | ||
#nullable enable | ||
using System.Security.Cryptography; | ||
|
||
using Org.BouncyCastle.Asn1; | ||
using Org.BouncyCastle.Asn1.Sec; | ||
using Org.BouncyCastle.Crypto; | ||
using Org.BouncyCastle.Crypto.Digests; | ||
using Org.BouncyCastle.Crypto.Parameters; | ||
using Org.BouncyCastle.Crypto.Signers; | ||
|
||
using Renci.SshNet.Common; | ||
|
||
namespace Renci.SshNet.Security | ||
{ | ||
public partial class EcdsaKey | ||
{ | ||
private sealed class BouncyCastleImpl : Impl | ||
{ | ||
private readonly ECPublicKeyParameters _publicKeyParameters; | ||
private readonly ECPrivateKeyParameters? _privateKeyParameters; | ||
private readonly DsaDigestSigner _signer; | ||
|
||
public BouncyCastleImpl(string curve_oid, byte[] qx, byte[] qy, byte[]? privatekey) | ||
{ | ||
DerObjectIdentifier oid; | ||
IDigest digest; | ||
switch (curve_oid) | ||
{ | ||
case ECDSA_P256_OID_VALUE: | ||
oid = SecObjectIdentifiers.SecP256r1; | ||
digest = new Sha256Digest(); | ||
KeyLength = 256; | ||
break; | ||
case ECDSA_P384_OID_VALUE: | ||
oid = SecObjectIdentifiers.SecP384r1; | ||
digest = new Sha384Digest(); | ||
KeyLength = 384; | ||
break; | ||
case ECDSA_P521_OID_VALUE: | ||
oid = SecObjectIdentifiers.SecP521r1; | ||
digest = new Sha512Digest(); | ||
KeyLength = 521; | ||
break; | ||
default: | ||
throw new SshException("Unexpected OID: " + curve_oid); | ||
} | ||
|
||
_signer = new DsaDigestSigner(new ECDsaSigner(), digest, PlainDsaEncoding.Instance); | ||
|
||
var x9ECParameters = SecNamedCurves.GetByOid(oid); | ||
var domainParameter = new ECNamedDomainParameters(oid, x9ECParameters); | ||
|
||
if (privatekey != null) | ||
{ | ||
_privateKeyParameters = new ECPrivateKeyParameters( | ||
new Org.BouncyCastle.Math.BigInteger(1, privatekey), | ||
domainParameter); | ||
|
||
_publicKeyParameters = new ECPublicKeyParameters( | ||
domainParameter.G.Multiply(_privateKeyParameters.D).Normalize(), | ||
domainParameter); | ||
} | ||
else | ||
{ | ||
_publicKeyParameters = new ECPublicKeyParameters( | ||
x9ECParameters.Curve.CreatePoint( | ||
new Org.BouncyCastle.Math.BigInteger(1, qx), | ||
new Org.BouncyCastle.Math.BigInteger(1, qy)), | ||
domainParameter); | ||
} | ||
} | ||
|
||
public override byte[]? PrivateKey { get; } | ||
|
||
public override ECDsa? Ecdsa { get; } | ||
|
||
public override int KeyLength { get; } | ||
|
||
public override byte[] Sign(byte[] input) | ||
{ | ||
_signer.Init(forSigning: true, _privateKeyParameters); | ||
_signer.BlockUpdate(input, 0, input.Length); | ||
|
||
return _signer.GenerateSignature(); | ||
} | ||
|
||
public override bool Verify(byte[] input, byte[] signature) | ||
{ | ||
_signer.Init(forSigning: false, _publicKeyParameters); | ||
_signer.BlockUpdate(input, 0, input.Length); | ||
|
||
return _signer.VerifySignature(signature); | ||
} | ||
|
||
public override void Export(out byte[] qx, out byte[] qy) | ||
{ | ||
qx = _publicKeyParameters.Q.XCoord.GetEncoded(); | ||
qy = _publicKeyParameters.Q.YCoord.GetEncoded(); | ||
} | ||
|
||
protected override void Dispose(bool disposing) | ||
{ | ||
} | ||
} | ||
} | ||
} | ||
#endif |
Oops, something went wrong.