NET中各類加密解密方法 關於PKCS5Padding與PKCS7Padding的區別

        /// <summary>
        /// AES對稱加密和分組加密中的四種模式(ECB、CBC、CFB、OFB),這三種的區別,主要來自於密鑰的長度,16位密鑰=128位,24位密鑰=192位,32位密鑰=256位
        /// 檢驗密鑰是否有效長度【16|24|32】
        /// </summary>
        /// <param name="key">密鑰</param>
        /// <returns>bool</returns>
        private static bool AesCheckKey(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                return false;
            if (16.Equals(key.Length) || 24.Equals(key.Length) || 32.Equals(key.Length))
                return true;
            else
                return false;
        }
            
        #region 參數是string類型的
        /// <summary>
        ///  AES加密 參數:string
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="key">密鑰</param>    
        /// <param name="base64">是否轉64進制</param>
        /// <param name="model">運算模式</param>
        /// <param name="padding">填充模式</param>
        /// <param name="encoding">編碼類型</param>
        /// <returns>加密後的字符串</returns>
        public static string AesEncrypt(string source, string key, bool base64 = false, CipherMode model = CipherMode.ECB, PaddingMode padding = PaddingMode.PKCS7, Encoding encoding = null)
        {
            if (string.IsNullOrWhiteSpace(source)) return null;
            if (!AesCheckKey(key)) return source;
            if (encoding == null) encoding = Encoding.UTF8;
            using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
            {
                aesProvider.Key = encoding.GetBytes(key);
                aesProvider.Mode = model;
                aesProvider.Padding = padding;
                //aesProvider.KeySize = 128;
                //aesProvider.BlockSize = 128;               
                using (ICryptoTransform cryptoTransform = aesProvider.CreateEncryptor())
                {
                    byte[] toEncryptArray = encoding.GetBytes(source);               
                    byte[] resultArray = cryptoTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
                    aesProvider.Clear();
                    //return Convert.ToBase64String(resultArray, 0, resultArray.Length);
                    return base64 ? Convert.ToBase64String(resultArray) : byteToHexString(resultArray);
                }             
            }

            //RijndaelManaged rijndaelCipher = new RijndaelManaged();
            //rijndaelCipher.Mode = CipherMode.ECB;
            //rijndaelCipher.Padding = PaddingMode.PKCS7;
            //rijndaelCipher.KeySize = 128;
            //rijndaelCipher.BlockSize = 128;
            //byte[] pwdBytes = System.Text.Encoding.UTF8.GetBytes(key);
            //byte[] keyBytes = new byte[16];
            //int len = pwdBytes.Length;
            //if (len > keyBytes.Length) len = keyBytes.Length;
            //System.Array.Copy(pwdBytes, keyBytes, len);
            //rijndaelCipher.Key = keyBytes;
            ////加密初始化向量
            //string iv = "  ";
            //byte[] ivBytes = System.Text.Encoding.UTF8.GetBytes(iv);
            //rijndaelCipher.IV = new byte[16];
            //ICryptoTransform transform = rijndaelCipher.CreateEncryptor();
            //byte[] plainText = System.Text.Encoding.UTF8.GetBytes(source);
            //byte[] cipherBytes = transform.TransformFinalBlock(plainText, 0, plainText.Length);
            //return byteToHexString(cipherBytes);// Convert.ToBase64String(cipherBytes);          
        }
              
        /// <summary>
        ///  AES解密 參數:string
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="key">密鑰</param>     
        /// <param name="base64">是否轉64進制</param>
        /// <param name="model">運算模式</param>
        /// <param name="padding">填充模式</param>
        /// <param name="encoding">編碼類型</param>
        /// <returns>解密後的字符串</returns>
        public static string AesDecrypt(string source, string key, bool base64 = false, CipherMode model = CipherMode.ECB, PaddingMode padding = PaddingMode.PKCS7, Encoding encoding = null)
        {
            if (string.IsNullOrWhiteSpace(source)) return null;
            if (!AesCheckKey(key)) return source;
            if (encoding == null) encoding = Encoding.UTF8;
            using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
            {
                aesProvider.Key = encoding.GetBytes(key);
                aesProvider.Mode = model;
                aesProvider.Padding = padding;
                //aesProvider.KeySize = 128;
                //aesProvider.BlockSize = 128;      
                using (ICryptoTransform cryptoTransform = aesProvider.CreateDecryptor())
                {
                    byte[] toEncryptArray = base64 == true ? Convert.FromBase64String(source) : stringToHexByte(source);                
                    byte[] resultArray = cryptoTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
                    aesProvider.Clear();
                    return encoding.GetString(resultArray);
                }
            }     
        }
        #endregion

        /// <summary>
        /// 字節數組轉16進制字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string byteToHexString(byte[] bytes)
        {
            string returnStr = "";
            if (bytes != null)
            {
                for (int i = 0; i < bytes.Length; i++)
                {
                    returnStr += bytes[i].ToString("X2");
                }
            }
            return returnStr;
        }

        /// <summary>
        /// 將16進制字符串轉換爲字節數組     
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private static byte[] stringToHexByte(string hexString)
        {
            hexString = hexString.Replace(" ", "");
            if ((hexString.Length % 2) != 0)
                hexString += " ";
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            return returnBytes;
        }
        
        #region 參數是byte[]類型的
        /// <summary>  
        /// AES加密 參數:byte[] 
        /// </summary>  
        /// <param name="source">源字符字節組</param>
        /// <param name="key">密鑰</param>     
        /// <param name="model">運算模式</param>
        /// <param name="padding">填充模式</param>
        /// <param name="encoding">編碼類型</param>
        /// <returns>加密後的字符字節組</returns>  
        public static byte[] AesEncrypt(byte[] source, string key, CipherMode model = CipherMode.ECB, PaddingMode padding = PaddingMode.PKCS7, Encoding encoding = null)
        {
            if (source == null) return null;
            if (!AesCheckKey(key)) return source;
            if (encoding == null) encoding = Encoding.UTF8;
            byte[] bKey = encoding.GetBytes(key);       
            byte[] cryptograph = null; //加密後的密文  
            Rijndael Aes = Rijndael.Create();
            Aes.Key = bKey;          
            //開闢一塊內存流  
            using (MemoryStream Memory = new MemoryStream())
            {
                //把內存流對象包裝成加密流對象  
                using (CryptoStream Encryptor = new CryptoStream(Memory, Aes.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    //明文數據寫入加密流  
                    Encryptor.Write(source, 0, source.Length);
                    Encryptor.FlushFinalBlock();
                    cryptograph = Memory.ToArray();
                }
            }
            return cryptograph;
        }

        /// <summary>  
        /// AES解密 參數:byte[] 
        /// </summary>  
        /// <param name="source">源字符字節組</param>
        /// <param name="key">密鑰</param>     
        /// <param name="model">運算模式</param>
        /// <param name="padding">填充模式</param>
        /// <param name="encoding">編碼類型</param>
        /// <returns>解密後的字符字節組</returns>  
        public static byte[] AesDecrypt(byte[] source, string key, CipherMode model = CipherMode.ECB, PaddingMode padding = PaddingMode.PKCS7, Encoding encoding = null)
        {
            if (source == null) return null;
            if (!AesCheckKey(key)) return source;
            if (encoding == null) encoding = Encoding.UTF8;
            byte[] bKey = encoding.GetBytes(key);      
            byte[] original = null; //解密後的明文  
            Rijndael Aes = Rijndael.Create();
            //開闢一塊內存流,存儲密文  
            using (MemoryStream Memory = new MemoryStream(source))
            {
                //把內存流對象包裝成加密流對象  
                using (CryptoStream Decryptor = new CryptoStream(Memory, Aes.CreateDecryptor(bKey, null), CryptoStreamMode.Read))
                {
                    //明文存儲區  
                    using (MemoryStream originalMemory = new MemoryStream())
                    {
                        byte[] Buffer = new byte[1024];
                        int readBytes = 0;
                        while ((readBytes = Decryptor.Read(Buffer, 0, Buffer.Length)) > 0)
                        {
                            originalMemory.Write(Buffer, 0, readBytes);
                        }
                        original = originalMemory.ToArray();
                    }
                }
            }
            return original;
        }
        #endregion        

        /// <summary>
        /// 對字符串SHA1加密
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="encoding">編碼類型</param>
        /// <returns>加密後的十六進制字符串</returns>
        public static string Sha1Encrypt(string source, Encoding encoding = null)
        {
            if (encoding == null) encoding = Encoding.UTF8;

            // 第一種方式
            byte[] byteArray = encoding.GetBytes(source);
            using (HashAlgorithm hashAlgorithm = new SHA1CryptoServiceProvider())
            {
                byteArray = hashAlgorithm.ComputeHash(byteArray);
                StringBuilder stringBuilder = new StringBuilder(256);
                foreach (byte item in byteArray)
                {
                    stringBuilder.AppendFormat("{0:x2}", item);
                }
                hashAlgorithm.Clear();
                return stringBuilder.ToString();
            }

            //// 第二種方式
            //using (SHA1 sha1 = SHA1.Create())
            //{
            //    byte[] hash = sha1.ComputeHash(encoding.GetBytes(source));
            //    StringBuilder stringBuilder = new StringBuilder();
            //    for (int index = 0; index < hash.Length; ++index)
            //        stringBuilder.Append(hash[index].ToString("x2"));
            //    sha1.Clear();
            //    return stringBuilder.ToString();
            //}
        }

        /// <summary>
        /// 對字符串MD5加密
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="encoding">編碼類型</param>
        /// <returns>加密後的十六進制字符串</returns>
        public static string Md5Encrypt(string source, Encoding encoding = null)
        {
            if (encoding == null) encoding = Encoding.UTF8;

            byte[] byteArray = encoding.GetBytes(source);
            using (HashAlgorithm hashAlgorithm = new MD5CryptoServiceProvider())
            {
                byteArray = hashAlgorithm.ComputeHash(byteArray);
                StringBuilder stringBuilder = new StringBuilder();
                foreach (byte item in byteArray)
                {
                    stringBuilder.AppendFormat("{0:x2}", item);
                }
                hashAlgorithm.Clear();
                return stringBuilder.ToString();
            }
        }

AES加密方式中關於PKCS5Padding與PKCS7Padding的區別html

在PKCS5Padding中,明肯定義Block的大小是8位,而在PKCS7Padding定義中,對於塊的大小是不肯定的,能夠在1-255之間(塊長度超出255的尚待研究),填充值的算法都是同樣的:java

value=k - (l mod k) ,K=塊大小,l=數據長度,若是l=8, 則須要填充額外的8個byte的8算法

在.net中,例如TripleDESCryptoServiceProvider ,默認BlockSize=64bits=8bytes,因此在這種狀況下在PKCS5Padding=PKCS7Padding。數組

若是在C#中本身定義了一個不是64bits的加密塊大小,同時使用PKCS7Padding,那麼在java中使用JDK標準的PKCS5Padding就不能解密了。ide

相關文章
相關標籤/搜索