iT邦幫忙

2022 iThome 鐵人賽

DAY 16
0
Software Development

玩轉C# 進階學習之旅系列 第 16

玩轉C#之【Encrypt加密解密】

  • 分享至 

  • xImage
  •  

介紹

這章節純看智商 /images/emoticon/emoticon06.gif

  • 不可逆加密:原文加密後變成密文,但密文沒辦法解密文回原文
  • 可逆加密:原文加密過後的密文,可以在將密文解密回原文
  • 對稱:表示加解密是否使用同一個key

MD5 不可逆加密

MD5 使用的命名空間是 System.Security.Cryptography

    /// <summary>
    /// 不可逆加密
    /// 1 防止被篡改
    /// 2 防止明文儲存
    /// 3 防止抵赖,數字簽名
    /// </summary>
    public class MD5Encrypt
    {
        #region MD5
        /// <summary>
        /// MD5加密
        /// 使用的UTF8編碼
        /// </summary>
        /// <param name="source">待加密字串</param>
        /// <param name="length">16或32值之一,其他則採用.net默認MD5加密算法</param>
        /// <returns>加密后的字串</returns>
        public static string Encrypt(string source, int length = 32)//默認參數
        {
            if (string.IsNullOrEmpty(source)) return string.Empty;
            HashAlgorithm provider = CryptoConfig.CreateFromName("MD5") as HashAlgorithm;
            byte[] bytes = Encoding.UTF8.GetBytes(source);//這裡需要區別編碼的
            byte[] hashValue = provider.ComputeHash(bytes);
            StringBuilder sb = new StringBuilder();
            switch (length)
            {
                case 16:
                    for (int i = 4; i < 12; i++)
                    {
                        sb.Append(hashValue[i].ToString("x2"));
                    }
                    break;
                case 32:
                    for (int i = 0; i < 16; i++)
                    {
                        sb.Append(hashValue[i].ToString("x2"));
                    }
                    break;
                default:
                    for (int i = 0; i < hashValue.Length; i++)
                    {
                        sb.Append(hashValue[i].ToString("x2"));
                    }
                    break;
            }
            return sb.ToString();
        }
        #endregion MD5

        #region MD5摘要
        /// <summary>
        /// 獲取檔案的MD5摘要
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string AbstractFile(string fileName)
        {
            using (FileStream file = new FileStream(fileName, FileMode.Open))
            {
                return AbstractFile(file);
            }
        }

        /// <summary>
        /// 根據stream獲取檔案摘要
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static string AbstractFile(Stream stream)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] retVal = md5.ComputeHash(stream);

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < retVal.Length; i++)
            {
                sb.Append(retVal[i].ToString("x2"));
            }
            return sb.ToString();
        }
        #endregion
    }

MD5是一種公開的算法,相同的字串可以得到一樣的結果
應用:可以做密碼檢查=>將使用者密碼md5一下,存到資料庫裡,下一次使用者輸入密碼的時候md5一下在做比對
MD5網路上的解密,都是使用樣本比對的方式
密碼複雜一點的方式,加鹽(密碼加上一段文字在做MD5) 或做兩次MD5

以下運用得原理,只有相同文件才能有相同的md5
應用:

  • 防止程式串改:下載VS安裝文件(md5)從官方網站下載,到非官方網站下載只要確認檔案的md5碼有沒有樣就可以

  • 急速秒傳:百度雲 一瞬間就傳完了,第一次上傳,傳完保存MD5,先計算md5--比對-匹配了就不需要上傳了

  • GIT/Svn: md5比對

任何數據MD5後結果都不一樣,到目前為止還沒碰過 2的128次方可能性

DES 對稱可逆加密

應用:數據傳輸
優點:加密速度快
缺點:密鑰的安全是問題
是公開的演算法,即使拿到密文,也推算不了密鑰,也推算不回原文

    /// <summary>
    /// DES AES Blowfish
    ///  對稱加密算法的優點是速度快,
    ///  缺點是密鑰管理不方便,要求共享密鑰。
    /// 可逆對稱加密,密鑰長度8
    /// </summary>
    public class DesEncrypt
    {
        private static byte[] _rgbKey = ASCIIEncoding.ASCII.GetBytes(Constant.DesKey.Substring(0, 8));
        private static byte[] _rgbIV = ASCIIEncoding.ASCII.GetBytes(Constant.DesKey.Insert(0, "w").Substring(0, 8));

        /// <summary>
        /// DES 加密
        /// </summary>
        /// <param name="text">需要加密的值</param>
        /// <returns>加密后的结果</returns>
        public static string Encrypt(string text)
        {
            DESCryptoServiceProvider dsp = new DESCryptoServiceProvider();
            using (MemoryStream memStream = new MemoryStream())
            {
                CryptoStream crypStream = new CryptoStream(memStream, dsp.CreateEncryptor(_rgbKey, _rgbIV), CryptoStreamMode.Write);
                StreamWriter sWriter = new StreamWriter(crypStream);
                sWriter.Write(text);
                sWriter.Flush();
                crypStream.FlushFinalBlock();
                memStream.Flush();
                return Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length);
            }
        }

        /// <summary>
        /// DES解密
        /// </summary>
        /// <param name="encryptText"></param>
        /// <returns>解密后的结果</returns>
        public static string Decrypt(string encryptText)
        {
            DESCryptoServiceProvider dsp = new DESCryptoServiceProvider();
            byte[] buffer = Convert.FromBase64String(encryptText);

            using (MemoryStream memStream = new MemoryStream())
            {
                CryptoStream crypStream = new CryptoStream(memStream, dsp.CreateDecryptor(_rgbKey, _rgbIV), CryptoStreamMode.Write);
                crypStream.Write(buffer, 0, buffer.Length);
                crypStream.FlushFinalBlock();
                return ASCIIEncoding.UTF8.GetString(memStream.ToArray());
            }
        }
    }

