using DigitalData.Core.Security.Cryptographer; using System.Security.Cryptography; namespace DigitalData.Core.Security.Config { public class AsymCryptParams : RSAFactoryParams { public string PemDirectory { get; init; } = string.Empty; public string Separator { get; init; } = "_-_"; public string EncryptorTag { get; init; } = "public"; public string DecryptorTag { get; init; } = "private"; public string EncryptedDecryptorTag { get; init; } = "enc-private"; public IEnumerable Decryptors { get; init; } = new List(); public IEnumerable Encryptors { get; init; } = new List(); /// /// 0: Issuer - 1: Audience - 2: Type tag - 3: Secret version /// private string CreateFileName(params object[] objs) => string.Join(Separator, objs); private static (bool IsDecryptor, bool IsEncrypted) StateOf(RSACryptographer crypt) => crypt switch { RSAEncryptor => (false, false), RSADecryptor decryptor => (true, decryptor.Encrypt), _ => throw new InvalidOperationException("Unknown cryptographer type. The crypt parameter must be either RSAEncryptor or RSADecryptor.") }; private string TypeTagOf((bool IsDecryptor, bool IsEncrypted) stateOfCrypt) => stateOfCrypt switch { (false, false) => EncryptorTag, (true, false) => DecryptorTag, (true, true) => EncryptedDecryptorTag, _ => throw new InvalidOperationException("Unknown cryptographer type. The crypt parameter must be either RSAEncryptor or RSADecryptor.") }; private string CreatePem((bool IsDecryptor, bool IsEncrypted) stateOfCrypt) => stateOfCrypt switch { (true, false) => Instance.RSAFactory.CreateRSAPrivateKeyPem(keySizeInBits: KeySizeInBits), (true, true) => Instance.RSAFactory.CreateEncryptedPrivateKeyPem(keySizeInBits: KeySizeInBits, password: Secrets.PBE_PASSWORD, pbeEncryptionAlgorithm: PbeEncryptionAlgorithm, hashAlgorithmName: PbeHashAlgorithmName, iterationCount: PbeIterationCount), _ => throw new InvalidOperationException("Unknown cryptographer type. The crypt parameter must be either RSAEncryptor or RSADecryptor.") }; public override void OnDeserialized() { base.OnDeserialized(); // Create root folder if it does not exist if (!Directory.Exists(PemDirectory)) Directory.CreateDirectory(PemDirectory); // merge decryptors and encryptors to process under one loop var cryptographers = Encryptors.Cast().Concat(Decryptors.Cast()); foreach (var crypt in cryptographers) { // set default path if (crypt.IsPemNull) { var state = StateOf(crypt); var file_name_params = new List { crypt.Issuer, crypt.Audience, TypeTagOf(state) }; if (state.IsEncrypted) file_name_params.Add(Secrets.Version); var file_name = CreateFileName(file_name_params); var path = Path.Combine(PemDirectory, file_name); if (File.Exists(path)) crypt.SetPem(File.ReadAllText(path)); else { var pem = CreatePem(state); crypt.SetPem(File.ReadAllText(pem)); Task.Run(async () => File.WriteAllTextAsync(path: path, pem)); } } crypt.Init(); } } } }