加密与在 .NET 中使用 OpenSSL 解密文件

发布于 2024-10-19 18:23:58 字数 1079 浏览 3 评论 0原文

我在 C# 项目中使用 OpenSSL Crypto 库来加密/解密文件。这是我的代码:

byte[] key = System.Text.Encoding.ASCII.GetBytes("password");

byte[] iv = System.Text.Encoding.ASCII.GetBytes("1234");


OpenSSL.Crypto.CipherContext cc = new OpenSSL.Crypto.CipherContext(
    OpenSSL.Crypto.Cipher.AES_256_ECB);

FileStream fIn = new FileStream("C:\\file.txt", FileMode.Open, 
    FileAccess.Read);
FileStream fOut = new FileStream("C:\\encrypted.txt", FileMode.OpenOrCreate,
    FileAccess.Write);
fOut.SetLength(0);

byte[] bin = new byte[100];
long rdlen = 0;
long totlen = fIn.Length;
int len;

DateTime start = DateTime.Now;
while (rdlen < totlen)
{
    // argument 1
    len = fIn.Read(bin, 0, 100);         
    // argument 2
    fOut.Write(cc.Crypt(bin,key,iv,true),0,100);                 
    rdlen = rdlen + len;
}

fOut.Flush();  
fOut.Close();
fIn.Close();

结果我得到了这个异常:

偏移量和长度超出范围 对于数组或计数大于 从索引到的元素数量 源集合结束。

当我将参数 1 和 2 的值从 100 更改为 64 时(bin 仍然始终是 byte[100]) 它工作了,文件被加密和解密,但解密文件的大小比原始文件大,并且在文本文件末尾包含 1 或 2 行以上。

I'm using the OpenSSL Crypto library in my C# project to encrypt/decrypt files. Here is my code :

byte[] key = System.Text.Encoding.ASCII.GetBytes("password");

byte[] iv = System.Text.Encoding.ASCII.GetBytes("1234");


OpenSSL.Crypto.CipherContext cc = new OpenSSL.Crypto.CipherContext(
    OpenSSL.Crypto.Cipher.AES_256_ECB);

FileStream fIn = new FileStream("C:\\file.txt", FileMode.Open, 
    FileAccess.Read);
FileStream fOut = new FileStream("C:\\encrypted.txt", FileMode.OpenOrCreate,
    FileAccess.Write);
fOut.SetLength(0);

byte[] bin = new byte[100];
long rdlen = 0;
long totlen = fIn.Length;
int len;

DateTime start = DateTime.Now;
while (rdlen < totlen)
{
    // argument 1
    len = fIn.Read(bin, 0, 100);         
    // argument 2
    fOut.Write(cc.Crypt(bin,key,iv,true),0,100);                 
    rdlen = rdlen + len;
}

fOut.Flush();  
fOut.Close();
fIn.Close();

As a result I got this exception:

Offset and length were out of bounds
for the array or count is greater than
the number of elements from index to
the end of the source collection.

When I changed the values of argument 1 and 2 from 100 to 64 (bin still always byte[100])
it worked, the file was encrypted and decrypted but the size of the decrypted file was bigger than the original one and contained 1 or 2 more lines at the end of the text file.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

没企图 2024-10-26 18:23:58

我不知道这个库,但这里的一个问题是,您正在使用 256 位 = 32 字节的块大小加密 100 字节的块。您的块应该是 32 字节的倍数。文件末尾的额外字节可能只是将最终块四舍五入到 32 字节。

正如 Philip 的回答所示,崩溃的可能原因是 Write 中的硬编码 100。 Crypt 函数将从其加密的最终块中返回 32、64 或 96 字节之一,这些字节都小于 100。(在有效的 100 字节情况下,您的数据可能会被填充到加密的 128 字节,并且因此,当您只写入 100 时,您就会丢失最后一个块的最后 28 个字节。)

