RijndaelManaged“填充無效且無法刪除”,僅在生產中解密時出現
我知道有人對此提出了其他問題,但到目前為止還沒有提供解決方案或正是我遇到的問題。
下面的類處理字元串的加密和解密,傳入的密鑰和向量總是相同的。
被加密和解密的字元串總是數字,大多數工作但偶爾會在解密時失敗(但僅在生產伺服器上)。我應該提到,本地和生產環境都在 Windows Server 2003 上的 IIS6 中,使用該類的程式碼位於 .ashx 處理程序中。在生產伺服器上失敗的例子是“0000232668”
錯誤資訊是
System.Security.Cryptography.CryptographicException:填充無效且無法刪除。在 System.Security.Cryptography.RijndaelManagedTransform.DecryptData(字節
$$ $$inputBuffer, Int32 inputOffset, Int32 inputCount, 字節$$ $$& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast) 對於程式碼
public class Aes { private byte[] Key; private byte[] Vector; private ICryptoTransform EncryptorTransform, DecryptorTransform; private System.Text.UTF8Encoding UTFEncoder; public Aes(byte[] key, byte[] vector) { this.Key = key; this.Vector = vector; // our encyption method RijndaelManaged rm = new RijndaelManaged(); rm.Padding = PaddingMode.PKCS7; // create an encryptor and decyptor using encryption method. key and vector EncryptorTransform = rm.CreateEncryptor(this.Key, this.Vector); DecryptorTransform = rm.CreateDecryptor(this.Key, this.Vector); // used to translate bytes to text and vice versa UTFEncoder = new System.Text.UTF8Encoding(); } /// Encrypt some text and return a string suitable for passing in a URL. public string EncryptToString(string TextValue) { return ByteArrToString(Encrypt(TextValue)); } /// Encrypt some text and return an encrypted byte array. public byte[] Encrypt(string TextValue) { //Translates our text value into a byte array. Byte[] bytes = UTFEncoder.GetBytes(TextValue); Byte[] encrypted = null; //Used to stream the data in and out of the CryptoStream. using (MemoryStream memoryStream = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(memoryStream, EncryptorTransform, CryptoStreamMode.Write)) { cs.Write(bytes, 0, bytes.Length); } encrypted = memoryStream.ToArray(); } return encrypted; } /// The other side: Decryption methods public string DecryptString(string EncryptedString) { return Decrypt(StrToByteArray(EncryptedString)); } /// Decryption when working with byte arrays. public string Decrypt(byte[] EncryptedValue) { Byte[] decryptedBytes = null; using (MemoryStream encryptedStream = new MemoryStream()) { using (CryptoStream decryptStream = new CryptoStream(encryptedStream, DecryptorTransform, CryptoStreamMode.Write)) { decryptStream.Write(EncryptedValue, 0, EncryptedValue.Length); } decryptedBytes = encryptedStream.ToArray(); } return UTFEncoder.GetString(decryptedBytes); } /// Convert a string to a byte array. NOTE: Normally we'd create a Byte Array from a string using an ASCII encoding (like so). // System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding(); // return encoding.GetBytes(str); // However, this results in character values that cannot be passed in a URL. So, instead, I just // lay out all of the byte values in a long string of numbers (three per - must pad numbers less than 100). public byte[] StrToByteArray(string str) { if (str.Length == 0) throw new Exception("Invalid string value in StrToByteArray"); byte val; byte[] byteArr = new byte[str.Length / 3]; int i = 0; int j = 0; do { val = byte.Parse(str.Substring(i, 3)); byteArr[j++] = val; i += 3; } while (i < str.Length); return byteArr; } // Same comment as above. Normally the conversion would use an ASCII encoding in the other direction: // System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); // return enc.GetString(byteArr); public string ByteArrToString(byte[] byteArr) { byte val; string tempStr = ""; for (int i = 0; i <= byteArr.GetUpperBound(0); i++) { val = byteArr[i]; if (val < (byte)10) tempStr += "00" + val.ToString(); else if (val < (byte)100) tempStr += "0" + val.ToString(); else tempStr += val.ToString(); } return tempStr; }**編輯:**感謝您的所有幫助,但是您的答案並沒有解決問題,結果證明這是非常簡單的事情。我在一台伺服器上生成了一個加密字元串,並將其交給另一台伺服器上的處理程序進行解密和處理,但事實證明,在不同伺服器上執行時加密的結果不同,因此接收伺服器無法解密它。其中一個答案偶然發現了這個提示,這就是我接受它的原因
當加密和解密由於某種原因沒有使用相同的密鑰或初始化向量時,您有時會收到有關無效填充的消息。填充是添加到明文末尾的一些字節,以使其組成完整數量的塊以供密碼處理。在 PKCS7 填充中,每個字節都等於添加的字節數,因此在解密後始終可以將其刪除。您的解密導致最後n個字節不等於最後一個字節的值n的字元串(希望這句話有意義)。所以我會仔細檢查你所有的鑰匙。
或者,在您的情況下,我建議您確保
RijndaelManagedTransform為每個加密和解密操作創建和處置一個實例,並使用密鑰和向量對其進行初始化。這個問題很可能是重用這個變換對象造成的,這意味著第一次使用後,它不再處於正確的初始狀態。
我傾向於在關閉 CryptoStream 之前顯式呼叫FlushFinalBlock方法。這意味著在您的加密方法中執行以下操作:
using (CryptoStream cs = new CryptoStream(memoryStream, EncryptorTransform, CryptoStreamMode.Write)) { cs.Write(bytes, 0, bytes.Length); cs.FlushFinalBlock(); }如果您不這樣做,則可能是加密數據被截斷 - 這將導致“無效填充”情況。使用 PKCS7 時始終存在填充,即使要加密的數據與密碼的塊長度對齊。