feat: implement machine key provider

- implement logic for hashing machine key
- extracted interfaces
This commit is contained in:
Stevan Freeborn
2026-03-31 07:15:03 -05:00
parent e05e959378
commit 2915c32274
5 changed files with 98 additions and 7 deletions
@@ -0,0 +1,6 @@
namespace StevanFreeborn.Extensions.Configuration.Secure.Cryptography;
internal interface IMachineIdKeyGenerator
{
string GetId();
}
@@ -0,0 +1,6 @@
namespace StevanFreeborn.Extensions.Configuration.Secure.Cryptography;
internal interface IEncryptionKeyProvider
{
byte[] GetKey();
}
@@ -5,11 +5,6 @@ using Microsoft.Extensions.Logging;
namespace StevanFreeborn.Extensions.Configuration.Secure.Cryptography;
internal interface IMachineIdKeyGenerator
{
string GetId();
}
internal sealed class MachineIdKeyGenerator : IMachineIdKeyGenerator
{
private const string IOPlatformUUID = nameof(IOPlatformUUID);
@@ -111,4 +106,4 @@ internal static partial class LogMessages
Message = "Using fallback strategy for Machine ID generation."
)]
public static partial void LogUsingFallbackStrategy(this ILogger logger);
}
}
@@ -1,5 +1,17 @@
using System.Security.Cryptography;
using System.Text;
namespace StevanFreeborn.Extensions.Configuration.Secure.Cryptography;
internal sealed class MachineIdKeyProvider
internal sealed class MachineIdKeyProvider(IMachineIdKeyGenerator generator) : IEncryptionKeyProvider
{
private readonly IMachineIdKeyGenerator _generator = generator;
public byte[] GetKey()
{
var machineId = _generator.GetId();
var @bytes = Encoding.UTF8.GetBytes(machineId);
using var sha256 = SHA256.Create();
return sha256.ComputeHash(@bytes);
}
}
@@ -1,6 +1,78 @@
using System.Security.Cryptography;
using System.Text;
using Moq;
using StevanFreeborn.Extensions.Configuration.Secure.Cryptography;
namespace StevanFreeborn.Extensions.Configuration.Secure.Tests.Unit.Cryptography;
public class MachineIdKeyProviderTests
{
private readonly Mock<IMachineIdKeyGenerator> _mockKeyGenerator = new();
private readonly MachineIdKeyProvider _sut;
public MachineIdKeyProviderTests()
{
_sut = new(_mockKeyGenerator.Object);
}
[Fact]
public void GetKey_WhenCalled_ItShouldReturn32ByteKey()
{
_mockKeyGenerator.Setup(static m => m.GetId()).Returns("random-stuff");
var result = _sut.GetKey();
result.Length.Should().Be(32);
}
[Fact]
public void GetKey_WhenCalledForSameInput_ItShouldProduceConsistentHash()
{
var input = "some-machine-id";
var mockInstanceOne = new Mock<IMachineIdKeyGenerator>();
mockInstanceOne.Setup(static m => m.GetId()).Returns(input);
var instanceOne = new MachineIdKeyProvider(mockInstanceOne.Object);
var resultOne = instanceOne.GetKey();
var mockInstanceTwo = new Mock<IMachineIdKeyGenerator>();
mockInstanceTwo.Setup(static m => m.GetId()).Returns(input);
var instanceTwo = new MachineIdKeyProvider(mockInstanceTwo.Object);
var resultTwo = instanceTwo.GetKey();
resultOne.Should().BeEquivalentTo(resultTwo);
}
[Fact]
public void GetKey_WhenCalledWithDifferentInput_ItShouldProduceDifferentHashes()
{
var inputOne = "inputOne";
var inputTwo = "inputTwo";
_mockKeyGenerator.SetupSequence(static m => m.GetId())
.Returns(inputOne)
.Returns(inputTwo);
var resultOne = _sut.GetKey();
var resultTwo = _sut.GetKey();
resultOne.Should().NotBeEquivalentTo(resultTwo);
}
[Fact]
public void GetKey_WhenCalled_ItShouldUseSHA256Hash()
{
var rawId = "rawId";
var expectedHash = SHA256.HashData(Encoding.UTF8.GetBytes(rawId));
_mockKeyGenerator.Setup(static m => m.GetId()).Returns(rawId);
var result = _sut.GetKey();
result.Should().BeEquivalentTo(expectedHash);
}
}