Encryption and decryption of files using OpenSSL in .NET.

I am 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:

The offset and length were outside for the array or counter greater than the number of elements from the index to the end of the original collection.

When I changed the values โ€‹โ€‹of arguments 1 and 2 from 100 to 64 (the bit is still always byte [100]) it worked, the file was encrypted and decrypted, but the size of the decrypted file was larger than the original and contained 1 or 2 lines at the end of the text file.

+4
source share
2 answers

I do not know the library, but one problem is that you are encrypting fragments of 100 bytes with a block size of 256 bits = 32 bytes. Your pieces should be a multiple of 32 bytes. Additional bytes at the end of the file are likely to round the end block to 32 bytes.

As with Philippe, the likely cause of the accident is a hard-coded 100 in the record. The Crypt function will save one of 32, 64 or 96 bytes from the last block that it encrypts, and all of them are less than 100. (In the case of 100 bytes, which works, the probability that your data will be filled up to 128 bytes is encrypted and so you lose the last 28 bytes of the last block when you write only 100.)

Besides

  • you pass in IV mode in ECB mode - you do not need it
  • repeating the Crypt call, you are apparently configuring the key for every 100 bytes. It is ineffective; you only need to do this once at the start of encryption. You should look for a way to initialize the class using the key (and IV in other modes), and then submit its data blocks at the same time, and not call Crypt with the key every time. I do not know what it will be in this library, but it must exist. In its current form, you also cannot use CBC or any similar mode, because you will write IV every 100 bytes, not once, and not bind the last block between adjacent 100 byte fragments.
  • If you want to use Crypt, why not just load the file into memory right away? I understand that it will not scale to gigabytes of data, but this is probably possible in your normal use case. Or at least choose a much larger data size, for example. 256k. However, you will still encounter a duplicate key setting / broken CBC if you go to a single block.
+3
source

When you point 100 to your call to fIn.Read(...) , you say "Read up to 100 bytes" - note that the actual number of bytes may be different; You must use the return value to determine how many of them have actually been read.

And in the call to fOut.Write you assume 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 always encrypt all 100 bytes of bin , even if you only read 1 from your file. If you read less than 100, you will encrypt everything that was "left" in bin (possibly 0s if not previously used).

Fix these length problems and you should be on the right track. Sort of:

 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; } 
+1
source

Source: https://habr.com/ru/post/1341694/


All Articles