using System.Security.Cryptography; using System.Text; using JdeScoping.Infrastructure.Security; using Microsoft.Extensions.Logging; using NSubstitute; using Shouldly; namespace JdeScoping.Infrastructure.Tests.Security; public class EphemeralRsaKeyServiceTests : IDisposable { private readonly ILogger _logger; private readonly EphemeralRsaKeyService _service; public EphemeralRsaKeyServiceTests() { _logger = Substitute.For>(); _service = new EphemeralRsaKeyService(_logger); } [Fact] public void Constructor_GeneratesNewKeyPair() { // Assert - service was created with a key that works var publicKey = _service.GetPublicKeyPem(); publicKey.ShouldStartWith("-----BEGIN PUBLIC KEY-----"); publicKey.ShouldEndWith("-----END PUBLIC KEY-----"); } [Fact] public void GetPublicKeyPem_ReturnsValidPemFormat() { // Act var publicKey = _service.GetPublicKeyPem(); // Assert - key can be imported using var rsa = RSA.Create(); rsa.ImportFromPem(publicKey); rsa.KeySize.ShouldBe(2048); } [Fact] public void Decrypt_WithValidCiphertext_ReturnsPlaintext() { // Arrange var plaintext = "Hello, World!"u8.ToArray(); var publicKeyPem = _service.GetPublicKeyPem(); // Encrypt with public key using var rsa = RSA.Create(); rsa.ImportFromPem(publicKeyPem); var ciphertext = rsa.Encrypt(plaintext, RSAEncryptionPadding.OaepSHA256); // Act var decrypted = _service.Decrypt(ciphertext); // Assert Encoding.UTF8.GetString(decrypted).ShouldBe("Hello, World!"); } [Fact] public void Decrypt_WithInvalidCiphertext_ThrowsCryptographicException() { // Arrange var invalidCiphertext = new byte[256]; // Random bytes won't decrypt // Act & Assert Should.Throw(() => _service.Decrypt(invalidCiphertext)); } [Fact] public void MultipleInstances_HaveDifferentKeys() { // Arrange using var service2 = new EphemeralRsaKeyService(_logger); // Act var key1 = _service.GetPublicKeyPem(); var key2 = service2.GetPublicKeyPem(); // Assert - each instance has its own unique key key1.ShouldNotBe(key2); } [Fact] public void Dispose_PreventsSubsequentOperations() { // Arrange var service = new EphemeralRsaKeyService(_logger); service.Dispose(); // Act & Assert Should.Throw(() => service.GetPublicKeyPem()); Should.Throw(() => service.Decrypt(new byte[1])); } public void Dispose() { _service.Dispose(); } }