- 注意:AEAD_AES_256_GCM Key的長度必須是32位,nonce的長度必須是12位,附加數據有可能為空值。AEAD_AES_128_GCM Key的長度必須是16位,nonce的長度必須是12位,附加數據有可能為空值。
使用中AEAD_AES_256_GCM
還是AEAD_AES_128_GCM
加密,是根據key的長度來決定的。
size = key.Length * 8
256 = 32 * 8, AEAD_AES_256_GCM的key長度必須是 32 位。
128 = 16 * 8, AEAD_AES_128_GCM的key長度必須是 16 位。
英文好的可以看這個文檔rfc5116
使用官方AesGcm類
自aspnetcore3.0之后,System.Security.Cryptography
支持 AES_GCM
,不支持.net framework。在加密時,請使用AesGcmEncryptToBase64_WithTag
方法,這個方法的結果包含了tag (authentication tag)。加密結果最后面的16位字符就是tag,但是官方的加密方法沒有幫我們拼接上。
/// <summary> /// 使用 AesGcm 解密 /// </summary> /// <param name="key">key32位字符</param> /// <param name="nonce">隨機串12位</param> /// <param name="encryptedData">密文(Base64字符)</param> /// <param name="associatedData">(可能null)</param> /// <returns></returns> static string AesGcmDecryptFromBase64(string key, string nonce, string encryptedData, string associatedData) { var keyBytes = Encoding.UTF8.GetBytes(key); var nonceBytes = Encoding.UTF8.GetBytes(nonce); var associatedBytes = associatedData == null ? null : Encoding.UTF8.GetBytes(associatedData); var encryptedBytes = Convert.FromBase64String(encryptedData); //tag size is 16 var cipherBytes = encryptedBytes[..^16]; var tag = encryptedBytes[^16..]; var decryptedData = new byte[cipherBytes.Length]; using var cipher = new AesGcm(keyBytes); cipher.Decrypt(nonceBytes, cipherBytes, tag, decryptedData, associatedBytes); return Encoding.UTF8.GetString(decryptedData); } /// <summary> /// 使用 AesGcm AEAD_AES_256_GCM 加密,不要在正式環境中使用這個方法。因為在解密時不知道tag,除非額外返回tag。 /// </summary> /// <param name="key">key32位字符</param> /// <param name="nonce">隨機串12位</param> /// <param name="plainData">明文</param> /// <param name="associatedData">附加數據(可能null)</param> /// <returns>只返回加密數據不包含authentication tag</returns> static string AesGcmEncryptToBase64(string key, string nonce, string plainData, string associatedData) { var keyBytes = Encoding.UTF8.GetBytes(key); var nonceBytes = Encoding.UTF8.GetBytes(nonce); var associatedBytes = associatedData == null ? null : Encoding.UTF8.GetBytes(associatedData); var plainBytes = Encoding.UTF8.GetBytes(plainData); var cipherBytes = new byte[plainBytes.Length]; using var cipher = new AesGcm(keyBytes); //tag size must be is 16 var tag = new byte[16]; cipher.Encrypt(nonceBytes, plainBytes, cipherBytes, tag, associatedBytes); return Convert.ToBase64String(cipherBytes); } /// <summary> /// 使用 AesGcm進行AEAD_AES_256_GCM加密 /// </summary> /// <param name="key">key32位字符</param> /// <param name="nonce">隨機串12位</param> /// <param name="plainData">明文</param> /// <param name="associatedData">附加數據(可能null)</param> /// <returns>base64(加密后數據 + authentication tag)</returns> static string AesGcmEncryptToBase64_WithTag(string key, string nonce, string plainData, string associatedData) { var keyBytes = Encoding.UTF8.GetBytes(key); var nonceBytes = Encoding.UTF8.GetBytes(nonce); var associatedBytes = associatedData == null ? null : Encoding.UTF8.GetBytes(associatedData); var plainBytes = Encoding.UTF8.GetBytes(plainData); var cipherBytes = new byte[plainBytes.Length]; //tag size is 16 var tag = new byte[16]; using var cipher = new AesGcm(keyBytes); cipher.Encrypt(nonceBytes, plainBytes, cipherBytes, tag, associatedBytes); var cipherWithTag = new byte[cipherBytes.Length + tag.Length]; Buffer.BlockCopy(cipherBytes, 0, cipherWithTag, 0, cipherBytes.Length); Buffer.BlockCopy(tag, 0, cipherWithTag, cipherBytes.Length, tag.Length); return Convert.ToBase64String(cipherWithTag); }
測試代碼
var text = "{'A':123, count:'10', isOk:false, body:{'Text':'select * from table_A where name=@_p1', result:[{'id':1, 'age':23}]}}"; //KEY 必須是兩個32位 var key = "1234567890_1234567890_1234567890"; var nonce = "77d0a5ff3937";//Guid.NewGuid().ToString("N").Substring(0, 12); var associated = "6df132d42d0b4581"; //Guid.NewGuid().ToString("N").Substring(0, 16); var pythonResult = "PrTO/594j0CYMi2CQF9IFIp7UNkiTtIiIUbmR+jv1c1iO8Ng/HDFHDjL2t0DYo7xo5Vr0O0fUg9hD3bfCoomP+taVaPrW2kJbPTiFXkohXk3T80lQIdWP5lrl21vJvZO3MbmvshyjU+Oxk7pSnjiE5mw/sPXBs4jzS5wtvLUgHvWGaNxzw=="; Console.WriteLine(); var cipherText = AesGcmEncryptToBase64(key, nonce, text, nonce); Console.WriteLine($"原始密文Base64 :\t{cipherText}"); //Console.WriteLine($"密文tag Base64:\t\t{AesGcmEncryptToBase64(keyBytes, nonceBytes, text, associatedBytes)}"); Console.WriteLine($"Python GCM密文 :\t{pythonResult}"); var cryptText1 = AesGcmEncryptByBouncyCastle(key, nonce, text, associated); Console.WriteLine($"BouncyCastle密文: \t{cryptText1} "); var cryptText2 = AesGcmEncryptToBase64_WithTag(key, nonce, text, associated); Console.WriteLine($"密文+Tag Base64 : \t{cryptText2} "); Console.WriteLine(); Console.WriteLine(); var t30 = AesGcmDecryptByBouncyCastle(key, nonce, pythonResult, associated); Console.WriteLine($"BouncyCastle 解密 Python :{t30} \tisOk:{text == t30}"); var t40 = AesGcmDecryptFromBase64(key, nonce, pythonResult, associated); Console.WriteLine($"AesGcm 解密 Python :{t40} \tisOk:{text == t40}"); Console.WriteLine(); Console.WriteLine(); var t31 = AesGcmDecryptByBouncyCastle(key, nonce, cryptText1, associated); Console.WriteLine($"BouncyCastle 解密 BouncyCastle:{t31} \tisOk:{text == t31}"); var t41 = AesGcmDecryptFromBase64(key, nonce, cryptText1, associated); Console.WriteLine($"AesGcm 解密 BouncyCastle:{t41} \tisOk:{text == t41}"); Console.WriteLine(); Console.WriteLine(); var t32 = AesGcmDecryptByBouncyCastle(key, nonce, cryptText2, associated); Console.WriteLine($"BouncyCastle 解密 密文+Tag :{t32} \tisOk:{text == t32}"); var t42 = AesGcmDecryptFromBase64(key, nonce, cryptText2, associated); Console.WriteLine($"AesGcm 解密 密文+Tag :{t42} \tisOk:{text == t42}");
轉載來源:https://www.cnblogs.com/jzblive/p/14386757.html