6 Replies - 338 Views - Last Post: 12 June 2020 - 12:00 PM Rate Topic: -----

#1 ArtificialSoldier   User is offline

  • D.I.C Lover
  • member icon

Reputation: 2768
  • View blog
  • Posts: 8,077
  • Joined: 15-January 14

Encryption, file writing, and byte arrays

Posted 11 June 2020 - 01:32 PM

My client is using this code to encrypt a file:

        private static byte[] GenerateRandomSalt()
        {
            byte[] data = new byte[32];
            using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
            {
                for (int i =0; i < 10; i++)
                {
                    rng.GetBytes(data);
                }
            }
            return data;
        }
        private static string FileEncrypt(string inputFile, string password)
        {
            string newFileName = inputFile + ".aes";
            //generate random salt
            byte[] salt = GenerateRandomSalt();
            //create output file name
            FileStream fsCrypt = new FileStream(newFileName, FileMode.Create);
            //convert password string to byte arrray
            byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(password);
            //Set Rijndael symmetric encryption algorithm
            RijndaelManaged AES = new RijndaelManaged();
            AES.KeySize = 256;
            AES.BlockSize = 128;
            AES.Padding = PaddingMode.PKCS7;
            // http://stackoverflow.com/questions/2659214/why-do-i-need-to-use-the-rfc2898derivebytes-class-in-net-instead-of-directly
            //"What it does is repeatedly hash the user password along with the salt." High iteration counts.
            var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);
            //Cipher modes: http://security.stackexchange.com/questions/52665/which-is-the-best-cipher-mode-and-padding-mode-for-aes-encryption
            AES.Mode = CipherMode.CFB;
            // write salt to the begining of the output file, so in this case can be random every time
            fsCrypt.Write(salt, 0, salt.Length);
            CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write);
            FileStream fsIn = new FileStream(inputFile, FileMode.Open);
            //create a buffer (1mb) so only this amount will allocate in the memory and not the whole file
            byte[] buffer = new byte[1048576];
            int read;
            try
            {
                while ((read = fsIn.Read(buffer, 0, buffer.Length)) > 0)
                {
                    //Application.DoEvents(); // -> for responsive GUI, using Task will be better!
                    cs.Write(buffer, 0, read);
                }
 
                // Close up
                fsIn.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex.Message);
            }
            finally
            {
                cs.Close();
                fsCrypt.Close();
            }
            return newFileName;
        }


To decrypt, in PHP, I'm getting the first 32 bytes of the file and using that as the salt. The first 32 bytes of one of the files is this:

6e59efbfbdefbfbdefbfbd20efbfbdefbfbd34efbfbd33efbfbd52efbfbdefbf

Looking at that led me to this article, about problems with converting a byte array to a string with a specific character set:

https://blog.gdssecu...-of-byte-a.html

Note that I did verify by opening the file itself that those are the actual first 32 bytes, that's not an issue with PHP trying to read it.

So I'm trying to figure where in that encryption function it might be converting a byte array to a string. Generating the salt seems fine (although he's doing that in a loop for some reason), then the salt gets passed to a constructor, and written using FileStream.Write, which looks like it will handle a byte array just fine.

Actually, looking at the encrypted file, the efbfbd sequence is all over the file, not just in the first part where the salt is stored. So I guess the entire writing process is wrong somewhere. Is there an issue passing the filestream to CryptoStream?

Is This A Good Question/Topic? 0
  • +

Replies To: Encryption, file writing, and byte arrays

#2 ArtificialSoldier   User is offline

  • D.I.C Lover
  • member icon

Reputation: 2768
  • View blog
  • Posts: 8,077
  • Joined: 15-January 14

Re: Encryption, file writing, and byte arrays

Posted 11 June 2020 - 03:21 PM

