From 644b005f2a7faf5a094a99289232ead68cf87a23 Mon Sep 17 00:00:00 2001 From: eelke Date: Tue, 24 Feb 2026 06:32:58 +0100 Subject: [PATCH] Support rotation of master key. The EncryptionService now loads a set of keys and uses the active one to encrypt and selects key based on keyid during decryption. Introduced EncryptedValue to hold keyId and encrypted data. (There are no intermeddiate keys yet) --- .../Apis/RealmApisTests.cs | 16 +-- .../Fixtures/ApplicationFactory.cs | 5 +- .../Mappers/KeyServiceTests.cs | 13 ++- IdentityShroud.Api/IdentityShroud.Api.csproj | 1 - .../ConfigurationSecretProviderTests.cs | 61 ++++++++++ .../Services/EncryptionServiceTests.cs | 110 ++++++++++++++++-- .../Services/RealmServiceTests.cs | 8 +- .../Contracts/IEncryptionService.cs | 4 +- .../Contracts/ISecretProvider.cs | 6 + IdentityShroud.Core/Model/ClientSecret.cs | 3 +- IdentityShroud.Core/Model/RealmKey.cs | 14 ++- .../Security/ConfigurationSecretProvider.cs | 5 + .../Security/EncryptedValue.cs | 6 + IdentityShroud.Core/Security/EncryptionKey.cs | 4 + IdentityShroud.Core/Services/ClientService.cs | 2 +- .../Services/EncryptionService.cs | 39 +++---- IdentityShroud.Core/Services/KeyService.cs | 21 ++-- .../EncryptionServiceSubstitute.cs | 8 +- IdentityShroud.sln.DotSettings.user | 5 +- 19 files changed, 259 insertions(+), 72 deletions(-) create mode 100644 IdentityShroud.Core.Tests/Security/ConfigurationSecretProviderTests.cs create mode 100644 IdentityShroud.Core/Security/EncryptedValue.cs create mode 100644 IdentityShroud.Core/Security/EncryptionKey.cs diff --git a/IdentityShroud.Api.Tests/Apis/RealmApisTests.cs b/IdentityShroud.Api.Tests/Apis/RealmApisTests.cs index 8d08a27..a91ea62 100644 --- a/IdentityShroud.Api.Tests/Apis/RealmApisTests.cs +++ b/IdentityShroud.Api.Tests/Apis/RealmApisTests.cs @@ -114,7 +114,7 @@ public class RealmApisTests : IClassFixture { // act var client = _factory.CreateClient(); - var response = await client.GetAsync("/realms/bar/.well-known/openid-configuration", + var response = await client.GetAsync($"/realms/{slug}/.well-known/openid-configuration", TestContext.Current.CancellationToken); // verify @@ -130,18 +130,20 @@ public class RealmApisTests : IClassFixture using var rsa = RSA.Create(2048); RSAParameters parameters = rsa.ExportParameters(includePrivateParameters: false); - RealmKey realmKey = new( - Guid.NewGuid(), - "RSA", - encryptionService.Encrypt(rsa.ExportPkcs8PrivateKey()), - DateTime.UtcNow); + RealmKey realmKey = new() + { + Id = Guid.NewGuid(), + KeyType = "RSA", + Key = encryptionService.Encrypt(rsa.ExportPkcs8PrivateKey()), + CreatedAt = DateTime.UtcNow, + }; await ScopedContextAsync(async db => { db.Realms.Add(new Realm() { Slug = "foo", Name = "Foo", Keys = [ realmKey ]}); await db.SaveChangesAsync(TestContext.Current.CancellationToken); }); - + // act var client = _factory.CreateClient(); var response = await client.GetAsync("/auth/realms/foo/openid-connect/jwks", diff --git a/IdentityShroud.Api.Tests/Fixtures/ApplicationFactory.cs b/IdentityShroud.Api.Tests/Fixtures/ApplicationFactory.cs index 2a2ae76..2a2be31 100644 --- a/IdentityShroud.Api.Tests/Fixtures/ApplicationFactory.cs +++ b/IdentityShroud.Api.Tests/Fixtures/ApplicationFactory.cs @@ -28,7 +28,10 @@ public class ApplicationFactory : WebApplicationFactory, IAsyncLifetime new Dictionary { ["Db:ConnectionString"] = _postgresqlServer.GetConnectionString(), - ["secrets:Master"] = "GVd07qW0frRX9quPX/X62L88BeRR7+IzgRJHtG7ZzHw=", + ["secrets:master:0:Id"] = "key1", + ["secrets:master:0:Active"] = "true", + ["secrets:master:0:Algorithm"] = "AES", + ["secrets:master:0:Key"] = "GVd07qW0frRX9quPX/X62L88BeRR7+IzgRJHtG7ZzHw=", }); }); diff --git a/IdentityShroud.Api.Tests/Mappers/KeyServiceTests.cs b/IdentityShroud.Api.Tests/Mappers/KeyServiceTests.cs index 196b15d..0df74a3 100644 --- a/IdentityShroud.Api.Tests/Mappers/KeyServiceTests.cs +++ b/IdentityShroud.Api.Tests/Mappers/KeyServiceTests.cs @@ -21,12 +21,12 @@ public class KeyServiceTests RSAParameters parameters = rsa.ExportParameters(includePrivateParameters: false); - RealmKey realmKey = new( - new("60bb79cf-4bac-4521-87f2-ac87cc15541f"), - "RSA", - rsa.ExportPkcs8PrivateKey(), - DateTime.UtcNow) + RealmKey realmKey = new() { + Id = new("60bb79cf-4bac-4521-87f2-ac87cc15541f"), + KeyType = "RSA", + Key = new("", rsa.ExportPkcs8PrivateKey()), + CreatedAt = DateTime.UtcNow, Priority = 10, }; @@ -34,10 +34,11 @@ public class KeyServiceTests KeyService sut = new(_encryptionService, new KeyProviderFactory(), new ClockService()); var jwk = sut.CreateJsonWebKey(realmKey); + Assert.NotNull(jwk); Assert.Equal("RSA", jwk.KeyType); Assert.Equal(realmKey.Id.ToString(), jwk.KeyId); Assert.Equal("sig", jwk.Use); Assert.Equal(parameters.Exponent, Base64Url.DecodeFromChars(jwk.Exponent)); Assert.Equal(parameters.Modulus, Base64Url.DecodeFromChars(jwk.Modulus)); } -} \ No newline at end of file +} diff --git a/IdentityShroud.Api/IdentityShroud.Api.csproj b/IdentityShroud.Api/IdentityShroud.Api.csproj index 860fbeb..31f88b2 100644 --- a/IdentityShroud.Api/IdentityShroud.Api.csproj +++ b/IdentityShroud.Api/IdentityShroud.Api.csproj @@ -17,7 +17,6 @@ - diff --git a/IdentityShroud.Core.Tests/Security/ConfigurationSecretProviderTests.cs b/IdentityShroud.Core.Tests/Security/ConfigurationSecretProviderTests.cs new file mode 100644 index 0000000..180732b --- /dev/null +++ b/IdentityShroud.Core.Tests/Security/ConfigurationSecretProviderTests.cs @@ -0,0 +1,61 @@ +using System.Text; +using IdentityShroud.Core.Security; +using Microsoft.Extensions.Configuration; + +namespace IdentityShroud.Core.Tests.Security; + +public class ConfigurationSecretProviderTests +{ + private static IConfiguration BuildConfigFromJson(string json) + { + // Convert the JSON string into a stream that the config builder can read. + var jsonBytes = Encoding.UTF8.GetBytes(json); + using var stream = new MemoryStream(jsonBytes); + + // Build the configuration just like the real app does, but from the stream. + var config = new ConfigurationBuilder() + .AddJsonStream(stream) // <-- reads from the in‑memory JSON + .Build(); + + return config; + } + + [Fact] + public void Test() + { + string jsonConfig = """ + { + "secrets": { + "master": [ + { + "Id": "first", + "Active": true, + "Algorithm": "AES", + "Key": "yoQ4W7EaNjo7s3FBYkWo5BLyX1BnLyWd7BlSaDIrkzo=" + }, + { + "Id": "second", + "Active": false, + "Algorithm": "AES", + "Key": "YSWK6vTJXCJOGLpCo+TtZ6anKNzvA1VT2xXLHbmq4M0=" + } + ] + } + } + """; + + + ConfigurationSecretProvider sut = new(BuildConfigFromJson(jsonConfig)); + + var keys = sut.GetKeys("master"); + + Assert.Equal(2, keys.Length); + var active = keys.Single(k => k.Active); + Assert.Equal("first", active.Id); + Assert.Equal("AES", active.Algorithm); + Assert.Equal(Convert.FromBase64String("yoQ4W7EaNjo7s3FBYkWo5BLyX1BnLyWd7BlSaDIrkzo="), active.Key); + + var inactive = keys.Single(k => !k.Active); + Assert.Equal("second", inactive.Id); + } +} \ No newline at end of file diff --git a/IdentityShroud.Core.Tests/Services/EncryptionServiceTests.cs b/IdentityShroud.Core.Tests/Services/EncryptionServiceTests.cs index 68ab90d..7a7be2c 100644 --- a/IdentityShroud.Core.Tests/Services/EncryptionServiceTests.cs +++ b/IdentityShroud.Core.Tests/Services/EncryptionServiceTests.cs @@ -1,5 +1,3 @@ -using System.Buffers.Text; -using System.Security.Cryptography; using IdentityShroud.Core.Contracts; using IdentityShroud.Core.Services; @@ -11,16 +9,22 @@ public class EncryptionServiceTests public void RoundtripWorks() { // Note this code will tend to only test the latest verion. - + // setup + byte[] keyValue = Convert.FromBase64String("IGd9yUMusjNW0ezv8ink3QWlAHKFH45d21LyrbJTokw="); var secretProvider = Substitute.For(); - secretProvider.GetSecret("Master").Returns("IGd9yUMusjNW0ezv8ink3QWlAHKFH45d21LyrbJTokw="); + EncryptionKey[] keys = + [ + new EncryptionKey("1", true, "AES", keyValue) + ]; + secretProvider.GetKeys("master").Returns(keys); + ReadOnlySpan input = "Hello, World!"u8; // act EncryptionService sut = new(secretProvider); - byte[] cipher = sut.Encrypt(input.ToArray()); + EncryptedValue cipher = sut.Encrypt(input.ToArray()); byte[] result = sut.Decrypt(cipher); // verify @@ -34,19 +38,109 @@ public class EncryptionServiceTests // make sure decoding of legacy data still works. // setup - Span cipher = + byte[] cipher = [ 1, 198, 55, 58, 56, 110, 238, 59, 158, 214, 85, 241, 26, 44, 140, 229, 128, 111, 167, 154, 160, 177, 152, 193, 74, 4, 235, 82, 207, 87, 32, 10, 239, 4, 246, 25, 21, 249, 25, 59, 160, 101 ]; + EncryptedValue secret = new("kid", cipher); + + byte[] keyValue = Convert.FromBase64String("IGd9yUMusjNW0ezv8ink3QWlAHKFH45d21LyrbJTokw="); var secretProvider = Substitute.For(); - secretProvider.GetSecret("Master").Returns("IGd9yUMusjNW0ezv8ink3QWlAHKFH45d21LyrbJTokw="); + EncryptionKey[] keys = + [ + new EncryptionKey("kid", true, "AES", keyValue) + ]; + secretProvider.GetKeys("master").Returns(keys); // act EncryptionService sut = new(secretProvider); - byte[] result = sut.Decrypt(cipher.ToArray()); + byte[] result = sut.Decrypt(secret); // verify Assert.Equal("Hello, World!"u8, result); } + + [Fact] + public void DetectsCorruptInput() + { + // When introducing a new version we need version specific tests to + // make sure decoding of legacy data still works. + + // setup + byte[] cipher = // NOTE INCORRECT CIPHER DO NOT USE IN OTHER TESTS + [ + 1, 198, 55, 58, 56, 110, 238, 59, 158, 214, 85, 241, 26, 44, 140, 229, 128, 111, 167, 154, 160, 177, 152, + 193, 75, 4, 235, 82, 207, 87, 32, 10, 239, 4, 246, 25, 21, 249, 25, 59, 160, 101 + ]; + EncryptedValue secret = new("kid", cipher); + + byte[] keyValue = Convert.FromBase64String("IGd9yUMusjNW0ezv8ink3QWlAHKFH45d21LyrbJTokw="); + var secretProvider = Substitute.For(); + EncryptionKey[] keys = + [ + new EncryptionKey("kid", true, "AES", keyValue) + ]; + secretProvider.GetKeys("master").Returns(keys); + + // act + EncryptionService sut = new(secretProvider); + Assert.Throws( + () => sut.Decrypt(secret), + ex => ex.Message.Contains("Decryption failed") ? null : "Expected Decryption failed in message"); + } + + [Fact] + public void DecodeSelectsRightKey() + { + // The key is marked inactive also it is the second key + + // setup + byte[] cipher = + [ + 1, 198, 55, 58, 56, 110, 238, 59, 158, 214, 85, 241, 26, 44, 140, 229, 128, 111, 167, 154, 160, 177, 152, + 193, 74, 4, 235, 82, 207, 87, 32, 10, 239, 4, 246, 25, 21, 249, 25, 59, 160, 101 + ]; + EncryptedValue secret = new("1", cipher); + + byte[] keyValue1 = Convert.FromBase64String("IGd9yUMusjNW0ezv8ink3QWlAHKFH45d21LyrbJTokw="); + byte[] keyValue2 = Convert.FromBase64String("Dat1RwRvuLX3wdKMMP4NwHdBl8tJJsKfp01qikyo8aw="); + var secretProvider = Substitute.For(); + EncryptionKey[] keys = + [ + new EncryptionKey("2", true, "AES", keyValue2), + new EncryptionKey("1", false, "AES", keyValue1), + ]; + secretProvider.GetKeys("master").Returns(keys); + + // act + EncryptionService sut = new(secretProvider); + byte[] result = sut.Decrypt(secret); + + // verify + Assert.Equal("Hello, World!"u8, result); + } + + [Fact] + public void EncryptionUsesActiveKey() + { + // setup + byte[] keyValue1 = Convert.FromBase64String("IGd9yUMusjNW0ezv8ink3QWlAHKFH45d21LyrbJTokw="); + byte[] keyValue2 = Convert.FromBase64String("Dat1RwRvuLX3wdKMMP4NwHdBl8tJJsKfp01qikyo8aw="); + var secretProvider = Substitute.For(); + EncryptionKey[] keys = + [ + new EncryptionKey("1", false, "AES", keyValue1), + new EncryptionKey("2", true, "AES", keyValue2), + ]; + secretProvider.GetKeys("master").Returns(keys); + + ReadOnlySpan input = "Hello, World!"u8; + // act + EncryptionService sut = new(secretProvider); + EncryptedValue cipher = sut.Encrypt(input.ToArray()); + + // Verify + Assert.Equal("2", cipher.KeyId); + } } \ No newline at end of file diff --git a/IdentityShroud.Core.Tests/Services/RealmServiceTests.cs b/IdentityShroud.Core.Tests/Services/RealmServiceTests.cs index acbc3bf..ea34ca8 100644 --- a/IdentityShroud.Core.Tests/Services/RealmServiceTests.cs +++ b/IdentityShroud.Core.Tests/Services/RealmServiceTests.cs @@ -39,7 +39,13 @@ public class RealmServiceTests : IClassFixture await using (var db = _dbFixture.CreateDbContext()) { _keyService.CreateKey(Arg.Any()) - .Returns(new RealmKey(Guid.NewGuid(), "TST", [21], DateTime.UtcNow)); + .Returns(new RealmKey() + { + Id = Guid.NewGuid(), + KeyType = "TST", + Key = new("kid", [21]), + CreatedAt = DateTime.UtcNow + }); // Act RealmService sut = new(db, _keyService); var response = await sut.Create( diff --git a/IdentityShroud.Core/Contracts/IEncryptionService.cs b/IdentityShroud.Core/Contracts/IEncryptionService.cs index 388304b..2fa7e9c 100644 --- a/IdentityShroud.Core/Contracts/IEncryptionService.cs +++ b/IdentityShroud.Core/Contracts/IEncryptionService.cs @@ -2,6 +2,6 @@ namespace IdentityShroud.Core.Contracts; public interface IEncryptionService { - byte[] Encrypt(ReadOnlyMemory plain); - byte[] Decrypt(ReadOnlyMemory cipher); + EncryptedValue Encrypt(ReadOnlyMemory plain); + byte[] Decrypt(EncryptedValue input); } \ No newline at end of file diff --git a/IdentityShroud.Core/Contracts/ISecretProvider.cs b/IdentityShroud.Core/Contracts/ISecretProvider.cs index 2a8e9e6..a586fe7 100644 --- a/IdentityShroud.Core/Contracts/ISecretProvider.cs +++ b/IdentityShroud.Core/Contracts/ISecretProvider.cs @@ -3,4 +3,10 @@ namespace IdentityShroud.Core.Contracts; public interface ISecretProvider { string GetSecret(string name); + + /// + /// Should return one active key, might return inactive keys. + /// + /// + EncryptionKey[] GetKeys(string name); } diff --git a/IdentityShroud.Core/Model/ClientSecret.cs b/IdentityShroud.Core/Model/ClientSecret.cs index bd57d37..0b0122d 100644 --- a/IdentityShroud.Core/Model/ClientSecret.cs +++ b/IdentityShroud.Core/Model/ClientSecret.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using IdentityShroud.Core.Contracts; namespace IdentityShroud.Core.Model; @@ -11,5 +12,5 @@ public class ClientSecret public Guid ClientId { get; set; } public DateTime CreatedAt { get; set; } public DateTime? RevokedAt { get; set; } - public required byte[] SecretEncrypted { get; set; } + public required EncryptedValue Secret { get; set; } } \ No newline at end of file diff --git a/IdentityShroud.Core/Model/RealmKey.cs b/IdentityShroud.Core/Model/RealmKey.cs index 14c7c9c..038f853 100644 --- a/IdentityShroud.Core/Model/RealmKey.cs +++ b/IdentityShroud.Core/Model/RealmKey.cs @@ -1,15 +1,19 @@ using System.ComponentModel.DataAnnotations.Schema; +using IdentityShroud.Core.Contracts; +using Microsoft.EntityFrameworkCore; namespace IdentityShroud.Core.Model; [Table("realm_key")] -public record RealmKey(Guid Id, string KeyType, byte[] KeyDataEncrypted, DateTime CreatedAt) +public record RealmKey { - public Guid Id { get; private set; } = Id; - public string KeyType { get; private set; } = KeyType; - public byte[] KeyDataEncrypted { get; private set; } = KeyDataEncrypted; - public DateTime CreatedAt { get; private set; } = CreatedAt; + public required Guid Id { get; init; } + public required string KeyType { get; init; } + + + public required EncryptedValue Key { get; init; } + public required DateTime CreatedAt { get; init; } public DateTime? RevokedAt { get; set; } /// diff --git a/IdentityShroud.Core/Security/ConfigurationSecretProvider.cs b/IdentityShroud.Core/Security/ConfigurationSecretProvider.cs index ab77ef1..dd616b1 100644 --- a/IdentityShroud.Core/Security/ConfigurationSecretProvider.cs +++ b/IdentityShroud.Core/Security/ConfigurationSecretProvider.cs @@ -14,4 +14,9 @@ public class ConfigurationSecretProvider(IConfiguration configuration) : ISecret { return secrets.GetValue(name) ?? ""; } + + public EncryptionKey[] GetKeys(string name) + { + return secrets.GetSection(name).Get() ?? []; + } } \ No newline at end of file diff --git a/IdentityShroud.Core/Security/EncryptedValue.cs b/IdentityShroud.Core/Security/EncryptedValue.cs new file mode 100644 index 0000000..655ab13 --- /dev/null +++ b/IdentityShroud.Core/Security/EncryptedValue.cs @@ -0,0 +1,6 @@ +using Microsoft.EntityFrameworkCore; + +namespace IdentityShroud.Core.Contracts; + +[Owned] +public record EncryptedValue(string KeyId, byte[] Value); \ No newline at end of file diff --git a/IdentityShroud.Core/Security/EncryptionKey.cs b/IdentityShroud.Core/Security/EncryptionKey.cs new file mode 100644 index 0000000..2e857a1 --- /dev/null +++ b/IdentityShroud.Core/Security/EncryptionKey.cs @@ -0,0 +1,4 @@ +namespace IdentityShroud.Core.Contracts; + +// Contains an encryption key and associated relevant data +public record EncryptionKey(string Id, bool Active, string Algorithm, byte[] Key); \ No newline at end of file diff --git a/IdentityShroud.Core/Services/ClientService.cs b/IdentityShroud.Core/Services/ClientService.cs index ed85daf..e6b5c32 100644 --- a/IdentityShroud.Core/Services/ClientService.cs +++ b/IdentityShroud.Core/Services/ClientService.cs @@ -57,7 +57,7 @@ public class ClientService( return new ClientSecret() { CreatedAt = clock.UtcNow(), - SecretEncrypted = cryptor.Encrypt(secret), + Secret = cryptor.Encrypt(secret), }; } diff --git a/IdentityShroud.Core/Services/EncryptionService.cs b/IdentityShroud.Core/Services/EncryptionService.cs index 8aa5bed..a6b39c0 100644 --- a/IdentityShroud.Core/Services/EncryptionService.cs +++ b/IdentityShroud.Core/Services/EncryptionService.cs @@ -1,6 +1,5 @@ using System.Security.Cryptography; using IdentityShroud.Core.Contracts; -using IdentityShroud.Core.Security; namespace IdentityShroud.Core.Services; @@ -17,16 +16,21 @@ public class EncryptionService : IEncryptionService new (12, 16), // version 1 ]; - private readonly byte[] _encryptionKey; + // Note this array is expected to have one item in it most of the during key rotation it will have two + // until it is ensured the old key can safely be removed. More then two will work but is not really expected. + private readonly EncryptionKey[] _encryptionKeys; + + private EncryptionKey ActiveKey => _encryptionKeys.Single(k => k.Active); + private EncryptionKey GetKey(string keyId) => _encryptionKeys.Single(k => k.Id == keyId); public EncryptionService(ISecretProvider secretProvider) { - _encryptionKey = Convert.FromBase64String(secretProvider.GetSecret("Master")); - if (_encryptionKey.Length != 32) // 256‑bit key - throw new Exception("Key must be 256 bits (32 bytes) for AES‑256‑GCM."); + _encryptionKeys = secretProvider.GetKeys("master"); + // if (_encryptionKey.Length != 32) // 256‑bit key + // throw new Exception("Key must be 256 bits (32 bytes) for AES‑256‑GCM."); } - public byte[] Encrypt(ReadOnlyMemory plaintext) + public EncryptedValue Encrypt(ReadOnlyMemory plaintext) { const int versionNumber = 1; AlgVersion versionParams = _versions[versionNumber]; @@ -44,26 +48,21 @@ public class EncryptionService : IEncryptionService // use the spans to place the data directly in its place RandomNumberGenerator.Fill(nonce); - using var aes = new AesGcm(_encryptionKey, versionParams.TagSize); + var encryptionKey = ActiveKey; + using var aes = new AesGcm(encryptionKey.Key, versionParams.TagSize); aes.Encrypt(nonce, plaintext.Span, cipher, tag); - return result; + return new (encryptionKey.Id, result); } - public byte[] Decrypt(ReadOnlyMemory input) + public byte[] Decrypt(EncryptedValue input) { - - // ---------------------------------------------------------------- - // 1️⃣ Extract the three components. - // ---------------------------------------------------------------- - // AesGcm.NonceByteSizes.MaxSize = 12 bytes (standard GCM nonce length) - // AesGcm.TagByteSizes.MaxSize = 16 bytes (128‑bit authentication tag) - //int nonceSize = AesGcm.NonceByteSizes.MaxSize; // 12 - //int tagSize = AesGcm.TagByteSizes.MaxSize; // 16 - var payload = input.Span; + var encryptionKey = GetKey(input.KeyId); + + var payload = input.Value.AsSpan(); int versionNumber = (int)payload[0]; if (versionNumber != 1) - throw new ArgumentException("Invalid payloag"); + throw new ArgumentException("Invalid payload"); AlgVersion versionParams = _versions[versionNumber]; @@ -77,7 +76,7 @@ public class EncryptionService : IEncryptionService byte[] plaintext = new byte[cipher.Length]; - using var aes = new AesGcm(_encryptionKey, versionParams.TagSize); + using var aes = new AesGcm(encryptionKey.Key, versionParams.TagSize); try { aes.Decrypt(nonce, cipher, tag, plaintext); diff --git a/IdentityShroud.Core/Services/KeyService.cs b/IdentityShroud.Core/Services/KeyService.cs index 6c5e828..16af5a4 100644 --- a/IdentityShroud.Core/Services/KeyService.cs +++ b/IdentityShroud.Core/Services/KeyService.cs @@ -29,23 +29,18 @@ public class KeyService( IKeyProvider provider = keyProviderFactory.CreateProvider(realmKey.KeyType); provider.SetJwkParameters( - cryptor.Decrypt(realmKey.KeyDataEncrypted), + cryptor.Decrypt(realmKey.Key), jwk); return jwk; } private RealmKey CreateKey(string keyType, byte[] plainKey) => - new RealmKey( - Guid.NewGuid(), - keyType, - cryptor.Encrypt(plainKey), - clock.UtcNow()); - - // public byte[] GetPrivateKey(IEncryptionService encryptionService) - // { - // if (_privateKeyDecrypted.Length == 0 && PrivateKeyEncrypted.Length > 0) - // _privateKeyDecrypted = encryptionService.Decrypt(PrivateKeyEncrypted); - // return _privateKeyDecrypted; - // } + new RealmKey() + { + Id = Guid.NewGuid(), + KeyType = keyType, + Key = cryptor.Encrypt(plainKey), + CreatedAt = clock.UtcNow(), + }; } diff --git a/IdentityShroud.TestUtils/Substitutes/EncryptionServiceSubstitute.cs b/IdentityShroud.TestUtils/Substitutes/EncryptionServiceSubstitute.cs index 5a81240..36045ae 100644 --- a/IdentityShroud.TestUtils/Substitutes/EncryptionServiceSubstitute.cs +++ b/IdentityShroud.TestUtils/Substitutes/EncryptionServiceSubstitute.cs @@ -8,11 +8,11 @@ public static class EncryptionServiceSubstitute { var encryptionService = Substitute.For(); encryptionService - .Encrypt(Arg.Any()) - .Returns(x => x.ArgAt(0)); + .Encrypt(Arg.Any>()) + .Returns(x => new EncryptedValue("kid", x.ArgAt>(0).ToArray())); encryptionService - .Decrypt(Arg.Any>()) - .Returns(x => x.ArgAt>(0).ToArray()); + .Decrypt(Arg.Any()) + .Returns(x => x.ArgAt(0).Value); return encryptionService; } } \ No newline at end of file diff --git a/IdentityShroud.sln.DotSettings.user b/IdentityShroud.sln.DotSettings.user index d90a7ba..795f362 100644 --- a/IdentityShroud.sln.DotSettings.user +++ b/IdentityShroud.sln.DotSettings.user @@ -20,10 +20,10 @@ ForceIncluded ForceIncluded ForceIncluded - /home/eelke/.cache/JetBrains/Rider2025.3/resharper-host/temp/Rider/vAny/CoverageData/_IdentityShroud.-1277985570/Snapshot/snapshot.utdcvr + /home/eelke/.dotnet/dotnet /home/eelke/.dotnet/sdk/10.0.102/MSBuild.dll - <SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <Solution /> </SessionState> @@ -36,4 +36,5 @@ + \ No newline at end of file