此外,

  1. 您还以 ECB 模式传递 IV - 您不需要
  2. 通过重复调用 Crypt 来实现这一点,您可能正在为之进行密钥设置每 100 字节。这是低效的;您只需在加密开始时执行一次。您应该寻找一种方法来使用密钥(以及其他模式中的 IV)初始化类,然后立即向其提供数据块进行加密,而不是每次都使用密钥调用 Crypt。我不知道这个图书馆里有什么,但它应该存在。按照目前的情况,您也不能使用 CBC 或任何类似的模式,因为您将每 100 字节而不是一次写入 IV,并且不会将最后一个块链接在相邻的 100 字节块之间。
  3. 如果你想使用 Crypt,为什么不立即将文件加载到内存中呢?我意识到这不会扩展到千兆字节的数据,但在您的正常用例中可能是可能的。或者至少选择一个更大的数据大小,例如 256k。然而,如果你超过一个街区,你仍然会面临重复的钥匙设置/损坏的 CBC。

I don't know the library but one problem here is that you're encrypting chunks of 100 bytes with a 256-bit = 32 byte block size. Your chunks should be multiples of 32 bytes. The extra bytes at the end of the file are likely just rounding the final block up to 32 bytes.

As in Philip's answer the likely cause of the crash is the hard-coded 100 in the Write, though. The Crypt function will be returing one of 32, 64 or 96 bytes from the final block it's encrypting, which are all short of 100. (In the 100 byte case that works, chances are your data is being padded out to 128 bytes encrypted and so you're losing the last 28 bytes of the last block when you only write 100.)

Also

  1. you're passing in an IV in ECB mode - you don't need this
  2. by repeatedly calling Crypt you're presumably doing key setup for every 100 bytes. This is inefficient; you only need to do it once at the start of the encryption. You should look for a way to initialise the class with the key (and IV in other modes) then feed it blocks of data to encrypt at once, rather than calling Crypt with the key every time. I don't know what this would be in this library but it ought to exist. As it stands you also can't use CBC or any similar mode because you'll be writing the IV every 100 bytes rather than once and not chaining the last block between adjacent 100 byte chunks.
  3. if you want to use Crypt, why not just load the file into memory at once? I realise that won't scale to gigabytes of data but it's likely possible in your normal use case. Or at least pick a much larger data size, e.g. 256k. However you'd still be faced with the repeated key set-up / broken CBC if you go above one block.
奈何桥上唱咆哮 2024-10-26 18:23:58

当您在对 fIn.Read(...) 的调用中指定 100 时,您是在说“读取最多 100 个字节” - 请注意,实际字节数可能会与众不同;您应该使用返回值来确定实际读取了多少个。

在对 fOut.Write 的调用中,您假设 cc.Crypt(bin,key,iv,true) 的输出正好是 100 个字节,即不是一个有效的假设。另请注意,即使您只从文件中读取 1 个字节,您也始终会加密 bin 的所有 100 个字节。如果您读取的内容少于 100,您将加密 bin 中“剩余”的内容(可能是 0,除非之前使用过)。

解决这些长度问题,您就应该走上正轨了。像这样的东西:

while (rdlen < totlen)
{
    len = fIn.Read(bin, 0, 100);         
    // note that we are encrypting all of "bin" here, may want to only 
    // encrypt "len" bytes..
    byte[] encrypted = cc.Crypt(bin, key, iv, true);
    fOut.Write(encrypted, 0, encrypted.Length);                 
    rdlen = rdlen + len;
}

When you specify 100 to your call to fIn.Read(...), you are saying "Read up to 100 bytes" - note that the actual number of bytes may be different; You should use the return value to determine how many were actually read.

And in the call to fOut.Write, you are assuming that the output of cc.Crypt(bin,key,iv,true) will be exactly 100 bytes, which is not a valid assumption. Also note that you are always encrypting all 100 bytes of bin, even if you only read 1 from your file. If you did read less than 100, you would be encrypting whatever was "left over" in bin (probably 0s, unless previously used).

Fix these length issues, and you should be on the right track. Something like:

while (rdlen < totlen)
{
    len = fIn.Read(bin, 0, 100);         
    // note that we are encrypting all of "bin" here, may want to only 
    // encrypt "len" bytes..
    byte[] encrypted = cc.Crypt(bin, key, iv, true);
    fOut.Write(encrypted, 0, encrypted.Length);                 
    rdlen = rdlen + len;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文