diff --git a/backend/SpMega.Backend/Pages/v1/AgreementPage.cshtml.cs b/backend/SpMega.Backend/Pages/v1/AgreementPage.cshtml.cs
new file mode 100644
index 0000000..5f41e95
--- /dev/null
+++ b/backend/SpMega.Backend/Pages/v1/AgreementPage.cshtml.cs
@@ -0,0 +1,11 @@
+using Microsoft.AspNetCore.Mvc.RazorPages;
+
+namespace SpMega.Backend;
+
+public class AgreementPage : PageModel
+{
+ public void OnGet()
+ {
+
+ }
+}
diff --git a/backend/SpMega.Backend/Services/EncryptionHelper.cs b/backend/SpMega.Backend/Services/EncryptionHelper.cs
new file mode 100644
index 0000000..bafd0a0
--- /dev/null
+++ b/backend/SpMega.Backend/Services/EncryptionHelper.cs
@@ -0,0 +1,114 @@
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace SpMega.Backend.Services;
+
+public static class EncryptionHelper
+{
+ private static byte[]? _key;
+
+ ///
+ /// Initializes the encryption key. The key will be derived using SHA-256 from the provided secret string
+ /// to ensure it is exactly 32 bytes (256 bits) long.
+ ///
+ public static void Initialize(string secretKey)
+ {
+ if (string.IsNullOrWhiteSpace(secretKey))
+ {
+ throw new ArgumentException("Encryption key cannot be null or empty.", nameof(secretKey));
+ }
+
+ _key = SHA256.HashData(Encoding.UTF8.GetBytes(secretKey));
+ }
+
+ ///
+ /// Encrypts the plain text using AES-256-CBC.
+ /// A unique Initialization Vector (IV) is generated for each encryption and stored alongside the ciphertext.
+ ///
+ public static string Encrypt(string plainText)
+ {
+ if (_key == null)
+ {
+ throw new InvalidOperationException("EncryptionHelper has not been initialized. Call Initialize() first.");
+ }
+
+ if (string.IsNullOrEmpty(plainText))
+ {
+ return plainText;
+ }
+
+ using var aes = Aes.Create();
+ aes.Key = _key;
+ aes.GenerateIV();
+ var iv = aes.IV;
+
+ using var encryptor = aes.CreateEncryptor(aes.Key, iv);
+ using var ms = new MemoryStream();
+
+ // Write the IV to the beginning of the stream so it is stored alongside the ciphertext
+ ms.Write(iv, 0, iv.Length);
+
+ using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
+ using (var writer = new StreamWriter(cs, Encoding.UTF8))
+ {
+ writer.Write(plainText);
+ }
+
+ return Convert.ToBase64String(ms.ToArray());
+ }
+
+ ///
+ /// Decrypts the cipher text using AES-256-CBC.
+ /// Reconstructs the Initialization Vector (IV) from the beginning of the ciphertext.
+ /// Falls back to returning the input string if decryption fails (e.g., for legacy plaintext tokens).
+ ///
+ public static string Decrypt(string cipherText)
+ {
+ if (_key == null)
+ {
+ throw new InvalidOperationException("EncryptionHelper has not been initialized. Call Initialize() first.");
+ }
+
+ if (string.IsNullOrEmpty(cipherText))
+ {
+ return cipherText;
+ }
+
+ try
+ {
+ var fullCipher = Convert.FromBase64String(cipherText);
+
+ using var aes = Aes.Create();
+ aes.Key = _key;
+
+ var ivLength = aes.BlockSize / 8;
+ if (fullCipher.Length < ivLength)
+ {
+ // Too short to be an encrypted payload, return original
+ return cipherText;
+ }
+
+ var iv = new byte[ivLength];
+ var cipher = new byte[fullCipher.Length - ivLength];
+
+ Buffer.BlockCopy(fullCipher, 0, iv, 0, ivLength);
+ Buffer.BlockCopy(fullCipher, ivLength, cipher, 0, cipher.Length);
+
+ aes.IV = iv;
+
+ using var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
+ using var ms = new MemoryStream(cipher);
+ using var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
+ using var reader = new StreamReader(cs, Encoding.UTF8);
+
+ return reader.ReadToEnd();
+ }
+ catch (Exception ex) when (ex is CryptographicException or FormatException)
+ {
+ // Fallback for legacy unencrypted tokens
+ return cipherText;
+ }
+ }
+}