You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨服务器AES+HMAC加解密出现'填充无效无法移除'问题求助

Fixing "Padding is invalid and cannot be removed" in Cross-Machine AES+HMAC Decryption

Let's break down why you're hitting this error when decrypting across machines (but not locally) and fix it step by step. The core issue almost always boils down to inconsistent handling of keys, IVs, ciphertext, or HMAC data between encryption and decryption endpoints—even tiny mismatches here will break padding validation (since padding is tied to the correct decryption key and data integrity).

Common Causes & Fixes

1. Ensure Uniform AES Configuration Across Both Machines

First, double-check that your AES instances are using identical settings on both the encrypting and decrypting sides. Even a single mismatch here will cause padding errors:

  • Mode: Default is CBC (make sure neither side changed it to ECB or another mode)
  • Padding: Default is PKCS7 (don't mix with Zeros or ANSIX923)
  • Key Size: Ensure you're using the same key size (128, 192, or 256 bits) on both ends.

Add explicit configuration to your AES initialization to avoid relying on defaults that might vary (unlikely, but safe practice):

using var aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.KeySize = 256; // Match this on both sides

2. Fix Base64 Encoding/Decoding Consistency

Since you're transmitting keys, IVs, and ciphertext as Base64 strings, make sure you're using the exact same Base64 handling on both ends:

  • Never modify the Base64 strings (no trimming, no adding newlines, no encoding conversions like UTF-16 instead of UTF-8 when converting the Base64 string to bytes).
  • When decoding, use Convert.FromBase64String() directly—don't pass the Base64 string through any string encoding/decoding steps first (Base64 is ASCII-compatible, so converting it to bytes via Encoding.UTF8.GetBytes() is unnecessary and risky if the string has unexpected characters).

Bad practice (avoid):

// Don't do this! Converting Base64 string to UTF8 bytes first is wrong
byte[] keyBytes = Encoding.UTF8.GetBytes(base64KeyString);

Correct practice:

byte[] keyBytes = Convert.FromBase64String(base64KeyString);
byte[] ivBytes = Convert.FromBase64String(base64IvString);
byte[] ciphertextBytes = Convert.FromBase64String(base64CiphertextString);

3. Validate HMAC Before Decrypting (Critical!)

The "padding invalid" error often happens when you try to decrypt data that failed HMAC validation (meaning the data was tampered with, or you used the wrong HMAC key). Always verify the HMAC first—only decrypt if the HMAC is valid.

In your AESThenHMAC class, make sure the decryption workflow:

  1. Splits the received data into ciphertext, IV, and HMAC value correctly (if you're concatenating them, use a safe separator like a byte that won't appear in Base64, or transmit them as separate fields).
  2. Recalculates the HMAC of the ciphertext + IV (or whatever data you signed during encryption) using the HMAC key.
  3. Compares the recalculated HMAC with the received HMAC using a constant-time comparison to avoid timing attacks.

Here's a snippet for safe HMAC validation:

public static bool ValidateHmac(byte[] dataToVerify, byte[] receivedHmac, byte[] hmacKey)
{
    using var hmac = new HMACSHA256(hmacKey);
    byte[] calculatedHmac = hmac.ComputeHash(dataToVerify);
    
    // Constant-time comparison to prevent timing attacks
    if (calculatedHmac.Length != receivedHmac.Length)
        return false;
    
    int mismatch = 0;
    for (int i = 0; i < calculatedHmac.Length; i++)
    {
        mismatch |= calculatedHmac[i] ^ receivedHmac[i];
    }
    return mismatch == 0;
}

If validation fails, do not proceed with decryption—throw an error instead of trying to decrypt garbage data (which causes the padding error).

4. Separate AES Key and HMAC Key (Best Practice)

Never use the same key for both AES encryption and HMAC—this violates cryptographic best practices and can lead to vulnerabilities. Generate two separate keys (one for AES, one for HMAC) and transmit both (as separate Base64 strings) to the decrypting side.

5. Avoid Transmitting the AES Key in Plaintext!

Wait a second—you mentioned transmitting the AES key as a Base64 string to the other application. That's a huge security risk! AES keys should never be transmitted in plaintext. Instead, use a key exchange protocol like ECDH, or encrypt the AES key with the recipient's public key (RSA) before transmission. While this doesn't directly fix your padding error, it's critical for security.

Example Corrected Workflow

Let's outline a safe, cross-machine compatible workflow:

Encryption Side:

  1. Generate separate AES key and HMAC key.
  2. Generate a random IV (16 bytes for AES-CBC).
  3. Encrypt the plaintext with AES, using the key and IV.
  4. Compute HMAC over the ciphertext + IV (or ciphertext alone, but including IV adds integrity to it).
  5. Transmit:
    • AES key (encrypted with recipient's public key, not plaintext!)
    • HMAC key (same as above, or use a shared secret if applicable)
    • IV (Base64 encoded)
    • Ciphertext (Base64 encoded)
    • HMAC value (Base64 encoded)

Decryption Side:

  1. Decrypt the AES/HMAC keys using your private key.
  2. Decode IV, ciphertext, and HMAC from Base64 to bytes.
  3. Validate HMAC over ciphertext + IV using the HMAC key.
  4. If HMAC is valid, decrypt the ciphertext with AES using the key and IV.
  5. If HMAC is invalid, throw an error (don't attempt decryption).

Fixing Your Test Code

If your current code is concatenating ciphertext, IV, and HMAC into a single string (e.g., with separators), make sure the splitting logic on the decrypting side is identical. For example, if you use | as a separator, ensure that none of the Base64 strings contain | (Base64 uses A-Z, a-z, 0-9, +, /, and =, so | is safe).

Example concatenation (encrypt side):

string encryptedData = $"{Convert.ToBase64String(ciphertext)}|{Convert.ToBase64String(iv)}|{Convert.ToBase64String(hmacValue)}";

Example splitting (decrypt side):

string[] parts = encryptedData.Split('|');
if (parts.Length != 3)
    throw new InvalidDataException("Invalid encrypted data format");

byte[] ciphertext = Convert.FromBase64String(parts[0]);
byte[] iv = Convert.FromBase64String(parts[1]);
byte[] receivedHmac = Convert.FromBase64String(parts[2]);

Final Checks

  • Run a test where you log the exact Base64 strings of the key, IV, ciphertext, and HMAC on both the encrypt and decrypt sides. Compare them byte-for-byte—if any differ, that's your culprit.
  • Ensure that both machines are using the same .NET version (unlikely to cause padding issues, but edge cases exist with older framework versions).

内容的提问来源于stack exchange,提问作者TLCONE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:37:13