2

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

有什么想法吗?

4

3 回答 3

5

块密码期望输入的长度是块大小的倍数。使用 AES,输入的长度必须是 16 的倍数。

您必须对明文应用某种填充,以便满足此要求。PKCS#7 填充是最佳选择。

然而,仔细想想,CFB 模式将分组密码变成了流密码。流密码不需要填充。在这方面,.NET 实现似乎被破坏了。

于 2013-07-14T18:26:25.020 回答
2

当您使用 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

}
于 2015-03-13T18:01:32.680 回答
1

我在这种情况下使用的一个(不理想的)解决方案是将明文的原始长度放入要加密的数据的前 x 个字节中。然后使用其余数据对长度进行加密。使用流解密时,您只需读取前 x 个字节并使用 BitConverter 类将它们转换回长度。然后,这会告诉您有多少后续解密的字节是您的消息的一部分。除此之外的任何数据都可以作为填充忽略。

于 2013-07-28T09:07:21.797 回答