using DigitalData.Core.Abstractions.Security; using System.Collections.Concurrent; using System.Security.Cryptography; namespace DigitalData.Core.Security.Extensions { public static class RSAExtensions { public static RSA ToRSA(this string pem) { var rsa = RSA.Create(); rsa.ImportFromPem(pem); return rsa; } public static bool TryGetEncryptor(this IDictionary pairs, string issuer, string audience, out IRSAEncryptor? encryptor) => pairs.TryGetValue($"{issuer}:{audience}", out encryptor); public static IRSAEncryptor? GetEncryptor(this IDictionary pairs, string issuer, string audience) => pairs.TryGetEncryptor(issuer: issuer, audience: audience, out var encryptor) ? encryptor : null; public static IRSADecryptor GetRSADecryptor(this ICryptFactory factory, string issuer, string audience) => factory[$"{issuer}:{audience}"]; public static bool TryGetRSADecryptor(this ICryptFactory factory, string issuer, string audience, out IRSADecryptor? decryptor) => factory.TryGetRSADecryptor($"{issuer}:{audience}", out decryptor); public static IRSAEncryptor GetRSAEncryptor(this ICryptFactory factory, string issuer, string audience) => factory[$"{issuer}:{audience}"].Encryptor; public static bool TryGetRSADecryptor(this ICryptFactory factory, string issuer, string audience, out IRSAEncryptor? encryptor) { if(factory.TryGetRSADecryptor($"{issuer}:{audience}", out var decryptor) && decryptor is not null) { encryptor = decryptor.Encryptor; return true; } else { encryptor = null; return false; } } private static string CreatePath(string key, string? directory = null) { directory ??= Environment.CurrentDirectory; if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } return Path.Combine(directory, $"{key}.pem"); } private static readonly ConcurrentDictionary FileLocks = new(); public static void SavePem(this IRSACryptographer decryptor, string key, string? directory = null) { var filePath = CreatePath(key : key, directory : directory); var fileLock = FileLocks.GetOrAdd(filePath, _ => new (1, 1)); fileLock.Wait(); try { File.WriteAllText(filePath, decryptor.Pem); } finally { fileLock.Release(); } } public static async Task SavePemAsync(this IRSACryptographer decryptor, string key, string? directory = null) { var filePath = CreatePath(key: key, directory: directory); var fileLock = FileLocks.GetOrAdd(filePath, _ => new (1, 1)); await fileLock.WaitAsync(); try { await File.WriteAllTextAsync(filePath, decryptor.Pem); } finally { fileLock.Release(); } } public static void SavePem(this IRSACryptographer decryptor, string issuer, string audience, string? directory = null) => decryptor.SavePem($"{issuer}:{audience}", directory); public static async Task SavePemAsync(this IRSACryptographer decryptor, string issuer, string audience, string? directory = null) => await decryptor.SavePemAsync($"{issuer}:{audience}", directory); } }