将php中的Aes加密转换为c#

将php中的Aes加密转换为c#,c#,php,encryption,aes,C#,Php,Encryption,Aes,我试图将php aes加密逻辑转换为c#,但无法使其按照服务器端点工作 有人能帮忙把下面的php代码转换成c吗 我尝试过php to.net迁移助手,但在加密功能附近失败 PHP代码: class Security { public static function encrypt($input, $key) { $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);

我试图将php aes加密逻辑转换为c#,但无法使其按照服务器端点工作

有人能帮忙把下面的php代码转换成c吗

我尝试过php to.net迁移助手,但在加密功能附近失败

PHP代码:

    class Security
{
    public static function encrypt($input, $key)
    {
        $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
        $input = Security::pkcs5_pad($input, $size);
        $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
        $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
        mcrypt_generic_init($td, $key, $iv);
        $data = mcrypt_generic($td, $input);
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);
        // $data = utf8_encode(base64_encode($data));

        $data = base64_encode($data);
        return $data;
    }


        private static function pkcs5_pad ($text, $blocksize)
    {
        $pad = $blocksize - (strlen($text) % $blocksize);
        return $text . str_repeat(chr($pad), $pad);
    }

    public static function decrypt($sStr, $sKey)
    {
        $decrypted= mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $sKey, base64_decode(str_replace(" ","+",$sStr)), MCRYPT_MODE_ECB);
        $dec_s = strlen($decrypted);
        $padding = ord($decrypted[$dec_s-1]);
        $decrypted = substr($decrypted, 0, -$padding);
        return $decrypted;
    }
}
c#代码

在C#中,您可以使用流(基本上)和CryptoServiceProviders。这也增加了PKCS7填充模式的功能性

也许我的这个AES密码专家班会帮你

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.IO;

namespace BerndoJLib.Cryptography
{
    /// <summary>
    /// 
    /// A helper class that controls security encrypting and decrypting of the database.
    /// Contains the methods to encrypt and decrypt byte arrays.
    /// 
    /// </summary>
    /// <remarks>
    /// Author: berndoJ / Copyright 2018 Johannes Berndorfer
    /// Created: 13.03.2018 11:20:56
    /// </remarks>
    public class Cryptographer
    {
        #region Public Objects

        /// <summary>
        /// Sets the options of this cryptographer / the algorithm options
        /// </summary>
        public EncryptionOptions AlgorithmOptions { get; set; }

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor of this class.
        /// </summary>
        /// <param name="AlgorithmOptions">The options of this cryptographer instance</param>
        public Cryptographer(EncryptionOptions AlgorithmOptions)
        {
            this.AlgorithmOptions = AlgorithmOptions;
        }

        #endregion

        #region Methods

        /// <summary>
        /// A function to generate a new sequence to use as a salt for one encryption.
        /// The byte-length of this sequence is set by the <see cref="AlgorithmOptions"/> property.
        /// The random byte generator <see cref="RNGCryptoServiceProvider"/> is a good option to use in this case.
        /// </summary>
        /// <returns>The sequence of bytes in an array</returns>
        public byte[] GenerateNewSaltSequence()
        {
            byte[] SaltSequence = new byte[this.AlgorithmOptions.SaltByteLength];
            RNGCryptoServiceProvider RNGCsp = new RNGCryptoServiceProvider();
            RNGCsp.GetNonZeroBytes(SaltSequence);
            return SaltSequence;
        }

        /// <summary>
        /// This function derives a specified byte array (length spec) from a string key entered. The key does not have to be from a certain length.
        /// For maintaining security, the byte[] returned by this function should be set to zero if not used anymore.
        /// The method used to achieve this process is made available by the <see cref="Rfc2898DeriveBytes"/> class.
        /// The count of iterations of this process is set by the <see cref="AlgorithmOptions"/> property.
        /// </summary>
        /// <param name="Key">The key in the form of a SecureString</param>
        /// <param name="KeySize">The size (in bits) of the key generated</param>
        /// <param name="SaltSequence">The salt sequence used to hash the key</param>
        /// <returns>A key in form of a byte array derived from the string counterpart</returns>
        public byte[] DeriveKeyFromString(SecureString Key, int KeySize, byte[] SaltSequence)
        {
            /*DeriveBytes DrvBytes = new Rfc2898DeriveBytes(Key, SaltSequence, this.AlgorithmOptions.KeyGenerationIterations);
            return DrvBytes.GetBytes(KeySize >> 3);*/ // The >> 3 just gets the floored value of bytes.
            IntPtr StrPtr = Marshal.SecureStringToBSTR(Key);
            byte[] PwdByteArray = null;
            try
            {
                int StrLength = Marshal.ReadInt32(StrPtr, -4);
                PwdByteArray = new byte[StrLength];
                GCHandle Handle = GCHandle.Alloc(PwdByteArray, GCHandleType.Pinned);
                try
                {
                    for (int i = 0; i < StrLength; i++)
                        PwdByteArray[i] = Marshal.ReadByte(StrPtr, i);
                    using (Rfc2898DeriveBytes DrvBytes = new Rfc2898DeriveBytes(PwdByteArray, SaltSequence, this.AlgorithmOptions.KeyGenerationIterations))
                        return DrvBytes.GetBytes(KeySize >> 3);
                }
                finally
                {
                    Array.Clear(PwdByteArray, 0, PwdByteArray.Length);
                    Handle.Free();
                }
            }
            finally
            {
                Marshal.ZeroFreeBSTR(StrPtr);
            }
        }

