95 lines
3.7 KiB
C#
95 lines
3.7 KiB
C#
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<string, IRSAEncryptor> pairs, string issuer, string audience, out IRSAEncryptor? encryptor)
|
|
=> pairs.TryGetValue($"{issuer}:{audience}", out encryptor);
|
|
|
|
public static IRSAEncryptor? GetEncryptor(this IDictionary<string, IRSAEncryptor> 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<string, SemaphoreSlim> 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);
|
|
}
|
|
} |