fronted: login
This commit is contained in:
168
back/services/Crypto/CryptoService.cs
Normal file
168
back/services/Crypto/CryptoService.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace back.services.Crypto;
|
||||
|
||||
public class CryptoService(IMemoryCache cache) : ICryptoService
|
||||
{
|
||||
private readonly IMemoryCache _cache = cache;
|
||||
private readonly MemoryCacheEntryOptions _CacheOptions = new()
|
||||
{
|
||||
AbsoluteExpiration = DateTimeOffset.Now.AddHours(1),
|
||||
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1),
|
||||
SlidingExpiration = TimeSpan.FromMinutes(30),
|
||||
Priority = CacheItemPriority.High,
|
||||
PostEvictionCallbacks =
|
||||
{
|
||||
new PostEvictionCallbackRegistration
|
||||
{
|
||||
EvictionCallback = (key, value, reason, state) =>
|
||||
{
|
||||
var clientId = key.ToString()?.Replace("_public","").Replace("_private","");
|
||||
if(string.IsNullOrEmpty(clientId)) { return; }
|
||||
// Handle the eviction of the certificate - removing public/private keys from the cache
|
||||
try{ cache.Remove($"{clientId}_public"); } catch{ }
|
||||
try{ cache.Remove($"{clientId}_private"); } catch{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public string? Encrypt(string plainText, string clientId)
|
||||
{
|
||||
// get keys from cache
|
||||
if (!_cache.TryGetValue($"{clientId}_private", out string? privateCert) || string.IsNullOrEmpty(privateCert))
|
||||
{
|
||||
throw new InvalidOperationException("Private certificate not found for the client.");
|
||||
}
|
||||
if (!_cache.TryGetValue($"{clientId}_public", out string? publicCert) || string.IsNullOrEmpty(publicCert))
|
||||
{
|
||||
throw new InvalidOperationException("Public certificate not found for the client.");
|
||||
}
|
||||
// import rsa keys and configure RSA for encryption
|
||||
using var rsa = RSA.Create(2048);
|
||||
rsa.ImportRSAPublicKey(Convert.FromBase64String(publicCert), out _);
|
||||
rsa.ImportRSAPrivateKey(Convert.FromBase64String(privateCert), out _);
|
||||
// Encrypt the plain text using RSA
|
||||
string? encryptedText = null;
|
||||
try
|
||||
{
|
||||
var plainBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
|
||||
var encryptedBytes = rsa.Encrypt(plainBytes, RSAEncryptionPadding.OaepSHA256);
|
||||
encryptedText = Convert.ToBase64String(encryptedBytes);
|
||||
}
|
||||
catch (CryptographicException ex)
|
||||
{
|
||||
// Handle encryption errors
|
||||
throw new InvalidOperationException("Encryption failed.", ex);
|
||||
}
|
||||
return encryptedText;
|
||||
}
|
||||
|
||||
public string? Decrypt(string encryptedText, string clientId)
|
||||
{
|
||||
// get keys from cache
|
||||
if (!_cache.TryGetValue($"{clientId}_private", out string? privateCert) || string.IsNullOrEmpty(privateCert))
|
||||
{
|
||||
throw new InvalidOperationException("Private certificate not found for the client.");
|
||||
}
|
||||
if (!_cache.TryGetValue($"{clientId}_public", out string? publicCert) || string.IsNullOrEmpty(publicCert))
|
||||
{
|
||||
throw new InvalidOperationException("Private certificate not found for the client.");
|
||||
}
|
||||
// import rsa keys and configure RSA for decryption
|
||||
using var rsa = RSA.Create(2048);
|
||||
rsa.ImportRSAPublicKey(Convert.FromBase64String(publicCert), out _);
|
||||
rsa.ImportRSAPrivateKey(Convert.FromBase64String(privateCert), out _);
|
||||
// Decrypt the encrypted text using RSA
|
||||
string? plainText = null;
|
||||
try
|
||||
{
|
||||
var encryptedBytes = Convert.FromBase64String(encryptedText);
|
||||
var decryptedBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA256);
|
||||
plainText = System.Text.Encoding.UTF8.GetString(decryptedBytes);
|
||||
}
|
||||
catch (CryptographicException ex)
|
||||
{
|
||||
// Handle decryption errors
|
||||
throw new InvalidOperationException("Decryption failed.", ex);
|
||||
}
|
||||
return plainText;
|
||||
}
|
||||
|
||||
public string GetPublicCertificate(string clientId)
|
||||
{
|
||||
if (_cache.TryGetValue($"{clientId}_public", out string? publicCert) && !string.IsNullOrEmpty(publicCert))
|
||||
{
|
||||
return publicCert;
|
||||
}
|
||||
(publicCert, _) = GenerateCertificate();
|
||||
_cache.Set($"{clientId}_public", publicCert, _CacheOptions);
|
||||
return publicCert;
|
||||
}
|
||||
|
||||
public string GetPrivateCertificate(string clientId)
|
||||
{
|
||||
if (_cache.TryGetValue($"{clientId}_private", out string? privateCert) && !string.IsNullOrEmpty(privateCert))
|
||||
{
|
||||
return privateCert;
|
||||
}
|
||||
(_, privateCert) = GenerateCertificate();
|
||||
_cache.Set($"{clientId}_private", privateCert, _CacheOptions);
|
||||
return privateCert;
|
||||
}
|
||||
|
||||
private static (string publicCert, string privateCert) GenerateCertificate()
|
||||
{
|
||||
// Generate a new RSA key pair for the client
|
||||
using var rsa = RSA.Create(2048);
|
||||
var publicKey = rsa.ExportRSAPublicKey();
|
||||
var privateKey = rsa.ExportRSAPrivateKey();
|
||||
// Convert to Base64 strings for storage
|
||||
var publicCert = Convert.ToBase64String(publicKey);
|
||||
var privateCert = Convert.ToBase64String(privateKey);
|
||||
return (publicCert, privateCert);
|
||||
}
|
||||
|
||||
public string? Hash(string plainText)
|
||||
{
|
||||
string? hash = null;
|
||||
if (string.IsNullOrEmpty(plainText))
|
||||
{
|
||||
return hash;
|
||||
}
|
||||
var plainBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
|
||||
var hashBytes = SHA256.HashData(plainBytes);
|
||||
hash = Convert.ToBase64String(hashBytes);
|
||||
return hash;
|
||||
}
|
||||
|
||||
public bool VerifyHash(string plainText, string hash)
|
||||
{
|
||||
var plainTextHash = Hash(plainText);
|
||||
if (string.IsNullOrEmpty(plainTextHash) || string.IsNullOrEmpty(hash))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return plainTextHash.Equals(hash, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public string Pepper()
|
||||
{
|
||||
// get pepper from environtment variable
|
||||
var pepper = Environment.GetEnvironmentVariable("PEPPER");
|
||||
if (string.IsNullOrEmpty(pepper))
|
||||
{
|
||||
return "BactilForteFlash20mg";
|
||||
}
|
||||
return pepper;
|
||||
}
|
||||
|
||||
public string Salt()
|
||||
{
|
||||
var saltBytes = new byte[32]; // 256 bits
|
||||
using var rng = RandomNumberGenerator.Create();
|
||||
rng.GetBytes(saltBytes);
|
||||
return Convert.ToBase64String(saltBytes);
|
||||
}
|
||||
}
|
13
back/services/Crypto/ICryptoService.cs
Normal file
13
back/services/Crypto/ICryptoService.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace back.services.Crypto;
|
||||
|
||||
public interface ICryptoService
|
||||
{
|
||||
string? Encrypt(string clientId, string plainText);
|
||||
string? Decrypt(string clientId, string encryptedText);
|
||||
string? Hash(string plainText);
|
||||
bool VerifyHash(string plainText, string hash);
|
||||
string Salt();
|
||||
string Pepper();
|
||||
string GetPublicCertificate(string clientId);
|
||||
string GetPrivateCertificate(string clientId);
|
||||
}
|
Reference in New Issue
Block a user