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)
146 lines
No EOL
5 KiB
C#
146 lines
No EOL
5 KiB
C#
using IdentityShroud.Core.Contracts;
|
|
using IdentityShroud.Core.Services;
|
|
|
|
namespace IdentityShroud.Core.Tests.Services;
|
|
|
|
public class EncryptionServiceTests
|
|
{
|
|
[Fact]
|
|
public void RoundtripWorks()
|
|
{
|
|
// Note this code will tend to only test the latest verion.
|
|
|
|
// setup
|
|
byte[] keyValue = Convert.FromBase64String("IGd9yUMusjNW0ezv8ink3QWlAHKFH45d21LyrbJTokw=");
|
|
var secretProvider = Substitute.For<ISecretProvider>();
|
|
EncryptionKey[] keys =
|
|
[
|
|
new EncryptionKey("1", true, "AES", keyValue)
|
|
];
|
|
secretProvider.GetKeys("master").Returns(keys);
|
|
|
|
|
|
ReadOnlySpan<byte> input = "Hello, World!"u8;
|
|
|
|
// act
|
|
EncryptionService sut = new(secretProvider);
|
|
EncryptedValue cipher = sut.Encrypt(input.ToArray());
|
|
byte[] result = sut.Decrypt(cipher);
|
|
|
|
// verify
|
|
Assert.Equal(input, result);
|
|
}
|
|
|
|
[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
|
|
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 =
|
|
[
|
|
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<ISecretProvider>();
|
|
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<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);
|
|
}
|
|
} |