// // Copyright (c) alveus.dev. All rights reserved. Licensed under the MIT License. // using System.Security.Cryptography; using System.Text; using Astral.Services.Constants; using Astral.Services.Interfaces; using Astral.Services.Options; using Injectio.Attributes; using Konscious.Security.Cryptography; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Astral.Services.Services; /// [RegisterSingleton] public class CryptographyService : ICryptographyService { private readonly PwdHashOptions _configuration; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// Instance of . /// Instance of . public CryptographyService( IOptions pwdHashSettings, ILogger logger) { _configuration = pwdHashSettings.Value; _logger = logger; } /// public byte[] GenerateSalt(int? size = null) { var result = RandomNumberGenerator.GetBytes(size ?? _configuration.SaltSize); return result; } /// public byte[] HashPassword(string password, byte[] salt) { var argon2Id = new Argon2id(Encoding.UTF8.GetBytes(password)); argon2Id.Salt = salt; argon2Id.DegreeOfParallelism = _configuration.DegreeOfParallelism; argon2Id.Iterations = _configuration.NumberOfIterations; argon2Id.MemorySize = _configuration.MemoryToUseKb; var bytes = argon2Id.GetBytes(_configuration.HashSize); GC.Collect(); return bytes; } /// public bool VerifyPassword(string password, byte[] salt, byte[] passwordHash) { var checkHash = HashPassword(password, salt); return passwordHash.SequenceEqual(checkHash); } /// public bool VerifyPassword(string password, string salt, string passwordHash) { var checkHash = HashPassword(password, Convert.FromBase64String(salt)); return Convert.FromBase64String(passwordHash).SequenceEqual(checkHash); } /// public string GenerateRandomString(int length) { const string availableChars = "ABCDEFGHIJKLMONOPQRSTUVWXYZabcdefghijklmonopqrstuvwxyz0123456789"; return RandomNumberGenerator.GetString(availableChars, length); } /// public string ConvertPublicKey(byte[] pkcs1Key, PublicKeyType type) { try { var rsa = RSA.Create(); var bytesRead = 0; switch (type) { case PublicKeyType.SpkiX509PublicKey: rsa.ImportSubjectPublicKeyInfo(pkcs1Key, out bytesRead); break; case PublicKeyType.Pkcs1PublicKey: rsa.ImportRSAPublicKey(pkcs1Key, out bytesRead); break; } var pem = string.Empty; if (bytesRead == 0) { _logger.LogError( "An error occured converting RSA public key from binary to SPKI (PEM). Bytes read: 0"); } else { pem = rsa.ExportSubjectPublicKeyInfoPem(); } rsa.Clear(); return pem; } catch (Exception e) { _logger.LogError("An error occured converting RSA public key from binary to SPKI (PEM). {exception}", e); } return string.Empty; } /// public string SimplifyPemKey(string pemKey) { pemKey = pemKey.Replace("-----BEGIN PUBLIC KEY-----", string.Empty); pemKey = pemKey.Replace("-----END PUBLIC KEY-----", string.Empty); pemKey = pemKey.Replace("\r", string.Empty); pemKey = pemKey.Replace("\n", string.Empty); return pemKey; } }