2026-02-15 19:18:02 +01:00
|
|
|
using IdentityShroud.Core.Contracts;
|
2026-02-08 11:57:57 +01:00
|
|
|
using IdentityShroud.Core.Services;
|
|
|
|
|
|
|
|
|
|
namespace IdentityShroud.Core.Tests.Services;
|
|
|
|
|
|
|
|
|
|
public class EncryptionServiceTests
|
|
|
|
|
{
|
|
|
|
|
[Fact]
|
|
|
|
|
public void RoundtripWorks()
|
|
|
|
|
{
|
2026-02-22 19:11:17 +01:00
|
|
|
// Note this code will tend to only test the latest verion.
|
2026-02-24 06:32:58 +01:00
|
|
|
|
2026-02-08 11:57:57 +01:00
|
|
|
// setup
|
2026-02-24 06:32:58 +01:00
|
|
|
byte[] keyValue = Convert.FromBase64String("IGd9yUMusjNW0ezv8ink3QWlAHKFH45d21LyrbJTokw=");
|
2026-02-15 19:18:02 +01:00
|
|
|
var secretProvider = Substitute.For<ISecretProvider>();
|
2026-02-24 06:32:58 +01:00
|
|
|
EncryptionKey[] keys =
|
|
|
|
|
[
|
|
|
|
|
new EncryptionKey("1", true, "AES", keyValue)
|
|
|
|
|
];
|
|
|
|
|
secretProvider.GetKeys("master").Returns(keys);
|
|
|
|
|
|
2026-02-15 19:18:02 +01:00
|
|
|
|
2026-02-22 19:11:17 +01:00
|
|
|
ReadOnlySpan<byte> input = "Hello, World!"u8;
|
2026-02-08 11:57:57 +01:00
|
|
|
|
|
|
|
|
// act
|
2026-02-22 19:11:17 +01:00
|
|
|
EncryptionService sut = new(secretProvider);
|
2026-02-24 06:32:58 +01:00
|
|
|
EncryptedValue cipher = sut.Encrypt(input.ToArray());
|
2026-02-22 19:11:17 +01:00
|
|
|
byte[] result = sut.Decrypt(cipher);
|
2026-02-08 11:57:57 +01:00
|
|
|
|
2026-02-22 19:11:17 +01:00
|
|
|
// verify
|
2026-02-08 11:57:57 +01:00
|
|
|
Assert.Equal(input, result);
|
|
|
|
|
}
|
2026-02-22 19:11:17 +01:00
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void DecodeV1_Success()
|
|
|
|
|
{
|
|
|
|
|
// When introducing a new version we need version specific tests to
|
|
|
|
|
// make sure decoding of legacy data still works.
|
|
|
|
|
|
|
|
|
|
// setup
|
2026-02-24 06:32:58 +01:00
|
|
|
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<ISecretProvider>();
|
|
|
|
|
EncryptionKey[] keys =
|
|
|
|
|
[
|
|
|
|
|
new EncryptionKey("kid", true, "AES", keyValue)
|
|
|
|
|
];
|
|
|
|
|
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 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<ISecretProvider>();
|
|
|
|
|
EncryptionKey[] keys =
|
|
|
|
|
[
|
|
|
|
|
new EncryptionKey("kid", true, "AES", keyValue)
|
|
|
|
|
];
|
|
|
|
|
secretProvider.GetKeys("master").Returns(keys);
|
|
|
|
|
|
|
|
|
|
// act
|
|
|
|
|
EncryptionService sut = new(secretProvider);
|
|
|
|
|
Assert.Throws<InvalidOperationException>(
|
|
|
|
|
() => 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 =
|
2026-02-22 19:11:17 +01:00
|
|
|
[
|
|
|
|
|
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
|
|
|
|
|
];
|
2026-02-24 06:32:58 +01:00
|
|
|
EncryptedValue secret = new("1", cipher);
|
|
|
|
|
|
|
|
|
|
byte[] keyValue1 = Convert.FromBase64String("IGd9yUMusjNW0ezv8ink3QWlAHKFH45d21LyrbJTokw=");
|
|
|
|
|
byte[] keyValue2 = Convert.FromBase64String("Dat1RwRvuLX3wdKMMP4NwHdBl8tJJsKfp01qikyo8aw=");
|
2026-02-22 19:11:17 +01:00
|
|
|
var secretProvider = Substitute.For<ISecretProvider>();
|
2026-02-24 06:32:58 +01:00
|
|
|
EncryptionKey[] keys =
|
|
|
|
|
[
|
|
|
|
|
new EncryptionKey("2", true, "AES", keyValue2),
|
|
|
|
|
new EncryptionKey("1", false, "AES", keyValue1),
|
|
|
|
|
];
|
|
|
|
|
secretProvider.GetKeys("master").Returns(keys);
|
2026-02-22 19:11:17 +01:00
|
|
|
|
|
|
|
|
// act
|
|
|
|
|
EncryptionService sut = new(secretProvider);
|
2026-02-24 06:32:58 +01:00
|
|
|
byte[] result = sut.Decrypt(secret);
|
2026-02-22 19:11:17 +01:00
|
|
|
|
|
|
|
|
// verify
|
|
|
|
|
Assert.Equal("Hello, World!"u8, result);
|
|
|
|
|
}
|
2026-02-24 06:32:58 +01:00
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void EncryptionUsesActiveKey()
|
|
|
|
|
{
|
|
|
|
|
// setup
|
|
|
|
|
byte[] keyValue1 = Convert.FromBase64String("IGd9yUMusjNW0ezv8ink3QWlAHKFH45d21LyrbJTokw=");
|
|
|
|
|
byte[] keyValue2 = Convert.FromBase64String("Dat1RwRvuLX3wdKMMP4NwHdBl8tJJsKfp01qikyo8aw=");
|
|
|
|
|
var secretProvider = Substitute.For<ISecretProvider>();
|
|
|
|
|
EncryptionKey[] keys =
|
|
|
|
|
[
|
|
|
|
|
new EncryptionKey("1", false, "AES", keyValue1),
|
|
|
|
|
new EncryptionKey("2", true, "AES", keyValue2),
|
|
|
|
|
];
|
|
|
|
|
secretProvider.GetKeys("master").Returns(keys);
|
|
|
|
|
|
|
|
|
|
ReadOnlySpan<byte> input = "Hello, World!"u8;
|
|
|
|
|
// act
|
|
|
|
|
EncryptionService sut = new(secretProvider);
|
|
|
|
|
EncryptedValue cipher = sut.Encrypt(input.ToArray());
|
|
|
|
|
|
|
|
|
|
// Verify
|
|
|
|
|
Assert.Equal("2", cipher.KeyId);
|
|
|
|
|
}
|
2026-02-08 11:57:57 +01:00
|
|
|
}
|