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

时间:2011-02-28 19:43:22

标签: c# .net encryption cryptography openssl

我在我的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仍然总是字节[100]) 它工作,文件被加密和解密,但解密文件的大小比原始文件大,并在文本文件的末尾包含1或2多行。

2 个答案:

答案 0 :(得分:3)

我不知道库,但这里的一个问题是你用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。

答案 1 :(得分:1)

当您对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;
}