使用特定偏移量的AES解密时输入数据不是完整的块?
The input data is not a complete block when decrypting AES with specific offset?
我正在尝试编写一个 encryption/decryption 方法进行练习,在初步 运行 工作后,我决定通过将 IV 加密到数据中来加强它并使其不易受攻击.我得到了它的工作,并决定通过在 IV 的左侧添加一些随机数据来为 IV 在数据中的位置引入偏移来再次加强它。到目前为止,一切正常,但现在我收到一条解密错误消息:
The input data is not a complete block.
以我对加密和解密的有限了解,这对我调试问题毫无用处。我搜索了高低,none 这个问题的答案,我发现似乎可以解决我的问题。答案通常是开发人员没有解密 byte[]
而是类似于 base 64 字符串的东西。
private static Guid TestGuid = Guid.NewGuid();
private static DateTime Timestamp = DateTime.Now;
private static string key = "PPPQmyuzqKtjzYlWM3mP0aDxaxCzlsACajIkTVN4IjI=";
public static void Main()
{
string data = TestGuid + "|" + Timestamp;
Console.WriteLine("Request Parameter: " + data);
string encryptedData = AESEncrypt(key, data, 1);
Console.WriteLine("Encrypted: " + encryptedData);
string decryptedData = AESDecrypt(key, encryptedData, 1);
Console.WriteLine("Decrypted: " + decryptedData);
}
public static string AESEncrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
byte[] encryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.GenerateIV();
algo.Padding = PaddingMode.PKCS7;
byte[] iv = new byte[offset + 16];
Random r = new Random();
using (MemoryStream ms = new MemoryStream())
{
for (int i = 0; i < offset; i++)
iv[i] = (byte)r.Next(1, 200);
for (int i = 0; i < algo.IV.Length; i++)
iv[offset + i - 1] = algo.IV[i];
ICryptoTransform encryptor = algo.CreateEncryptor(algo.Key, algo.IV);
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (BinaryWriter bw = new BinaryWriter(cs))
{
bw.Write(iv, 0, offset);
ms.Write(iv, offset, algo.IV.Length);
bw.Write(data);
cs.FlushFinalBlock();
}
encryptedData = ms.ToArray();
}
}
}
if (encryptedData != null)
return Convert.ToBase64String(encryptedData);
throw new Exception("An unxpected error occurred and the provided data was not encrypted.");
}
public static string AESDecrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
string decryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.Padding = PaddingMode.PKCS7;
byte[] decodedData = Convert.FromBase64String(data);
using (MemoryStream ms = new MemoryStream(decodedData))
{
byte[] ivData = new byte[offset + 16];
ms.Read(ivData, 0, offset + 16);
List<byte> iv = new List<byte>();
for (int i = offset - 1; i < ivData.Length - 1; i++)
iv.Add(ivData[i]);
algo.IV = iv.ToArray();
ICryptoTransform decryptor = algo.CreateDecryptor(algo.Key, algo.IV);
List<byte> dataToDecrypt = new List<byte>();
for (int i = 0; i + offset < decodedData.Length; i++)
dataToDecrypt.Add(decodedData[i + offset]);
using (MemoryStream ds = new MemoryStream(dataToDecrypt.ToArray()))
{
using (CryptoStream cs = new CryptoStream(ds, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
decryptedData = sr.ReadToEnd();
}
}
}
}
}
if (!string.IsNullOrWhiteSpace(decryptedData))
return decryptedData;
throw new Exception("An unxpected error occurred and the provided data was not decrypted.");
}
是什么导致了这个错误,为什么会导致错误,我该如何解决这个错误,为什么这个解决方案有效?
在加密过程中弄乱最终的加密流(将原始字节输入其中)是一个致命错误,应该避免
出现问题是因为
bw.Write(iv, 0, offset);
ms.Write(iv, offset, algo.IV.Length);
将修改后的 IV 的第一个随机字节提供给加密流,并将其其余部分提供给原始输出流,修改后的 iv 的第一个字节不会立即写入内存流,而是一部分第一个加密块,因此,解密期间密码的大小将缺少一些字节,例如它缺少 1 个字节,其中 offset = 1
但是您希望它们立即作为独立字节写入,因为在解密部分您从流中读取了偏移量 + 16 个字节,因此您读入了加密块并使其小于块大小AES。如果调试代码,您可以看到这一点。加密字节的最终大小是 0x50 而解密字节的大小是 0x50 - offset = 0x4f (offset = 1)
对于解决方案,
- 您可以从密钥中导出 IV(如果您重复使用密钥,这将是不安全的)并且不必将其包含在您的密码中。
- 您可以将 IV(和您的随机字节)添加到您的加密缓冲区并先读取它,然后使用它进行解密,
赞:
public static string AESEncrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
byte[] encryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.GenerateIV();
algo.Padding = PaddingMode.PKCS7;
Random r = new Random();
using (MemoryStream ms = new MemoryStream())
{
for (int i = 0; i < offset; i++)
{
ms.WriteByte((byte)r.Next(0, 200));
}
ms.Write(algo.IV, 0, 16);
ICryptoTransform encryptor = algo.CreateEncryptor(algo.Key, algo.IV);
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (BinaryWriter bw = new BinaryWriter(cs))
{
bw.Write(data);
cs.FlushFinalBlock();
}
encryptedData = ms.ToArray();
}
}
}
if (encryptedData != null)
return Convert.ToBase64String(encryptedData);
throw new Exception("An unxpected error occurred and the provided data was not encrypted.");
}
public static string AESDecrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
string decryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.Padding = PaddingMode.PKCS7;
byte[] decodedData = Convert.FromBase64String(data);
using (MemoryStream ms = new MemoryStream(decodedData))
{
for (int i = 0; i < offset; i++) ms.ReadByte();
byte[] iv = new byte[16];
ms.Read(iv, 0, 16);
algo.IV = iv.ToArray();
ICryptoTransform decryptor = algo.CreateDecryptor(algo.Key, algo.IV);
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
decryptedData = sr.ReadToEnd();
}
}
}
}
if (!string.IsNullOrWhiteSpace(decryptedData))
return decryptedData;
throw new Exception("An unxpected error occurred and the provided data was not decrypted.");
}
我正在尝试编写一个 encryption/decryption 方法进行练习,在初步 运行 工作后,我决定通过将 IV 加密到数据中来加强它并使其不易受攻击.我得到了它的工作,并决定通过在 IV 的左侧添加一些随机数据来为 IV 在数据中的位置引入偏移来再次加强它。到目前为止,一切正常,但现在我收到一条解密错误消息:
The input data is not a complete block.
以我对加密和解密的有限了解,这对我调试问题毫无用处。我搜索了高低,none 这个问题的答案,我发现似乎可以解决我的问题。答案通常是开发人员没有解密 byte[]
而是类似于 base 64 字符串的东西。
private static Guid TestGuid = Guid.NewGuid();
private static DateTime Timestamp = DateTime.Now;
private static string key = "PPPQmyuzqKtjzYlWM3mP0aDxaxCzlsACajIkTVN4IjI=";
public static void Main()
{
string data = TestGuid + "|" + Timestamp;
Console.WriteLine("Request Parameter: " + data);
string encryptedData = AESEncrypt(key, data, 1);
Console.WriteLine("Encrypted: " + encryptedData);
string decryptedData = AESDecrypt(key, encryptedData, 1);
Console.WriteLine("Decrypted: " + decryptedData);
}
public static string AESEncrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
byte[] encryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.GenerateIV();
algo.Padding = PaddingMode.PKCS7;
byte[] iv = new byte[offset + 16];
Random r = new Random();
using (MemoryStream ms = new MemoryStream())
{
for (int i = 0; i < offset; i++)
iv[i] = (byte)r.Next(1, 200);
for (int i = 0; i < algo.IV.Length; i++)
iv[offset + i - 1] = algo.IV[i];
ICryptoTransform encryptor = algo.CreateEncryptor(algo.Key, algo.IV);
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (BinaryWriter bw = new BinaryWriter(cs))
{
bw.Write(iv, 0, offset);
ms.Write(iv, offset, algo.IV.Length);
bw.Write(data);
cs.FlushFinalBlock();
}
encryptedData = ms.ToArray();
}
}
}
if (encryptedData != null)
return Convert.ToBase64String(encryptedData);
throw new Exception("An unxpected error occurred and the provided data was not encrypted.");
}
public static string AESDecrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
string decryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.Padding = PaddingMode.PKCS7;
byte[] decodedData = Convert.FromBase64String(data);
using (MemoryStream ms = new MemoryStream(decodedData))
{
byte[] ivData = new byte[offset + 16];
ms.Read(ivData, 0, offset + 16);
List<byte> iv = new List<byte>();
for (int i = offset - 1; i < ivData.Length - 1; i++)
iv.Add(ivData[i]);
algo.IV = iv.ToArray();
ICryptoTransform decryptor = algo.CreateDecryptor(algo.Key, algo.IV);
List<byte> dataToDecrypt = new List<byte>();
for (int i = 0; i + offset < decodedData.Length; i++)
dataToDecrypt.Add(decodedData[i + offset]);
using (MemoryStream ds = new MemoryStream(dataToDecrypt.ToArray()))
{
using (CryptoStream cs = new CryptoStream(ds, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
decryptedData = sr.ReadToEnd();
}
}
}
}
}
if (!string.IsNullOrWhiteSpace(decryptedData))
return decryptedData;
throw new Exception("An unxpected error occurred and the provided data was not decrypted.");
}
是什么导致了这个错误,为什么会导致错误,我该如何解决这个错误,为什么这个解决方案有效?
在加密过程中弄乱最终的加密流(将原始字节输入其中)是一个致命错误,应该避免
出现问题是因为
bw.Write(iv, 0, offset);
ms.Write(iv, offset, algo.IV.Length);
将修改后的 IV 的第一个随机字节提供给加密流,并将其其余部分提供给原始输出流,修改后的 iv 的第一个字节不会立即写入内存流,而是一部分第一个加密块,因此,解密期间密码的大小将缺少一些字节,例如它缺少 1 个字节,其中 offset = 1
但是您希望它们立即作为独立字节写入,因为在解密部分您从流中读取了偏移量 + 16 个字节,因此您读入了加密块并使其小于块大小AES。如果调试代码,您可以看到这一点。加密字节的最终大小是 0x50 而解密字节的大小是 0x50 - offset = 0x4f (offset = 1)
对于解决方案,
- 您可以从密钥中导出 IV(如果您重复使用密钥,这将是不安全的)并且不必将其包含在您的密码中。
- 您可以将 IV(和您的随机字节)添加到您的加密缓冲区并先读取它,然后使用它进行解密,
赞:
public static string AESEncrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
byte[] encryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.GenerateIV();
algo.Padding = PaddingMode.PKCS7;
Random r = new Random();
using (MemoryStream ms = new MemoryStream())
{
for (int i = 0; i < offset; i++)
{
ms.WriteByte((byte)r.Next(0, 200));
}
ms.Write(algo.IV, 0, 16);
ICryptoTransform encryptor = algo.CreateEncryptor(algo.Key, algo.IV);
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (BinaryWriter bw = new BinaryWriter(cs))
{
bw.Write(data);
cs.FlushFinalBlock();
}
encryptedData = ms.ToArray();
}
}
}
if (encryptedData != null)
return Convert.ToBase64String(encryptedData);
throw new Exception("An unxpected error occurred and the provided data was not encrypted.");
}
public static string AESDecrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
string decryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.Padding = PaddingMode.PKCS7;
byte[] decodedData = Convert.FromBase64String(data);
using (MemoryStream ms = new MemoryStream(decodedData))
{
for (int i = 0; i < offset; i++) ms.ReadByte();
byte[] iv = new byte[16];
ms.Read(iv, 0, 16);
algo.IV = iv.ToArray();
ICryptoTransform decryptor = algo.CreateDecryptor(algo.Key, algo.IV);
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
decryptedData = sr.ReadToEnd();
}
}
}
}
if (!string.IsNullOrWhiteSpace(decryptedData))
return decryptedData;
throw new Exception("An unxpected error occurred and the provided data was not decrypted.");
}