using DigitalData.Core.Abstractions.Security; using Microsoft.IdentityModel.Tokens; using System.Security.Cryptography; namespace DigitalData.Core.Security.Cryptographer { 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 _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); } }