我有一个PDF文件
当我想使用低于Length of the data to encrypt is invalid.
错误的代码对其进行加密时:
string inputFile = @"C:\sample.pdf";
string outputFile = @"C:\sample_enc.pdf";
try
{
using (RijndaelManaged aes = new RijndaelManaged())
{
byte[] key = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
byte[] iv = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
aes.Key = key;
aes.IV = iv;
aes.Mode = CipherMode.CFB;
aes.Padding = PaddingMode.None;
aes.KeySize = 128;
aes.BlockSize = 128;
using (FileStream fsCrypt = new FileStream(outputFile, FileMode.Create))
{
using (ICryptoTransform encryptor = aes.CreateEncryptor(key,iv))
{
using (CryptoStream cs = new CryptoStream(fsCrypt, encryptor, CryptoStreamMode.Write))
{
using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
{
int data;
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
}
}
}
}
}
}
}
catch (Exception ex)
{
// Length of the data to encrypt is invalid.
Console.WriteLine(ex.Message);
}
使用CipherMode.CBC
和PaddingMode.PKCS7
,我没有任何错误
但由于我的客户端,我必须使用 AES / CFB 加密文件无填充。
有什么想法在这里发生了什么?
答案 0 :(得分:3)
块密码期望输入的长度是块大小的倍数。使用AES时,输入的长度必须是16的倍数。
您必须对明文应用某种填充,以满足此要求。 PKCS#7填充是最佳选择。
但是,第二个想法是,CFB模式将块密码转换为流密码。流密码不需要填充。在这方面,.NET实现似乎已被打破。
答案 1 :(得分:1)
我在这种情况下使用的(非理想的)解决方案是将明文的原始长度放入要加密的数据的前x个字节中。然后用剩余的数据加密长度。使用流解密时,您只需读取前x个字节,然后使用BitConverter类将它们转换回长度。然后,它会告诉您有多少后续解密字节是您的消息的一部分。除此之外的任何数据都可以作为填充进行忽略。
答案 2 :(得分:1)
当您使用PaddingMode.None时,您可以自己包装ICrytoTransform并处理最终块:
new CryptoStream(fsCrypt, new NoPaddingTransformWrapper(encryptor), CryptoStreamMode.Write)
以下是包装类本身:
public class NoPaddingTransformWrapper : ICryptoTransform
{
private ICryptoTransform m_Transform;
public NoPaddingTransformWrapper(ICryptoTransform symmetricAlgoTransform)
{
if (symmetricAlgoTransform == null)
throw new ArgumentNullException("symmetricAlgoTransform");
m_Transform = symmetricAlgoTransform;
}
#region simple wrap
public bool CanReuseTransform
{
get { return m_Transform.CanReuseTransform; }
}
public bool CanTransformMultipleBlocks
{
get { return m_Transform.CanTransformMultipleBlocks; }
}
public int InputBlockSize
{
get { return m_Transform.InputBlockSize; }
}
public int OutputBlockSize
{
get { return m_Transform.OutputBlockSize; }
}
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
return m_Transform.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
#endregion
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
{
if (inputCount % m_Transform.InputBlockSize == 0)
return m_Transform.TransformFinalBlock(inputBuffer, inputOffset, inputCount);
else
{
byte[] lastBlocks = new byte[inputCount / m_Transform.InputBlockSize + m_Transform.InputBlockSize];
Buffer.BlockCopy(inputBuffer,inputOffset, lastBlocks, 0, inputCount);
byte[] result = m_Transform.TransformFinalBlock(lastBlocks, 0, lastBlocks.Length);
Debug.Assert(inputCount < result.Length);
Array.Resize(ref result, inputCount);
return result;
}
}
public void Dispose()
{
m_Transform.Dispose();
}
}
或者您可以包装一个SymmetricAlgorithm,以便它根据填充模式在CreateEncryptor / CreateDecryptor中进行适当的包装:
public class NoPadProblemSymmetricAlgorithm : SymmetricAlgorithm
{
private SymmetricAlgorithm m_Algo;
public NoPadProblemSymmetricAlgorithm(SymmetricAlgorithm algo)
{
if (algo == null)
throw new ArgumentNullException();
m_Algo = algo;
}
public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)
{
if (m_Algo.Padding == PaddingMode.None)
return new NoPaddingTransformWrapper(m_Algo.CreateDecryptor(rgbKey, rgbIV));
else
return m_Algo.CreateDecryptor(rgbKey, rgbIV);
}
public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
{
if (m_Algo.Padding == PaddingMode.None)
return new NoPaddingTransformWrapper(m_Algo.CreateEncryptor(rgbKey, rgbIV));
else
return m_Algo.CreateEncryptor(rgbKey, rgbIV);
}
#region simple wrap
public override void GenerateIV()
{
m_Algo.GenerateIV();
}
public override void GenerateKey()
{
m_Algo.GenerateIV();
}
public override int BlockSize
{
get { return m_Algo.BlockSize; }
set { m_Algo.BlockSize = value; }
}
public override int FeedbackSize
{
get { return m_Algo.FeedbackSize; }
set { m_Algo.FeedbackSize = value; }
}
public override byte[] IV
{
get { return m_Algo.IV; }
set { m_Algo.IV = value; }
}
public override byte[] Key
{
get { return m_Algo.Key; }
set { m_Algo.Key = value; }
}
public override int KeySize
{
get { return m_Algo.KeySize; }
set { m_Algo.KeySize = value; }
}
public override KeySizes[] LegalBlockSizes
{
get { return m_Algo.LegalBlockSizes; }
}
public override KeySizes[] LegalKeySizes
{
get { return m_Algo.LegalKeySizes; }
}
public override CipherMode Mode
{
get { return m_Algo.Mode; }
set { m_Algo.Mode = value; }
}
public override PaddingMode Padding
{
get { return m_Algo.Padding; }
set { m_Algo.Padding = m_Algo.Padding; }
}
protected override void Dispose(bool disposing)
{
if (disposing)
m_Algo.Dispose();
base.Dispose(disposing);
}
#endregion
}