From 960e5c56dd5f17cc3734af1b6e04087daf583fd3 Mon Sep 17 00:00:00 2001 From: Scott Brady Date: Sat, 30 Mar 2024 08:41:41 +0000 Subject: [PATCH] Added tests for EdDsa as AsymmetricAlgorithm --- .../ExtendedJsonWebAlgorithmsKeyTypes.cs | 8 - .../Crypto/ExtendedSecurityAlgorithms.cs | 8 +- .../Extensions/ExtendedJsonWebKeyConverter.cs | 2 +- .../ScottBrady.IdentityModel.csproj | 2 +- src/ScottBrady.IdentityModel/Tokens/EdDsa.cs | 82 ++++++--- .../Tokens/EdDsaSecurityKey.cs | 4 +- .../ScottBrady.IdentityModel.Tests.csproj | 1 + .../EdDsaBaseClassTests.cs | 159 ++++++++++++++++++ .../AsymmetricAlgorithm/EdDsaCreationTests.cs | 86 ++++++++++ .../AsymmetricAlgorithm/EdDsaSigningTests.cs | 55 ++++++ .../AsymmetricAlgorithm/EdDsaTestBase.cs | 24 +++ .../EdDSA/EdDsaSignatureProviderTests.cs | 1 - .../Tokens/EdDSA/EdDsaTests.cs | 99 ----------- .../ExtendedJsonWebKeyConverterTests.cs | 2 +- 14 files changed, 394 insertions(+), 139 deletions(-) delete mode 100644 src/ScottBrady.IdentityModel/Crypto/ExtendedJsonWebAlgorithmsKeyTypes.cs create mode 100644 test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaBaseClassTests.cs create mode 100644 test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaCreationTests.cs create mode 100644 test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaSigningTests.cs create mode 100644 test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaTestBase.cs delete mode 100644 test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/EdDsaTests.cs diff --git a/src/ScottBrady.IdentityModel/Crypto/ExtendedJsonWebAlgorithmsKeyTypes.cs b/src/ScottBrady.IdentityModel/Crypto/ExtendedJsonWebAlgorithmsKeyTypes.cs deleted file mode 100644 index 83fd3b0..0000000 --- a/src/ScottBrady.IdentityModel/Crypto/ExtendedJsonWebAlgorithmsKeyTypes.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace ScottBrady.IdentityModel.Crypto -{ - public static class ExtendedJsonWebAlgorithmsKeyTypes - { - // https://datatracker.ietf.org/doc/html/draft-ietf-jose-cfrg-curves-06#section-2 - public const string ECDH = "OKP"; - } -} diff --git a/src/ScottBrady.IdentityModel/Crypto/ExtendedSecurityAlgorithms.cs b/src/ScottBrady.IdentityModel/Crypto/ExtendedSecurityAlgorithms.cs index dddd5d8..ded5eb2 100644 --- a/src/ScottBrady.IdentityModel/Crypto/ExtendedSecurityAlgorithms.cs +++ b/src/ScottBrady.IdentityModel/Crypto/ExtendedSecurityAlgorithms.cs @@ -13,7 +13,7 @@ public static class ExtendedSecurityAlgorithms // https://tools.ietf.org/html/rfc8037#section-5 public const string EdDsa = "EdDSA"; - public class Curves + public static class Curves { // https://tools.ietf.org/html/rfc8037#section-5 public const string Ed25519 = "Ed25519"; @@ -21,4 +21,10 @@ public class Curves public const string X25519 = "X25519"; public const string X448 = "X448"; } + + public static class KeyTypes + { + // https://datatracker.ietf.org/doc/html/draft-ietf-jose-cfrg-curves-06#section-2 + public const string Ecdh = "OKP"; + } } \ No newline at end of file diff --git a/src/ScottBrady.IdentityModel/Extensions/ExtendedJsonWebKeyConverter.cs b/src/ScottBrady.IdentityModel/Extensions/ExtendedJsonWebKeyConverter.cs index 57d6305..7ba0ca8 100644 --- a/src/ScottBrady.IdentityModel/Extensions/ExtendedJsonWebKeyConverter.cs +++ b/src/ScottBrady.IdentityModel/Extensions/ExtendedJsonWebKeyConverter.cs @@ -14,7 +14,7 @@ public static JsonWebKey ConvertFromEdDsaSecurityKey(EdDsaSecurityKey securityKe Crv = parameters.Curve, X = parameters.X != null ? Base64UrlEncoder.Encode(parameters.X) : null, D = parameters.D != null ? Base64UrlEncoder.Encode(parameters.D) : null, - Kty = ExtendedJsonWebAlgorithmsKeyTypes.ECDH, + Kty = ExtendedSecurityAlgorithms.KeyTypes.Ecdh, Alg = ExtendedSecurityAlgorithms.EdDsa, CryptoProviderFactory = securityKey.CryptoProviderFactory, }; diff --git a/src/ScottBrady.IdentityModel/ScottBrady.IdentityModel.csproj b/src/ScottBrady.IdentityModel/ScottBrady.IdentityModel.csproj index 0af5167..360c967 100644 --- a/src/ScottBrady.IdentityModel/ScottBrady.IdentityModel.csproj +++ b/src/ScottBrady.IdentityModel/ScottBrady.IdentityModel.csproj @@ -11,7 +11,7 @@ IdentityModel Base16 Base62 EdDSA true true - 3.1.0 + 4.0.0 Apache-2.0 1591 diff --git a/src/ScottBrady.IdentityModel/Tokens/EdDsa.cs b/src/ScottBrady.IdentityModel/Tokens/EdDsa.cs index 4b01b31..d363421 100644 --- a/src/ScottBrady.IdentityModel/Tokens/EdDsa.cs +++ b/src/ScottBrady.IdentityModel/Tokens/EdDsa.cs @@ -10,46 +10,59 @@ namespace ScottBrady.IdentityModel.Tokens; -public class EdDsa: AsymmetricAlgorithm +public class EdDsa : AsymmetricAlgorithm { internal EdDsaParameters Parameters { get; private init; } + internal AsymmetricKeyParameter PrivateKeyParameter { get; private init; } + internal AsymmetricKeyParameter PublicKeyParameter { get; private init; } private EdDsa() { } public static EdDsa Create(EdDsaParameters parameters) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); - + parameters.Validate(); - return new EdDsa {Parameters = parameters}; + return new EdDsa + { + Parameters = parameters, + PrivateKeyParameter = CreatePrivateKeyParameter(parameters), + PublicKeyParameter = CreatePublicKeyParameter(parameters) + }; } /// /// Create new key for EdDSA. /// /// Create key for curve Ed25519 or Ed448. - public static EdDsa Create(string curve) + public new static EdDsa Create(string curve) { if (string.IsNullOrWhiteSpace(curve)) throw new ArgumentNullException(nameof(curve)); + IAsymmetricCipherKeyPairGenerator generator; if (curve == ExtendedSecurityAlgorithms.Curves.Ed25519) { - var generator = new Ed25519KeyPairGenerator(); + generator = new Ed25519KeyPairGenerator(); generator.Init(new Ed25519KeyGenerationParameters(new SecureRandom())); - var keyPair = generator.GenerateKeyPair(); - return new EdDsa {Parameters = new EdDsaParameters(keyPair, curve)}; + } - - if (curve == ExtendedSecurityAlgorithms.Curves.Ed448) + else if (curve == ExtendedSecurityAlgorithms.Curves.Ed448) { - var generator = new Ed448KeyPairGenerator(); + generator = new Ed448KeyPairGenerator(); generator.Init(new Ed448KeyGenerationParameters(new SecureRandom())); - var keyPair = generator.GenerateKeyPair(); - - return new EdDsa {Parameters = new EdDsaParameters(keyPair, curve)}; } - - throw new NotSupportedException("Unsupported EdDSA curve"); + else + { + throw new NotSupportedException("Unsupported EdDSA curve"); + } + + var keyPair = generator.GenerateKeyPair(); + return new EdDsa + { + Parameters = new EdDsaParameters(keyPair, curve), + PrivateKeyParameter = keyPair.Private, + PublicKeyParameter = keyPair.Public + }; } /// @@ -61,12 +74,23 @@ public static EdDsa CreateFromJwk(string jwk) throw new NotImplementedException(); } + public override string KeyExchangeAlgorithm => null; + public override string SignatureAlgorithm => ExtendedSecurityAlgorithms.EdDsa; + public override int KeySize => Parameters.D?.Length ?? Parameters.X?.Length ?? throw new InvalidOperationException("Missing EdDsa key"); + + public override KeySizes[] LegalKeySizes => Parameters.Curve switch + { + ExtendedSecurityAlgorithms.Curves.Ed25519 => new[] { new KeySizes(32, 32, 0) }, + ExtendedSecurityAlgorithms.Curves.Ed448 => new[] { new KeySizes(57, 57, 0) }, + _ => throw new NotSupportedException() + }; + public byte[] Sign(byte[] input) { if (input == null) throw new ArgumentNullException(nameof(input)); var signer = CreateSigner(); - signer.Init(true, CreatePrivateKeyParameter()); + signer.Init(true, PrivateKeyParameter); signer.BlockUpdate(input, 0, input.Length); return signer.GenerateSignature(); @@ -89,28 +113,32 @@ public bool Verify(byte[] input, byte[] signature) if (signature == null) throw new ArgumentNullException(nameof(signature)); var validator = CreateSigner(); - validator.Init(false, CreatePublicKeyParameter()); + validator.Init(false, PublicKeyParameter); validator.BlockUpdate(input, 0, input.Length); return validator.VerifySignature(signature); } - private AsymmetricKeyParameter CreatePrivateKeyParameter() + private static AsymmetricKeyParameter CreatePrivateKeyParameter(EdDsaParameters parameters) { - return Parameters.Curve switch + if (parameters.D == null) return null; + + return parameters.Curve switch { - ExtendedSecurityAlgorithms.Curves.Ed25519 => new Ed25519PrivateKeyParameters(Parameters.D, 0), - ExtendedSecurityAlgorithms.Curves.Ed448 => new Ed448PrivateKeyParameters(Parameters.D, 0), + ExtendedSecurityAlgorithms.Curves.Ed25519 => new Ed25519PrivateKeyParameters(parameters.D), + ExtendedSecurityAlgorithms.Curves.Ed448 => new Ed448PrivateKeyParameters(parameters.D), _ => throw new NotSupportedException() }; } - private AsymmetricKeyParameter CreatePublicKeyParameter() + private static AsymmetricKeyParameter CreatePublicKeyParameter(EdDsaParameters parameters) { - return Parameters.Curve switch + if (parameters.X == null) return null; + + return parameters.Curve switch { - ExtendedSecurityAlgorithms.Curves.Ed25519 => new Ed25519PublicKeyParameters(Parameters.X, 0), - ExtendedSecurityAlgorithms.Curves.Ed448 => new Ed448PublicKeyParameters(Parameters.X, 0), + ExtendedSecurityAlgorithms.Curves.Ed25519 => new Ed25519PublicKeyParameters(parameters.X), + ExtendedSecurityAlgorithms.Curves.Ed448 => new Ed448PublicKeyParameters(parameters.X), _ => throw new NotSupportedException() }; } @@ -124,4 +152,8 @@ private ISigner CreateSigner() _ => throw new NotSupportedException() }; } + + public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan password) => throw new NotImplementedException(); + public override void ImportFromEncryptedPem(ReadOnlySpan input, ReadOnlySpan passwordBytes) => throw new NotImplementedException(); + public override void ImportFromPem(ReadOnlySpan input) => throw new NotImplementedException(); } \ No newline at end of file diff --git a/src/ScottBrady.IdentityModel/Tokens/EdDsaSecurityKey.cs b/src/ScottBrady.IdentityModel/Tokens/EdDsaSecurityKey.cs index b8cc3ab..5af9f01 100644 --- a/src/ScottBrady.IdentityModel/Tokens/EdDsaSecurityKey.cs +++ b/src/ScottBrady.IdentityModel/Tokens/EdDsaSecurityKey.cs @@ -17,9 +17,9 @@ private EdDsaSecurityKey() CryptoProviderFactory.CustomCryptoProvider = new ExtendedCryptoProvider(); } - public EdDsaSecurityKey(EdDsa edDsa) : this() + public EdDsaSecurityKey(EdDsa edDsaCreation) : this() { - EdDsa = edDsa ?? throw new ArgumentNullException(nameof(edDsa)); + EdDsa = edDsaCreation ?? throw new ArgumentNullException(nameof(edDsaCreation)); } [Obsolete("Deprecated in favor of EdDsa constructor")] diff --git a/test/ScottBrady.IdentityModel.Tests/ScottBrady.IdentityModel.Tests.csproj b/test/ScottBrady.IdentityModel.Tests/ScottBrady.IdentityModel.Tests.csproj index e2ce262..1ee1b2f 100644 --- a/test/ScottBrady.IdentityModel.Tests/ScottBrady.IdentityModel.Tests.csproj +++ b/test/ScottBrady.IdentityModel.Tests/ScottBrady.IdentityModel.Tests.csproj @@ -5,6 +5,7 @@ + diff --git a/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaBaseClassTests.cs b/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaBaseClassTests.cs new file mode 100644 index 0000000..b4a25ef --- /dev/null +++ b/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaBaseClassTests.cs @@ -0,0 +1,159 @@ +using System; +using System.Security.Cryptography; +using AutoFixture; +using FluentAssertions; +using ScottBrady.IdentityModel.Crypto; +using ScottBrady.IdentityModel.Tokens; +using Xunit; + +namespace ScottBrady.IdentityModel.Tests.Tokens.EdDSA.AsymmetricAlgorithm; + +public class EdDsaBaseClassTests : EdDsaTestBase +{ + public static TheoryData Keys + => new TheoryData { { _ed25519Key, 32 }, { _ed448Key, 57 } }; + + private static readonly Fixture _fixture = new(); + private static readonly EdDsa _ed25519Key = EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519); + private static readonly EdDsa _ed448Key = EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed448); + + [Theory, MemberData(nameof(Keys))] + public void KeySize_Expect32(EdDsa key, int expectedKeySize) + => key.KeySize.Should().Be(expectedKeySize); + +#pragma warning disable SYSLIB0045 + [Fact] + public void Create_WhenEdDsaCurve_ExpectNull() + => System.Security.Cryptography.AsymmetricAlgorithm.Create(ExtendedSecurityAlgorithms.EdDsa).Should().BeNull(); +#pragma warning restore SYSLIB0045 + +#pragma warning disable SYSLIB0007 + [Fact] + public void Create_ExpectPlatformNotSupportedException() + => Assert.Throws(EdDsa.Create); +#pragma warning restore SYSLIB0007 + + [Theory, MemberData(nameof(Keys))] + public void LegalKeySizes_ExpectCorrectValues(EdDsa key, int keySize) + => key.LegalKeySizes.Should().BeEquivalentTo(new[] { new KeySizes(keySize, keySize, 0) }); + + [Theory, MemberData(nameof(Keys))] + public void SignatureAlgorithm_ExpectEdDSA(EdDsa key, int _) + => key.SignatureAlgorithm.Should().Be(ExtendedSecurityAlgorithms.EdDsa); + + [Theory, MemberData(nameof(Keys))] + public void KeyExchangeAlgorithm_ExpectNull(EdDsa key, int _) + => key.KeyExchangeAlgorithm.Should().BeNull(); + + [Theory, MemberData(nameof(Keys))] + public void FromXmlString_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.FromXmlString("")); + + [Theory, MemberData(nameof(Keys))] + public void ToXmlString_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ToXmlString(true)); + + [Theory, MemberData(nameof(Keys))] + public void ImportEncryptedPkcs8PrivateKey_WithPasswordBytes_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ImportEncryptedPkcs8PrivateKey(Array.Empty(), Array.Empty(), out var _)); + + [Theory, MemberData(nameof(Keys))] + public void ImportEncryptedPkcs8PrivateKey_WithPasswordString_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ImportEncryptedPkcs8PrivateKey(Array.Empty(), Array.Empty(), out var _)); + + [Theory, MemberData(nameof(Keys))] + public void ImportPkcs8PrivateKey_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ImportPkcs8PrivateKey(Array.Empty(), out var _)); + + [Theory, MemberData(nameof(Keys))] + public void ImportSubjectPublicKeyInfo_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ImportSubjectPublicKeyInfo(Array.Empty(), out var _)); + + [Theory, MemberData(nameof(Keys))] + public void ExportEncryptedPkcs8PrivateKey_WithPasswordBytes_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ExportEncryptedPkcs8PrivateKey(Array.Empty(), _fixture.Create())); + + [Theory, MemberData(nameof(Keys))] + public void ExportEncryptedPkcs8PrivateKey_WithPasswordString_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ExportEncryptedPkcs8PrivateKey(Array.Empty(), _fixture.Create())); + + [Theory, MemberData(nameof(Keys))] + public void ExportPkcs8PrivateKey_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(key.ExportPkcs8PrivateKey); + + [Theory, MemberData(nameof(Keys))] + public void ExportSubjectPublicKeyInfo_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(key.ExportSubjectPublicKeyInfo); + + [Theory, MemberData(nameof(Keys))] + public void TryExportEncryptedPkcs8PrivateKey_WithPasswordBytes_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.TryExportEncryptedPkcs8PrivateKey(Array.Empty(), _fixture.Create(), Array.Empty(), out var _)); + + [Theory, MemberData(nameof(Keys))] + public void TryExportEncryptedPkcs8PrivateKey_WithPasswordString_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.TryExportEncryptedPkcs8PrivateKey(Array.Empty(), _fixture.Create(), Array.Empty(), out var _)); + + [Theory, MemberData(nameof(Keys))] + public void TryExportPkcs8PrivateKey_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.TryExportPkcs8PrivateKey(Array.Empty(), out var _)); + + [Theory, MemberData(nameof(Keys))] + public void TryExportSubjectPublicKeyInfo_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.TryExportSubjectPublicKeyInfo(Array.Empty(), out var _)); + + [Theory, MemberData(nameof(Keys))] + public void ImportFromEncryptedPem_WithPasswordString_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ImportFromEncryptedPem(Array.Empty(), Array.Empty())); + + [Theory, MemberData(nameof(Keys))] + public void ImportFromEncryptedPem_WithPasswordBytes_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ImportFromEncryptedPem(Array.Empty(), Array.Empty())); + + [Theory, MemberData(nameof(Keys))] + public void ImportFromPem_WithPasswordBytes_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ImportFromPem(Array.Empty())); + +#if NET8 + [Theory, MemberData(nameof(Keys))] + public void ExportPkcs8PrivateKeyPem_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ExportPkcs8PrivateKeyPem()); + + [Theory, MemberData(nameof(Keys))] + public void ExportEncryptedPkcs8PrivateKeyPem_WithPasswordString_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ExportEncryptedPkcs8PrivateKeyPem(Array.Empty(), _fixture.Create())); + + [Theory, MemberData(nameof(Keys))] + public void ExportEncryptedPkcs8PrivateKeyPem_WithPasswordBytes_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ExportEncryptedPkcs8PrivateKeyPem(Array.Empty(), _fixture.Create())); + + [Theory, MemberData(nameof(Keys))] + public void ExportSubjectPublicKeyInfoPem_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.ExportSubjectPublicKeyInfoPem(); + + [Theory, MemberData(nameof(Keys))] + public void TryExportSubjectPublicKeyInfoPem_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.TryExportSubjectPublicKeyInfoPem(Array.Empty(), out var _)); + + [Theory, MemberData(nameof(Keys))] + public void TryExportPkcs8PrivateKeyPem_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.TryExportPkcs8PrivateKeyPem(Array.Empty(), out var _)); + + [Theory, MemberData(nameof(Keys))] + public void TryExportEncryptedPkcs8PrivateKeyPem_WithPasswordString_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.TryExportEncryptedPkcs8PrivateKeyPem(Array.Empty(), _fixture.Create()), Array.Empty(), out var _)); + + [Theory, MemberData(nameof(Keys))] + public void TryExportEncryptedPkcs8PrivateKeyPem_WithPasswordBytes_ExpectNotImplementedException(EdDsa key, int _) + => Assert.Throws(() => key.TryExportEncryptedPkcs8PrivateKeyPem(Array.Empty(), _fixture.Create()), Array.Empty(), out var _)); +#endif + + [Theory, MemberData(nameof(Keys))] + public void Clear_WhenDisposed_ExpectNoException(EdDsa key, int _) + => key.Clear(); + + [Theory, MemberData(nameof(Keys))] + public void Dispose_WhenDisposed_ExpectNoException(EdDsa key, int _) + => key.Dispose(); + + +} \ No newline at end of file diff --git a/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaCreationTests.cs b/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaCreationTests.cs new file mode 100644 index 0000000..e05307d --- /dev/null +++ b/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaCreationTests.cs @@ -0,0 +1,86 @@ +using System; +using System.Security.Cryptography; +using FluentAssertions; +using Org.BouncyCastle.Crypto.Parameters; +using ScottBrady.IdentityModel.Crypto; +using ScottBrady.IdentityModel.Tokens; +using Xunit; + +namespace ScottBrady.IdentityModel.Tests.Tokens.EdDSA.AsymmetricAlgorithm; + +public class EdDsaCreationTests : EdDsaTestBase +{ + [Fact] + public void FromParameters_WhenParametersAreNull_ExpectArgumentNullException() + => Assert.Throws(() => EdDsa.Create((EdDsaParameters) null)); + + [Fact] + public void FromParameters_WhenParametersDoNotContainKeys_ExpectCryptographicException() + => Assert.Throws(() => EdDsa.Create(new EdDsaParameters(ExtendedSecurityAlgorithms.Curves.Ed25519))); + + [Fact] + public void FromParameters_WhenEd25519PrivateKey_ExpectCorrectParameters() + { + var bcParameters = (Ed25519PrivateKeyParameters)GenerateEd25519KeyPair().Private; + + var parameters = new EdDsaParameters(ExtendedSecurityAlgorithms.Curves.Ed25519) { D = bcParameters.GetEncoded() }; + var key = EdDsa.Create(parameters); + + key.Parameters.Should().Be(parameters); + key.PrivateKeyParameter.Should().NotBeNull(); + key.PrivateKeyParameter.Should().BeOfType(); + key.PrivateKeyParameter.Should().BeEquivalentTo(bcParameters); + key.PublicKeyParameter.Should().BeNull(); + } + + [Fact] + public void FromParameters_WhenEd448PrivateKey_ExpectCorrectParameters() + { + var bcParameters = (Ed448PrivateKeyParameters)GenerateEd448KeyPair().Private; + + var parameters = new EdDsaParameters(ExtendedSecurityAlgorithms.Curves.Ed448) { D = bcParameters.GetEncoded() }; + var key = EdDsa.Create(parameters); + + key.Parameters.Should().Be(parameters); + key.PrivateKeyParameter.Should().NotBeNull(); + key.PrivateKeyParameter.Should().BeOfType(); + key.PrivateKeyParameter.Should().BeEquivalentTo(bcParameters); + key.PublicKeyParameter.Should().BeNull(); + } + + [Fact] + public void FromParameters_WhenEd25519PublicKey_ExpectCorrectParameters() + { + var bcParameters = (Ed25519PublicKeyParameters)GenerateEd25519KeyPair().Public; + + var parameters = new EdDsaParameters(ExtendedSecurityAlgorithms.Curves.Ed25519) { X = bcParameters.GetEncoded() }; + var key = EdDsa.Create(parameters); + + key.Parameters.Should().Be(parameters); + key.PrivateKeyParameter.Should().BeNull(); + key.PublicKeyParameter.Should().NotBeNull(); + key.PublicKeyParameter.Should().BeOfType(); + key.PublicKeyParameter.Should().BeEquivalentTo(bcParameters); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void FromCurve_WhenNullOrWhitespaceCurve_ExpectArgumentNullException(string curve) + => Assert.Throws(() => EdDsa.Create(curve)); + + [Fact] + public void FromCurve_WhenUnsupportedAlgorithm_ExpectNotSupportedException() + => Assert.Throws(() => EdDsa.Create("P-521")); + + [Theory] + [InlineData(ExtendedSecurityAlgorithms.Curves.Ed25519, 32)] + [InlineData(ExtendedSecurityAlgorithms.Curves.Ed448, 57)] + public void FromCurve_WhenEd25519_ExpectCorrectKeyParameters(string curve, int keyLength) + { + var alg = EdDsa.Create(curve); + alg.Parameters.D.Length.Should().Be(keyLength); + alg.Parameters.X.Length.Should().Be(keyLength); + } +} \ No newline at end of file diff --git a/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaSigningTests.cs b/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaSigningTests.cs new file mode 100644 index 0000000..562fe2b --- /dev/null +++ b/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaSigningTests.cs @@ -0,0 +1,55 @@ +using System; +using System.Security.Cryptography; +using FluentAssertions; +using ScottBrady.IdentityModel.Crypto; +using ScottBrady.IdentityModel.Tokens; +using Xunit; + +namespace ScottBrady.IdentityModel.Tests.Tokens.EdDSA.AsymmetricAlgorithm; + +public class EdDsaSigningTests : EdDsaTestBase +{ + [Fact] + public void Sign_WhenInputNull_ExpectArgumentNullException() + => Assert.Throws(() => EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Sign(null)); + + [Fact] + public void Verify_WhenInputNull_ExpectArgumentNullException() + => Assert.Throws(() => EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(null, new byte[32])); + + [Fact] + public void Verify_WhenSignatureNull_ExpectArgumentNullException() + => Assert.Throws(() => EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(new byte[32], null)); + + [Fact] + public void VerifyWithOffsets_WhenSignatureNull_ExpectArgumentNullException() + => Assert.Throws(() => + EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(new byte[32],0,0, null,0,32)); + + [Fact] + public void VerifyWithOffsets_WhenInputNull_ExpectArgumentNullException() + => Assert.Throws(() => + EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(null,0,0, new byte[32],0,32)); + + [Fact] + public void VerifyWithOffsets_WhenInputLengthZero_ExpectArgumentException() + => Assert.Throws(() => + EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(new byte[32],0,0, new byte[32],0,32)); + + [Fact] + public void VerifyWithOffsets_WhenSignatureLengthZero_ExpectArgumentException() + => Assert.Throws(() => + EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(new byte[32],0,32, new byte[32],0,0)); + + [Theory] + [InlineData(ExtendedSecurityAlgorithms.Curves.Ed25519)] + [InlineData(ExtendedSecurityAlgorithms.Curves.Ed448)] + public void SignAndVerify_ExpectValidSignature(string curve) + { + var key = EdDsa.Create(curve); + var input = RandomNumberGenerator.GetBytes(RandomNumberGenerator.GetInt32(1, 3072)); + + var signature = key.Sign(input); + key.Verify(input, signature).Should().BeTrue(); + } +} \ No newline at end of file diff --git a/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaTestBase.cs b/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaTestBase.cs new file mode 100644 index 0000000..de26080 --- /dev/null +++ b/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/AsymmetricAlgorithm/EdDsaTestBase.cs @@ -0,0 +1,24 @@ +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace ScottBrady.IdentityModel.Tests.Tokens.EdDSA.AsymmetricAlgorithm; + +public abstract class EdDsaTestBase +{ + protected static AsymmetricCipherKeyPair GenerateEd25519KeyPair() + { + var keyPairGenerator = new Ed25519KeyPairGenerator(); + keyPairGenerator.Init(new Ed25519KeyGenerationParameters(new SecureRandom())); + return keyPairGenerator.GenerateKeyPair(); + } + + protected static AsymmetricCipherKeyPair GenerateEd448KeyPair() + { + var keyPairGenerator = new Ed448KeyPairGenerator(); + keyPairGenerator.Init(new Ed448KeyGenerationParameters(new SecureRandom())); + return keyPairGenerator.GenerateKeyPair(); + } + +} \ No newline at end of file diff --git a/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/EdDsaSignatureProviderTests.cs b/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/EdDsaSignatureProviderTests.cs index 7b400a2..3acb966 100644 --- a/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/EdDsaSignatureProviderTests.cs +++ b/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/EdDsaSignatureProviderTests.cs @@ -1,4 +1,3 @@ -using System; using System.Text; using FluentAssertions; using Microsoft.IdentityModel.Tokens; diff --git a/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/EdDsaTests.cs b/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/EdDsaTests.cs deleted file mode 100644 index 8322f9b..0000000 --- a/test/ScottBrady.IdentityModel.Tests/Tokens/EdDSA/EdDsaTests.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using FluentAssertions; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Generators; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Security; -using ScottBrady.IdentityModel.Crypto; -using ScottBrady.IdentityModel.Tokens; -using Xunit; - -namespace ScottBrady.IdentityModel.Tests.Tokens.EdDSA; - -public class EdDsaTests -{ - [Fact] - public void Create_FromParameters_WhenParametersAreNull_ExpectArgumentNullException() - => Assert.Throws(() => EdDsa.Create((EdDsaParameters) null)); - - [Fact] - public void Create_FromParameters_ExpectCorrectParameters() - { - var parameters = new EdDsaParameters(ExtendedSecurityAlgorithms.Curves.Ed448) {D = new byte[57]}; - var key = EdDsa.Create(parameters); - key.Parameters.Should().Be(parameters); - } - - [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData(" ")] - public void Create_WhenNullOrWhitespaceCurve_ExpectArgumentNullException(string curve) - => Assert.Throws(() => EdDsa.Create(curve)); - - [Fact] - public void Create_WhenUnsupportedAlgorithm_ExpectNotSupportedException() - => Assert.Throws(() => EdDsa.Create("P-521")); - - [Fact] - public void Create_WhenEd25519_ExpectCorrectKeyParameters() - { - var alg = EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519); - alg.Parameters.D.Length.Should().Be(32); - alg.Parameters.X.Length.Should().Be(32); - } - - [Fact] - public void Create_WhenEd448_ExpectCorrectKeyParameters() - { - var alg = EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed448); - alg.Parameters.D.Length.Should().Be(57); - alg.Parameters.X.Length.Should().Be(57); - } - - [Fact] - public void Sign_WhenInputNull_ExpectArgumentNullException() - => Assert.Throws(() => EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Sign(null)); - - [Fact] - public void Verify_WhenInputNull_ExpectArgumentNullException() - => Assert.Throws(() => EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(null, new byte[32])); - - [Fact] - public void Verify_WhenSignatureNull_ExpectArgumentNullException() - => Assert.Throws(() => EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(new byte[32], null)); - - [Fact] - public void VerifyWithOffsets_WhenSignatureNull_ExpectArgumentNullException() - => Assert.Throws(() => - EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(new byte[32],0,0, null,0,32)); - - [Fact] - public void VerifyWithOffsets_WhenInputNull_ExpectArgumentNullException() - => Assert.Throws(() => - EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(null,0,0, new byte[32],0,32)); - - [Fact] - public void VerifyWithOffsets_WhenInputLengthZero_ExpectArgumentException() - => Assert.Throws(() => - EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(new byte[32],0,0, new byte[32],0,32)); - - [Fact] - public void VerifyWithOffsets_WhenSignatureLengthZero_ExpectArgumentException() - => Assert.Throws(() => - EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519).Verify(new byte[32],0,32, new byte[32],0,0)); - - private static AsymmetricCipherKeyPair GenerateEd25519KeyPair() - { - var keyPairGenerator = new Ed25519KeyPairGenerator(); - keyPairGenerator.Init(new Ed25519KeyGenerationParameters(new SecureRandom())); - return keyPairGenerator.GenerateKeyPair(); - } - - private static AsymmetricCipherKeyPair GenerateEd448KeyPair() - { - var keyPairGenerator = new Ed448KeyPairGenerator(); - keyPairGenerator.Init(new Ed448KeyGenerationParameters(new SecureRandom())); - return keyPairGenerator.GenerateKeyPair(); - } -} \ No newline at end of file diff --git a/test/ScottBrady.IdentityModel.Tests/Tokens/ExtendedJsonWebKeyConverterTests.cs b/test/ScottBrady.IdentityModel.Tests/Tokens/ExtendedJsonWebKeyConverterTests.cs index 80cc635..156724a 100644 --- a/test/ScottBrady.IdentityModel.Tests/Tokens/ExtendedJsonWebKeyConverterTests.cs +++ b/test/ScottBrady.IdentityModel.Tests/Tokens/ExtendedJsonWebKeyConverterTests.cs @@ -14,7 +14,7 @@ public void JsonWebKeyConverter_ConvertFromEdDsaSecurityKey() var jwk = ExtendedJsonWebKeyConverter.ConvertFromEdDsaSecurityKey(originKey); Assert.NotNull(jwk); Assert.Equal(ExtendedSecurityAlgorithms.Curves.Ed25519, jwk.Crv); - Assert.Equal(ExtendedJsonWebAlgorithmsKeyTypes.ECDH, jwk.Kty); + Assert.Equal(ExtendedSecurityAlgorithms.KeyTypes.Ecdh, jwk.Kty); Assert.Equal(ExtendedSecurityAlgorithms.EdDsa, jwk.Alg); Assert.NotNull(jwk.D); Assert.NotNull(jwk.X);