2017年10月30日 星期一

C# 字串或檔案對稱加密、解密方式(AES、DES 演算法)

最近因為突然想要練習一下對字串做加解密的功能,基本上, MSDN 已經提供蠻完整的範例了,但還是參考了一下其他大神的寫法,在這邊記錄一下自己的版本

DES 演算法方式:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public static class DesCrypto
{
    public static string DesKey = "abcd1234"; //必須為 8 個 ASCII 字元
    public static string DesIv = "efgh5678"; //必須為 8 個 ASCII 字元

    /// <summary>   
    /// DES 加密字串   
    /// </summary>   
    /// <param  name="original">原始字串</param>   
    /// <param  name="key">Key,長度必須為 8 個 ASCII 字元</param>   
    /// <param  name="iv">IV,長度必須為 8 個 ASCII 字元</param>   
    /// <returns></returns>   
    public static string DesEncrypt(string original, string key, string iv)
    {
        string encrypt = "";

        try
        {
            var des = new DESCryptoServiceProvider();
            des.Key = Encoding.ASCII.GetBytes(key);
            des.IV = Encoding.ASCII.GetBytes(iv);
            byte[] dataByteArray = Encoding.UTF8.GetBytes(original);

            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(dataByteArray, 0, dataByteArray.Length);
                    cs.FlushFinalBlock();
                    encrypt = Convert.ToBase64String(ms.ToArray());
                }
            }
        }
        catch (Exception ex)
        {
            //todo...
        }

        return encrypt;
    }

    public static string DesEncrypt(string original)
    {
        return DesEncrypt(original, DesKey, DesIv);
    }


    /// <summary>   
    /// DES 解密字串   
    /// </summary>   
    /// <param  name="hexString">加密字串</param>   
    /// <param  name="key">Key,長度必須為 8 個 ASCII 字元</param>   
    /// <param  name="iv">IV,長度必須為 8 個 ASCII 字元</param>   
    /// <returns></returns>   
    public static string DesDecrypt(string hexString, string key, string iv)
    {
        string decrypt = hexString;
        try
        {
            var des = new DESCryptoServiceProvider();
            des.Key = Encoding.ASCII.GetBytes(DesKey);
            des.IV = Encoding.ASCII.GetBytes(DesIv);
            byte[] dataByteArray = Convert.FromBase64String(hexString);

            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(dataByteArray, 0, dataByteArray.Length);
                    cs.FlushFinalBlock();
                    decrypt =  Encoding.UTF8.GetString(ms.ToArray());
                }
            }
        }
        catch (Exception ex)
        {
            //todo...
        }
        
        return decrypt;
    }

    public static bool TryDesDecrypt(string hexString, out string original)
    {
        return hexString != (original = DesDecrypt(hexString, DesKey, DesIv));
    }
}

PS: 8 Bit = 1 Byte(ASCII), 128 Bit = 16 Byte, 256 Bit = 32 Byte


