refactor(DigitalData.Core.Security): Umbenennung des Unternamensraums von Cryptographer in RSAKey

This commit is contained in:
Developer 02
2025-01-07 12:09:34 +01:00
parent ac0b6f739b
commit 7f2d2dadfa
8 changed files with 8 additions and 9 deletions

View File

@@ -0,0 +1,68 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Security.Config;
using Microsoft.Extensions.Options;
using System.Security.Cryptography;
namespace DigitalData.Core.Security.RSAKey
{
public class RSAFactory<TRSAFactoryParams> : IAsymmetricKeyFactory where TRSAFactoryParams : RSAFactoryParams
{
protected readonly TRSAFactoryParams _params;
public RSAFactory(IOptions<TRSAFactoryParams> options)
{
options.Value.Init();
_params = options.Value;
}
public string CreatePrivateKeyPem(int? keySizeInBits = null, bool encrypt = false) => encrypt
? CreateEncryptedPrivateKeyPem(keySizeInBits: keySizeInBits)
: RSA.Create(keySizeInBits ?? _params.KeySizeInBits).ExportRSAPrivateKeyPem();
public string CreateEncryptedPrivateKeyPem(
PbeEncryptionAlgorithm? pbeEncryptionAlgorithm = null,
HashAlgorithmName? hashAlgorithmName = null,
int? iterationCount = null,
int? keySizeInBits = null,
string? password = null)
{
password ??= _params.PbePassword;
var pbeParameters = pbeEncryptionAlgorithm is null && hashAlgorithmName is null && iterationCount is null
? new PbeParameters(
pbeEncryptionAlgorithm ?? _params.PbeEncryptionAlgorithm,
hashAlgorithmName ?? _params.PbeHashAlgorithm,
iterationCount ?? _params.PbeIterationCount)
: _params.PbeParameters;
var encryptedPrivateKey = RSA.Create(keySizeInBits ?? _params.KeySizeInBits).ExportEncryptedPkcs8PrivateKey(password.AsSpan(), pbeParameters);
var pemChars = PemEncoding.Write(_params.EncryptedPrivateKeyPemLabel, encryptedPrivateKey);
return new string(pemChars);
}
public string CreateEncryptedPrivateKeyPem(
PbeParameters pbeParameters,
int? keySizeInBits = null,
string? password = null)
{
password ??= _params.PbePassword;
var encryptedPrivateKey = RSA.Create(keySizeInBits ?? _params.KeySizeInBits).ExportEncryptedPkcs8PrivateKey(password.AsSpan(), pbeParameters);
var pemChars = PemEncoding.Write(_params.EncryptedPrivateKeyPemLabel, encryptedPrivateKey);
return new string(pemChars);
}
public IAsymmetricPrivateKey CreatePrivateKey(string pem, string? issuer = null, string? audience = null, bool encrypt = false, RSAEncryptionPadding? padding = null) => new RSAPrivateKey()
{
Pem = pem,
Issuer = issuer ?? string.Empty,
Audience = audience ?? string.Empty,
IsEncrypted = encrypt,
Padding = padding ?? RSAEncryptionPadding.OaepSHA256
};
}
}

View File

@@ -0,0 +1,38 @@
using DigitalData.Core.Abstractions.Security;
using Microsoft.IdentityModel.Tokens;
using System.Reflection;
using System.Security.Cryptography;
namespace DigitalData.Core.Security.RSAKey
{
public class RSAKeyBase : IAsymmetricKey
{
public virtual string Pem { get; init; }
public RSAEncryptionPadding Padding { get; init; } = RSAEncryptionPadding.OaepSHA256;
// TODO: add as json converter to IConfigurIConfiguration.Config
public string PaddingName
{
get => Padding.ToString();
init => Padding = typeof(RSAEncryptionPadding).GetProperty(value, BindingFlags.Public | BindingFlags.Static)?.GetValue(null) as RSAEncryptionPadding ?? throw new ArgumentException($"Padding '{value}' not found.");
}
protected virtual RSA RSA { get; } = RSA.Create();
public string Issuer { get; init; } = string.Empty;
public string Audience { get; init; } = string.Empty;
private readonly Lazy<RsaSecurityKey> _lazyRsaSecurityKey;
public RsaSecurityKey RsaSecurityKey => _lazyRsaSecurityKey.Value;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
internal RSAKeyBase()
{
_lazyRsaSecurityKey = new(() => new RsaSecurityKey(RSA));
}
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
}
}

View File

@@ -0,0 +1,66 @@
using DigitalData.Core.Abstractions.Security;
using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography;
namespace DigitalData.Core.Security.RSAKey
{
public class RSAPrivateKey : RSAKeyBase, IAsymmetricPrivateKey, IAsymmetricKey
{
private string? _pem;
public override string Pem
{
#pragma warning disable CS8603 // Possible null reference return.
get => _pem;
#pragma warning restore CS8603 // Possible null reference return.
init
{
_pem = value;
Init();
}
}
public bool IsPemNull => _pem is null;
public bool IsEncrypted { get; init; }
private readonly Lazy<IAsymmetricPublicKey> _lazyPublicKey;
public IAsymmetricPublicKey PublicKey => _lazyPublicKey.Value;
public RSAPrivateKey()
{
_lazyPublicKey = new(() => new RSAPublicKey()
{
Pem = RSA.ExportRSAPublicKeyPem(),
Padding = Padding
});
}
public byte[] Decrypt(byte[] data) => RSA.Decrypt(data, Padding);
public string Decrypt(string data) => RSA.Decrypt(data.Base64ToByte(), Padding).BytesToString();
internal void SetPem(string pem)
{
_pem = pem;
Init();
}
private void Init()
{
if (string.IsNullOrEmpty(_pem))
throw PemIsNullException;
if (IsEncrypted)
RSA.ImportFromEncryptedPem(Pem, Secrets.PBE_PASSWORD.AsSpan());
else
RSA.ImportFromPem(Pem);
}
private InvalidOperationException PemIsNullException => new($"Pem is null or empty. Issuer: {Issuer}, Audience: {Audience}.");
public SigningCredentials CreateSigningCredentials(string algorithm = SecurityAlgorithms.RsaSha256, string? digest = null)
=> digest is null ? new(RsaSecurityKey, algorithm) : new(RsaSecurityKey, algorithm, digest);
}
}

View File

@@ -0,0 +1,23 @@
using DigitalData.Core.Abstractions.Security;
namespace DigitalData.Core.Security.RSAKey
{
public class RSAPublicKey : RSAKeyBase, IAsymmetricPublicKey, IAsymmetricKey
{
public override string Pem
{
get => base.Pem;
init
{
base.Pem = value;
RSA.ImportFromPem(value);
}
}
public byte[] Encrypt(byte[] data) => RSA.Encrypt(data, Padding);
public string Encrypt(string data) => RSA.Encrypt(data.ToBytes(), Padding).ToBase64String();
public bool Verify(string data, string signature) => Encrypt(data) == signature;
}
}