1. 程式人生 > >用AES加密/解密字串

用AES加密/解密字串

高階加密標準(AES,Advanced Encryption Standard)為最常見的對稱加密演算法(微信小程式加密傳輸就是用這個加密演算法的)。對稱加密演算法也就是加密和解密用相同的金鑰,具體的加密流程如下圖: 

下面簡單介紹下各個部分的作用與意義:

  • 明文P

    沒有經過加密的資料。

  • 金鑰K

    用來加密明文的密碼,在對稱加密演算法中,加密與解密的金鑰是相同的。金鑰為接收方與傳送方協商產生,但不可以直接在網路上傳輸,否則會導致金鑰洩漏,通常是通過非對稱加密演算法加密金鑰,然後再通過網路傳輸給對方,或者直接面對面商量金鑰。金鑰是絕對不可以洩漏的,否則會被攻擊者還原密文,竊取機密資料。

  • AES加密函式

    設AES加密函式為E,則 C = E(K, P),其中P為明文,K為金鑰,C為密文。也就是說,把明文P和金鑰K作為加密函式的引數輸入,則加密函式E會輸出密文C。

  • 密文C

    經加密函式處理後的資料

  • AES解密函式

    設AES解密函式為D,則 P = D(K, C),其中C為密文,K為金鑰,P為明文。也就是說,把密文C和金鑰K作為解密函式的引數輸入,則解密函式會輸出明文P。

在這裡簡單介紹下對稱加密演算法與非對稱加密演算法的區別。

  • 對稱加密演算法

    加密和解密用到的金鑰是相同的,這種加密方式加密速度非常快,適合經常傳送資料的場合。缺點是金鑰的傳輸比較麻煩。

  • 非對稱加密演算法

    加密和解密用的金鑰是不同的,這種加密方式是用數學上的難解問題構造的,通常加密解密的速度比較慢,適合偶爾傳送資料的場合。優點是金鑰傳輸方便。常見的非對稱加密演算法為RSA、ECC和EIGamal。

實際中,一般是通過RSA加密AES的金鑰,傳輸到接收方,接收方解密得到AES金鑰,然後傳送方和接收方用AES金鑰來通訊。

加密 

/// <summary>
/// 使用AES加密字串
/// </summary>
/// <param name="encryptString">待加密字串</param>
/// <param name="encryptKey">加密密匙</param>
/// <param name="salt">鹽</param>
/// <returns>加密結果,加密失敗則返回源串</returns>
public static string EncryptAES(string encryptString, string encryptKey, string salt)
            {
                AesManaged aes = null;
                MemoryStream ms = null;
                CryptoStream cs = null;

                try
                {
                    Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(encryptKey, Encoding.UTF8.GetBytes(salt));

                    aes = new AesManaged();
                    aes.Key = rfc2898.GetBytes(aes.KeySize / 8);
                    aes.IV = rfc2898.GetBytes(aes.BlockSize / 8);

                    ms = new MemoryStream();
                    cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write);

                    byte[] data = Encoding.UTF8.GetBytes(encryptString);
                    cs.Write(data, 0, data.Length);
                    cs.FlushFinalBlock();

                    return Convert.ToBase64String(ms.ToArray());
                }
                catch
                {
                    return encryptString;
                }
                finally
                {
                    if (cs != null)
                        cs.Close();

                    if (ms != null)
                        ms.Close();

                    if (aes != null)
                        aes.Clear();
                }
            }

解密 

/// <summary>
/// 使用AES解密字串
/// </summary>
/// <param name="decryptString">待解密字串</param>
/// <param name="decryptKey">解密密匙</param>
/// <param name="salt">鹽</param>
/// <returns>解密結果,解謎失敗則返回源串</returns>
public static string DecryptAES(string decryptString, string decryptKey, string salt)
            {
                AesManaged aes = null;
                MemoryStream ms = null;
                CryptoStream cs = null;

                try
                {
                    Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(decryptKey, Encoding.UTF8.GetBytes(salt));

                    aes = new AesManaged();
                    aes.Key = rfc2898.GetBytes(aes.KeySize / 8);
                    aes.IV = rfc2898.GetBytes(aes.BlockSize / 8);

                    ms = new MemoryStream();
                    cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write);

                    byte[] data = Convert.FromBase64String(decryptString);
                    cs.Write(data, 0, data.Length);
                    cs.FlushFinalBlock();

                    return Encoding.UTF8.GetString(ms.ToArray(), 0, ms.ToArray().Length);
                }
                catch
                {
                    return decryptString;
                }
                finally
                {
                    if (cs != null)
                        cs.Close();

                    if (ms != null)
                        ms.Close();

                    if (aes != null)
                        aes.Clear();
                }
            }