AES 演算法方式 I (含檔案加解密):

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public static class AesCrypto
{
    public static string AesKey = "隨便輸入一組字串"; //密鑰
    public static string AesIv = "也是隨便輸入一組字串"; //密鑰向量

    /// <summary>
    /// AES 加密字串
    /// </summary>
    /// <param name="original">原始字串</param>
    /// <param name="key">自訂金鑰</param>
    /// <param name="iv">自訂向量</param>
    /// <returns></returns>
    public static string AesEncrypt(string original, string key = null, string iv = null)
    {
        key = string.IsNullOrEmpty(key) ? AesKey : key;
        iv = string.IsNullOrEmpty(iv) ? AesIv : iv;

        string encrypt = "";
        try
        {
            AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider();
            byte[] keyData = sha256.ComputeHash(Encoding.UTF8.GetBytes(key));
            byte[] ivData = md5.ComputeHash(Encoding.UTF8.GetBytes(iv));
            byte[] dataByteArray = Encoding.UTF8.GetBytes(original);

            using (MemoryStream ms = new MemoryStream())
            {
                using (
                    CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(keyData, ivData), CryptoStreamMode.Write)
                )
                {
                    cs.Write(dataByteArray, 0, dataByteArray.Length);
                    cs.FlushFinalBlock();
                    encrypt = Convert.ToBase64String(ms.ToArray());
                }
            }
        }
        catch (Exception ex)
        {
            //todo...
        }

        return encrypt;
    }

    /// <summary>
    /// AES 解密字串
    /// </summary>
    /// <param name="hexString">已加密字串</param>
    /// <param name="key">自訂金鑰</param>
    /// <param name="iv">自訂向量</param>
    /// <returns></returns>
    public static string AesDecrypt(string hexString, string key = null, string iv = null)
    {
        key = string.IsNullOrEmpty(key) ? AesKey : key;
        iv = string.IsNullOrEmpty(iv) ? AesIv : iv;

        string decrypt = hexString;
        try
        {
            SymmetricAlgorithm aes = new AesCryptoServiceProvider();
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider();
            byte[] keyData = sha256.ComputeHash(Encoding.UTF8.GetBytes(key));
            byte[] ivData = md5.ComputeHash(Encoding.UTF8.GetBytes(iv));
            byte[] dataByteArray = Convert.FromBase64String(hexString);

            using (MemoryStream ms = new MemoryStream())
            {
                using (
                    CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(keyData, ivData), CryptoStreamMode.Write)
                )
                {
                    cs.Write(dataByteArray, 0, dataByteArray.Length);
                    cs.FlushFinalBlock();
                    decrypt = Encoding.UTF8.GetString(ms.ToArray());
                }
            }
        }
        catch (Exception ex)
        {
            //todo...
        }

        return decrypt;
    }

    public static bool TryAesDecrypt(string hexString, out string original, string key = null, string iv = null)
    {
        return hexString != (original = AesDecrypt(hexString, key, iv));
    }

    /// <summary>
    /// AES 加密檔案
    /// </summary>
    /// <param name="sourceFile">原始檔案路徑</param>
    /// <param name="encryptFile">加密後檔案路徑</param>
    /// <param name="key">自訂金鑰</param>
    /// <param name="iv">自訂向量</param>
    public static bool AesEncryptFile(string sourceFile, string encryptFile, string key = null, string iv = null)
    {
        key = string.IsNullOrEmpty(key) ? AesKey : key;
        iv = string.IsNullOrEmpty(iv) ? AesIv : iv;

        if (string.IsNullOrEmpty(sourceFile) || string.IsNullOrEmpty(encryptFile) || !File.Exists(sourceFile))
        {
            return false;
        }

        try
        {
            AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider();
            byte[] keyData = sha256.ComputeHash(Encoding.UTF8.GetBytes(key));
            byte[] ivData = md5.ComputeHash(Encoding.UTF8.GetBytes(iv));
            aes.Key = keyData;
            aes.IV = ivData;

            using (FileStream sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read))
            {
                using (FileStream encryptStream = new FileStream(encryptFile, FileMode.Create, FileAccess.Write))
                {
                    //檔案加密
                    byte[] dataByteArray = new byte[sourceStream.Length];
                    sourceStream.Read(dataByteArray, 0, dataByteArray.Length);

                    using (CryptoStream cs = new CryptoStream(encryptStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(dataByteArray, 0, dataByteArray.Length);
                        cs.FlushFinalBlock();
                    }
                }
            }
        }
        catch (Exception ex)
        {
            //todo...
            return false;
        }

        return true;
    }

    /// <summary>
    /// AES 解密檔
    /// </summary>
    /// <param name="encryptFile"></param>
    /// <param name="decryptFile"></param>
    /// <param name="key"></param>
    /// <param name="iv"></param>
    /// <returns></returns>
    public static bool AesDecryptFile(string encryptFile, string decryptFile, string key = null, string iv = null)
    {
        key = string.IsNullOrEmpty(key) ? AesKey : key;
        iv = string.IsNullOrEmpty(iv) ? AesIv : iv;

        if (string.IsNullOrEmpty(encryptFile) || string.IsNullOrEmpty(decryptFile) || !File.Exists(encryptFile))
        {
            return false;
        }

        try
        {
            AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider();
            byte[] keyData = sha256.ComputeHash(Encoding.UTF8.GetBytes(key));
            byte[] ivData = md5.ComputeHash(Encoding.UTF8.GetBytes(iv));
            aes.Key = keyData;
            aes.IV = ivData;

            using (FileStream encryptStream = new FileStream(encryptFile, FileMode.Open, FileAccess.Read))
            {
                using (FileStream decryptStream = new FileStream(decryptFile, FileMode.Create, FileAccess.Write))
                {
                    byte[] dataByteArray = new byte[encryptStream.Length];
                    encryptStream.Read(dataByteArray, 0, dataByteArray.Length);
                    using (CryptoStream cs = new CryptoStream(decryptStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(dataByteArray, 0, dataByteArray.Length);
                        cs.FlushFinalBlock();
                    }
                }
            }
        }
        catch (Exception ex)
        {
            //todo...
            return false;
        }

        return true;
    }
}


