using System.Security.Cryptography; using System.Text; using Microsoft.Extensions.Configuration; using SPMS.Application.Interfaces; using SPMS.Domain.Common; using SPMS.Domain.Exceptions; namespace SPMS.Infrastructure.Security; public class CredentialEncryptionService : ICredentialEncryptionService { private readonly byte[] _key; public CredentialEncryptionService(IConfiguration configuration) { var keyBase64 = configuration["CredentialEncryption:Key"]; if (string.IsNullOrEmpty(keyBase64)) { throw new InvalidOperationException("CredentialEncryption:Key is not configured."); } _key = Convert.FromBase64String(keyBase64); if (_key.Length != 32) { throw new InvalidOperationException("CredentialEncryption:Key must be 32 bytes (256 bits)."); } } public string Encrypt(string plainText) { if (string.IsNullOrEmpty(plainText)) return string.Empty; var iv = AesEncryption.GenerateIv(); var plainBytes = Encoding.UTF8.GetBytes(plainText); var encryptedBytes = AesEncryption.Encrypt(plainBytes, _key, iv); var result = new byte[iv.Length + encryptedBytes.Length]; Buffer.BlockCopy(iv, 0, result, 0, iv.Length); Buffer.BlockCopy(encryptedBytes, 0, result, iv.Length, encryptedBytes.Length); return Convert.ToBase64String(result); } public string Decrypt(string encryptedText) { if (string.IsNullOrEmpty(encryptedText)) return string.Empty; try { var encryptedData = Convert.FromBase64String(encryptedText); if (encryptedData.Length < 16) { throw new SpmsException(ErrorCodes.DecryptionFailed, "Invalid encrypted data.", 500); } var iv = encryptedData[..16]; var ciphertext = encryptedData[16..]; var decryptedBytes = AesEncryption.Decrypt(ciphertext, _key, iv); return Encoding.UTF8.GetString(decryptedBytes); } catch (CryptographicException) { throw new SpmsException(ErrorCodes.DecryptionFailed, "Failed to decrypt credentials.", 500); } } }