日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

正确使用AES对称加密

發布時間:2023/12/4 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 正确使用AES对称加密 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正確使用AES對稱加密

經常我看到項目中有人使用了對稱加密算法,用來加密客戶或項目傳輸中的部分數據。但我注意到開發 人員由于不熟悉原理,或者簡單復制網上的代碼示例,有導致代碼存在安全風險。

我經常遇到的問題,有如下:

  • 如使用了過時的加密算法(如DES)

  • 設置了不安全的加密模式(ECB)

  • 不正確地處理初始向量(IV)

對稱加密算法

算法位長建議
RC440?
DES56?
3DES112?
AES128?

TL;DR:

RC4/DES/3DES都?不符合?加密/破解的安全性要求。

DES是56位加密,聽起來感覺3DES應該是168位,但實際上其有效加密位長只有112位。

其它更長的加密算法,如AES 192位/AES 256位也符合要求。

加密模式

TL;DR: 不要使用ECB。

ECB不需要初始向量(IV),這個“驚人”的發現常常讓開發簡單粗暴地設計為ECB。ECB的問題在于輸入和輸出存在非常明顯的關聯,攻擊者可以從輸出輕松地猜出輸入數據。

C#的AES算法默認模式為CBC,該算法沒有上述的安全問題,而且最為通用,可以使用該模式。

初始向量

TL;DR:
初始向量?必須?為完全隨機數,完全隨機數應該使用RandomNumberGenerator進行加密。

回想這個問題,數據加密完后,該發送什么給接收方?僅數據?那么初始向量(IV)怎么辦?

大多數開發選擇的辦法是,寫一個固定的初始向量(IV)用于加密,然后解密時,也使用相同的初始向量。這樣就導致相同的輸入會產生相同的輸出

為什么相同的輸入應該產生不同的輸出?因為根據歷史經驗,攻擊者可以獲取一些信息,知道某個確定輸入的含義。一旦再次捕獲到相同的加密數據,就能輕易破解。

所以,發送數據應該包含:版本+初始向量+數據。

面向字符串

加密是面向字節還是字符串?我認為應該面向字節。如果面向字符串,那么很多問題很難受到重視。

試著回答這個問題:

  • 用戶的密碼是什么樣子的?

  • 是長度為固定32位的HEX字符嗎?如1C8F7B2C9759209C6ACC3C105D39BBAC?

  • 還是用戶想輸入什么就輸入什么?如My-Super-Str0ng-Password!!?

我認為加密算法應該面向字節流/字節數據,而不是字符串。將字符串發送給客戶、放在JSON中進行端對端傳輸,是沒什么毛病的做法。但基于以下原因,我強烈建議加密/解密算法要基于字節數據:

  • 避免密碼太長或太短的問題

  • 來回轉換為字符串效率低下

  • 字符串轉換為字節數組容易,其它數據序列化為字節數據也容易

我的加密/解密方法

// 代碼按原樣提供,可隨意使用,但不對其安全性作任何保證。string Encrypt(string password, string purpose, byte[] plainBytes){ byte[] key = PasswordToKey(password, purpose); using (var aes = Aes.Create()) { aes.Key = key; using (ICryptoTransform encryptor = aes.CreateEncryptor()) { byte[] cipherBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length); byte[] packedBytes = Pack( version: 1, iv: aes.IV, cipherBytes: cipherBytes); return Base64UrlEncode(packedBytes); } }}byte[] Decrypt(string packedString, string password, string purpose){ byte[] key = PasswordToKey(password, purpose); byte[] packedBytes = Base64UrlDecode(packedString); (byte version, byte[] iv, byte[] cipherBytes) = Unpack(packedBytes); using (var aes = Aes.Create()) { using (ICryptoTransform decryptor = aes.CreateDecryptor(key, iv)) { return decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length); } }}

其中公共方法:

// 代碼按原樣提供,可隨意使用,但不對其安全性作任何保證。byte[] PasswordToKey(string password, string purpose){ using (var hmac = new HMACMD5(Encoding.UTF8.GetBytes(purpose))) { return hmac.ComputeHash(Encoding.UTF8.GetBytes(password)); }}string Base64UrlEncode(byte[] bytes){ return Convert.ToBase64String(bytes) .Replace("/", "_") .Replace("+", "-") .Replace("=", "");}byte[] Base64UrlDecode(string base64Url){ return Convert.FromBase64String(base64Url .Replace("_", "/") .Replace("-", "+"));}(byte version, byte[] iv, byte[] cipherBytes) Unpack(byte[] packedBytes){ if (packedBytes[0] == 1) { // version 1 return (1, packedBytes[1..1 + 16], packedBytes[1 + 16..]); } else { throw new NotImplementedException("unknown version"); }}byte[] Pack(byte version, byte[] iv, byte[] cipherBytes){ return new[] { version }.Concat(iv).Concat(cipherBytes).ToArray();}

解釋:

  • Base64UrlEncode/Decode:用于將字符串在Url上傳輸,將+/=轉換成:-_

  • Pack/Unpack:將版本/初始向量/密文打包/解包

  • PasswordToKey:將長度不一樣密碼,加上purpose,轉換為長度一樣的key,其中改成HMACSHA256可以使用256位的AES算法。

測試代碼:

// 代碼按原樣提供,可隨意使用,但不對其安全性作任何保證。string purpose = "這個算法是用來搞SSO的";// 返回:AcfCe3AQcmNkeNThv-u09H_HyGKy_iRy-7uGiW0IZOHIEncrypt("密碼here", purpose, Encoding.UTF8.GetBytes("Hello World"));// 返回:Hello WorldEncoding.UTF8.GetString(Decrypt("AcfCe3AQcmNkeNThv-u09H_HyGKy_iRy-7uGiW0IZOHI", "密碼here", purpose));


創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的正确使用AES对称加密的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。