我正在尝试使用变量 IV 进行一些(基本?)AES 加密,但会返回垃圾,如果要加密的字符串太短,我会收到“填充无效且无法删除”。我将 IV 包含在加密值中以实现随机性,然后在解密剩余值之前将其删除。
public class AesEncryption
{
private static byte[] key = new byte[32] { some key }; // 256-bit key
public static string Encrypt(string plaintext)
{
using (Aes aesAlg = Aes.Create())
{
var iv = aesAlg.IV;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(key, iv);
byte[] encryptedBytes;
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var streamWriter = new StreamWriter(csEncrypt))
{
streamWriter.Write(plaintext);
}
}
encryptedBytes = msEncrypt.ToArray();
}
return new AesCbcCiphertext(iv, encryptedBytes).ToString();
}
}
public static string Decrypt(string ciphertext)
{
var cbcCiphertext = AesCbcCiphertext.FromBase64String(ciphertext);
using (Aes aesAlg = Aes.Create())
{
aesAlg.Padding = PaddingMode.PKCS7;
ICryptoTransform decryptor = aesAlg.CreateDecryptor(key, aesAlg.IV);
using (var msDecrypt = new MemoryStream(cbcCiphertext.CiphertextBytes))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var streamReader = new StreamReader(csDecrypt))
{
return streamReader.ReadToEnd();
}
}
}
}
}
internal class AesCbcCiphertext
{
public byte[] IV { get; }
public byte[] CiphertextBytes { get; }
public static AesCbcCiphertext FromBase64String(string data)
{
var dataBytes = Convert.FromBase64String(data);
return new AesCbcCiphertext(
dataBytes.Take(16).ToArray(),
dataBytes.Skip(16).ToArray()
);
}
public AesCbcCiphertext(byte[] iv, byte[] ciphertextBytes)
{
IV = iv;
CiphertextBytes = ciphertextBytes;
}
public override string ToString()
{
var total = IV.Concat(CiphertextBytes).ToArray();
return Convert.ToBase64String(IV.Concat(CiphertextBytes).ToArray());
}
}
我想我已经阅读了 Stack 上与其相关的所有帖子,并以各种方式调整了解密,但没有成功。有趣的是,如果我使用相同的硬编码 IV,它就可以工作。我以为 IV 对于解密来说并不重要?
在
.NET 8
中尝试这样:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class Program
{
private const int AES_BLOCK_SIZE = 16;
public static String AesEncrypt(String strPlain, byte[] Key, byte[] IV)
{
try
{
if(String.IsNullOrEmpty(strPlain))
{
return String.Empty;
}
byte[] bytesEncrypted = Array.Empty<byte>();
using (Aes aes = Aes.Create())
{
aes.KeySize = AES_BLOCK_SIZE * 8 * 2; // 32 bytes = 256 bits
aes.BlockSize = AES_BLOCK_SIZE * 8; // 16 bytes = 128 bits
aes.Key = Key;
aes.IV = IV;
aes.Padding = PaddingMode.Zeros;
aes.Mode = CipherMode.CBC;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(strPlain);
}
bytesEncrypted = ms.ToArray();
}
}
}
return Convert.ToBase64String(bytesEncrypted);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return String.Empty;
}
public static String AesDecrypt(String strCipher, byte[] Key, byte[] IV)
{
try
{
if(String.IsNullOrEmpty(strCipher))
{
return String.Empty;
}
byte[] bytesCipher = Convert.FromBase64String(strCipher);
if (bytesCipher is null)
{
return String.Empty;
}
if (bytesCipher.Length == 0)
{
return String.Empty;
}
String strPlain = String.Empty;
byte[] bytesPlain = Array.Empty<byte>();
using (Aes aes = Aes.Create())
{
aes.KeySize = AES_BLOCK_SIZE * 8 * 2; // 32 bytes = 256 bits
aes.BlockSize = AES_BLOCK_SIZE * 8; // 16 bytes = 128 bits
aes.Key = Key;
aes.IV = IV;
aes.Padding = PaddingMode.Zeros;
aes.Mode = CipherMode.CBC;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream(bytesCipher))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
strPlain = sr.ReadToEnd();
}
}
}
}
return strPlain;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return String.Empty;
}
public static void Main()
{
//41413744443430333035394e36373038 41413744443430333035394e36373038 = 256 bits
byte[] key = new byte[] {0x41, 0x41, 0x37, 0x44, 0x44, 0x34, 0x30, 0x33, 0x30, 0x35, 0x39, 0x4e, 0x36, 0x37, 0x30, 0x38,
0x41, 0x41, 0x37, 0x44, 0x44, 0x34, 0x30, 0x33, 0x30, 0x35, 0x39, 0x4e, 0x36, 0x37, 0x30, 0x38};
//000102030405060708090A0B0C0D0E0F = 128 bits
byte[] iv = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
string plaintext = "Islam Rahmatan lil 'Alamin";
using (Aes myAes = Aes.Create())
{
string ciphertext = AesEncrypt(plaintext, key, iv);
string plaintext2 = AesDecrypt(ciphertext, key, iv);
Console.WriteLine("Plaintext: {0}", plaintext);
Console.WriteLine("Cipher: {0}", ciphertext);
Console.WriteLine("Plaintext2: {0}", plaintext2);
Console.ReadLine();
}
}
}
输出:
Plaintext: Islam Rahmatan lil 'Alamin
Cipher: q/EtEjCBlyfWkHET3WwbZDt1XLN3XDrq/oO7D0m4Txg=
Plaintext2: Islam Rahmatan lil 'Alamin