RSA 非對稱可逆加密

加密鑰做為私鑰
解密鑰做為公鑰
保證訊息一定來自某個人

張景嵐將訊息加密用的鑰始,只讓自己知道,並且將解開訊息需要用的鑰始公開給大家知道,如果有一段訊息能夠透過景嵐公開出的鑰始解出正確的訊息,就能確定此訊息一定是張景嵐發出來的

加密鑰做為公開
解密鑰做為私有
表示訊息只有我能看的到

張景嵐將訊息解密用的鑰始,只讓自己知道,並且將加密用的鑰始給大家知道,這時候大家都能把自己的訊息加密,但是只有張景嵐能夠知道是什麼訊息

加密解密速度不快,安全性好

    /// <summary>
    /// RSA ECC
    /// 可逆非對稱加密 
    /// 非對稱加密算法的優點是密鑰管理很方便,缺點速度慢。
    /// </summary>
    public class RsaEncrypt
    {
        /// <summary>
        /// 獲取加密/解密對
        /// 给你一個,是無法推算出另外一个的
        /// 
        /// Encrypt   Decrypt
        /// </summary>
        /// <returns>Encrypt   Decrypt</returns>
        public static KeyValuePair<string, string> GetKeyPair()
        {
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            string publicKey = RSA.ToXmlString(false);
            string privateKey = RSA.ToXmlString(true);
            return new KeyValuePair<string, string>(publicKey, privateKey);
        }

        /// <summary>
        /// 加密:内容+加密key
        /// </summary>
        /// <param name="content"></param>
        /// <param name="encryptKey">加密key</param>
        /// <returns></returns>
        public static string Encrypt(string content, string encryptKey)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(encryptKey);
            UnicodeEncoding ByteConverter = new UnicodeEncoding();
            byte[] DataToEncrypt = ByteConverter.GetBytes(content);
            byte[] resultBytes = rsa.Encrypt(DataToEncrypt, false);
            return Convert.ToBase64String(resultBytes);
        }

        /// <summary>
        /// 解密  内容+解密key
        /// </summary>
        /// <param name="content"></param>
        /// <param name="decryptKey">解密key</param>
        /// <returns></returns>
        public static string Decrypt(string content, string decryptKey)
        {
            byte[] dataToDecrypt = Convert.FromBase64String(content);
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.FromXmlString(decryptKey);
            byte[] resultBytes = RSA.Decrypt(dataToDecrypt, false);
            UnicodeEncoding ByteConverter = new UnicodeEncoding();
            return ByteConverter.GetString(resultBytes);
        }


        /// <summary>
        /// 可以合併在一起的,每次產生一组新的密鑰
        /// </summary>
        /// <param name="content"></param>
        /// <param name="encryptKey">加密key</param>
        /// <param name="decryptKey">解密key</param>
        /// <returns>加密后结果</returns>
        private static string Encrypt(string content, out string publicKey, out string privateKey)
        {
            RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider();
            publicKey = rsaProvider.ToXmlString(false);
            privateKey = rsaProvider.ToXmlString(true);

            UnicodeEncoding ByteConverter = new UnicodeEncoding();
            byte[] DataToEncrypt = ByteConverter.GetBytes(content);
            byte[] resultBytes = rsaProvider.Encrypt(DataToEncrypt, false);
            return Convert.ToBase64String(resultBytes);
        }
    }

關於數字證書SSL之後會專門寫一篇文章跟大家講解

參考資料

MD5 類別

本篇已同步發表至個人部落格
https://moushih.com/2022ithome16/


上一篇
玩轉C#之【表達式目錄樹】
下一篇
玩轉C#之【數據結構】
系列文
玩轉C# 進階學習之旅31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言