        /// <summary>
        /// Encrypts the given data (in form of a byte[]) with the Key given. All the options and so on are defined by the <see cref="AlgorithmOptions"/> property.
        /// </summary>
        /// <param name="DataIn">The data given to the function in form of a byte array</param>
        /// <param name="Key">The key to encrypt the data</param>
        /// <returns>An EncryptedData object which contains IV, Salt and EncryptedData</returns>
        public EncryptedData Encrypt(byte[] DataIn, SecureString Key)
        {
            // EncryptedData context init
            EncryptedData EncryptedDataContext = new EncryptedData();
            EncryptedDataContext.Salt = this.GenerateNewSaltSequence();
            // CSP init
            using(AesCryptoServiceProvider AESCsp = new AesCryptoServiceProvider())
            {
                // Generate the IV and store it in the EncryptedData context.
                AESCsp.GenerateIV();
                EncryptedDataContext.IV = AESCsp.IV;
                // Derive the byte[] key from the string key
                AESCsp.Key = this.DeriveKeyFromString(Key, AESCsp.KeySize, EncryptedDataContext.Salt);
                // Init the CSP options
                AESCsp.Mode = this.AlgorithmOptions.CipherModeUsed;
                AESCsp.Padding = this.AlgorithmOptions.PaddingModeUsed;
                // Encryption code
                using (MemoryStream MemStrm = new MemoryStream(DataIn.Length))
                {
                    using (ICryptoTransform EncryptionTransformer = AESCsp.CreateEncryptor())
                    {
                        using (CryptoStream CryptoStrm = new CryptoStream(MemStrm, EncryptionTransformer, CryptoStreamMode.Write))
                        {
                            CryptoStrm.Write(DataIn, 0, DataIn.Length);
                            CryptoStrm.FlushFinalBlock();
                            EncryptedDataContext.EncryptedDataContent = MemStrm.ToArray();
                        }
                    }
                }
                // Disposing the key object in the AESCsp to reduce chance of acidentially leaving it in memory after the using closed AESCsp.
                Array.Clear(AESCsp.Key, 0, AESCsp.Key.Length);
                // Returning the EncryptedData
                return EncryptedDataContext;
            }
        }

        /// <summary>
        /// Decrypts the given encrypted data with the use of the given key.
        /// <para>
        /// Returns a tuple which contains the following information: If the decryption was successful (If the key was the right one) and the decrypted data if the decrpyton was in fact successful.
        /// </para>
        /// </summary>
        /// <param name="EncryptedDataIn">The data given to the decryption method</param>
        /// <param name="Key">The key to decrypt the data</param>
        /// <returns>A tuple with: The successfulness of the decryption (is key correct); The decrypted data;</returns>
        public Tuple<bool, byte[]> Decrypt(EncryptedData EncryptedDataIn, SecureString Key)
        {
            // Create a return tuple, Item1 is the successfulness, Item2 the decrypted data if the decryption was successful.
            Tuple<bool, byte[]> DecryptionResult = new Tuple<bool, byte[]>(false, null);
            try
            {
                using (AesCryptoServiceProvider AESCsp = new AesCryptoServiceProvider())
                {
                    // Init the IV
                    AESCsp.IV = EncryptedDataIn.IV;
                    // Init the AESCsp key object
                    AESCsp.Key = this.DeriveKeyFromString(Key, AESCsp.KeySize, EncryptedDataIn.Salt);
                    // Init the CSP options
                    AESCsp.Mode = this.AlgorithmOptions.CipherModeUsed;
                    AESCsp.Padding = this.AlgorithmOptions.PaddingModeUsed;
                    // Decryption code
                    using (MemoryStream MemStrm = new MemoryStream(EncryptedDataIn.EncryptedDataContent))
                    {
                        using (ICryptoTransform DecryptionTransformer = AESCsp.CreateDecryptor())
                        {
                            using (CryptoStream CryptoStrm = new CryptoStream(MemStrm, DecryptionTransformer, CryptoStreamMode.Read))
                            {
                                using (MemoryStream SequenceMemStrm = new MemoryStream())
                                {
                                    // Define a buffer to read sequences.
                                    byte[] SequenceBuffer = new byte[2048];
                                    // Init a variable that keeps track of how many bytes have been written to the buffer
                                    int ReadBytes;
                                    // Loop to read all the bytes in the CryptoStrm
                                    while((ReadBytes = CryptoStrm.Read(SequenceBuffer, 0, SequenceBuffer.Length)) > 0)
                                    {
                                        SequenceMemStrm.Write(SequenceBuffer, 0, ReadBytes);
                                    }
                                    // Set the DecryptionResult to: successful; Data in SequenceMemStrm;
                                    DecryptionResult = new Tuple<bool, byte[]>(true, SequenceMemStrm.ToArray());
                                }
                            }
                        }
                    }
                    // Disposing the key object in the AESCsp to reduce chance of acidentially leaving it in memory after the using closed AESCsp.
                    Array.Clear(AESCsp.Key, 0, AESCsp.Key.Length);
                    // Returning the DecryptionResult
                    return DecryptionResult;
                }
            }
            catch (Exception)
            {
                // The decryption failed, the key is not the right one.
                DecryptionResult = new Tuple<bool, byte[]>(false, null);
                return DecryptionResult;
            }
        }

