diff --git a/DigitalData.Core.Abstractions/Security/IAsymmetricDecryptor.cs b/DigitalData.Core.Abstractions/Security/IAsymmetricDecryptor.cs new file mode 100644 index 0000000..136f173 --- /dev/null +++ b/DigitalData.Core.Abstractions/Security/IAsymmetricDecryptor.cs @@ -0,0 +1,7 @@ +namespace DigitalData.Core.Abstractions.Security +{ + public interface IAsymmetricDecryptor : IAsymmetricPrivateKey + { + byte[] Decrypt(byte[] data); + } +} \ No newline at end of file diff --git a/DigitalData.Core.Abstractions/Security/IAsymmetricPrivateKey.cs b/DigitalData.Core.Abstractions/Security/IAsymmetricPrivateKey.cs index 4b23bf9..b630732 100644 --- a/DigitalData.Core.Abstractions/Security/IAsymmetricPrivateKey.cs +++ b/DigitalData.Core.Abstractions/Security/IAsymmetricPrivateKey.cs @@ -9,11 +9,7 @@ namespace DigitalData.Core.Abstractions.Security IAsymmetricPublicKey PublicKey { get; } PrivateKeyTokenDescriptor? TokenDescriptor { get; init; } - - byte[] Decrypt(byte[] data); - - string Decrypt(string data); - + SigningCredentials CreateSigningCredentials(string algorithm = SecurityAlgorithms.RsaSha256, string? digest = null); } } \ No newline at end of file diff --git a/DigitalData.Core.Abstractions/Security/ICryptograph.cs b/DigitalData.Core.Abstractions/Security/ICryptograph.cs index 74d9fd9..e4c663d 100644 --- a/DigitalData.Core.Abstractions/Security/ICryptograph.cs +++ b/DigitalData.Core.Abstractions/Security/ICryptograph.cs @@ -2,9 +2,9 @@ { public interface ICryptograph : IAsymmetricKeyFactory { - IEnumerable PrivateKeys { get; } + IEnumerable Decryptors { get; } - IAsymmetricPrivateKey VaultPrivateKey { get; } + IAsymmetricDecryptor VaultDecryptor { get; } IEnumerable PublicKeys { get; } } diff --git a/DigitalData.Core.Abstractions/Security/PrivateKeyTokenDescriptor.cs b/DigitalData.Core.Abstractions/Security/PrivateKeyTokenDescriptor.cs index dd7919d..3596f76 100644 --- a/DigitalData.Core.Abstractions/Security/PrivateKeyTokenDescriptor.cs +++ b/DigitalData.Core.Abstractions/Security/PrivateKeyTokenDescriptor.cs @@ -17,7 +17,7 @@ namespace DigitalData.Core.Abstractions.Security /// /// Defines the compression algorithm that will be used to compress the JWT token payload. /// - public string CompressionAlgorithm { get; set; } + public string CompressionAlgorithm { get; set; } /// /// Gets or sets the used to create a encrypted security token. diff --git a/DigitalData.Core.Abstractions/Security/SecurityExtensions.cs b/DigitalData.Core.Abstractions/Security/SecurityExtensions.cs index 497a421..7d41486 100644 --- a/DigitalData.Core.Abstractions/Security/SecurityExtensions.cs +++ b/DigitalData.Core.Abstractions/Security/SecurityExtensions.cs @@ -1,4 +1,7 @@ -namespace DigitalData.Core.Abstractions.Security +using System.Security.Cryptography; +using System.Text; + +namespace DigitalData.Core.Abstractions.Security { public static class SecurityExtensions { @@ -25,5 +28,12 @@ public static bool TryMatch(this IEnumerable contextes, IUniqueSecurityContext lookupContext, out TUniqueSecurityContext context) where TUniqueSecurityContext : IUniqueSecurityContext => contextes.TryGet(lookupContext.Issuer, lookupContext.Audience, out context); + + internal static byte[] Base64ToByte(this string base64String) => Convert.FromBase64String(base64String); + + internal static string BytesToString(this byte[] bytes) => Encoding.UTF8.GetString(bytes); + + public static string Decrypt(this IAsymmetricDecryptor decryptor, string data) => decryptor + .Decrypt(data.Base64ToByte()).BytesToString(); } } \ No newline at end of file diff --git a/DigitalData.Core.Security/Config/CryptographParams.cs b/DigitalData.Core.Security/Config/CryptographParams.cs index 0c2b10b..f9f2cf0 100644 --- a/DigitalData.Core.Security/Config/CryptographParams.cs +++ b/DigitalData.Core.Security/Config/CryptographParams.cs @@ -39,9 +39,9 @@ namespace DigitalData.Core.Security.Config /// public string DateTagFormat { get; init; } = "MM//2"; - public IEnumerable PrivateKeys { get; init; } = new List(); + public IEnumerable Decryptors { get; init; } = new List(); - public RSAPrivateKey? VaultPrivateKey { get; init; } + public RSADecryptor? VaultDecryptor { get; init; } public CryptographParams() { @@ -52,7 +52,7 @@ namespace DigitalData.Core.Security.Config if (!Directory.Exists(PemDirectory)) Directory.CreateDirectory(PemDirectory); - foreach (var decryptor in PrivateKeys) + foreach (var decryptor in Decryptors) { // set default path if (decryptor.IsPemNull) diff --git a/DigitalData.Core.Security/Cryptograph.cs b/DigitalData.Core.Security/Cryptograph.cs index e278270..13c2468 100644 --- a/DigitalData.Core.Security/Cryptograph.cs +++ b/DigitalData.Core.Security/Cryptograph.cs @@ -8,12 +8,12 @@ namespace DigitalData.Core.Security { public class Cryptograph : RSAFactory, ICryptograph, IAsymmetricKeyFactory { - public IEnumerable PrivateKeys { get; } + public IEnumerable Decryptors { get; } /// /// It is a separate decryptor for permanently stored encrypted data. It is assigned to the first Default decryptor by default. /// - public IAsymmetricPrivateKey VaultPrivateKey { get; } + public IAsymmetricDecryptor VaultDecryptor { get; } private readonly Lazy> _lazyPublicKeys; @@ -25,18 +25,18 @@ namespace DigitalData.Core.Security { logger?.LogInformation("Core.Secrets version: {Version}, Created on: {CreationDate}.", Secrets.Version, Secrets.CreationDate.ToString("dd.MM.yyyy")); - if (!_params.PrivateKeys.Any()) + if (!_params.Decryptors.Any()) throw new InvalidOperationException( "Any decryptor is not found. Ensure that at least one decryptor is configured in the provided parameters. " + "This issue typically arises if the configuration for decryptors is incomplete or missing. " + "Check the 'Decryptors' collection in the configuration and verify that it contains valid entries." ); - PrivateKeys = _params.PrivateKeys; + Decryptors = _params.Decryptors; - VaultPrivateKey = _params.VaultPrivateKey ?? PrivateKeys.First(); + VaultDecryptor = _params.VaultDecryptor ?? Decryptors.First(); - _lazyPublicKeys = new(PrivateKeys.Select(decryptor => decryptor.PublicKey)); + _lazyPublicKeys = new(Decryptors.Select(decryptor => decryptor.PublicKey)); } } } \ No newline at end of file diff --git a/DigitalData.Core.Security/Extension.cs b/DigitalData.Core.Security/Extension.cs index 7045254..b8262ba 100644 --- a/DigitalData.Core.Security/Extension.cs +++ b/DigitalData.Core.Security/Extension.cs @@ -1,6 +1,5 @@ using AutoMapper; using DigitalData.Core.Abstractions.Security; -using DigitalData.Core.Security.Config; using Microsoft.IdentityModel.Tokens; namespace DigitalData.Core.Security @@ -8,13 +7,9 @@ namespace DigitalData.Core.Security internal static class Extension { internal static string ToBase64String(this byte[] bytes) => Convert.ToBase64String(bytes); - - internal static byte[] Base64ToByte(this string base64String) => Convert.FromBase64String(base64String); - + internal static byte[] ToBytes(this string str) => System.Text.Encoding.UTF8.GetBytes(str); - internal static string BytesToString(this byte[] bytes) => System.Text.Encoding.UTF8.GetString(bytes); - /// /// Converts a to a formatted string based on the specified format string. ///
diff --git a/DigitalData.Core.Security/JwtSignatureHandler.cs b/DigitalData.Core.Security/JwtSignatureHandler.cs index 3005c67..5ae3aea 100644 --- a/DigitalData.Core.Security/JwtSignatureHandler.cs +++ b/DigitalData.Core.Security/JwtSignatureHandler.cs @@ -35,14 +35,14 @@ namespace DigitalData.Core.Security public SecurityToken CreateToken(TPrincipal subject, string issuer, string audience) { - var key = _cryptograph.PrivateKeys?.Get(issuer: issuer, audience: audience) + var key = _cryptograph.Decryptors?.Get(issuer: issuer, audience: audience) ?? throw new InvalidOperationException($"No or multiple token description found for issuer '{issuer}' and audience '{audience}'."); return CreateToken(subject: subject, key: (RSAPrivateKey)key); } public SecurityToken CreateToken(TPrincipal subject, string apiRoute) { - var key = _cryptograph.PrivateKeys.SingleOrDefault(key => ((RSAPrivateKey)key).TokenDescriptor?.ApiRoute == apiRoute) + var key = _cryptograph.Decryptors.SingleOrDefault(key => ((RSAPrivateKey)key).TokenDescriptor?.ApiRoute == apiRoute) ?? throw new InvalidOperationException($"No or multiple token description found for api route '{apiRoute}'."); return CreateToken(subject: subject, key: (RSAPrivateKey)key); diff --git a/DigitalData.Core.Security/RSAKey/RSADecryptor.cs b/DigitalData.Core.Security/RSAKey/RSADecryptor.cs new file mode 100644 index 0000000..406eae4 --- /dev/null +++ b/DigitalData.Core.Security/RSAKey/RSADecryptor.cs @@ -0,0 +1,9 @@ +using DigitalData.Core.Abstractions.Security; + +namespace DigitalData.Core.Security.RSAKey +{ + public class RSADecryptor : RSAPrivateKey, IAsymmetricDecryptor + { + public byte[] Decrypt(byte[] data) => RSA.Decrypt(data, Padding); + } +} \ No newline at end of file diff --git a/DigitalData.Core.Security/RSAKey/RSAPrivateKey.cs b/DigitalData.Core.Security/RSAKey/RSAPrivateKey.cs index a62d4e9..00f86ed 100644 --- a/DigitalData.Core.Security/RSAKey/RSAPrivateKey.cs +++ b/DigitalData.Core.Security/RSAKey/RSAPrivateKey.cs @@ -54,10 +54,6 @@ namespace DigitalData.Core.Security.RSAKey }); } - 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;