vkstarry
vkstarry

Reputation: 55

File corrupt after BinaryRead/Write / FileStream.Read/Write /File.Read/WriteAllBytes

I'm doing file encrypt/decrypt application and stuck for a long time. I can't believe it gonna be this hard just to read and write files.

Here's the variable

    byte[] FileBytes = null; //file bytes
    byte[] KeyBytes = null; //key bytes
    byte[] ResBytes = null; //result bytes

Read all bytes from the file

    private void ReadFile()
    {
        using (BinaryReader br = new BinaryReader(File.Open(this.txtFilePath.Text, FileMode.Open, FileAccess.Read)))
        {
            int x = 0;

            this.FileBytes = new byte[(int)br.BaseStream.Length];
            int length = (int)br.BaseStream.Length;

            while (x < length)
            {
                this.FileBytes[x] = br.ReadByte();

                x++;
            }

            br.Close();
        }
    }

Write the file

    private void WriteFile()
    {
        using (BinaryWriter bw = new BinaryWriter(File.Open(this.OutputPath, FileMode.Create)))
        {
            // 3. Use foreach and write all 12 integers.
            foreach (byte b in this.ResBytes)
            {
                bw.Write(b);
            }

            bw.Flush();
            bw.Close();
        }
    }

Encryption method

    public byte ApplyVernam(byte inByte, byte keyByte)
    {
        if (inByte == keyByte) { return inByte; }
        else { return (byte)(inByte ^ keyByte); }
    }

And here's the execute button click event (I put FileBytes[1] as key) and yes, the file corrupted except for text document. I thought BinaryWriter is good to do file encryption, but why it's not working? Something wrong in my code? I need explanation here. Thank you very much.

    private void btnExecute_Click(object sender, EventArgs e)
    {
        try
        {
            this.ReadFile();
            this.ResBytes = new byte[this.FileBytes.Length];

            int x = 0;

            while (x < this.FileBytes.Length)
            {
                this.ResBytes[x] = this.ApplyVernam(this.FileBytes[x], this.FileBytes[1]);
                x++;
            }

            this.WriteFile();
        }
        catch
        {
            throw;
        }
    }

Upvotes: 0

Views: 1479

Answers (1)

Iridium
Iridium

Reputation: 23721

Your encryption method is not invertible, and so you cannot reliably decrypt a general binary message with it. The problem occurs because it is possible for two different plaintext values to encrypt to the same ciphertext value, and when this happens there's no way for you to determine when decrypting which was the correct input value.

Example:

if inByte = 100 and keyByte = 100:
    ApplyVernam(100, 100) = 100

if inByte = 0, keyByte = 100:
    ApplyVernam(0, 100) = 100

It's now impossible to tell whether the original plaintext byte was 0 or 100 when trying to decrypt.

I would suggest removing the line: if (inByte == keyByte) { return inByte; } from your ApplyVernam method so that it always XORs the input with the key and so is fully invertible.

As mentioned in my comment, your "key" is the byte at position 1 in the input, but this is also being encrypted, and so when you decrypt, the byte at position 1 is no longer the original key. Changing the following line may resolve the issue:

From:

this.ResBytes[x] = this.ApplyVernam(this.FileBytes[x], this.FileBytes[1]);

To:

this.ResBytes[x] = x == 1 ? this.FileBytes[x] : this.ApplyVernam(this.FileBytes[x], this.FileBytes[1]);

This will ensure that the key byte is written unencrypted to the output.

Upvotes: 2

Related Questions