-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Expanded support for Ed25519 with JWT signing
- Loading branch information
1 parent
795e1b3
commit dd3a662
Showing
10 changed files
with
358 additions
and
5 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
using System.Runtime.CompilerServices; | ||
|
||
[assembly:InternalsVisibleTo("ScottBrady.IdentityModel.Tests")] |
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
36 changes: 36 additions & 0 deletions
36
src/ScottBrady.IdentityModel/Tokens/EdDsaSignatureProvider.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,36 @@ | ||
using Microsoft.IdentityModel.Tokens; | ||
using Org.BouncyCastle.Crypto.Signers; | ||
|
||
namespace ScottBrady.IdentityModel.Tokens | ||
{ | ||
internal class EdDsaSignatureProvider : SignatureProvider | ||
{ | ||
private readonly EdDsaSecurityKey edDsaKey; | ||
|
||
public EdDsaSignatureProvider(EdDsaSecurityKey key, string algorithm) | ||
: base(key, algorithm) | ||
{ | ||
edDsaKey = key; | ||
} | ||
|
||
protected override void Dispose(bool disposing) { } | ||
|
||
public override byte[] Sign(byte[] input) | ||
{ | ||
var signer = new Ed25519Signer(); | ||
signer.Init(true, edDsaKey.KeyParameters); | ||
signer.BlockUpdate(input, 0, input.Length); | ||
|
||
return signer.GenerateSignature(); | ||
} | ||
|
||
public override bool Verify(byte[] input, byte[] signature) | ||
{ | ||
var validator = new Ed25519Signer(); | ||
validator.Init(false, edDsaKey.KeyParameters); | ||
validator.BlockUpdate(input, 0, input.Length); | ||
|
||
return validator.VerifySignature(signature); | ||
} | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
src/ScottBrady.IdentityModel/Tokens/ExtendedCryptoProvider.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,28 @@ | ||
using System; | ||
using Microsoft.IdentityModel.Tokens; | ||
using ScottBrady.IdentityModel.Tokens; | ||
|
||
namespace ScottBrady.IdentityModel.Crypto | ||
{ | ||
internal class ExtendedCryptoProvider : ICryptoProvider | ||
{ | ||
public bool IsSupportedAlgorithm(string algorithm, params object[] args) | ||
=> algorithm == ExtendedSecurityAlgorithms.EdDsa; | ||
|
||
public object Create(string algorithm, params object[] args) | ||
{ | ||
if (algorithm == ExtendedSecurityAlgorithms.EdDsa && args[0] is EdDsaSecurityKey key) | ||
{ | ||
return new EdDsaSignatureProvider(key, algorithm); | ||
} | ||
|
||
throw new NotSupportedException(); | ||
} | ||
|
||
public void Release(object cryptoInstance) | ||
{ | ||
if (cryptoInstance is IDisposable disposableObject) | ||
disposableObject.Dispose(); | ||
} | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
test/ScottBrady.IdentityModel.Tests/Tokens/EdDsaSecurityKeyTests.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,61 @@ | ||
using System; | ||
using FluentAssertions; | ||
using Microsoft.IdentityModel.Tokens; | ||
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 | ||
{ | ||
public class EdDsaSecurityKeyTests | ||
{ | ||
[Fact] | ||
public void ctor_WhenKeyParametersAreNull_ExpectArgumentNullException() | ||
=> Assert.Throws<ArgumentNullException>(() => new EdDsaSecurityKey((Ed25519PublicKeyParameters) null)); | ||
|
||
[Fact] | ||
public void ctor_WhenEd25519PrivateKey_ExpectKeySetAndCorrectCurve() | ||
{ | ||
var keyPair = GenerateEd25519KeyPair(); | ||
|
||
var securityKey = new EdDsaSecurityKey((Ed25519PrivateKeyParameters) keyPair.Private); | ||
|
||
securityKey.CryptoProviderFactory.CustomCryptoProvider.Should().BeOfType<ExtendedCryptoProvider>(); | ||
securityKey.KeyParameters.Should().Be(keyPair.Private); | ||
securityKey.Curve.Should().Be(ExtendedSecurityAlgorithms.Curves.Ed25519); | ||
securityKey.PrivateKeyStatus.Should().Be(PrivateKeyStatus.Exists); | ||
|
||
#pragma warning disable 618 | ||
securityKey.HasPrivateKey.Should().BeTrue(); | ||
#pragma warning restore 618 | ||
} | ||
|
||
[Fact] | ||
public void ctor_WhenEd25519PublicKey_ExpectKeySetAndCorrectCurve() | ||
{ | ||
var keyPair = GenerateEd25519KeyPair(); | ||
|
||
var securityKey = new EdDsaSecurityKey((Ed25519PublicKeyParameters) keyPair.Public); | ||
|
||
securityKey.CryptoProviderFactory.CustomCryptoProvider.Should().BeOfType<ExtendedCryptoProvider>(); | ||
securityKey.KeyParameters.Should().Be(keyPair.Public); | ||
securityKey.Curve.Should().Be(ExtendedSecurityAlgorithms.Curves.Ed25519); | ||
securityKey.PrivateKeyStatus.Should().Be(PrivateKeyStatus.DoesNotExist); | ||
|
||
#pragma warning disable 618 | ||
securityKey.HasPrivateKey.Should().BeFalse(); | ||
#pragma warning restore 618 | ||
} | ||
|
||
private static AsymmetricCipherKeyPair GenerateEd25519KeyPair() | ||
{ | ||
var keyPairGenerator = new Ed25519KeyPairGenerator(); | ||
keyPairGenerator.Init(new Ed25519KeyGenerationParameters(new SecureRandom())); | ||
return keyPairGenerator.GenerateKeyPair(); | ||
} | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
test/ScottBrady.IdentityModel.Tests/Tokens/EdDsaSignatureProviderTests.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,70 @@ | ||
using FluentAssertions; | ||
using Microsoft.IdentityModel.Tokens; | ||
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 | ||
{ | ||
public class EdDsaSignatureProviderTests | ||
{ | ||
// privateKey = "FU1F1QTjYwfB-xkO6aknnBifE_Ywa94U04xpd-XJfBs" | ||
|
||
[Fact] | ||
public void ctor_ExpectPropertiesSet() | ||
{ | ||
var keyPairGenerator = new Ed25519KeyPairGenerator(); | ||
keyPairGenerator.Init(new Ed25519KeyGenerationParameters(new SecureRandom())); | ||
var keyPair = keyPairGenerator.GenerateKeyPair(); | ||
|
||
var expectedSecurityKey = new EdDsaSecurityKey((Ed25519PublicKeyParameters) keyPair.Public); | ||
var expectedAlgorithm = ExtendedSecurityAlgorithms.EdDsa; | ||
|
||
var provider = new EdDsaSignatureProvider(expectedSecurityKey, expectedAlgorithm); | ||
|
||
provider.Key.Should().Be(expectedSecurityKey); | ||
provider.Algorithm.Should().Be(expectedAlgorithm); | ||
} | ||
|
||
[Fact] | ||
public void Sign_WhenSigningWithEd25519Curve_ExpectCorrectSignature() | ||
{ | ||
const string plaintext = | ||
"eyJraWQiOiIxMjMiLCJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJ5b3UiLCJzdWIiOiJib2IiLCJpc3MiOiJtZSIsImV4cCI6MTU5MDg0MTg4N30"; | ||
const string expectedSignature = | ||
"OyBxBr344Ny-0vRCeEMLSnuEO1IecybvJBivrjum4d-dgN5WLnEAGAO43MlZeRGn1F3fRXO_xlYot68PtDuiAA"; | ||
|
||
const string privateKey = "FU1F1QTjYwfB-xkO6aknnBifE_Ywa94U04xpd-XJfBs"; | ||
var edDsaSecurityKey = new EdDsaSecurityKey(new Ed25519PrivateKeyParameters(Base64UrlEncoder.DecodeBytes(privateKey), 0)); | ||
|
||
var signatureProvider = new EdDsaSignatureProvider(edDsaSecurityKey, ExtendedSecurityAlgorithms.EdDsa); | ||
|
||
var signature = signatureProvider.Sign(System.Text.Encoding.UTF8.GetBytes(plaintext)); | ||
|
||
signature.Should().BeEquivalentTo(Base64UrlEncoder.DecodeBytes(expectedSignature)); | ||
} | ||
|
||
[Fact] | ||
public void Verify_WhenJwtSignedWithEd25519Curve_ExpectTrue() | ||
{ | ||
const string plaintext = | ||
"eyJraWQiOiIxMjMiLCJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9.eyJhdWQiOiJ5b3UiLCJzdWIiOiJib2IiLCJpc3MiOiJtZSIsImV4cCI6MTU5MDg0MTg4N30"; | ||
const string signature = | ||
"OyBxBr344Ny-0vRCeEMLSnuEO1IecybvJBivrjum4d-dgN5WLnEAGAO43MlZeRGn1F3fRXO_xlYot68PtDuiAA"; | ||
|
||
const string publicKey = "60mR98SQlHUSeLeIu7TeJBTLRG10qlcDLU4AJjQdqMQ"; | ||
var edDsaSecurityKey = new EdDsaSecurityKey(new Ed25519PublicKeyParameters(Base64UrlEncoder.DecodeBytes(publicKey), 0)); | ||
|
||
var signatureProvider = new EdDsaSignatureProvider(edDsaSecurityKey, ExtendedSecurityAlgorithms.EdDsa); | ||
|
||
var isValidSignature = signatureProvider.Verify( | ||
System.Text.Encoding.UTF8.GetBytes(plaintext), | ||
Base64UrlEncoder.DecodeBytes(signature)); | ||
|
||
isValidSignature.Should().BeTrue(); | ||
} | ||
} | ||
} |
82 changes: 82 additions & 0 deletions
82
test/ScottBrady.IdentityModel.Tests/Tokens/ExtendedCryptoProviderTests.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 @@ | ||
using System; | ||
using System.IO; | ||
using System.Security.Cryptography; | ||
using FluentAssertions; | ||
using Microsoft.IdentityModel.Tokens; | ||
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 | ||
{ | ||
public class ExtendedCryptoProviderTests | ||
{ | ||
private ExtendedCryptoProvider sut = new ExtendedCryptoProvider(); | ||
|
||
[Theory] | ||
[InlineData("eddsa")] | ||
[InlineData("RS256")] | ||
[InlineData("EDDSA")] | ||
public void IsSupportedAlgorithm_WhenNotSupportedAlgorithm_ExpectFalse(string algorithm) | ||
=> sut.IsSupportedAlgorithm(algorithm); | ||
|
||
[Theory] | ||
[InlineData(ExtendedSecurityAlgorithms.EdDsa)] | ||
public void IsSupportedAlgorithm_WhenSupportedAlgorithm_ExpectTrue(string algorithm) | ||
=> sut.IsSupportedAlgorithm(algorithm); | ||
|
||
[Fact] | ||
public void Release_WhenObjectImplementsIDisposable_ExpectObjectDisposed() | ||
{ | ||
var memoryStream = new MemoryStream(); | ||
sut.Release(memoryStream); | ||
Assert.Throws<ObjectDisposedException>(() => memoryStream.Read(Span<byte>.Empty)); | ||
} | ||
|
||
[Fact] | ||
public void Release_WhenObjectDoesNotImplementIDisposable_ExpectNoOp() | ||
{ | ||
var uri = new Uri("urn:test"); | ||
sut.Release(uri); | ||
} | ||
|
||
[Fact] | ||
public void Create_WhenAlgorithmIsNotEdDsaButHasEdDsaSecurityKey_ExpectNotSupportedException() | ||
{ | ||
var keyPairGenerator = new Ed25519KeyPairGenerator(); | ||
keyPairGenerator.Init(new Ed25519KeyGenerationParameters(new SecureRandom())); | ||
var keyPair = keyPairGenerator.GenerateKeyPair(); | ||
|
||
var securityKey = new EdDsaSecurityKey((Ed25519PublicKeyParameters) keyPair.Public); | ||
|
||
Assert.Throws<NotSupportedException>(() => sut.Create(SecurityAlgorithms.RsaSha256, securityKey)); | ||
} | ||
|
||
[Fact] | ||
public void Create_WhenAlgorithmIsEdDsaButIsNotEdDsaSecurityKey_ExpectNotSupportedException() | ||
{ | ||
var securityKey = new RsaSecurityKey(RSA.Create()); | ||
|
||
Assert.Throws<NotSupportedException>(() => sut.Create(ExtendedSecurityAlgorithms.EdDsa, securityKey)); | ||
} | ||
|
||
[Fact] | ||
public void Create_WhenAlgorithmIsEdDsaWithEdDsaSecurityKey_ExpectEdDsaSignatureProvider() | ||
{ | ||
var keyPairGenerator = new Ed25519KeyPairGenerator(); | ||
keyPairGenerator.Init(new Ed25519KeyGenerationParameters(new SecureRandom())); | ||
var keyPair = keyPairGenerator.GenerateKeyPair(); | ||
|
||
var securityKey = new EdDsaSecurityKey((Ed25519PublicKeyParameters) keyPair.Public); | ||
|
||
var signatureProvider = sut.Create(ExtendedSecurityAlgorithms.EdDsa, securityKey); | ||
|
||
var edDsaSignatureProvider = Assert.IsType<EdDsaSignatureProvider>(signatureProvider); | ||
edDsaSignatureProvider.Algorithm.Should().Be(ExtendedSecurityAlgorithms.EdDsa); | ||
edDsaSignatureProvider.Key.Should().Be(securityKey); | ||
} | ||
} | ||
} |
Oops, something went wrong.