using Microsoft.Extensions.Configuration; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace GB5Shared.EncryptionHelper { public static class PasswordEncryption { public static string Encrypt(string plaintext, string key) { if (string.IsNullOrEmpty(key)) { throw new ArgumentException("Key cannot be null or empty."); } // Derive a 32-byte key from the string using SHA-256 byte[] keyBytes; using (SHA256 sha256 = SHA256.Create()) { keyBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(key)); } // Generate a 12-byte IV (nonce) for AES-GCM byte[] iv = new byte[12]; using (var rng = RandomNumberGenerator.Create()) { rng.GetBytes(iv); } byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext); // Initialize the cipher GcmBlockCipher cipher = new GcmBlockCipher(new AesEngine()); AeadParameters parameters = new AeadParameters(new KeyParameter(keyBytes), 128, iv); cipher.Init(true, parameters); // Get the required output buffer size int outputLength = cipher.GetOutputSize(plaintextBytes.Length); byte[] output = new byte[outputLength]; // Encrypt the data int len = cipher.ProcessBytes(plaintextBytes, 0, plaintextBytes.Length, output, 0); cipher.DoFinal(output, len); // Concatenate IV and the encrypted data (ciphertext + tag) byte[] result = new byte[iv.Length + output.Length]; Buffer.BlockCopy(iv, 0, result, 0, iv.Length); Buffer.BlockCopy(output, 0, result, iv.Length, output.Length); return Convert.ToBase64String(result); } public static string Decrypt(string encryptedText, string key) { if (string.IsNullOrWhiteSpace(encryptedText)) { throw new ArgumentException("Encrypted text cannot be null or empty.",nameof(encryptedText)); } if (string.IsNullOrWhiteSpace(key)) { throw new ArgumentException("Key cannot be null or empty.",nameof(key)); } // Convert Base64 encrypted value back to bytes byte[] encryptedBytes; try { encryptedBytes = Convert.FromBase64String(encryptedText); } catch (FormatException ex) { throw new InvalidOperationException("The encrypted value is not a valid Base64 string.",ex); } // Your Encrypt() uses a 12-byte IV const int ivLength = 12; // AES-GCM authentication tag is 16 bytes const int tagLength = 16; if (encryptedBytes.Length <= ivLength + tagLength) { throw new InvalidOperationException("The encrypted value is invalid or corrupted."); } // --------------------------------------------------------- // Derive the same 32-byte AES key using SHA-256 // --------------------------------------------------------- byte[] keyBytes; using (SHA256 sha256 = SHA256.Create()) { keyBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(key)); } // --------------------------------------------------------- // Extract IV // --------------------------------------------------------- byte[] iv = new byte[ivLength]; Buffer.BlockCopy(encryptedBytes,0,iv,0,ivLength); // --------------------------------------------------------- // Extract CipherText + Authentication Tag // --------------------------------------------------------- int cipherTextLength =encryptedBytes.Length - ivLength; byte[] cipherText =new byte[cipherTextLength]; Buffer.BlockCopy(encryptedBytes,ivLength,cipherText,0,cipherTextLength); // --------------------------------------------------------- // Initialize AES-GCM for DECRYPTION // --------------------------------------------------------- GcmBlockCipher cipher =new GcmBlockCipher(new AesEngine()); AeadParameters parameters =new AeadParameters(new KeyParameter(keyBytes),128,iv); cipher.Init(false, parameters); // --------------------------------------------------------- // Decrypt // --------------------------------------------------------- byte[] plainText =new byte[cipher.GetOutputSize(cipherText.Length)]; try { int len =cipher.ProcessBytes(cipherText,0,cipherText.Length,plainText,0); len += cipher.DoFinal(plainText,len); return Encoding.UTF8.GetString(plainText,0,len); } catch (Org.BouncyCastle.Crypto.InvalidCipherTextException ex) { throw new InvalidOperationException("Unable to decrypt the password. " +"The encryption key may be incorrect or the encrypted value may be corrupted.",ex); } } } }