diff --git a/src/MaksIT.Core.Tests/Security/JwkGeneratorTests.cs b/src/MaksIT.Core.Tests/Security/JwkGeneratorTests.cs
index bf10eeb..d336ced 100644
--- a/src/MaksIT.Core.Tests/Security/JwkGeneratorTests.cs
+++ b/src/MaksIT.Core.Tests/Security/JwkGeneratorTests.cs
@@ -10,16 +10,16 @@ public class JwkGeneratorTests
var result = JwkGenerator.TryGenerateRsa(2048, false, null, null, null, out var jwk, out var errorMessage);
Assert.True(result, errorMessage);
Assert.NotNull(jwk);
- Assert.Equal(JwkKeyType.Rsa.Name, jwk.Kty);
- Assert.NotNull(jwk.N);
- Assert.NotNull(jwk.E);
- Assert.Null(jwk.D);
- Assert.Null(jwk.P);
- Assert.Null(jwk.Q);
- Assert.Null(jwk.DP);
- Assert.Null(jwk.DQ);
- Assert.Null(jwk.QI);
- Assert.False(string.IsNullOrWhiteSpace(jwk.Kid));
+ Assert.Equal(JwkKeyType.Rsa.Name, jwk.KeyType);
+ Assert.NotNull(jwk.RsaModulus);
+ Assert.NotNull(jwk.RsaExponent);
+ Assert.Null(jwk.PrivateKey);
+ Assert.Null(jwk.RsaFirstPrimeFactor);
+ Assert.Null(jwk.RsaSecondPrimeFactor);
+ Assert.Null(jwk.RsaFirstFactorCRTExponent);
+ Assert.Null(jwk.RsaSecondFactorCRTExponent);
+ Assert.Null(jwk.RsaFirstCRTCoefficient);
+ Assert.False(string.IsNullOrWhiteSpace(jwk.KeyId));
}
[Fact]
@@ -28,13 +28,13 @@ public class JwkGeneratorTests
var result = JwkGenerator.TryGenerateRsa(2048, true, null, null, null, out var jwk, out var errorMessage);
Assert.True(result, errorMessage);
Assert.NotNull(jwk);
- Assert.Equal(JwkKeyType.Rsa.Name, jwk.Kty);
- Assert.NotNull(jwk.D);
- Assert.NotNull(jwk.P);
- Assert.NotNull(jwk.Q);
- Assert.NotNull(jwk.DP);
- Assert.NotNull(jwk.DQ);
- Assert.NotNull(jwk.QI);
+ Assert.Equal(JwkKeyType.Rsa.Name, jwk.KeyType);
+ Assert.NotNull(jwk.PrivateKey);
+ Assert.NotNull(jwk.RsaFirstPrimeFactor);
+ Assert.NotNull(jwk.RsaSecondPrimeFactor);
+ Assert.NotNull(jwk.RsaFirstFactorCRTExponent);
+ Assert.NotNull(jwk.RsaSecondFactorCRTExponent);
+ Assert.NotNull(jwk.RsaFirstCRTCoefficient);
}
[Theory]
@@ -47,12 +47,12 @@ public class JwkGeneratorTests
var result = JwkGenerator.TryGenerateEc(curveObj, false, null, null, null, out var jwk, out var errorMessage);
Assert.True(result, errorMessage);
Assert.NotNull(jwk);
- Assert.Equal(JwkKeyType.Ec.Name, jwk.Kty);
- Assert.Equal(curve, jwk.Crv);
- Assert.NotNull(jwk.X);
- Assert.NotNull(jwk.Y);
- Assert.Null(jwk.D_EC);
- Assert.False(string.IsNullOrWhiteSpace(jwk.Kid));
+ Assert.Equal(JwkKeyType.Ec.Name, jwk.KeyType);
+ Assert.Equal(curve, jwk.EcCurve);
+ Assert.NotNull(jwk.EcX);
+ Assert.NotNull(jwk.EcY);
+ Assert.Null(jwk.PrivateKey);
+ Assert.False(string.IsNullOrWhiteSpace(jwk.KeyId));
}
[Theory]
@@ -65,9 +65,9 @@ public class JwkGeneratorTests
var result = JwkGenerator.TryGenerateEc(curveObj, true, null, null, null, out var jwk, out var errorMessage);
Assert.True(result, errorMessage);
Assert.NotNull(jwk);
- Assert.Equal(JwkKeyType.Ec.Name, jwk.Kty);
- Assert.Equal(curve, jwk.Crv);
- Assert.NotNull(jwk.D_EC);
+ Assert.Equal(JwkKeyType.Ec.Name, jwk.KeyType);
+ Assert.Equal(curve, jwk.EcCurve);
+ Assert.NotNull(jwk.PrivateKey);
}
[Fact]
@@ -76,9 +76,9 @@ public class JwkGeneratorTests
var result = JwkGenerator.TryGenerateOct(256, null, null, null, out var jwk, out var errorMessage);
Assert.True(result, errorMessage);
Assert.NotNull(jwk);
- Assert.Equal(JwkKeyType.Oct.Name, jwk.Kty);
- Assert.NotNull(jwk.K);
- Assert.False(string.IsNullOrWhiteSpace(jwk.Kid));
+ Assert.Equal(JwkKeyType.Oct.Name, jwk.KeyType);
+ Assert.NotNull(jwk.SymmetricKey);
+ Assert.False(string.IsNullOrWhiteSpace(jwk.KeyId));
}
[Fact]
@@ -102,6 +102,6 @@ public class JwkGeneratorTests
Assert.True(result2, errorMessage2);
Assert.NotNull(jwk1);
Assert.NotNull(jwk2);
- Assert.NotEqual(jwk1.Kid, jwk2.Kid);
+ Assert.NotEqual(jwk1.KeyId, jwk2.KeyId);
}
}
diff --git a/src/MaksIT.Core/MaksIT.Core.csproj b/src/MaksIT.Core/MaksIT.Core.csproj
index ee16bd0..416491f 100644
--- a/src/MaksIT.Core/MaksIT.Core.csproj
+++ b/src/MaksIT.Core/MaksIT.Core.csproj
@@ -8,7 +8,7 @@
MaksIT.Core
- 1.5.4
+ 1.5.6
Maksym Sadovnychyy
MAKS-IT
MaksIT.Core
diff --git a/src/MaksIT.Core/Security/JWK/Base64UrlUtility.cs b/src/MaksIT.Core/Security/JWK/Base64UrlUtility.cs
index e4ce427..10e5551 100644
--- a/src/MaksIT.Core/Security/JWK/Base64UrlUtility.cs
+++ b/src/MaksIT.Core/Security/JWK/Base64UrlUtility.cs
@@ -1,7 +1,6 @@
-using System;
-using System.Buffers;
using System.Text;
+
namespace MaksIT.Core.Security.JWK;
///
@@ -14,8 +13,11 @@ public static class Base64UrlUtility
///
public static string Encode(byte[] data)
{
- if (data == null) throw new ArgumentNullException(nameof(data));
+ if (data == null)
+ throw new ArgumentNullException(nameof(data));
+
string base64 = Convert.ToBase64String(data);
+
return base64.TrimEnd('=')
.Replace('+', '-')
.Replace('/', '_');
@@ -26,7 +28,9 @@ public static class Base64UrlUtility
///
public static string Encode(string value)
{
- if (value == null) throw new ArgumentNullException(nameof(value));
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+
return Encode(Encoding.UTF8.GetBytes(value));
}
@@ -35,13 +39,17 @@ public static class Base64UrlUtility
///
public static byte[] Decode(string base64Url)
{
- if (base64Url == null) throw new ArgumentNullException(nameof(base64Url));
+ if (base64Url == null)
+ throw new ArgumentNullException(nameof(base64Url));
+
string padded = base64Url.Replace('-', '+').Replace('_', '/');
+
switch (base64Url.Length % 4)
{
case 2: padded += "=="; break;
case 3: padded += "="; break;
}
+
return Convert.FromBase64String(padded);
}
diff --git a/src/MaksIT.Core/Security/JWK/Jwk.cs b/src/MaksIT.Core/Security/JWK/Jwk.cs
index 97bc897..b9920a9 100644
--- a/src/MaksIT.Core/Security/JWK/Jwk.cs
+++ b/src/MaksIT.Core/Security/JWK/Jwk.cs
@@ -3,71 +3,172 @@
namespace MaksIT.Core.Security.JWK;
-///
-/// Standard JWK class supporting RSA, EC, and octet keys.
-///
+
public class Jwk {
- // Common fields
- [JsonPropertyName("kty")]
- public string? Kty { get; set; }
+ #region Common fields
+ ///
+ /// "kty" (Key Type) Parameter
+ ///
+ /// The "kty" (key type) parameter identifies the cryptographic algorithm
+ /// family used with the key, such as "RSA" or "EC".
+ ///
+ ///
+ [JsonPropertyName("kty")]
+ public string? KeyType { get; set; }
- [JsonPropertyName("kid")]
- public string? Kid { get; set; }
+ ///
+ /// "kid" (Key ID) Parameter
+ ///
+ /// The "kid" (key ID) parameter is used to match a specific key. This
+ /// is used, for instance, to choose among a set of keys within a JWK Set
+ /// during key rollover. The structure of the "kid" value is
+ /// unspecified.
+ ///
+ ///
+ [JsonPropertyName("kid")]
+ public string? KeyId { get; set; }
- [JsonPropertyName("alg")]
- public string? Alg { get; set; }
+ ///
+ /// "alg" (Algorithm) Parameter
+ ///
+ /// The "alg" (algorithm) parameter identifies the algorithm intended for
+ /// use with the key.
+ ///
+ ///
+ [JsonPropertyName("alg")]
+ public string? Algorithm { get; set; }
- [JsonPropertyName("use")]
- public string? Use { get; set; }
+ ///
+ /// "use" (Public Key Use) Parameter
+ ///
+ /// The "use" (public key use) parameter identifies the intended use of
+ /// the public key. The "use" parameter is employed to indicate whether
+ /// a public key is used for encrypting data or verifying the signature
+ /// on data.
+ ///
+ ///
+ [JsonPropertyName("use")]
+ public string? KeyUse { get; set; }
- [JsonPropertyName("key_ops")]
- public string[]? KeyOps { get; set; }
+ ///
+ /// "key_ops" (Key Operations) Parameter
+ ///
+ /// The "key_ops" (key operations) parameter identifies the operation(s) for which the key is intended to be used.
+ ///
+ ///
+ [JsonPropertyName("key_ops")]
+ public string[]? KeyOperations { get; set; }
+ #endregion
- // RSA fields
- [JsonPropertyName("n")]
- public string? N { get; set; } // Modulus
+ #region RSA fields
+ ///
+ /// The modulus value for the public RSA key. It is represented as the Base64URL encoding of value's big endian representation.
+ ///
+ [JsonPropertyName("n")]
+ public string? RsaModulus { get; set; }
- [JsonPropertyName("e")]
- public string? E { get; set; } // Exponent
+ ///
+ /// The exponent value for the public RSA key. It is represented as the Base64URL encoding of value's big endian representation.
+ ///
+ [JsonPropertyName("e")]
+ public string? RsaExponent { get; set; }
- [JsonPropertyName("d")]
- public string? D { get; set; } // Private exponent
+ ///
+ /// The first prime factor. It is represented as the Base64URL encoding of the value's big endian representation.
+ ///
+ [JsonPropertyName("p")]
+ public string? RsaFirstPrimeFactor { get; set; }
- [JsonPropertyName("p")]
- public string? P { get; set; }
+ ///
+ /// The second prime factor. It is represented as the Base64URL encoding of the value's big endian representation.
+ ///
+ [JsonPropertyName("q")]
+ public string? RsaSecondPrimeFactor { get; set; }
- [JsonPropertyName("q")]
- public string? Q { get; set; }
+ ///
+ /// The first factor Chinese Remainder Theorem exponent. It is represented as the Base64URL encoding of the value's big endian representation.
+ ///
+ [JsonPropertyName("dp")]
+ public string? RsaFirstFactorCRTExponent { get; set; }
- [JsonPropertyName("dp")]
- public string? DP { get; set; }
+ ///
+ /// The second factor Chinese Remainder Theorem exponent. It is represented as the Base64URL encoding of the value's big endian representation.
+ ///
+ [JsonPropertyName("dq")]
+ public string? RsaSecondFactorCRTExponent { get; set; }
- [JsonPropertyName("dq")]
- public string? DQ { get; set; }
+ ///
+ /// The first Chinese Remainder Theorem coefficient. It is represented as the Base64URL encoding of the value's big endian representation.
+ ///
+ [JsonPropertyName("qi")]
+ public string? RsaFirstCRTCoefficient { get; set; }
- [JsonPropertyName("qi")]
- public string? QI { get; set; }
+ ///
+ /// The other primes information, should they exist, null or an empty list if not specified.
+ ///
+ [JsonPropertyName("oth")]
+ public List? RsaOtherPrimesInfo { get; set; }
+ #endregion
- // EC fields
- [JsonPropertyName("crv")]
- public string? Crv { get; set; }
+ #region EC fields
+ ///
+ /// The "crv" (Curve) parameter identifies the cryptographic curve used with the key.
+ ///
+ [JsonPropertyName("crv")]
+ public string? EcCurve { get; set; }
- [JsonPropertyName("x")]
- public string? X { get; set; }
+ ///
+ /// The "x" coordinate for the EC public key. It is represented as the Base64URL encoding of the coordinate's big endian representation.
+ ///
+ [JsonPropertyName("x")]
+ public string? EcX { get; set; }
- [JsonPropertyName("y")]
- public string? Y { get; set; }
+ ///
+ /// The "y" coordinate for the EC public key. It is represented as the Base64URL encoding of the coordinate's big endian representation.
+ ///
+ [JsonPropertyName("y")]
+ public string? EcY { get; set; }
+ #endregion
- [JsonPropertyName("d_ec")]
- public string? D_EC { get; set; } // EC private key
+ #region Private Key field
+ ///
+ /// The private key value ("d"). Used for RSA (private exponent) and EC (private key).
+ /// RFC 7518 uses "d" for both.
+ ///
+ [JsonPropertyName("d")]
+ public string? PrivateKey { get; set; }
+ #endregion
- // Symmetric (octet) fields
- [JsonPropertyName("k")]
- public string? K { get; set; }
+ #region Symmetric (octet) fields
+ ///
+ /// The symmetric (octet) key value. It is represented as the Base64URL encoding of the value's big endian representation.
+ ///
+ [JsonPropertyName("k")]
+ public string? SymmetricKey { get; set; }
+ #endregion
+}
- // Backward compatibility for old code
- [JsonIgnore]
- public string? Exponent { get => E; set => E = value; }
- [JsonIgnore]
- public string? Modulus { get => N; set => N = value; }
+///
+/// Represents an entry in the 'oth' (Other Primes Info) parameter for multi-prime RSA keys.
+///
+public class OtherPrimeInfo {
+ #region OtherPrimeInfo fields
+ ///
+ /// The value of the other prime factor.
+ ///
+ [JsonPropertyName("r")]
+ public string? PrimeFactor { get; set; }
+
+ ///
+ /// The CRT exponent of the other prime factor.
+ ///
+ [JsonPropertyName("d")]
+ public string? FactorCRTExponent { get; set; }
+
+ ///
+ /// The CRT coefficient of the other prime factor.
+ ///
+ [JsonPropertyName("t")]
+ public string? FactorCRTCoefficient { get; set; }
+ #endregion
}
\ No newline at end of file
diff --git a/src/MaksIT.Core/Security/JWK/JwkGenerator.cs b/src/MaksIT.Core/Security/JWK/JwkGenerator.cs
index b842e05..caa3119 100644
--- a/src/MaksIT.Core/Security/JWK/JwkGenerator.cs
+++ b/src/MaksIT.Core/Security/JWK/JwkGenerator.cs
@@ -4,10 +4,11 @@ using System.Text.Json.Serialization;
using System.Diagnostics.CodeAnalysis;
using MaksIT.Core.Extensions;
+
namespace MaksIT.Core.Security.JWK;
///
-/// Provides utilities for JWK (JSON Web Key) operations, including RFC 7638 thumbprint computation and key generation.
+/// Provides utilities for JWK (JSON Web Key) operations, including RFC7638 thumbprint computation and key generation.
///
public static class JwkGenerator {
public static bool TryGenerateRsa(int keySize, bool includePrivate, JwkAlgorithm? alg, string? use, string[]? keyOps, [NotNullWhen(true)] out Jwk? jwk, [NotNullWhen(false)] out string? errorMessage) {
@@ -15,7 +16,8 @@ public static class JwkGenerator {
jwk = GenerateRsa(keySize, includePrivate, alg, use, keyOps);
errorMessage = null;
return true;
- } catch (Exception ex) {
+ }
+ catch (Exception ex) {
jwk = null;
errorMessage = ex.Message;
return false;
@@ -27,7 +29,8 @@ public static class JwkGenerator {
jwk = GenerateEc(curve, includePrivate, alg, use, keyOps);
errorMessage = null;
return true;
- } catch (Exception ex) {
+ }
+ catch (Exception ex) {
jwk = null;
errorMessage = ex.Message;
return false;
@@ -39,7 +42,8 @@ public static class JwkGenerator {
jwk = GenerateOct(keySizeBits, alg, use, keyOps);
errorMessage = null;
return true;
- } catch (Exception ex) {
+ }
+ catch (Exception ex) {
jwk = null;
errorMessage = ex.Message;
return false;
@@ -51,7 +55,8 @@ public static class JwkGenerator {
jwk = GenerateRsaFromRsa(rsa, includePrivate, alg, use, keyOps);
errorMessage = null;
return true;
- } catch (Exception ex) {
+ }
+ catch (Exception ex) {
jwk = null;
errorMessage = ex.Message;
return false;
@@ -59,9 +64,9 @@ public static class JwkGenerator {
}
public static bool TryComputeThumbprint(
- Jwk jwk,
- [NotNullWhen(true)] out string? thumbprint,
- [NotNullWhen(false)] out string? errorMessage) {
+ Jwk jwk,
+ [NotNullWhen(true)] out string? thumbprint,
+ [NotNullWhen(false)] out string? errorMessage) {
thumbprint = null;
errorMessage = null;
@@ -69,17 +74,17 @@ public static class JwkGenerator {
errorMessage = "JWK cannot be null.";
return false;
}
- if (string.IsNullOrEmpty(jwk.E) || string.IsNullOrEmpty(jwk.N)) {
- errorMessage = "JWK must have Exponent and Modulus set.";
+ if (string.IsNullOrEmpty(jwk.RsaExponent) || string.IsNullOrEmpty(jwk.RsaModulus)) {
+ errorMessage = "JWK must have RsaExponent and RsaModulus set.";
return false;
}
try {
- // RFC 7638: Lexicographic order: e, kty, n
+ // RFC7638: Lexicographic order: e, kty, n
var orderedJwk = new OrderedJwk {
- E = jwk.E!,
+ E = jwk.RsaExponent!,
Kty = "RSA",
- N = jwk.N!
+ N = jwk.RsaModulus!
};
var json = orderedJwk.ToJson();
@@ -97,22 +102,22 @@ public static class JwkGenerator {
using var rsa = RSA.Create(keySize);
var parameters = rsa.ExportParameters(includePrivate);
var jwk = new Jwk {
- Kty = JwkKeyType.Rsa.Name,
- N = Base64UrlEncode(parameters.Modulus!),
- E = Base64UrlEncode(parameters.Exponent!),
- Alg = (alg ?? (keySize >= 4096 ? JwkAlgorithm.Rs512 : JwkAlgorithm.Rs256)).Name,
- Use = use,
- KeyOps = keyOps,
+ KeyType = JwkKeyType.Rsa.Name,
+ RsaModulus = Base64UrlEncode(parameters.Modulus!),
+ RsaExponent = Base64UrlEncode(parameters.Exponent!),
+ Algorithm = (alg ?? (keySize >= 4096 ? JwkAlgorithm.Rs512 : JwkAlgorithm.Rs256)).Name,
+ KeyUse = use,
+ KeyOperations = keyOps,
};
if (includePrivate) {
- jwk.D = Base64UrlEncode(parameters.D!);
- jwk.P = Base64UrlEncode(parameters.P!);
- jwk.Q = Base64UrlEncode(parameters.Q!);
- jwk.DP = Base64UrlEncode(parameters.DP!);
- jwk.DQ = Base64UrlEncode(parameters.DQ!);
- jwk.QI = Base64UrlEncode(parameters.InverseQ!);
+ jwk.PrivateKey = Base64UrlEncode(parameters.D!);
+ jwk.RsaFirstPrimeFactor = Base64UrlEncode(parameters.P!);
+ jwk.RsaSecondPrimeFactor = Base64UrlEncode(parameters.Q!);
+ jwk.RsaFirstFactorCRTExponent = Base64UrlEncode(parameters.DP!);
+ jwk.RsaSecondFactorCRTExponent = Base64UrlEncode(parameters.DQ!);
+ jwk.RsaFirstCRTCoefficient = Base64UrlEncode(parameters.InverseQ!);
}
- jwk.Kid = ComputeKid(jwk);
+ jwk.KeyId = ComputeKid(jwk);
return jwk;
}
@@ -127,31 +132,31 @@ public static class JwkGenerator {
using var ec = ECDsa.Create(ecCurve);
var parameters = ec.ExportParameters(includePrivate);
var jwk = new Jwk {
- Kty = JwkKeyType.Ec.Name,
- Crv = curve.Name,
- X = Base64UrlEncode(parameters.Q.X!),
- Y = Base64UrlEncode(parameters.Q.Y!),
- Alg = (alg ?? (curve == JwkCurve.P384 ? JwkAlgorithm.Es384 : curve == JwkCurve.P521 ? JwkAlgorithm.Es512 : JwkAlgorithm.Es256)).Name,
- Use = use,
- KeyOps = keyOps,
+ KeyType = JwkKeyType.Ec.Name,
+ EcCurve = curve.Name,
+ EcX = Base64UrlEncode(parameters.Q.X!),
+ EcY = Base64UrlEncode(parameters.Q.Y!),
+ Algorithm = (alg ?? (curve == JwkCurve.P384 ? JwkAlgorithm.Es384 : curve == JwkCurve.P521 ? JwkAlgorithm.Es512 : JwkAlgorithm.Es256)).Name,
+ KeyUse = use,
+ KeyOperations = keyOps,
};
if (includePrivate && parameters.D != null) {
- jwk.D_EC = Base64UrlEncode(parameters.D);
+ jwk.PrivateKey = Base64UrlEncode(parameters.D);
}
- jwk.Kid = ComputeKid(jwk);
+ jwk.KeyId = ComputeKid(jwk);
return jwk;
}
private static Jwk GenerateOct(int keySizeBits = 256, JwkAlgorithm? alg = null, string? use = null, string[]? keyOps = null) {
var key = RandomNumberGenerator.GetBytes(keySizeBits / 8);
var jwk = new Jwk {
- Kty = JwkKeyType.Oct.Name,
- K = Base64UrlEncode(key),
- Alg = (alg ?? (keySizeBits == 256 ? JwkAlgorithm.A256Gcm : keySizeBits == 128 ? JwkAlgorithm.A128Gcm : JwkAlgorithm.A512Gcm)).Name,
- Use = use,
- KeyOps = keyOps,
+ KeyType = JwkKeyType.Oct.Name,
+ SymmetricKey = Base64UrlEncode(key),
+ Algorithm = (alg ?? (keySizeBits == 256 ? JwkAlgorithm.A256Gcm : keySizeBits == 128 ? JwkAlgorithm.A128Gcm : JwkAlgorithm.A512Gcm)).Name,
+ KeyUse = use,
+ KeyOperations = keyOps,
};
- jwk.Kid = ComputeKid(jwk);
+ jwk.KeyId = ComputeKid(jwk);
return jwk;
}
@@ -159,22 +164,22 @@ public static class JwkGenerator {
if (rsa == null) throw new ArgumentNullException(nameof(rsa));
var parameters = rsa.ExportParameters(includePrivate);
var jwk = new Jwk {
- Kty = JwkKeyType.Rsa.Name,
- N = Base64UrlUtility.Encode(parameters.Modulus!),
- E = Base64UrlUtility.Encode(parameters.Exponent!),
- Alg = (alg ?? JwkAlgorithm.Rs256).Name,
- Use = use,
- KeyOps = keyOps,
+ KeyType = JwkKeyType.Rsa.Name,
+ RsaModulus = Base64UrlUtility.Encode(parameters.Modulus!),
+ RsaExponent = Base64UrlUtility.Encode(parameters.Exponent!),
+ Algorithm = (alg ?? JwkAlgorithm.Rs256).Name,
+ KeyUse = use,
+ KeyOperations = keyOps,
};
if (includePrivate) {
- jwk.D = Base64UrlUtility.Encode(parameters.D!);
- jwk.P = Base64UrlUtility.Encode(parameters.P!);
- jwk.Q = Base64UrlUtility.Encode(parameters.Q!);
- jwk.DP = Base64UrlUtility.Encode(parameters.DP!);
- jwk.DQ = Base64UrlUtility.Encode(parameters.DQ!);
- jwk.QI = Base64UrlUtility.Encode(parameters.InverseQ!);
+ jwk.PrivateKey = Base64UrlUtility.Encode(parameters.D!);
+ jwk.RsaFirstPrimeFactor = Base64UrlUtility.Encode(parameters.P!);
+ jwk.RsaSecondPrimeFactor = Base64UrlUtility.Encode(parameters.Q!);
+ jwk.RsaFirstFactorCRTExponent = Base64UrlUtility.Encode(parameters.DP!);
+ jwk.RsaSecondFactorCRTExponent = Base64UrlUtility.Encode(parameters.DQ!);
+ jwk.RsaFirstCRTCoefficient = Base64UrlUtility.Encode(parameters.InverseQ!);
}
- jwk.Kid = ComputeKid(jwk);
+ jwk.KeyId = ComputeKid(jwk);
return jwk;
}
@@ -184,15 +189,15 @@ public static class JwkGenerator {
private static string ComputeKid(Jwk jwk) {
// Use thumbprint as kid if possible
- if (jwk.Kty == "RSA" && !string.IsNullOrEmpty(jwk.N) && !string.IsNullOrEmpty(jwk.E)) {
+ if (jwk.KeyType == "RSA" && !string.IsNullOrEmpty(jwk.RsaModulus) && !string.IsNullOrEmpty(jwk.RsaExponent)) {
TryComputeThumbprint(jwk, out var thumb, out _);
return thumb ?? Guid.NewGuid().ToString("N");
}
// For EC and oct, use a hash of the key material
using var sha = SHA256.Create();
- string keyMaterial = jwk.Kty switch {
- "EC" => jwk.X + jwk.Y + jwk.Crv,
- "oct" => jwk.K,
+ string keyMaterial = jwk.KeyType switch {
+ "EC" => jwk.EcX + jwk.EcY + jwk.EcCurve,
+ "oct" => jwk.SymmetricKey,
_ => null
} ?? Guid.NewGuid().ToString();
var hash = sha.ComputeHash(Encoding.UTF8.GetBytes(keyMaterial));