        #endregion
    }

    /// <summary>
    /// 
    /// A struct obhject that defines a data set containing information of the salt, iv and the encrypted content.
    /// 
    /// </summary>
    /// <remarks>
    /// Author: berndoJ / Copyright 2018 Johannes Berndorfer
    /// Created: 13.03.2018 11:20:56
    /// </remarks>
    public struct EncryptedData
    {
        /// <summary>
        /// The initialization vector of the encryption
        /// </summary>
        public byte[] IV { get; set; }

        /// <summary>
        /// The salt used to genereate a key from a password string
        /// </summary>
        public byte[] Salt { get; set; }

        /// <summary>
        /// The encrypted data content of this struct
        /// </summary>
        public byte[] EncryptedDataContent { get; set; }
    }

    /// <summary>
    /// 
    /// A class that contains some options used for the encryption/decryption process.
    /// The objects in the class are readonly, set only when instanciating the class.
    /// 
    /// </summary>
    /// <remarks>
    /// Author: berndoJ / Copyright 2018 Johannes Berndorfer
    /// Created: 13.03.2018 11:20:56
    /// </remarks>
    public class EncryptionOptions
    {
        #region Presets

        /// <summary>
        /// The default encryption options for the cryptographer.
        /// </summary>
        public static readonly EncryptionOptions DEFAULT_OPTS = new EncryptionOptions(3000, 128, CipherMode.CBC, PaddingMode.PKCS7);

        #endregion

        #region Public Objects

        /// <summary>
        /// Defines how many iterations should be done when generating a key from a string password
        /// Standart is 3000 / Minimum is 1000
        /// </summary>
        public int KeyGenerationIterations { get; private set; }

        /// <summary>
        /// Defines the byte length of a standart generated salt.
        /// The minimum value is 64. Standart is 128
        /// </summary>
        public int SaltByteLength { get; private set; }

        /// <summary>
        /// Defines the cipher mode used.
        /// Standard is <see cref="CipherMode.CBC"/>
        /// </summary>
        public CipherMode CipherModeUsed { get; private set; }

