Files
Joseph Doherty 04383d672c refactor: UI file upload components and ephemeral RSA key service
Replace InputFile with RadzenUpload in filter panels for better UX,
switch to ephemeral RSA keys (safe for transport-only encryption),
and add test scripts and documentation files.
2026-01-28 17:22:30 -05:00

102 lines
2.9 KiB
C#

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<EphemeralRsaKeyService> _logger;
private readonly EphemeralRsaKeyService _service;
public EphemeralRsaKeyServiceTests()
{
_logger = Substitute.For<ILogger<EphemeralRsaKeyService>>();
_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<CryptographicException>(() => _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<ObjectDisposedException>(() => service.GetPublicKeyPem());
Should.Throw<ObjectDisposedException>(() => service.Decrypt(new byte[1]));
}
public void Dispose()
{
_service.Dispose();
}
}