using System.Security.Cryptography; using System.Text; using Azaion.Common.Entities; namespace Azaion.Services; public static class Security { private const int BUFFER_SIZE = 524288; // 512 KB buffer size public static string ToHash(this string str) => Convert.ToBase64String(SHA384.HashData(Encoding.UTF8.GetBytes(str))); public static string GetHWHash(string hardware) => $"Azaion_{hardware}_%$$$)0_".ToHash(); public static string GetApiEncryptionKey(string email, string password, string? hardwareHash) => $"{email}-{password}-{hardwareHash}-#%@AzaionKey@%#---".ToHash(); public static async Task EncryptTo(this Stream inputStream, Stream toStream, string key, CancellationToken cancellationToken = default) { inputStream.Seek(0, SeekOrigin.Begin); if (inputStream is { CanRead: false }) throw new ArgumentNullException(nameof(inputStream)); if (key is not { Length: > 0 }) throw new ArgumentNullException(nameof(key)); using var aes = Aes.Create(); aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; aes.Key = SHA256.HashData(Encoding.UTF8.GetBytes(key)); aes.GenerateIV(); using var encryptor = aes.CreateEncryptor(aes.Key, aes.IV); await using var cs = new CryptoStream(toStream, encryptor, CryptoStreamMode.Write, leaveOpen: true); await toStream.WriteAsync(aes.IV.AsMemory(0, aes.IV.Length), cancellationToken); var buffer = new byte[BUFFER_SIZE]; int bytesRead; while ((bytesRead = await inputStream.ReadAsync(buffer, cancellationToken)) > 0) await cs.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken); } public static async Task DecryptTo(this Stream encryptedStream, Stream toStream, string key, CancellationToken cancellationToken = default) { encryptedStream.Seek(0, SeekOrigin.Begin); using var aes = Aes.Create(); aes.Key = SHA256.HashData(Encoding.UTF8.GetBytes(key)); var iv = new byte[aes.BlockSize / 8]; _ = await encryptedStream.ReadAsync(iv, cancellationToken); aes.IV = iv; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; using var decryptor = aes.CreateDecryptor(aes.Key, aes.IV); await using var cryptoStream = new CryptoStream(encryptedStream, decryptor, CryptoStreamMode.Read, leaveOpen: true); var buffer = new byte[BUFFER_SIZE]; int bytesRead; while ((bytesRead = await cryptoStream.ReadAsync(buffer, cancellationToken)) > 0) await toStream.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken); toStream.Seek(0, SeekOrigin.Begin); } }