feat(infrastructure): implement RsaKeyService with tests
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
// NEW/tests/JdeScoping.Infrastructure.Tests/Security/RsaKeyServiceTests.cs
|
||||
using JdeScoping.Core.Interfaces;
|
||||
using JdeScoping.Infrastructure.Security;
|
||||
using Shouldly;
|
||||
|
||||
namespace JdeScoping.Infrastructure.Tests.Security;
|
||||
|
||||
public class RsaKeyServiceTests : IDisposable
|
||||
{
|
||||
private readonly string _testKeyPath;
|
||||
|
||||
public RsaKeyServiceTests()
|
||||
{
|
||||
_testKeyPath = Path.Combine(Path.GetTempPath(), $"test-rsa-key-{Guid.NewGuid()}.bin");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (File.Exists(_testKeyPath))
|
||||
File.Delete(_testKeyPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPublicKeyPem_ReturnsValidPemFormat()
|
||||
{
|
||||
// Arrange
|
||||
var service = new RsaKeyService(_testKeyPath);
|
||||
|
||||
// Act
|
||||
var pem = service.GetPublicKeyPem();
|
||||
|
||||
// Assert
|
||||
pem.ShouldStartWith("-----BEGIN PUBLIC KEY-----");
|
||||
pem.ShouldEndWith("-----END PUBLIC KEY-----");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WhenKeyFileMissing_GeneratesAndPersistsKey()
|
||||
{
|
||||
// Arrange - ensure file doesn't exist
|
||||
File.Exists(_testKeyPath).ShouldBeFalse();
|
||||
|
||||
// Act
|
||||
_ = new RsaKeyService(_testKeyPath);
|
||||
|
||||
// Assert
|
||||
File.Exists(_testKeyPath).ShouldBeTrue();
|
||||
new FileInfo(_testKeyPath).Length.ShouldBeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WhenKeyFileExists_LoadsSameKey()
|
||||
{
|
||||
// Arrange - create service to generate key
|
||||
var service1 = new RsaKeyService(_testKeyPath);
|
||||
var publicKey1 = service1.GetPublicKeyPem();
|
||||
|
||||
// Act - create new service instance
|
||||
var service2 = new RsaKeyService(_testKeyPath);
|
||||
var publicKey2 = service2.GetPublicKeyPem();
|
||||
|
||||
// Assert - same key loaded
|
||||
publicKey2.ShouldBe(publicKey1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Decrypt_WithValidCiphertext_ReturnsPlaintext()
|
||||
{
|
||||
// Arrange
|
||||
var service = new RsaKeyService(_testKeyPath);
|
||||
var plaintext = "Hello, World!"u8.ToArray();
|
||||
|
||||
// Encrypt using public key (simulating what client does)
|
||||
using var rsa = System.Security.Cryptography.RSA.Create();
|
||||
rsa.ImportFromPem(service.GetPublicKeyPem());
|
||||
var ciphertext = rsa.Encrypt(plaintext, System.Security.Cryptography.RSAEncryptionPadding.OaepSHA256);
|
||||
|
||||
// Act
|
||||
var decrypted = service.Decrypt(ciphertext);
|
||||
|
||||
// Assert
|
||||
decrypted.ShouldBe(plaintext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Decrypt_WithInvalidCiphertext_ThrowsCryptographicException()
|
||||
{
|
||||
// Arrange
|
||||
var service = new RsaKeyService(_testKeyPath);
|
||||
var invalidCiphertext = new byte[] { 1, 2, 3, 4, 5 };
|
||||
|
||||
// Act & Assert
|
||||
Should.Throw<System.Security.Cryptography.CryptographicException>(
|
||||
() => service.Decrypt(invalidCiphertext));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user