尝试在 AES 中解密时出现错误“填充无效且无法删除。”
这是我用来加密和解密的代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using System.Xml;
namespace ClassLibrary
{
public static class AesHelper
{
private const int KeySize = 256;
private const int BlockSize = 128;
private const int Iterations = 1000;
/// <summary>
/// AES encryption of a plain text string using the specified secret Key and IV Salt.
/// </summary>
/// <param name="plainText">The plain text you wish to encrypt to cipher text.</param>
/// <param name="key">The secret key.</param>
/// <param name="iv">A secret salt for the initialization vector.</param>
/// <returns>An encrypted cipher text</returns>
public static string EncryptToAes(string plainText, string key, string iv)
{
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
keyBytes = SHA256.Create().ComputeHash(keyBytes);
byte[] bytesEncrypted = Encrypt(plainBytes, keyBytes, ivBytes);
return Convert.ToBase64String(bytesEncrypted);
}
/// <summary>
/// Decrypts the cipher text back to plain text using the same secret Key phrase and IV
/// Salt that was previously used to encrypt.
/// </summary>
/// <param name="cipherText">A string encrypted earlier using the same secret Key phrase and IV Salt.</param>
/// <param name="key">The secret Key.</param>
/// <param name="iv">A secret salt for the initialization vector.</param>
/// <returns>A plain text string.</returns>
public static string DecryptToString(string cipherText, string key, string iv)
{
byte[] cipherBytes = Convert.FromBase64String(cipherText);
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
keyBytes = SHA256.Create().ComputeHash(keyBytes);
byte[] bytesDecrypted = Decrypt(cipherBytes, keyBytes, ivBytes);
return Encoding.UTF8.GetString(bytesDecrypted);
}
/// <summary>
/// Creates a AES instance.
/// </summary>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns>A AES instance</returns>
private static Aes CreateAesInstance(byte[] key, byte[] iv)
{
var aes = Aes.Create();
aes.KeySize = KeySize;
aes.BlockSize = BlockSize;
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
var derived = new Rfc2898DeriveBytes(key, iv, Iterations);
aes.Key = derived.GetBytes(aes.KeySize / 8);
aes.IV = derived.GetBytes(aes.BlockSize / 8);
return aes;
}
/// <summary>
/// Encrypts bytes with AES.
/// </summary>
/// <param name="bytesToBeEncrypted"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns>The encrypted bytes</returns>
private static byte[] Encrypt(byte[] bytesToBeEncrypted, byte[] key, byte[] iv)
{
byte[] encryptedBytes = null;
using (var aes = CreateAesInstance(key, iv))
{
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.FlushFinalBlock();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
/// <summary>
/// Decrypt encrypted bytes.
/// </summary>
/// <param name="bytesToBeDecrypted"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns>Decrypted bytes</returns>
private static byte[] Decrypt(byte[] bytesToBeDecrypted, byte[] key, byte[] iv)
{
byte[] decryptedBytes = null;
using (var aes = CreateAesInstance(key, iv))
{
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.FlushFinalBlock();
}
decryptedBytes = TrimZeroPadding(ms.ToArray());
}
}
return decryptedBytes;
}
/// <summary>
/// Trims padding from byte array.
/// </summary>
/// <param name="array"></param>
/// <returns>Byte array without padding.</returns>
private static byte[] TrimZeroPadding(byte[] array)
{
if (array == null || array.Length == 0)
{
return null;
}
var lastZeroIndex = array.Length;
for (int i = array.Length - 1; i >= 0; i--)
{
if (array[i] == char.MinValue)
{
lastZeroIndex = i;
}
else
{
break;
}
}
return array.Where((item, index) => index < lastZeroIndex).ToArray();
}
}
}
密钥和 IV 都是硬编码的,所以它们不会出错,加密和解密方法使用:
CreateAesInstance
我将 paddign 设置为的位置:
PaddingMode.PKCS7;
所以我猜这也不是问题?
错误“填充无效,无法删除。”当解密数据包含与预期填充不匹配的填充时发生。在您提供的代码中,使用的填充模式是 PKCS7,它向明文添加填充以确保它是块大小的倍数。解密时,填充会自动删除。但是,如果填充不正确,则无法删除,从而导致错误。
要修复这个错误,你应该确保用于加密和解密的密钥和IV是相同的。也有可能密文在传输过程中被修改或损坏,所以您应该验证密文没有损坏。此外,您可以修改 TrimZeroPadding 方法来检查填充字节并手动删除填充。
这是检查填充的 Decrypt 方法的更新版本:
private static byte[] Decrypt(byte[] bytesToBeDecrypted, byte[] key, byte[] iv)
{
byte[] decryptedBytes = null;
using (var aes = CreateAesInstance(key, iv))
{
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.FlushFinalBlock();
}
var decrypted = ms.ToArray();
var pad = decrypted[decrypted.Length - 1];
var padCount = (int)pad;
if (padCount > 0 && padCount < aes.BlockSize / 8)
{
var padded = true;
for (var i = decrypted.Length - padCount; i < decrypted.Length - 1; i++)
{
if (decrypted[i] != pad)
{
padded = false;
break;
}
}
if (padded)
{
decryptedBytes = new byte[decrypted.Length - padCount];
Array.Copy(decrypted, 0, decryptedBytes, 0, decryptedBytes.Length);
}
}
if (decryptedBytes == null)
{
decryptedBytes = decrypted;
}
}
}
return decryptedBytes;
}
您可以使用这个更新的 Decrypt 方法来解密没有填充错误的密文。