AES 演算法方式 II:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class AesCrypto
{        
    private static string AesKey = "abcdefgh12345678"; //密鑰(16 byte)
    private static string AesIv = "87654321hgfedcba"; //密鑰向量(16 byte)

    /// <summary>
    /// AES 加密字串
    /// </summary>
    /// <param name="original">原始字串</param>
    /// <param name="key">自訂金鑰</param>
    /// <param name="iv">自訂向量</param>
    /// <returns></returns>
    public static string AesEncrypt(string original, string key = null, string iv = null)
    {
        key = string.IsNullOrEmpty(key) ? AesKey : key;
        iv = string.IsNullOrEmpty(iv) ? AesIv : iv;
        string encrypt = "";

        try
        {
            using(Aes aesAlg = Aes.Create()) 
            {                
                aesAlg.Key = Encoding.UTF8.GetBytes(key);
                aesAlg.IV = Encoding.UTF8.GetBytes(iv);

                // Create the streams used for encryption.
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV), CryptoStreamMode.Write))
                    {
                        using (StreamWriter sw = new StreamWriter(cs))
                        {
                            //Write all data to the stream.
                            sw.Write(original);
                        }

                        encrypt = Convert.ToBase64String(ms.ToArray());
                    }
                }
            }
        }
        catch (Exception ex)
        {
            //todo...
        }

        return encrypt;
    }

    /// <summary>
    /// AES 解密字串
    /// </summary>
    /// <param name="hexString">已加密字串</param>
    /// <param name="key">自訂金鑰</param>
    /// <param name="iv">自訂向量</param>
    /// <returns></returns>
    public static string AesDecrypt(string hexString, string key = null, string iv = null)
    {
        key = string.IsNullOrEmpty(key) ? AesKey : key;
        iv = string.IsNullOrEmpty(iv) ? AesIv : iv;
        string decrypt = "";

        var encrypted = Convert.FromBase64String(hexString);
        
        try
        {
            using(Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = Encoding.UTF8.GetBytes(key);
                aesAlg.IV = Encoding.UTF8.GetBytes(iv);

                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                // Create the streams used for decryption.
                using (MemoryStream ms = new MemoryStream(encrypted))
                {
                    using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader sr = new StreamReader(cs))
                        {
                            // Read the decrypted bytes from the decrypting stream and place them in a string.
                            decrypt = sr.ReadToEnd();
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            //todo...
        }

        return decrypt;
    }

}


參考資料:

[JW]使用 AES 演算法為字串加密解密

[余小章]字串及檔案 利用 DES / AES 演算法加解密

MSDN的AES類別參考

MSDN的DES類別參考

訪客統計