04383d672c
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.
102 lines
2.9 KiB
C#
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();
|
|
}
|
|
}
|