C#AES:加密文件会导致“要加密的数据长度无效”。错误

时间:2013-07-14 17:45:49

标签: c# encryption aes rijndael

我有一个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.CBCPaddingMode.PKCS7,我没有任何错误 但由于我的客户端,我必须使用 AES / CFB 加密文件无填充

有什么想法在这里发生了什么?

3 个答案:

答案 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

}