astral-api/Astral.Services/Services/CryptographyService.cs

126 lines
4.1 KiB
C#
Raw Normal View History

2024-12-11 21:36:30 +01:00
// <copyright file="CryptographyService.cs" company="alveus.dev">
// Copyright (c) alveus.dev. All rights reserved. Licensed under the MIT License.
// </copyright>
using System.Security.Cryptography;
using System.Text;
using Astral.Services.Constants;
2024-12-11 21:36:30 +01:00
using Astral.Services.Interfaces;
using Astral.Services.Options;
using Injectio.Attributes;
using Konscious.Security.Cryptography;
using Microsoft.Extensions.Logging;
2024-12-11 21:36:30 +01:00
using Microsoft.Extensions.Options;
namespace Astral.Services.Services;
/// <inheritdoc />
[RegisterSingleton]
public class CryptographyService : ICryptographyService
{
private readonly PwdHashOptions _configuration;
private readonly ILogger<CryptographyService> _logger;
2024-12-11 21:36:30 +01:00
/// <summary>
/// Initializes a new instance of the <see cref="CryptographyService" /> class.
/// </summary>
/// <param name="pwdHashSettings">Instance of <see cref="IOptions{PwdHashOptions}" />.</param>
/// <param name="logger">Instance of <see cref="ILogger{CryptographyService}" />.</param>
public CryptographyService(
IOptions<PwdHashOptions> pwdHashSettings,
ILogger<CryptographyService> logger)
2024-12-11 21:36:30 +01:00
{
_configuration = pwdHashSettings.Value;
_logger = logger;
2024-12-11 21:36:30 +01:00
}
/// <inheritdoc />
public byte[] GenerateSalt(int? size = null)
{
var result = RandomNumberGenerator.GetBytes(size ?? _configuration.SaltSize);
return result;
}
/// <inheritdoc />
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;
}
/// <inheritdoc />
public bool VerifyPassword(string password, byte[] salt, byte[] passwordHash)
{
var checkHash = HashPassword(password, salt);
return passwordHash.SequenceEqual(checkHash);
}
/// <inheritdoc />
public bool VerifyPassword(string password, string salt, string passwordHash)
{
var checkHash = HashPassword(password, Convert.FromBase64String(salt));
return Convert.FromBase64String(passwordHash).SequenceEqual(checkHash);
}
/// <inheritdoc />
public string GenerateRandomString(int length)
{
const string availableChars = "ABCDEFGHIJKLMONOPQRSTUVWXYZabcdefghijklmonopqrstuvwxyz0123456789";
return RandomNumberGenerator.GetString(availableChars, length);
}
/// <inheritdoc />
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 = "";
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;
}
/// <inheritdoc />
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;
}
2024-12-11 21:36:30 +01:00
}