如何使用 .NET 加密文件并具有与原始文件相同的文件大小?

信息安全 加密 。网 AES
2021-08-27 02:33:02

我正在使用 .NET,并且我编写了一个很棒的例程 (xD),它使用 AES256 CBC 加密和解密文件。它工作得很好,但现在他们告诉我加密文件的大小必须与解密文件的大小相同。(我发誓,其他一些 API 有问题,不是我的错。)

所以,我已经尝试了我能找到的一切,但没有任何效果。.NET Framework 有一个 CipherMode.CTS,看起来与我需要的完全一样,但不幸的是,它目前不受支持。

我试图将填充设置为无,但当然我有错误,因为块大小小于它应该是的。

想法?

编辑:我设法以两种方式解决了这个问题:


使用 .NET API SymmetricAlgorithm alg = new RijndaelManaged(); alg.Mode = CipherMode.CFB; alg.Padding = PaddingMode.None; alg.FeedbackSize = 8;


使用 BouncyCastle API 的 IBufferedCipher cipher = new CtsBlockCipher(new CbcBlockCipher(new AesFastEngine()));

希望这可以帮助其他有同样问题的人:)

3个回答

即使您使用 CTS,您仍然需要一个初始化向量 (IV),必须(我坚持,必须)使用加密强伪随机数生成器为每个文件重新生成它。因此,如果不增加尺寸,您将无法适应所有这些。这是不可避免的,只要您使用“正常”分组密码。

此外,如果您需要加密,那么您很可能需要完整性,即MAC,这本质上需要一些额外的空间。

您可以尝试在加密之前压缩文件(System.IO.Compression.DeflateStream);这可以为您提供所需的额外喘息空间(不是以一种有保证的方式,但它会起作用,特别是如果您需要加密的文件是 XML 文件或类似的文件,具有很多结构)。

正如 Thomas 所写,要安全地加密文件,除了加密文件之外,您还必须有一个 IV。要使 IV 安全,它需要满足两个条件:

  1. 相同的 IV 和密钥对不用于两条不同的消息。
  2. 攻击者无法预测用于他选择的消息的 IV,该消息使用与攻击者想要解密的消息相同的密钥进行加密。

这两个条件通常通过对每条消息使用不同的随机 IV 来满足,在您的情况下,这需要将 IV 添加到加密文件中,从而增加文件大小。但是,如果某些条件为真,您可以使用文件属性(路径、名称、日期和时间)作为 IV(这样就不需要将 IV 添加到加密文件中)。条件是:

  1. 每台机器的加密密钥都是唯一的。这确保了相同的 IV 永远不会与相同的加密密钥一起使用,因为您不能在同一台机器上拥有具有相同文件属性的两个文件。
  2. 每个用户的加密密钥都是唯一的。这确保了攻击者无法通过选择的明文攻击 来解密其他用户的文件,因为密钥不同。

如果满足这两个条件,您可以使用流密码操作模式(例如 CTR、OFB、CFB)并将文件属性用作 IV。

有几个选项:

  1. 看看是否TripleDESCryptoServiceProvider支持 CTS。
  2. 将 CBC 模式的 AES 转换为流密码。

对于后者,只需加密零块并使用生成的密码流对您的明文进行异或运算:

// work out what the padding length needs to be
int paddingSize = cipher.BlockSize - (message.Length % cipher.BlockSize);
int paddedSize = message.Length + paddingSize;

// build a block of zeros
byte[] zeros = new byte[paddedSize];

// create a keystream from the key and IV, using the zeros as a plaintext
byte[] keystream = EncryptAES(zeros, key, iv);

// produce the ciphertext by xoring the plaintext and the keystream
byte[] ciphertext = new byte[message.Length];
for (int i = 0; i < message.Length; i++)
    ciphertext[i] = message[i] ^ keystream[i];

这既可以用作加密算法,也可以用作解密算法——只需使用相同的密钥和 IV 将密文反馈回来,您就会得到原始明文。但是,正如 Thomas Pornin 指出的那样,您仍然需要为每条消息发送一个唯一的 IV。