gpt4 book ai didi

.net - 在 .NET 中使用 AES 加密 - CryptographicException 表示填充无效且无法删除

转载 作者:行者123 更新时间:2023-12-04 10:21:35 25 4
gpt4 key购买 nike

我用 C# 编写了一些 AES 加密代码,但无法正确加密和解​​密。如果我输入“test”作为密码,“这个数据必须对所有人保密!”我收到以下异常:

System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed.
at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Stream.Dispose()
...

如果我输入的内容少于 16 个字符,则不会有任何输出。

我相信我需要在加密中进行一些特殊处理,因为 AES 是一种分组密码,但我不确定那到底是什么,而且我无法在网上找到任何说明如何操作的示例。这是我的代码:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public static class DatabaseCrypto
{
public static EncryptedData Encrypt(string password, string data)
{
return DatabaseCrypto.Transform(true, password, data, null, null) as EncryptedData;
}

public static string Decrypt(string password, EncryptedData data)
{
return DatabaseCrypto.Transform(false, password, data.DataString, data.SaltString, data.MACString) as string;
}

private static object Transform(bool encrypt, string password, string data, string saltString, string macString)
{
using (AesManaged aes = new AesManaged())
{
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
int key_len = aes.KeySize / 8;
int iv_len = aes.BlockSize / 8;
const int salt_size = 8;
const int iterations = 8192;

byte[] salt = encrypt ? new byte[salt_size] : Convert.FromBase64String(saltString);
if (encrypt)
{
new RNGCryptoServiceProvider().GetBytes(salt);
}

byte[] bc_key = new Rfc2898DeriveBytes("BLK" + password, salt, iterations).GetBytes(key_len);
byte[] iv = new Rfc2898DeriveBytes("IV" + password, salt, iterations).GetBytes(iv_len);
byte[] mac_key = new Rfc2898DeriveBytes("MAC" + password, salt, iterations).GetBytes(16);

aes.Key = bc_key;
aes.IV = iv;

byte[] rawData = encrypt ? Encoding.UTF8.GetBytes(data) : Convert.FromBase64String(data);

using (ICryptoTransform transform = encrypt ? aes.CreateEncryptor() : aes.CreateDecryptor())
using (MemoryStream memoryStream = encrypt ? new MemoryStream() : new MemoryStream(rawData))
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, encrypt ? CryptoStreamMode.Write : CryptoStreamMode.Read))
{
if (encrypt)
{
cryptoStream.Write(rawData, 0, rawData.Length);

return new EncryptedData(salt, mac_key, memoryStream.ToArray());
}
else
{
byte[] originalData = new byte[rawData.Length];
int count = cryptoStream.Read(originalData, 0, originalData.Length);

return Encoding.UTF8.GetString(originalData, 0, count);
}
}
}
}
}

public class EncryptedData
{
public EncryptedData()
{
}

public EncryptedData(byte[] salt, byte[] mac, byte[] data)
{
this.Salt = salt;
this.MAC = mac;
this.Data = data;
}

public EncryptedData(string salt, string mac, string data)
{
this.SaltString = salt;
this.MACString = mac;
this.DataString = data;
}

public byte[] Salt
{
get;
set;
}

public string SaltString
{
get { return Convert.ToBase64String(this.Salt); }
set { this.Salt = Convert.FromBase64String(value); }
}

public byte[] MAC
{
get;
set;
}

public string MACString
{
get { return Convert.ToBase64String(this.MAC); }
set { this.MAC = Convert.FromBase64String(value); }
}

public byte[] Data
{
get;
set;
}

public string DataString
{
get { return Convert.ToBase64String(this.Data); }
set { this.Data = Convert.FromBase64String(value); }
}
}

static void ReadTest()
{
Console.WriteLine("Enter password: ");
string password = Console.ReadLine();

using (StreamReader reader = new StreamReader("aes.cs.txt"))
{
EncryptedData enc = new EncryptedData();
enc.SaltString = reader.ReadLine();
enc.MACString = reader.ReadLine();
enc.DataString = reader.ReadLine();

Console.WriteLine("The decrypted data was: " + DatabaseCrypto.Decrypt(password, enc));
}
}

static void WriteTest()
{
Console.WriteLine("Enter data: ");
string data = Console.ReadLine();
Console.WriteLine("Enter password: ");
string password = Console.ReadLine();

EncryptedData enc = DatabaseCrypto.Encrypt(password, data);

using (StreamWriter stream = new StreamWriter("aes.cs.txt"))
{
stream.WriteLine(enc.SaltString);
stream.WriteLine(enc.MACString);
stream.WriteLine(enc.DataString);

Console.WriteLine("The encrypted data was: " + enc.DataString);
}
}

最佳答案

在需要填充的模式(如 CBC)中使用 AES 等分组密码时,您必须意识到输出将始终是块大小的倍数。为此,PKCS7 等填充模式将在加密过程结束时向密码添加一些字节。但是您必须让加密器知道何时结束。为此,您所要做的就是插入语句

cryptoStream.FlushFinalBlock();  


cryptoStream.Write(rawData, 0, rawData.Length);

PS:

也许它只是为了调试,但是您的盐生成方法每次都会生成完全相同的盐。

关于.net - 在 .NET 中使用 AES 加密 - CryptographicException 表示填充无效且无法删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4545387/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com