I'm using openssl to encrypt/decrypt strings in PHP:
function str_encryptaesgcm($plaintext, $password, $encoding = null) {
$aes = array("key" => substr(hash("sha256", $password, true), 0, 32), "cipher" => "aes-256-gcm", "iv" => openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-gcm")));
$encryptedstring = openssl_encrypt($plaintext, $aes["cipher"], $aes["key"], OPENSSL_RAW_DATA, $aes["iv"], $aes["tag"], "", 16);
return $encoding == "hex" ? bin2hex($aes["iv"].$encryptedstring.$aes["tag"]) : ($encoding == "base64" ? base64_encode($aes["iv"].$encryptedstring.$aes["tag"]) : $aes["iv"].$encryptedstring.$aes["tag"]);
}
function str_decryptaesgcm($encryptedstring, $password, $encoding = null) {
$encryptedstring = $encoding == "hex" ? hex2bin($encryptedstring) : ($encoding == "base64" ? base64_decode($encryptedstring) : $encryptedstring);
$aes = array("key" => substr(hash("sha256", $password, true), 0, 32), "cipher" => "aes-256-gcm", "ivlength" => openssl_cipher_iv_length("aes-256-gcm"), "iv" => substr($encryptedstring, 0, openssl_cipher_iv_length("aes-256-gcm")), "tag" => substr($encryptedstring, -16));
return openssl_decrypt(substr($encryptedstring, $aes["ivlength"], -16), $aes["cipher"], $aes["key"], OPENSSL_RAW_DATA, $aes["iv"], $aes["tag"]);
}
and everything works correctly, in fact I get:
$text = "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...";
$pass = "A random password to encrypt";
$enc = str_encryptaesgcm($text, $pass, "base64"); // OUTPUT: TrbntVEj8GEGeLE6ZYJnDIXnqSese5biWn604NePb2r6jsFhuzJsNHnN2GCizrGfhP4W39tahrGj0tORxvUbDpGT76WHr/v2wmnHHHiDGyjeKlWLu9/gfeualYvhsNF/N9inSpqxE2lQ+/vwpUJKYJw3bfo7DoGPDNk=
$dec = str_decryptaesgcm($enc, $pass, "base64"); // OUTPUT: Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...
Unfortunately though, I need to decrypt the string from C#, therefore I'm using BouncyCastle to do this, and this is the class that I'm using:
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace PoGORaidEngine.Crypto
{
internal static class AESGCM
{
private const int KEY_BIT_SIZE = 256;
private const int MAC_BIT_SIZE = 128;
private const int NONCE_BIT_SIZE = 96; // 12 bytes (openssl)
internal static string DecryptString(string EncryptedString, string Password)
{
if (string.IsNullOrEmpty(EncryptedString))
return string.Empty;
byte[] Key = Encoding.UTF8.GetBytes(SHA256String(Password).Substring(0, 32));
byte[] EncryptedData = Convert.FromBase64String(EncryptedString);
if (Key == null || Key.Length != KEY_BIT_SIZE / 8)
throw new ArgumentException(string.Format("Key needs to be {0} bit.", KEY_BIT_SIZE), "Key");
using (MemoryStream MStream = new MemoryStream(EncryptedData))
using (BinaryReader Binary = new BinaryReader(MStream))
{
byte[] IV = Binary.ReadBytes(NONCE_BIT_SIZE / 8);
GcmBlockCipher Cipher = new GcmBlockCipher(new AesEngine());
Cipher.Init(false, new AeadParameters(new KeyParameter(Key), MAC_BIT_SIZE, IV));
byte[] CipherText = Binary.ReadBytes(EncryptedData.Length - IV.Length);
byte[] PlainText = new byte[Cipher.GetOutputSize(CipherText.Length)];
int Length = Cipher.ProcessBytes(CipherText, 0, CipherText.Length, PlainText, 0);
Cipher.DoFinal(PlainText, Length);
return Encoding.UTF8.GetString(PlainText);
}
}
private static string SHA256String(string Password)
{
using (SHA256 Hash = SHA256.Create())
{
byte[] PasswordBytes = Hash.ComputeHash(Encoding.UTF8.GetBytes(Password));
StringBuilder SB = new StringBuilder();
for (int i = 0; i < PasswordBytes.Length; i++)
SB.Append(PasswordBytes[i].ToString("X2"));
return SB.ToString();
}
}
}
}
but when I call the method to decrypt the following exception is thrown:
Org.BouncyCastle.Crypto.InvalidCipherTextException: mac check in GCM failed
I wasted several hours trying to figure out the problem but without success, I also tried to search here, on Stackoverflow, but nothing I found answers my question, not even this answer. Is there anyone who has tested and tried to decrypt from PHP (openssl) to C# with BouncyCastle using AES256-GCM? Thanks in advance for any help.
UPDATE
I've tried to update the PHP method to encrypt in order to see if data is ok:
function str_encryptaesgcm($plaintext, $password, $encoding = null) {
$aes = array("key" => substr(hash("sha256", $password, true), 0, 32), "cipher" => "aes-256-gcm", "iv" => openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-gcm")));
$encryptedstring = openssl_encrypt($plaintext, $aes["cipher"], $aes["key"], OPENSSL_RAW_DATA, $aes["iv"], $aes["tag"], "", 16);
switch ($encoding) {
case "base64":
return array("encrypteddata" => base64_encode($aes["iv"].$encryptedstring.$aes["tag"]), "iv" => base64_encode($aes["iv"]), "encryptedstring" => base64_encode($encryptedstring), "tag" => base64_encode($aes["tag"]));
case "hex":
return array("encrypteddata" => bin2hex($aes["iv"].$encryptedstring.$aes["tag"]), "iv" => bin2hex($aes["iv"]), "encryptedstring" => bin2hex($encryptedstring), "tag" => bin2hex($aes["tag"]));
default:
return array("encrypteddata" => $aes["iv"].$encryptedstring.$aes["tag"], "iv" => $aes["iv"], "encryptedstring" => $encryptedstring, "tag" => $aes["tag"]);
}
}
So I get:
{"encrypteddata":"w2eUXD41sCgTBvN7PtKlhzHB0lodPohnOh8V1lWsATvRujwsV18DDftGqJLqpsWxatYUX7C0jxjLcPQUoazIfiVdRmAsbGAKuvXYSsNjQ6ahGY4AxowAp0p\/IGDuYWbCrof6GZHUyoxv9Ry8NP1yxNItnBlUhGS8ua0=","iv":"w2eUXD41sCgTBvN7","encryptedstring":"PtKlhzHB0lodPohnOh8V1lWsATvRujwsV18DDftGqJLqpsWxatYUX7C0jxjLcPQUoazIfiVdRmAsbGAKuvXYSsNjQ6ahGY4AxowAp0p\/IGDuYWbCrof6GZHUyoxv9Q==","tag":"HLw0\/XLE0i2cGVSEZLy5rQ=="}
This makes me understand that on the PHP side everything is ok, also because when I perform the decryption from PHP everything works correctly. I tried to update the class on the C# code as proposed by Micheal Fehr, however I get a new exception: Org.BouncyCastle.Crypto.InvalidCipherTextException: data too short
:
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace PoGORaidEngine.Crypto
{
internal static class AESGCM
{
private const int MAC_BIT_SIZE = 128;
private const int NONCE_BIT_SIZE = 96;
internal static string DecryptString(string EncryptedString, string Password)
{
if (string.IsNullOrEmpty(EncryptedString))
return string.Empty;
byte[] EncryptedData = Convert.FromBase64String(EncryptedString);
byte[] Key = DerivateKey(Password);
byte[] IV;
byte[] CipherText;
byte[] Tag;
using (MemoryStream MStream = new MemoryStream(EncryptedData))
using (BinaryReader Binary = new BinaryReader(MStream))
{
IV = Binary.ReadBytes(NONCE_BIT_SIZE / 8);
CipherText = Binary.ReadBytes(EncryptedData.Length - IV.Length - (MAC_BIT_SIZE / 8));
Tag = Binary.ReadBytes(MAC_BIT_SIZE / 8);
}
byte[] AAED = new byte[0];
byte[] DecryptedData = new byte[CipherText.Length];
GcmBlockCipher Cipher = new GcmBlockCipher(new AesEngine());
Cipher.Init(false, new AeadParameters(new KeyParameter(Key), MAC_BIT_SIZE, IV, AAED));
int Length = Cipher.ProcessBytes(CipherText, 0, CipherText.Length, DecryptedData, 0);
Cipher.DoFinal(DecryptedData, Length);
return Encoding.UTF8.GetString(DecryptedData);
}
private static byte[] DerivateKey(string Password)
{
using (SHA256 Hash = SHA256.Create())
return Hash.ComputeHash(Encoding.UTF8.GetBytes(Password));
}
}
}
As a counter test I tried to get in base64 IV, clean encrypted string and tag and the data match perfectly, as in PHP.
I'm sure the solution is very close. The problem arises on: Cipher.DoFinal(DecryptedData, Length);
(new byte[CipherText.Length]
).
--- SOLUTION ---
Note: I've replaced the simple SHA256 derivation key with PBKDF2-SHA512 (with 20K iterations) to improve the security.
PHP functions:
function str_encryptaesgcm($plaintext, $password, $encoding = null) {
$keysalt = openssl_random_pseudo_bytes(16);
$key = hash_pbkdf2("sha512", $password, $keysalt, 20000, 32, true);
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-gcm"));
$tag = "";
$encryptedstring = openssl_encrypt($plaintext, "aes-256-gcm", $key, OPENSSL_RAW_DATA, $iv, $tag, "", 16);
return $encoding == "hex" ? bin2hex($keysalt.$iv.$encryptedstring.$tag) : ($encoding == "base64" ? base64_encode($keysalt.$iv.$encryptedstring.$tag) : $keysalt.$iv.$encryptedstring.$tag);
}
function str_decryptaesgcm($encryptedstring, $password, $encoding = null) {
$encryptedstring = $encoding == "hex" ? hex2bin($encryptedstring) : ($encoding == "base64" ? base64_decode($encryptedstring) : $encryptedstring);
$keysalt = substr($encryptedstring, 0, 16);
$key = hash_pbkdf2("sha512", $password, $keysalt, 20000, 32, true);
$ivlength = openssl_cipher_iv_length("aes-256-gcm");
$iv = substr($encryptedstring, 16, $ivlength);
$tag = substr($encryptedstring, -16);
return openssl_decrypt(substr($encryptedstring, 16 + $ivlength, -16), "aes-256-gcm", $key, OPENSSL_RAW_DATA, $iv, $tag);
}
C# Class (using AesGcm available in .NET Core 3 or above)
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace PRBMono.Crypto
{
internal static class AES
{
private static readonly int NONCE_BITS_SIZE = AesGcm.NonceByteSizes.MaxSize;
private static readonly int SALTKEY_BITS_SIZE = AesGcm.TagByteSizes.MaxSize;
private static readonly int MAC_BITS_SIZE = AesGcm.TagByteSizes.MaxSize;
private static readonly int KEY_ITERATIONS = 20000;
internal static string EncryptString(string String, bool Base64Encode = true)
{
if (string.IsNullOrEmpty(String))
return null;
byte[] SaltKey = CryptoMethods.RandomBytes(SALTKEY_BITS_SIZE);
byte[] Key = CryptoMethods.PBKDF2DerivateKey(Server.Config.Server_AESKey, HashAlgorithmName.SHA512, SaltKey, KEY_ITERATIONS, 32);
using AesGcm Aes = new(Key);
byte[] Data = Encoding.UTF8.GetBytes(String);
byte[] CipherData = new byte[Data.Length];
byte[] IV = CryptoMethods.RandomBytes(NONCE_BITS_SIZE);
byte[] Tag = new byte[MAC_BITS_SIZE];
Aes.Encrypt(IV, Data, CipherData, Tag);
using MemoryStream MStream = new();
using (BinaryWriter Binary = new(MStream))
{
Binary.Write(SaltKey);
Binary.Write(IV);
Binary.Write(CipherData);
Binary.Write(Tag);
}
return Base64Encode ? Convert.ToBase64String(MStream.ToArray()) : CryptoMethods.ByteArrayToHex(MStream.ToArray()).ToLower();
}
internal static string DecryptString(string EncryptedString, bool Base64Encode = true)
{
if (string.IsNullOrEmpty(EncryptedString))
return string.Empty;
byte[] EncryptedData = Base64Encode ? Convert.FromBase64String(EncryptedString) : CryptoMethods.HexToByteArray(EncryptedString);
byte[] SaltKey, Key, IV, CipherData, Tag;
using (MemoryStream MStream = new(EncryptedData))
using (BinaryReader Binary = new(MStream))
{
SaltKey = Binary.ReadBytes(SALTKEY_BITS_SIZE);
Key = CryptoMethods.PBKDF2DerivateKey(Server.Config.Server_AESKey, HashAlgorithmName.SHA512, SaltKey, KEY_ITERATIONS, 32);
IV = Binary.ReadBytes(NONCE_BITS_SIZE);
CipherData = Binary.ReadBytes(EncryptedData.Length - SaltKey.Length - IV.Length - MAC_BITS_SIZE);
Tag = Binary.ReadBytes(MAC_BITS_SIZE);
}
using AesGcm Aes = new(Key);
byte[] DecryptedData = new byte[CipherData.Length];
Aes.Decrypt(IV, CipherData, Tag, DecryptedData);
return Encoding.UTF8.GetString(DecryptedData);
}
}
}
C# Class (With BouncyCastle):
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace PoGORaidEngine.Crypto
{
internal static class AESGCM
{
private const int MAC_BIT_SIZE = 128;
private const int SALTKEY_BIT_SIZE = 128;
private const int NONCE_BIT_SIZE = 96;
internal static string DecryptString(string EncryptedString, string Password)
{
if (string.IsNullOrEmpty(EncryptedString))
return string.Empty;
byte[] EncryptedData = Convert.FromBase64String(EncryptedString);
byte[] SaltKey;
byte[] Key;
byte[] IV;
byte[] CipherText;
byte[] Tag;
using (MemoryStream MStream = new MemoryStream(EncryptedData))
using (BinaryReader Binary = new BinaryReader(MStream))
{
SaltKey = Binary.ReadBytes(SALTKEY_BIT_SIZE / 8);
Key = PBKDF2DerivateKey(Password, HashAlgorithmName.SHA512, SaltKey, 20000, 32);
IV = Binary.ReadBytes(NONCE_BIT_SIZE / 8);
CipherText = Binary.ReadBytes(EncryptedData.Length - SaltKey.Length - IV.Length - (MAC_BIT_SIZE / 8));
Tag = Binary.ReadBytes(MAC_BIT_SIZE / 8);
}
byte[] DecryptedData = new byte[CipherText.Length];
byte[] CipherTextTag = new byte[CipherText.Length + Tag.Length];
Buffer.BlockCopy(CipherText, 0, CipherTextTag, 0, CipherText.Length);
Buffer.BlockCopy(Tag, 0, CipherTextTag, CipherText.Length, Tag.Length);
GcmBlockCipher Cipher = new GcmBlockCipher(new AesEngine());
Cipher.Init(false, new AeadParameters(new KeyParameter(Key), MAC_BIT_SIZE, IV));
int Length = Cipher.ProcessBytes(CipherTextTag, 0, CipherTextTag.Length, DecryptedData, 0);
Cipher.DoFinal(DecryptedData, Length);
return Encoding.UTF8.GetString(DecryptedData);
}
private static byte[] PBKDF2DerivateKey(string Password, HashAlgorithmName Algorithm, byte[] Salt, int Iterations, int Length)
{
using (Rfc2898DeriveBytes DeriveBytes = new Rfc2898DeriveBytes(Password, Salt, Iterations, Algorithm))
return DeriveBytes.GetBytes(Length);
}
}
}
I'm not for sure that your "key derivation" on C# is working as on PHP, so I used my own one. As well, I used an own decryption function that runs without Bouncy Castle, and it could be a good basis for your work with Bouncy Castle.
Kindly note that a key derivation using SHA-hashes is UNSECURE and you should use something like PBKDF2 for this task.
I'm using the sample output
TrbntVEj8GEGeLE6ZYJnDIXnqSese5biWn604NePb2r6jsFhuzJsNHnN2GCizrGfhP4W39tahrGj0tORxvUbDpGT76WHr/v2wmnHHHiDGyjeKlWLu9/gfeualYvhsNF/N9inSpqxE2lQ+/vwpUJKYJw3bfo7DoGPDNk=
as input for the decryption function in C# - this is the result:
AES GCM 256 String decryption
* * * Decryption * * *
ciphertext (Base64): TrbntVEj8GEGeLE6ZYJnDIXnqSese5biWn604NePb2r6jsFhuzJsNHnN2GCizrGfhP4W39tahrGj0tORxvUbDpGT76WHr/v2wmnHHHiDGyjeKlWLu9/gfeualYvhsNF/N9inSpqxE2lQ+/vwpUJKYJw3bfo7DoGPDNk=
plaintext: Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...
Kindly note that my code has no exception handling and is for educational purpose only, the code is running with .net 5 in an online compiler (https://dotnetfiddle.net/WvUkXf):
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class Program {
public static void Main() {
Console.WriteLine("AES GCM 256 String decryption");
// decryption
Console.WriteLine("\n* * * Decryption * * *");
string password = "A random password to encrypt";
//generate hash of password # # # this is UNSECURE # # #
SHA256 mySHA256 = SHA256.Create();
byte[] Key = mySHA256.ComputeHash(Encoding.UTF8.GetBytes(password));
// ciphertext taken from encryption function in PHP
string soCiphertextBase64 = "TrbntVEj8GEGeLE6ZYJnDIXnqSese5biWn604NePb2r6jsFhuzJsNHnN2GCizrGfhP4W39tahrGj0tORxvUbDpGT76WHr/v2wmnHHHiDGyjeKlWLu9/gfeualYvhsNF/N9inSpqxE2lQ+/vwpUJKYJw3bfo7DoGPDNk=";
Console.WriteLine("ciphertext (Base64): " + soCiphertextBase64);
string soDecryptedtext = soAesGcmDecryptFromBase64(Key, soCiphertextBase64);
Console.WriteLine("plaintext: " + soDecryptedtext);
}
static string soAesGcmDecryptFromBase64(byte[] key, string data) {
const int MAC_BIT_SIZE = 128;
const int NONCE_BIT_SIZE = 96; // 12 bytes (openssl)
byte[] EncryptedData = Convert.FromBase64String(data);
byte[] IV;
byte[] CipherText;
byte[] Tag;
using (MemoryStream MStream = new MemoryStream(EncryptedData))
using (BinaryReader Binary = new BinaryReader(MStream)) {
IV = Binary.ReadBytes(NONCE_BIT_SIZE / 8);
CipherText = Binary.ReadBytes(EncryptedData.Length - IV.Length - (MAC_BIT_SIZE / 8));
Tag = Binary.ReadBytes((MAC_BIT_SIZE / 8));
}
string decryptedtext;
byte[] associatedData = new byte[0];
byte[] decryptedData = new byte[CipherText.Length];
using(var cipher = new AesGcm(key)) {
cipher.Decrypt(IV, CipherText, Tag, decryptedData, associatedData);
decryptedtext = Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);
return decryptedtext;
}
}
}
Edit: Did you notice that the GCM-Tag is never used in your updated decryption function?
Bouncy Castle's GCM function works similar to the Java-pendant and needs a ciphertext that has the tag appended to the ciphertext.
In the end you need to do some byte array copy operations:
byte[] CipherTextTag = new byte[CipherText.Length + Tag.Length];
System.Buffer.BlockCopy(CipherText, 0, CipherTextTag, 0, CipherText.Length);
System.Buffer.BlockCopy(Tag, 0, CipherTextTag, CipherText.Length, Tag.Length);
int Length = Cipher.ProcessBytes(CipherTextTag, 0, CipherTextTag.Length, DecryptedData, 0);
Using this "complete ciphertext" you get it to run with the original PHP code:
AES GCM 256 String decryption
* * * Decryption * * *
ciphertext (Base64): aV+gDmSBbi9PjOT9FD8LcuISbEQ5F3q0X8qzf3MKiDzxo12WQVirsnltbApLMMG9JScVfTXx7PJw7EVFoKz8JLMYLMu/JsRGcfvihSK+d/yeRTBEuJHL74Hv2Zr7b4CoMJhEUmYF3KT2Onlj4lI5ChOjmgXvpSev/xc=
plaintext: Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...
The complete code:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
public class Program {
public static void Main() {
Console.WriteLine("AES GCM 256 String decryption");
// decryption
Console.WriteLine("\n* * * Decryption * * *");
string password = "A random password to encrypt";
//generate hash of password # # # this is UNSECURE # # #
string soCiphertextBase64 = "aV+gDmSBbi9PjOT9FD8LcuISbEQ5F3q0X8qzf3MKiDzxo12WQVirsnltbApLMMG9JScVfTXx7PJw7EVFoKz8JLMYLMu/JsRGcfvihSK+d/yeRTBEuJHL74Hv2Zr7b4CoMJhEUmYF3KT2Onlj4lI5ChOjmgXvpSev/xc=";
Console.WriteLine("ciphertext (Base64): " + soCiphertextBase64);
string soDecryptedtextAsk = DecryptString(soCiphertextBase64, password);
Console.WriteLine("plaintext: " + soDecryptedtextAsk);
}
static string DecryptString(string EncryptedString, string Password)
{
const int MAC_BIT_SIZE = 128;
const int NONCE_BIT_SIZE = 96;
if (string.IsNullOrEmpty(EncryptedString))
return string.Empty;
byte[] EncryptedData = Convert.FromBase64String(EncryptedString);
byte[] Key = DerivateKey(Password);
byte[] IV;
byte[] CipherText;
byte[] Tag;
using (MemoryStream MStream = new MemoryStream(EncryptedData))
using (BinaryReader Binary = new BinaryReader(MStream))
{
IV = Binary.ReadBytes(NONCE_BIT_SIZE / 8);
CipherText = Binary.ReadBytes(EncryptedData.Length - IV.Length - (MAC_BIT_SIZE / 8));
Tag = Binary.ReadBytes(MAC_BIT_SIZE / 8);
}
byte[] AAED = new byte[0];
byte[] DecryptedData = new byte[CipherText.Length];
GcmBlockCipher Cipher = new GcmBlockCipher(new AesEngine());
Cipher.Init(false, new AeadParameters(new KeyParameter(Key), MAC_BIT_SIZE, IV, AAED));
// combine ciphertext + tag
byte[] CipherTextTag = new byte[CipherText.Length + Tag.Length];
System.Buffer.BlockCopy(CipherText, 0, CipherTextTag, 0, CipherText.Length);
System.Buffer.BlockCopy(Tag, 0, CipherTextTag, CipherText.Length, Tag.Length);
int Length = Cipher.ProcessBytes(CipherTextTag, 0, CipherTextTag.Length, DecryptedData, 0);
//int Length = Cipher.ProcessBytes(CipherText, 0, CipherText.Length, DecryptedData, 0);
Cipher.DoFinal(DecryptedData, Length);
return Encoding.UTF8.GetString(DecryptedData);
}
private static byte[] DerivateKey(string Password)
{
using (SHA256 Hash = SHA256.Create())
return Hash.ComputeHash(Encoding.UTF8.GetBytes(Password));
}
}