Dot-Net

如何獲得 C# 和 SQL2k8 AES 加密之間的兼容性?

  • May 12, 2010

我對兩列進行了 AES 加密:其中一列儲存在 SQL Server 2000數據庫中;另一個儲存在 SQL Server 2008數據庫中。

由於第一列的數據庫 (2000) 沒有用於加密/解密的本機功能,因此我們決定在應用程序級別使用 .NET 類對兩者進行加密邏輯。

但是由於第二列的數據庫(2008)允許這種功能,我們希望使用數據庫功能的數據遷移更快,因為SQL 2k中的數據遷移比這一秒小得多,並且會持續更長時間超過 50 小時,因為是在應用程序級別製作的。

我的問題從這一點開始:使用相同的密鑰,我在加密一個值時沒有得到相同的結果,也沒有相同的結果大小。

下面我們有雙方的完整邏輯。當然我沒有顯示關鍵,但其他一切都是一樣的:

private byte[] RijndaelEncrypt(byte[] clearData, byte[] Key)
{
   var memoryStream = new MemoryStream();

   Rijndael algorithm = Rijndael.Create();

   algorithm.Key = Key;
   algorithm.IV = InitializationVector;

   var criptoStream = new CryptoStream(memoryStream, algorithm.CreateEncryptor(), CryptoStreamMode.Write);
   criptoStream.Write(clearData, 0, clearData.Length);
   criptoStream.Close();

   byte[] encryptedData = memoryStream.ToArray();
   return encryptedData;
}

private byte[] RijndaelDecrypt(byte[] cipherData, byte[] Key)
{
   var memoryStream = new MemoryStream();

   Rijndael algorithm = Rijndael.Create();

   algorithm.Key = Key;
   algorithm.IV = InitializationVector;

   var criptoStream = new CryptoStream(memoryStream, algorithm.CreateDecryptor(), CryptoStreamMode.Write);

   criptoStream.Write(cipherData, 0, cipherData.Length);

   criptoStream.Close();

   byte[] decryptedData = memoryStream.ToArray();

   return decryptedData;
}

這是 SQL 程式碼範例:

open symmetric key columnKey decryption by password = N'{pwd!!i_ll_not_show_it_here}'

declare @enc varchar(max)

set @enc = dbo.VarBinarytoBase64(EncryptByKey(Key_GUID('columnKey'), 'blablabla'))

select LEN(@enc), @enc

這個 varbinaryToBase64 是一個經過測試的 sql 函式,我們用來將 varbinary 轉換為我們用來在 .net 應用程序中儲存字元串的相同格式。

C# 中的結果是: eg0wgTeR3noWYgvdmpzTKijkdtTsdvnvKzh+uhyN3Lo=

SQL2k8 中的相同結果是: AI0zI7D77EmqgTQrdgMBHAEAAACyACXb+P3HvctA0yBduAuwPS4Ah3AB4Dbdj2KBGC1Dk4b8GEbtXs5fINzvusp8FRBknF15Br2xI1CqP0Qb/M4w

我只是還沒有得到我做錯了什麼。

你有什麼想法?

**編輯:**我認為至關重要的一點:我的 C# 程式碼中有一個初始化向量,16 個字節。此 IV 未設置為 SQL 對稱密鑰,我可以這樣做嗎?

但即使沒有用 C# 填充 IV,我也會得到非常不同的結果,無論是內容還是長度。

有幾件事我會看:

  1. 絕對確保明文的內容和編碼相同。IIRC,流預設為 UTF-8,而如果您的VarBinaryToBase64函式採用 nvarchar 參數,它將是 Unicode。
  2. 確保兩種加密算法使用相同的塊大小。在 SQL 中,您在呼叫時確定算法CREATE SYMMETRIC KEY。如果不指定算法,則使用 AES256。在 .NET using 中RijndaelManaged,我相信預設塊大小為 128,但您可以將其設置為 256(如果您使用Aes該類,則不能)。
  3. 我要尋找的最後一件事是 SQL Server 如何處理您在修改後的文章中提到的初始化向量。我想說它為此使用了authenticator參數,但這是一個瘋狂的猜測。

編輯

我走得很遠。鑑於我的發現,您不能使用 .NET 類來解密由 SQL Server 內置加密加密的文本,因為 SQL Server 在加密的內容中添加了一堆粘液,包括隨機初始化向量。來自 Michael Cole 的書“Pro T-SQL 2005 Programmer’s Guide”(儘管 2008 的做法相同):

當 SQL Server 通過對稱密鑰加密時,它會將元數據添加到加密結果以及填充中,從而使加密結果比未加密的純文字更大(有時明顯更大)。帶有元數據的加密結果的格式遵循以下格式:

  • 加密結果的前 16 個字節表示用於加密數據的對稱密鑰的 GUID
  • 接下來的 4 個字節代表版本號,目前硬編碼為“01000000”。
  • 接下來的 8 個字節用於 DES 加密(16 個字節用於 AES 加密)代表隨機生成的初始化向量。
  • 接下來的 8 個字節是標頭資訊,表示用於加密數據的選項。如果使用了authenticator 選項,這個頭資訊包括一個20 字節的認證器SHA1 散列,使得頭資訊的長度為28 字節。
  • 加密數據的最後一部分是實際數據和填充本身。對於 DES 算法,此加密數據的長度將是 8 個字節的倍數。對於 AES 算法,長度將是 16 字節的倍數。

引用自:https://stackoverflow.com/questions/2822592