I just considered that it's calling this function to send the file, maybe the issue is here:

        private static void UploadToFTPSite(string file)
        {
 
            try {
 
               
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://example.com/employees" + DateTime.Now.ToString("MMddyyyy_hhmm") + ".data.aes");
                request.Method = WebRequestMethods.Ftp.UploadFile;
                request.Credentials = new NetworkCredential("user", "pass");
                byte[] fileContents;
                using (StreamReader sourceStream = new StreamReader(file))
                {
                    fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
                }
                request.ContentLength = fileContents.Length;
                using (Stream requestStream = request.GetRequestStream())
                {
                    requestStream.Write(fileContents, 0, fileContents.Length);
                }
                using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
                {
                    Console.WriteLine($"Upload File Complete, status {response.StatusDescription}");
                }
 
                }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
 
        }


I'll start looking through that.

That looks like the issue:

Quote

StreamReader: Implements a TextReader that reads characters from a byte stream in a particular encoding.

StreamReader is designed for character input in a particular encoding, whereas the Stream class is designed for byte input and output.

Was This Post Helpful? 0
  • +
  • -

#3 ArtificialSoldier   User is offline

  • D.I.C Lover
  • member icon

Reputation: 2768
  • View blog
  • Posts: 8,077
  • Joined: 15-January 14

Re: Encryption, file writing, and byte arrays

Posted 11 June 2020 - 03:38 PM

It looks like Stream is just an abstract class, but I assume FileStream would work there. And then maybe use FileStream.copyTo to send it to the requestStream? Or does there need to be an explicit read and then write there for some reason? I think much of this code is originally just from Stack Overflow.

It looks like request.ContentLength needs the length of the data, which is why it was read first, but maybe there's another way to get a file size.
Was This Post Helpful? 0
  • +
  • -

#4 Ornstein   User is offline

  • D.I.C Head

Reputation: 105
  • View blog
  • Posts: 216
  • Joined: 13-May 15

Re: Encryption, file writing, and byte arrays

Posted 11 June 2020 - 03:52 PM

I've only skimmed this, but I get the impression you generally need to be looking for anything where raw binary data is being treated as a UTF-8 string. That's perhaps where/why these UTF-8 replacement characters are sneaking in. This for example stands out straight away:

fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());

Was This Post Helpful? 0
  • +
  • -

#5 ArtificialSoldier   User is offline

  • D.I.C Lover
  • member icon

Reputation: 2768
  • View blog
  • Posts: 8,077
  • Joined: 15-January 14

Re: Encryption, file writing, and byte arrays

Posted 11 June 2020 - 04:32 PM

Yeah, that entire using block needs to be changed. I don't have a lot of experience with C# or a way to run this though, so I'm going to try to suggest something as best I can.

Can I just replace that using block with this:

fileContents = File.ReadAllBytes(file);


https://docs.microso..._System_String_
Was This Post Helpful? 0
  • +
  • -

#6 Ornstein   User is offline

  • D.I.C Head

Reputation: 105
  • View blog
  • Posts: 216
  • Joined: 13-May 15

Re: Encryption, file writing, and byte arrays

Posted 12 June 2020 - 04:10 AM

I can't see why it wouldn't work. (The original code doesn't seem to be concerned about large files anyway)

Now that I'm not hung over: The CopyTo approach should work also, aye. I'm fairly sure there's even easier ways in general of doing binary file uploads via FTP (e.g. WebClient.UploadFile).

If knowing the file size really is important for some reason, you could use FileInfo instead.
Was This Post Helpful? 0
  • +
  • -

#7 ArtificialSoldier   User is offline

  • D.I.C Lover
  • member icon

Reputation: 2768
  • View blog
  • Posts: 8,077
  • Joined: 15-January 14

Re: Encryption, file writing, and byte arrays

Posted 12 June 2020 - 12:00 PM

It looks like that change did the trick. I'm sure that there are more efficient ways to get this done, I'm seeing a lot of comments in the code about Stack Overflow so I think it was mostly cobbled together, I don't think that they have a staff of developers to look at something like this.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1