        /// <summary>
        /// Defines the padding mode used in the process.
        /// Standard is <see cref="PaddingMode.PKCS7"/>
        /// </summary>
        public PaddingMode PaddingModeUsed { get; private set; }

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor of this class.
        /// </summary>
        /// <param name="SaltGenerationIterations">Iterations when generating salt.</param>
        /// <param name="CipherModeUsed">The cipher mode used in the process.</param>
        /// <param name="PaddingModeUsed">The padding mode used in the process.</param>
        public EncryptionOptions(int KeyGenerationIterations, int SaltByteLength, CipherMode CipherModeUsed, PaddingMode PaddingModeUsed)
        {
            if (KeyGenerationIterations < 1000) throw new InvalidOperationException();
            if (SaltByteLength < 64) throw new InvalidOperationException();
            this.KeyGenerationIterations = KeyGenerationIterations;
            this.SaltByteLength = SaltByteLength;
            this.CipherModeUsed = CipherModeUsed;
            this.PaddingModeUsed = PaddingModeUsed;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Gets the serialized version of an instance of this class.
        /// </summary>
        /// <returns>The serialized version of this class.</returns>
        public string GetSerialized()
        {
            // Init of SerializedString
            string SerializedString = "";
            // Key gen iterations
            SerializedString += $"KeyGenIterations:{this.KeyGenerationIterations.ToString()}";
            // Salt byte length
            SerializedString += $";SaltByteLength:{this.SaltByteLength.ToString()}";
            // Cipher mode
            string CipherModeStr = "";
            switch (this.CipherModeUsed)
            {
                case CipherMode.CBC:
                    CipherModeStr = "CBC";
                    break;
                case CipherMode.CFB:
                    CipherModeStr = "CFB";
                    break;
                case CipherMode.CTS:
                    CipherModeStr = "CTS";
                    break;
                case CipherMode.ECB:
                    CipherModeStr = "ECB";
                    break;
                case CipherMode.OFB:
                    CipherModeStr = "OFB";
                    break;
                default:
                    CipherModeStr = "CBC";
                    break;
            }
            SerializedString += $";CipherMode:{CipherModeStr}";
            // Padding mode
            string PaddingModeStr = "";
            switch (this.PaddingModeUsed)
            {
                case PaddingMode.ANSIX923:
                    PaddingModeStr = "ANSIX923";
                    break;
                case PaddingMode.ISO10126:
                    PaddingModeStr = "ISO10126";
                    break;
                case PaddingMode.None:
                    PaddingModeStr = "None";
                    break;
                case PaddingMode.PKCS7:
                    PaddingModeStr = "PKCS7";
                    break;
                case PaddingMode.Zeros:
                    PaddingModeStr = "Zeros";
                    break;
                default:
                    PaddingModeStr = "PKCS7";
                    break;
            }
            SerializedString += $";PaddingMode:{PaddingModeStr}";
            // Return
            return SerializedString;
        }

        #endregion

        #region Static Methods

        /// <summary>
        /// Deserializes a string to this class
        /// </summary>
        /// <param name="SerializedString">The serialized class</param>
        /// <returns>The class</returns>
        public static EncryptionOptions Deserialize(string SerializedString)
        {
            // Init of fields
            int KeyGenIterations = 3000;
            int SaltByteLength = 128;
            CipherMode CipherModeUsed = CipherMode.CBC;
            PaddingMode PaddingModeUsed = PaddingMode.PKCS7;
            // Init of strings
            try
            {
                string[] Components = SerializedString.Split(';');
                if (Components.Length == 4)
                {
                    // Key gen iterations
                    string Comp1 = Components[0];
                    string[] Comp1Vals = Comp1.Split(':');
                    KeyGenIterations = int.Parse(Comp1Vals[1]);
                    // Salt byte length
                    string Comp2 = Components[1];
                    string[] Comp2Vals = Comp2.Split(':');
                    SaltByteLength = int.Parse(Comp2Vals[1]);
                    // Cipher mode
                    string Comp3 = Components[2];
                    string[] Comp3Vals = Comp3.Split(':');
                    switch (Comp3Vals[1])
                    {
                        case "CBC":
                            CipherModeUsed = CipherMode.CBC;
                            break;
                        case "CFB":
                            CipherModeUsed = CipherMode.CFB;
                            break;
                        case "CTS":
                            CipherModeUsed = CipherMode.CTS;
                            break;
                        case "ECB":
                            CipherModeUsed = CipherMode.ECB;
                            break;
                        case "OFB":
                            CipherModeUsed = CipherMode.OFB;
                            break;
                        default:
                            CipherModeUsed = CipherMode.CBC;
                            break;
                    }
                    // Padding mode
                    string Comp4 = Components[3];
                    string[] Comp4Vals = Comp4.Split(':');
                    switch (Comp4Vals[1])
                    {
                        case "ANSIX923":
                            PaddingModeUsed = PaddingMode.ANSIX923;
                            break;
                        case "ISO10126":
                            PaddingModeUsed = PaddingMode.ISO10126;
                            break;
                        case "None":
                            PaddingModeUsed = PaddingMode.None;
                            break;
                        case "PKCS7":
                            PaddingModeUsed = PaddingMode.PKCS7;
                            break;
                        case "Zeros":
                            PaddingModeUsed = PaddingMode.Zeros;
                            break;
                        default:
                            PaddingModeUsed = PaddingMode.PKCS7;
                            break;
                    }
                }
            }
            catch (Exception) { }
            return new EncryptionOptions(KeyGenIterations, SaltByteLength, CipherModeUsed, PaddingModeUsed);
        }

        #endregion
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
使用系统安全;
使用System.Security.Cryptography;
使用System.Runtime.InteropServices;
使用System.IO;
名称空间BerndoJLib.Cryptography
{
/// 
/// 
///控制数据库安全加密和解密的助手类。
///包含加密和解密字节数组的方法。
/// 
/// 
/// 
///作者:berndoJ/版权所有2018 Johannes Berndorfer
///创建时间:13.03.2018 11:20:56
/// 
公共类密码器
{
#区域公共对象
/// 
///设置此加密程序/算法选项的选项
/// 
公共加密选项算法选项{get;set;}
#端区
#区域构造函数
/// 
///这个类的构造函数。
/// 
///此加密程序实例的选项
公共加密程序(加密选项算法选项)
{
this.AlgorithmOptions=算法选项;
}
#端区
#区域方法
/// 
///一个函数,用于生成一个新序列,用作一次加密的salt。
///此序列的字节长度由属性设置。
///在这种情况下,可以使用随机字节生成器。
/// 
///数组中的字节序列
公共字节[]GenerateNewSaltSequence()
{
byte[]SaltSequence=新字节[this.AlgorithmOptions.SaltByteLength];
RNGCryptoServiceProvider RNGCsp=新的RNGCryptoServiceProvider();
RNGCsp.GetNonZeroBytes(SaltSequence);
返回序列;
}
/// 
///此函数从输入的字符串键派生指定的字节数组(长度规范)。该键不必来自特定长度。
///为了维护安全性,如果不再使用,则此函数返回的字节[]应设置为零。
///类提供了用于实现此过程的方法。
///此过程的迭代次数由属性设置。
/// 
///SecureString形式的密钥
///生成的密钥的大小(以位为单位)
///用于散列密钥的salt序列
///从字符串对应项派生的字节数组形式的键
公共字节[]DeriveKeyFromString(SecureString键,int-KeySize,字节[]SaltSequence)
{
/*DeriveBytes DrvBytes=新的Rfc2898DeriveBytes(键,SaltSequence,this.AlgorithmOptions.KeyGenerationIterations);
返回DrvBytes.GetBytes(KeySize>>3);*///The>>3只获取字节的下限值。
IntPtr StrPtr=Marshal.SecureStringToBSTR(键);
字节[]PwdByteArray=null;
尝试
{
int StrLength=Marshal.ReadInt32(strprtr,-4);
PwdByteArray=新字节[StrLength];
GCHandle=GCHandle.Alloc(PwdByteArray,GCHandleType.pinted);
尝试
{
对于(int i=0;i>3);
}
最后
{
Array.Clear(PwdByteArray,0,PwdByteArray.Length);
Handle.Free();
}
}
最后
{
ZeroFreeBSTR元帅(StrPtr);
}
}
/// 
///使用给定的密钥加密给定的数据(以字节[]的形式)。所有选项等都由属性定义。
/// 
///以字节数组形式提供给函数的数据
///加密数据的密钥
///包含IV、Salt和EncryptedData的EncryptedData对象
公共加密数据加密(字节[]数据输入,SecureString密钥)
{
//EncryptedData上下文初始化
EncryptedData EncryptedDataContext=新的EncryptedData();
EncryptedDataContext.Salt=this.GenerateNewSaltSequence();
//CSP初始化
使用(AESCryptServiceProvider AESCsp=新的AESCryptServiceProvider())
{
//生成IV并将其存储在EncryptedData上下文中。
AESCsp.GenerateIV();
EncryptedDataContext.IV=AESCsp.IV;
//从字符串键派生字节[]键
AESCsp.Key=this.DeriveKeyFromString(Key,AESCsp.KeySize,EncryptedDataContext.Salt);
//初始化CSP选项
AESCsp.Mode=this.AlgorithmOptions.CipherModeUsed;
AESCsp.Padding=this.AlgorithmOptions.PaddingModeUsed;
//加密码
使用(MemoryStream MemStrm=新的MemoryStream(数据长度))
{
使用(ICryptoTransform EncryptionTransformer=AESCsp.CreateEncryptor())
{
使用(CryptoStream CryptoStrm=new CryptoStream(MemStrm、EncryptionTransformer、CryptoStreamMode.Write))
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.IO;

namespace BerndoJLib.Cryptography
{
    /// <summary>
    /// 
    /// A helper class that controls security encrypting and decrypting of the database.
    /// Contains the methods to encrypt and decrypt byte arrays.
    /// 
    /// </summary>
    /// <remarks>
    /// Author: berndoJ / Copyright 2018 Johannes Berndorfer
    /// Created: 13.03.2018 11:20:56
    /// </remarks>
    public class Cryptographer
    {
        #region Public Objects

        /// <summary>
        /// Sets the options of this cryptographer / the algorithm options
        /// </summary>
        public EncryptionOptions AlgorithmOptions { get; set; }

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor of this class.
        /// </summary>
        /// <param name="AlgorithmOptions">The options of this cryptographer instance</param>
        public Cryptographer(EncryptionOptions AlgorithmOptions)
        {
            this.AlgorithmOptions = AlgorithmOptions;
        }

        #endregion

        #region Methods

        /// <summary>
        /// A function to generate a new sequence to use as a salt for one encryption.
        /// The byte-length of this sequence is set by the <see cref="AlgorithmOptions"/> property.
        /// The random byte generator <see cref="RNGCryptoServiceProvider"/> is a good option to use in this case.
        /// </summary>
        /// <returns>The sequence of bytes in an array</returns>
        public byte[] GenerateNewSaltSequence()
        {
            byte[] SaltSequence = new byte[this.AlgorithmOptions.SaltByteLength];
            RNGCryptoServiceProvider RNGCsp = new RNGCryptoServiceProvider();
            RNGCsp.GetNonZeroBytes(SaltSequence);
            return SaltSequence;
        }

        /// <summary>
        /// This function derives a specified byte array (length spec) from a string key entered. The key does not have to be from a certain length.
        /// For maintaining security, the byte[] returned by this function should be set to zero if not used anymore.
        /// The method used to achieve this process is made available by the <see cref="Rfc2898DeriveBytes"/> class.
        /// The count of iterations of this process is set by the <see cref="AlgorithmOptions"/> property.
        /// </summary>
        /// <param name="Key">The key in the form of a SecureString</param>
        /// <param name="KeySize">The size (in bits) of the key generated</param>
        /// <param name="SaltSequence">The salt sequence used to hash the key</param>
        /// <returns>A key in form of a byte array derived from the string counterpart</returns>
        public byte[] DeriveKeyFromString(SecureString Key, int KeySize, byte[] SaltSequence)
        {
            /*DeriveBytes DrvBytes = new Rfc2898DeriveBytes(Key, SaltSequence, this.AlgorithmOptions.KeyGenerationIterations);
            return DrvBytes.GetBytes(KeySize >> 3);*/ // The >> 3 just gets the floored value of bytes.
            IntPtr StrPtr = Marshal.SecureStringToBSTR(Key);
            byte[] PwdByteArray = null;
            try
            {
                int StrLength = Marshal.ReadInt32(StrPtr, -4);
                PwdByteArray = new byte[StrLength];
                GCHandle Handle = GCHandle.Alloc(PwdByteArray, GCHandleType.Pinned);
                try
                {
                    for (int i = 0; i < StrLength; i++)
                        PwdByteArray[i] = Marshal.ReadByte(StrPtr, i);
                    using (Rfc2898DeriveBytes DrvBytes = new Rfc2898DeriveBytes(PwdByteArray, SaltSequence, this.AlgorithmOptions.KeyGenerationIterations))
                        return DrvBytes.GetBytes(KeySize >> 3);
                }
                finally
                {
                    Array.Clear(PwdByteArray, 0, PwdByteArray.Length);
                    Handle.Free();
                }
            }
            finally
            {
                Marshal.ZeroFreeBSTR(StrPtr);
            }
        }

        /// <summary>
        /// Encrypts the given data (in form of a byte[]) with the Key given. All the options and so on are defined by the <see cref="AlgorithmOptions"/> property.
        /// </summary>
        /// <param name="DataIn">The data given to the function in form of a byte array</param>
        /// <param name="Key">The key to encrypt the data</param>
        /// <returns>An EncryptedData object which contains IV, Salt and EncryptedData</returns>
        public EncryptedData Encrypt(byte[] DataIn, SecureString Key)
        {
            // EncryptedData context init
            EncryptedData EncryptedDataContext = new EncryptedData();
            EncryptedDataContext.Salt = this.GenerateNewSaltSequence();
            // CSP init
            using(AesCryptoServiceProvider AESCsp = new AesCryptoServiceProvider())
            {
                // Generate the IV and store it in the EncryptedData context.
                AESCsp.GenerateIV();
                EncryptedDataContext.IV = AESCsp.IV;
                // Derive the byte[] key from the string key
                AESCsp.Key = this.DeriveKeyFromString(Key, AESCsp.KeySize, EncryptedDataContext.Salt);
                // Init the CSP options
                AESCsp.Mode = this.AlgorithmOptions.CipherModeUsed;
                AESCsp.Padding = this.AlgorithmOptions.PaddingModeUsed;
                // Encryption code
                using (MemoryStream MemStrm = new MemoryStream(DataIn.Length))
                {
                    using (ICryptoTransform EncryptionTransformer = AESCsp.CreateEncryptor())
                    {
                        using (CryptoStream CryptoStrm = new CryptoStream(MemStrm, EncryptionTransformer, CryptoStreamMode.Write))
                        {
                            CryptoStrm.Write(DataIn, 0, DataIn.Length);
                            CryptoStrm.FlushFinalBlock();
                            EncryptedDataContext.EncryptedDataContent = MemStrm.ToArray();
                        }
                    }
                }
                // Disposing the key object in the AESCsp to reduce chance of acidentially leaving it in memory after the using closed AESCsp.
                Array.Clear(AESCsp.Key, 0, AESCsp.Key.Length);
                // Returning the EncryptedData
                return EncryptedDataContext;
            }
        }

        /// <summary>
        /// Decrypts the given encrypted data with the use of the given key.
        /// <para>
        /// Returns a tuple which contains the following information: If the decryption was successful (If the key was the right one) and the decrypted data if the decrpyton was in fact successful.
        /// </para>
        /// </summary>
        /// <param name="EncryptedDataIn">The data given to the decryption method</param>
        /// <param name="Key">The key to decrypt the data</param>
        /// <returns>A tuple with: The successfulness of the decryption (is key correct); The decrypted data;</returns>
        public Tuple<bool, byte[]> Decrypt(EncryptedData EncryptedDataIn, SecureString Key)
        {
            // Create a return tuple, Item1 is the successfulness, Item2 the decrypted data if the decryption was successful.
            Tuple<bool, byte[]> DecryptionResult = new Tuple<bool, byte[]>(false, null);
            try
            {
                using (AesCryptoServiceProvider AESCsp = new AesCryptoServiceProvider())
                {
                    // Init the IV
                    AESCsp.IV = EncryptedDataIn.IV;
                    // Init the AESCsp key object
                    AESCsp.Key = this.DeriveKeyFromString(Key, AESCsp.KeySize, EncryptedDataIn.Salt);
                    // Init the CSP options
                    AESCsp.Mode = this.AlgorithmOptions.CipherModeUsed;
                    AESCsp.Padding = this.AlgorithmOptions.PaddingModeUsed;
                    // Decryption code
                    using (MemoryStream MemStrm = new MemoryStream(EncryptedDataIn.EncryptedDataContent))
                    {
                        using (ICryptoTransform DecryptionTransformer = AESCsp.CreateDecryptor())
                        {
                            using (CryptoStream CryptoStrm = new CryptoStream(MemStrm, DecryptionTransformer, CryptoStreamMode.Read))
                            {
                                using (MemoryStream SequenceMemStrm = new MemoryStream())
                                {
                                    // Define a buffer to read sequences.
                                    byte[] SequenceBuffer = new byte[2048];
                                    // Init a variable that keeps track of how many bytes have been written to the buffer
                                    int ReadBytes;
                                    // Loop to read all the bytes in the CryptoStrm
                                    while((ReadBytes = CryptoStrm.Read(SequenceBuffer, 0, SequenceBuffer.Length)) > 0)
                                    {
                                        SequenceMemStrm.Write(SequenceBuffer, 0, ReadBytes);
                                    }
                                    // Set the DecryptionResult to: successful; Data in SequenceMemStrm;
                                    DecryptionResult = new Tuple<bool, byte[]>(true, SequenceMemStrm.ToArray());
                                }
                            }
                        }
                    }
                    // Disposing the key object in the AESCsp to reduce chance of acidentially leaving it in memory after the using closed AESCsp.
                    Array.Clear(AESCsp.Key, 0, AESCsp.Key.Length);
                    // Returning the DecryptionResult
                    return DecryptionResult;
                }
            }
            catch (Exception)
            {
                // The decryption failed, the key is not the right one.
                DecryptionResult = new Tuple<bool, byte[]>(false, null);
                return DecryptionResult;
            }
        }

        #endregion
    }

    /// <summary>
    /// 
    /// A struct obhject that defines a data set containing information of the salt, iv and the encrypted content.
    /// 
    /// </summary>
    /// <remarks>
    /// Author: berndoJ / Copyright 2018 Johannes Berndorfer
    /// Created: 13.03.2018 11:20:56
    /// </remarks>
    public struct EncryptedData
    {
        /// <summary>
        /// The initialization vector of the encryption
        /// </summary>
        public byte[] IV { get; set; }

        /// <summary>
        /// The salt used to genereate a key from a password string
        /// </summary>
        public byte[] Salt { get; set; }

        /// <summary>
        /// The encrypted data content of this struct
        /// </summary>
        public byte[] EncryptedDataContent { get; set; }
    }

    /// <summary>
    /// 
    /// A class that contains some options used for the encryption/decryption process.
    /// The objects in the class are readonly, set only when instanciating the class.
    /// 
    /// </summary>
    /// <remarks>
    /// Author: berndoJ / Copyright 2018 Johannes Berndorfer
    /// Created: 13.03.2018 11:20:56
    /// </remarks>
    public class EncryptionOptions
    {
        #region Presets

        /// <summary>
        /// The default encryption options for the cryptographer.
        /// </summary>
        public static readonly EncryptionOptions DEFAULT_OPTS = new EncryptionOptions(3000, 128, CipherMode.CBC, PaddingMode.PKCS7);

        #endregion

        #region Public Objects

        /// <summary>
        /// Defines how many iterations should be done when generating a key from a string password
        /// Standart is 3000 / Minimum is 1000
        /// </summary>
        public int KeyGenerationIterations { get; private set; }

        /// <summary>
        /// Defines the byte length of a standart generated salt.
        /// The minimum value is 64. Standart is 128
        /// </summary>
        public int SaltByteLength { get; private set; }

        /// <summary>
        /// Defines the cipher mode used.
        /// Standard is <see cref="CipherMode.CBC"/>
        /// </summary>
        public CipherMode CipherModeUsed { get; private set; }

        /// <summary>
        /// Defines the padding mode used in the process.
        /// Standard is <see cref="PaddingMode.PKCS7"/>
        /// </summary>
        public PaddingMode PaddingModeUsed { get; private set; }

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor of this class.
        /// </summary>
        /// <param name="SaltGenerationIterations">Iterations when generating salt.</param>
        /// <param name="CipherModeUsed">The cipher mode used in the process.</param>
        /// <param name="PaddingModeUsed">The padding mode used in the process.</param>
        public EncryptionOptions(int KeyGenerationIterations, int SaltByteLength, CipherMode CipherModeUsed, PaddingMode PaddingModeUsed)
        {
            if (KeyGenerationIterations < 1000) throw new InvalidOperationException();
            if (SaltByteLength < 64) throw new InvalidOperationException();
            this.KeyGenerationIterations = KeyGenerationIterations;
            this.SaltByteLength = SaltByteLength;
            this.CipherModeUsed = CipherModeUsed;
            this.PaddingModeUsed = PaddingModeUsed;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Gets the serialized version of an instance of this class.
        /// </summary>
        /// <returns>The serialized version of this class.</returns>
        public string GetSerialized()
        {
            // Init of SerializedString
            string SerializedString = "";
            // Key gen iterations
            SerializedString += $"KeyGenIterations:{this.KeyGenerationIterations.ToString()}";
            // Salt byte length
            SerializedString += $";SaltByteLength:{this.SaltByteLength.ToString()}";
            // Cipher mode
            string CipherModeStr = "";
            switch (this.CipherModeUsed)
            {
                case CipherMode.CBC:
                    CipherModeStr = "CBC";
                    break;
                case CipherMode.CFB:
                    CipherModeStr = "CFB";
                    break;
                case CipherMode.CTS:
                    CipherModeStr = "CTS";
                    break;
                case CipherMode.ECB:
                    CipherModeStr = "ECB";
                    break;
                case CipherMode.OFB:
                    CipherModeStr = "OFB";
                    break;
                default:
                    CipherModeStr = "CBC";
                    break;
            }
            SerializedString += $";CipherMode:{CipherModeStr}";
            // Padding mode
            string PaddingModeStr = "";
            switch (this.PaddingModeUsed)
            {
                case PaddingMode.ANSIX923:
                    PaddingModeStr = "ANSIX923";
                    break;
                case PaddingMode.ISO10126:
                    PaddingModeStr = "ISO10126";
                    break;
                case PaddingMode.None:
                    PaddingModeStr = "None";
                    break;
                case PaddingMode.PKCS7:
                    PaddingModeStr = "PKCS7";
                    break;
                case PaddingMode.Zeros:
                    PaddingModeStr = "Zeros";
                    break;
                default:
                    PaddingModeStr = "PKCS7";
                    break;
            }
            SerializedString += $";PaddingMode:{PaddingModeStr}";
            // Return
            return SerializedString;
        }

        #endregion

        #region Static Methods

        /// <summary>
        /// Deserializes a string to this class
        /// </summary>
        /// <param name="SerializedString">The serialized class</param>
        /// <returns>The class</returns>
        public static EncryptionOptions Deserialize(string SerializedString)
        {
            // Init of fields
            int KeyGenIterations = 3000;
            int SaltByteLength = 128;
            CipherMode CipherModeUsed = CipherMode.CBC;
            PaddingMode PaddingModeUsed = PaddingMode.PKCS7;
            // Init of strings
            try
            {
                string[] Components = SerializedString.Split(';');
                if (Components.Length == 4)
                {
                    // Key gen iterations
                    string Comp1 = Components[0];
                    string[] Comp1Vals = Comp1.Split(':');
                    KeyGenIterations = int.Parse(Comp1Vals[1]);
                    // Salt byte length
                    string Comp2 = Components[1];
                    string[] Comp2Vals = Comp2.Split(':');
                    SaltByteLength = int.Parse(Comp2Vals[1]);
                    // Cipher mode
                    string Comp3 = Components[2];
                    string[] Comp3Vals = Comp3.Split(':');
                    switch (Comp3Vals[1])
                    {
                        case "CBC":
                            CipherModeUsed = CipherMode.CBC;
                            break;
                        case "CFB":
                            CipherModeUsed = CipherMode.CFB;
                            break;
                        case "CTS":
                            CipherModeUsed = CipherMode.CTS;
                            break;
                        case "ECB":
                            CipherModeUsed = CipherMode.ECB;
                            break;
                        case "OFB":
                            CipherModeUsed = CipherMode.OFB;
                            break;
                        default:
                            CipherModeUsed = CipherMode.CBC;
                            break;
                    }
                    // Padding mode
                    string Comp4 = Components[3];
                    string[] Comp4Vals = Comp4.Split(':');
                    switch (Comp4Vals[1])
                    {
                        case "ANSIX923":
                            PaddingModeUsed = PaddingMode.ANSIX923;
                            break;
                        case "ISO10126":
                            PaddingModeUsed = PaddingMode.ISO10126;
                            break;
                        case "None":
                            PaddingModeUsed = PaddingMode.None;
                            break;
                        case "PKCS7":
                            PaddingModeUsed = PaddingMode.PKCS7;
                            break;
                        case "Zeros":
                            PaddingModeUsed = PaddingMode.Zeros;
                            break;
                        default:
                            PaddingModeUsed = PaddingMode.PKCS7;
                            break;
                    }
                }
            }
            catch (Exception) { }
            return new EncryptionOptions(KeyGenIterations, SaltByteLength, CipherModeUsed, PaddingModeUsed);
        }

        #endregion
    }
}
public static string Encrypt(string plainText, string key)
{
    using (var enc = new RijndaelManaged())
    {
        byte[] key2 = Encoding.UTF8.GetBytes(key);
        // Rijndael supports keys of 16, 24, 32 byte long
        Array.Resize(ref key2, key2.Length <= 16 ? 16 : key2.Length <= 24 ? 24 : 32);
        enc.Key = key2; 
        enc.Mode = CipherMode.ECB;
        enc.Padding = PaddingMode.PKCS7;

        using (ICryptoTransform crypt = enc.CreateEncryptor())
        {
            byte[] plain = Encoding.UTF8.GetBytes(plainText);
            byte[] cipher = crypt.TransformFinalBlock(plain, 0, plain.Length);
            return Convert.ToBase64String(cipher);
        }
    }
}
public static string Decrypt(string cipherText, string key)
{
    using (var enc = new RijndaelManaged())
    {
        byte[] key2 = Encoding.UTF8.GetBytes(key);
        // Rijndael supports keys of 16, 24, 32 byte long
        Array.Resize(ref key2, key2.Length <= 16 ? 16 : key2.Length <= 24 ? 24 : 32);
        enc.Key = key2;
        enc.Mode = CipherMode.ECB;
        enc.Padding = PaddingMode.PKCS7;

        using (ICryptoTransform crypt = enc.CreateDecryptor())
        {
            byte[] cipher = Convert.FromBase64String(cipherText);
            byte[] plain = crypt.TransformFinalBlock(cipher, 0, cipher.Length);
            return Encoding.UTF8.GetString(plain);
        }
    }
}