using System; using System.IO; using Microsoft.AspNetCore.DataProtection; namespace Marechai.Helpers { /// /// Handles encryption and decryption of credentials using ASP.NET Core Data Protection API (DPAPI). /// This provides local, secure credential storage without requiring external services. /// public class CredentialEncryptor { private readonly IDataProtector _protector; private const string PurposeString = "Marechai.CredentialEncryption"; public CredentialEncryptor(IDataProtectionProvider protectionProvider) { if(protectionProvider == null) throw new ArgumentNullException(nameof(protectionProvider)); _protector = protectionProvider.CreateProtector(PurposeString); } /// /// Encrypts a plaintext credential string using the Data Protection API. /// /// The plaintext credential to encrypt /// Base64-encoded encrypted credential public string EncryptCredential(string plaintext) { if(string.IsNullOrEmpty(plaintext)) throw new ArgumentException("Credential cannot be null or empty", nameof(plaintext)); try { string encryptedString = _protector.Protect(plaintext); return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(encryptedString)); } catch(Exception ex) { throw new InvalidOperationException("Failed to encrypt credential", ex); } } /// /// Decrypts a Base64-encoded encrypted credential string. /// /// The Base64-encoded encrypted credential /// The decrypted plaintext credential public string DecryptCredential(string encryptedBase64) { if(string.IsNullOrEmpty(encryptedBase64)) throw new ArgumentException("Encrypted credential cannot be null or empty", nameof(encryptedBase64)); try { byte[] encryptedBytes = Convert.FromBase64String(encryptedBase64); string encryptedString = System.Text.Encoding.UTF8.GetString(encryptedBytes); return _protector.Unprotect(encryptedString); } catch(Exception ex) { throw new InvalidOperationException("Failed to decrypt credential", ex); } } /// /// Determines if a credential appears to be encrypted (Base64-encoded). /// /// The credential to check /// True if the credential appears to be encrypted, false otherwise public static bool IsEncrypted(string credential) { if(string.IsNullOrEmpty(credential)) return false; try { // Try to decode as Base64 - if it succeeds and doesn't look like a connection string, it's likely encrypted byte[] data = Convert.FromBase64String(credential); string decoded = System.Text.Encoding.UTF8.GetString(data); // If decoded string doesn't contain typical connection string characters, it's likely encrypted return !decoded.Contains("=") && !decoded.Contains(";"); } catch { return false; } } } }