在C#中使用OpenSSL用AES256-GCM解密由PHP加密的字符串

2022-05-30 00:00:00 openssl php c# bouncycastle aes-gcm

我正在使用OpenSSL加密/解密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"]);
}

并且一切正常,实际上我得到的是:

$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...

遗憾的是,我需要解密C#中的字符串,因此我使用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 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();
            }
        }
    }
}

但是,当我调用方法进行解密时,抛出了以下异常:

Org.BouncyCastle.Crypto.InvalidCipherTextException: mac check in GCM failed
我花了几个小时试图弄清楚这个问题,但没有成功,我也试图在Stackoverflow上搜索此处,但没有找到我的问题的答案,甚至这个answer。 有没有人测试过并尝试用BouncyCastle用AES256-GCM从PHP(OpenSSL)解密到C#?预先感谢您的帮助。

更新

我已尝试更新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);

    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"]);
    }
}

所以我得到:

{"encrypteddata":"w2eUXD41sCgTBvN7PtKlhzHB0lodPohnOh8V1lWsATvRujwsV18DDftGqJLqpsWxatYUX7C0jxjLcPQUoazIfiVdRmAsbGAKuvXYSsNjQ6ahGY4AxowAp0p/IGDuYWbCrof6GZHUyoxv9Ry8NP1yxNItnBlUhGS8ua0=","iv":"w2eUXD41sCgTBvN7","encryptedstring":"PtKlhzHB0lodPohnOh8V1lWsATvRujwsV18DDftGqJLqpsWxatYUX7C0jxjLcPQUoazIfiVdRmAsbGAKuvXYSsNjQ6ahGY4AxowAp0p/IGDuYWbCrof6GZHUyoxv9Q==","tag":"HLw0/XLE0i2cGVSEZLy5rQ=="}

这让我明白,在PHP端一切正常,这也是因为当我从PHP执行解密时,一切都正常工作。我尝试按照Micheal Fehr的建议更新C#代码上的类,但得到一个新的异常: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));
        }
    }
}

作为一项计数器测试,我试图在Base64 IV中清除加密的字符串和标记,数据完全匹配,就像在PHP中一样。 我相信解决方案已经非常接近了。问题出现在:Cipher.DoFinal(DecryptedData, Length);(new byte[CipherText.Length])。

-解决方案-

注意:我已将简单的SHA256派生密钥替换为PBKDF2-SHA512(迭代次数为20K)以提高安全性。

PHP函数:

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#类(使用.NET Core 3或更高版本中提供的AesGcm)

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#类(带有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);
        }
    }
}

php>

我不确定您在C#上的密钥派生是否能像在推荐答案上一样工作,所以我使用了我自己的密钥派生。此外,我还使用了自己的解密函数,该函数在运行时不运行Bouly Castle,这可能是您使用Bouly Castle的一个很好的基础。

请注意,使用SHA-Hash的密钥派生不安全,您应该使用类似于PBKDF2的内容来执行此任务。

我使用的是示例输出

TrbntVEj8GEGeLE6ZYJnDIXnqSese5biWn604NePb2r6jsFhuzJsNHnN2GCizrGfhP4W39tahrGj0tORxvUbDpGT76WHr/v2wmnHHHiDGyjeKlWLu9/gfeualYvhsNF/N9inSpqxE2lQ+/vwpUJKYJw3bfo7DoGPDNk=

作为C#中解密函数的输入-结果如下:

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...

请注意,我的代码没有异常处理,仅用于教育目的,代码在一个在线编译器中与.Net 5一起运行(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("
* * * 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;
        }
    }
}

编辑:您是否注意到在更新后的解密函数中从未使用过gcm标记?

弹跳城堡的GCM函数的工作原理类似于Java-Pendant,它需要一个将标签附加到密文上的密文。

最后需要做一些字节数组复制操作:

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);

使用这个完整的密文,您可以让它与原始的PHP代码一起运行:

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...

完整代码:

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("
* * * 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));
        }
}

相关文章