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.CBCPaddingMode.PKCS7、エラーはありません。
しかし、私のクライアントのために、AES/CFB with No Paddingを使用してファイルを暗号化する必要があります。

ここで何が起こっているのか、何か考えはありますか?

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 に答える