diff --git a/DigitalData.Core.Security/Config/AsymCryptParams.cs b/DigitalData.Core.Security/Config/AsymCryptParams.cs index 2f9f499..a7418b0 100644 --- a/DigitalData.Core.Security/Config/AsymCryptParams.cs +++ b/DigitalData.Core.Security/Config/AsymCryptParams.cs @@ -1,4 +1,5 @@ -using DigitalData.Core.Abstractions.Security; +using DigitalData.Core.Security.Cryptographer; +using System.Security.Cryptography; namespace DigitalData.Core.Security.Config { @@ -6,10 +7,7 @@ namespace DigitalData.Core.Security.Config { public string PemDirectory { get; init; } = string.Empty; - /// - /// 0: Issuer - 1: Audience - 2: Type tag - 3: Version - /// - public string FileNameFormat { get; init; } = "{0}_-_{1}_-_{2}_-_{3}.pem"; + public string Separator { get; init; } = "_-_"; public string EncryptorTag { get; init; } = "public"; @@ -17,40 +15,72 @@ namespace DigitalData.Core.Security.Config public string EncryptedDecryptorTag { get; init; } = "enc-private"; - public IEnumerable Decryptors { get; init; } = new List(); + public IEnumerable Decryptors { get; init; } = new List(); - public IEnumerable Encryptors { get; init; } = new List(); - - private string TypeTagOf(IRSACryptographer crypt) + 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 { - if (crypt is IRSAEncryptor) - return EncryptorTag; - else if (crypt is IRSADecryptor decryptor) - return decryptor.Encrypt ? EncryptedDecryptorTag : DecryptorTag; - else - throw new InvalidOperationException( - "Unknown cryptographer type. The crypt parameter must be either IRSAEncryptor or IRSADecryptor."); - } + 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(); - var cryptographers = Encryptors.Cast().Concat(Decryptors.Cast()); + // 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.Pem is null) - //{ - // crypt.Directory ??= Directory; - // crypt.FileName ??= string.Format( - // FileNameFormat, - // crypt.Issuer, - // crypt.Audience, - // TypeTagOf(crypt), - // Secrets.Version); - //} + 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(); }