From f69317efe5bb35110688cf93048de70752c61452 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Wed, 1 Apr 2026 12:45:57 -0500 Subject: [PATCH] feat: implement static key provider --- .../Cryptography/StaticKeyProvider.cs | 37 ++++++++++++++++++ .../Cryptography/StaticKeyProviderTests.cs | 39 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 src/StevanFreeborn.Extensions.Configuration.Secure/Cryptography/StaticKeyProvider.cs create mode 100644 tests/StevanFreeborn.Extensions.Configuration.Secure.Tests/Unit/Cryptography/StaticKeyProviderTests.cs diff --git a/src/StevanFreeborn.Extensions.Configuration.Secure/Cryptography/StaticKeyProvider.cs b/src/StevanFreeborn.Extensions.Configuration.Secure/Cryptography/StaticKeyProvider.cs new file mode 100644 index 0000000..799caf3 --- /dev/null +++ b/src/StevanFreeborn.Extensions.Configuration.Secure/Cryptography/StaticKeyProvider.cs @@ -0,0 +1,37 @@ +namespace StevanFreeborn.Extensions.Configuration.Secure.Cryptography; + +internal sealed class StaticKeyProvider : IEncryptionKeyProvider +{ + private readonly byte[] _key; + + public StaticKeyProvider(string base64Key) + { + if (string.IsNullOrWhiteSpace(base64Key)) + { + throw new ArgumentNullException(nameof(base64Key)); + } + + byte[] decodedKey; + + try + { + decodedKey = Convert.FromBase64String(base64Key); + } + catch (FormatException ex) + { + throw new ArgumentException("The provided key is not a valid Base64 string.", nameof(base64Key), ex); + } + + if (decodedKey.Length != 32) + { + throw new ArgumentException("The encryption key must be exactly 32 bytes (256 bits) for AES-256 encryption.", nameof(base64Key)); + } + + _key = decodedKey; + } + + public byte[] GetKey() + { + return _key; + } +} \ No newline at end of file diff --git a/tests/StevanFreeborn.Extensions.Configuration.Secure.Tests/Unit/Cryptography/StaticKeyProviderTests.cs b/tests/StevanFreeborn.Extensions.Configuration.Secure.Tests/Unit/Cryptography/StaticKeyProviderTests.cs new file mode 100644 index 0000000..08cfeee --- /dev/null +++ b/tests/StevanFreeborn.Extensions.Configuration.Secure.Tests/Unit/Cryptography/StaticKeyProviderTests.cs @@ -0,0 +1,39 @@ +using StevanFreeborn.Extensions.Configuration.Secure.Cryptography; + +namespace StevanFreeborn.Extensions.Configuration.Secure.Tests.Unit.Cryptography; + +public class StaticKeyProviderTests +{ + [Fact] + public void Constructor_ShouldThrowArgumentNullException_WhenKeyIsNull() + { + var act = () => new StaticKeyProvider(null!); + + act.Should().Throw(); + } + + [Fact] + public void Constructor_WhenCalledAndKeyIsNot32Bytes_ItShouldThrowArgumentException() + { + var shortKey = Convert.ToBase64String(new byte[16]); + + var act = () => new StaticKeyProvider(shortKey); + + act.Should().Throw().WithMessage("*must be exactly 32 bytes*"); + } + + [Fact] + public void GetKey_WhenCalled_ItShouldReturnValid32ByteArray() + { + var expectedBytes = new byte[32]; + Random.Shared.NextBytes(expectedBytes); + var base64Key = Convert.ToBase64String(expectedBytes); + + var provider = new StaticKeyProvider(base64Key); + + var result = provider.GetKey(); + + result.Should().BeEquivalentTo(expectedBytes); + result.Length.Should().Be(32); + } +} \ No newline at end of file