Stzer Stzer - 24 days ago 7
C# Question

c# Encryption in a multi-layered Streams read/write

There are files created from multiple layers of data:

//input is not always the same, but the structure is, so for example there might be h4 and h5, but I will know that, so that is not the problem
private void generalizationofwrittendata(string filename, int someint, int chunks, string outputfilename, ICryptoTransform crypt, byte[] somedata, int h1, int h2, int h3)
{
using (FileStream fs = new FileStream(outputfilename, FileMode.Create, FileAccess.Write))
{
using (BinaryWriter w = new BinaryWriter(fs, Encoding.ASCII))
{
//writing some data with binary writer
w.Write(h1);
w.Write(h2);
w.Write(h3);
using (FileStream fsIn = File.OpenRead(filename))
{
using (CryptoStream cs = new CryptoStream(fs, crypt, CryptoStreamMode.Write))
{
//writing the rest of data with crypto stream
cs.Write(somedata, 0, somedata.Length);
byte[] chunk = new byte[chunks];
int bytesRead = 0;
while ((bytesRead = fsIn.Read(chunk, 0, chunks)) > 0)
{
cs.Write(chunk, 0, bytesRead);
}
}
}
}
}
}


"generalizationofwrittendata" works perfectly fine in an intended way.

Now the problem is in separating all of that data from the file:

private void test(string filename, int someint, int chunks, string outputfilename, ICryptoTransform crypt)
{
using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
using (BinaryReader br = new BinaryReader(fs, Encoding.ASCII))
{
//reading some not encrypted data
int h1 = br.ReadInt32();
int h2 = br.ReadInt32();
int h3 = br.ReadInt32();
using (CryptoStream cs = new CryptoStream(fs, crypt, CryptoStreamMode.Read))
{
using (BinaryReader br2 = new BinaryReader(cs, Encoding.ASCII))
{
//reading some encrypted data
byte[] somedata = br2.ReadBytes(someint);
//writing the rest of the data to file
using (FileStream fsOut = new FileStream(outputfilename, FileMode.Create))
{
byte[] chunk = new byte[chunks];
int bytesRead = 0;
while ((bytesRead = cs.Read(chunk, 0, chunks)) > 0)
{
fsOut.Write(chunk, 0, bytesRead);
}
}
}
}
}
}
}


This approach simply doesn't work. Only h1,h2,h3 can be received back in this way. somedata will be different and the written file will be longer than the original data, which lead me to thinking that the problem is with CryptoStream+BinaryReader reading from the beginning of the file.
Probably you will suggest me to use
MemoryStream
, but this will be valid only for small files, thus will lead to memory out of range exception.
The only other solution I found was SubStream implementation, but unfortunately when I used it between "fs" and "cs" it resulted in wrong "somedata" and the resulted file had wrong data as well.

Maybe there is a way to do this using Memory-Mapped Files? But I'm not quite sure how would I need to approach it in that way.
Or maybe I'm missing something else, since writing in "generalizationofwrittendata" using BinaryWriter and then CryptoStream does seem to work just fine.

Update#1:

So after receiving replies I've rechecked all of the code, especially related to ICryptoTransform. The ICryptoTransform is definitely not the problem, it is exactly the same for both methods.

The other thing that I noticed was that I used "BinaryReader br2" for no apparent reason, so I have removed that:

private void test(string filename, int someint, int chunks, string outputfilename, ICryptoTransform crypt)
{
using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
using (BinaryReader br = new BinaryReader(fs, Encoding.ASCII))
{
//reading some not encrypted data
int h1 = br.ReadInt32();
int h2 = br.ReadInt32();
int h3 = br.ReadInt32();
using (CryptoStream cs = new CryptoStream(fs, crypt, CryptoStreamMode.Read))
{
//reading some encrypted data
byte[] somedata = new byte[someint];
cs.Read(somedata, 0, someint);
//writing the rest of the data to file
using (FileStream fsOut = new FileStream(outputfilename, FileMode.Create))
{
byte[] chunk = new byte[chunks];
int bytesRead = 0;
while ((bytesRead = cs.Read(chunk, 0, chunks)) > 0)
{
fsOut.Write(chunk, 0, bytesRead);
}
}
}
}
}
}


But unfortunately that hasn't solved the issue, both somedata and the data written to file aren't the same as original.

Update#2:

So that was a stupid problem - I've created
CreateEncryptor()
instead of
CreateDecryptor()
for decryption.

Answer Source

Possibly I am being thick, but couldn't you just seek to the appropriate position of fs and continue to use the same binary reader?

I will try this but setting up a crypto key will take some time.

Edit: Also, are you certain that you are building the CryptoTransform correctly when you decrypt?

Edit: Your code works as you supplied it when I use the following code:

    byte[] testdata = new byte[] { 0x12, 0x34, 0x56 };
    byte[] key;
    byte[] iv;

    String encryptedFile = "encrypted.bin";
    private void buttonCrypt_Click(object sender, EventArgs e)
    {
        ICryptoTransform transform;
        RijndaelManaged rjndl = new RijndaelManaged();
        rjndl.KeySize = 256;
        rjndl.BlockSize = 256;
        rjndl.Mode = CipherMode.CBC;
        transform = rjndl.CreateEncryptor();
        key = (byte[])rjndl.Key.Clone();
        iv = (byte[])rjndl.IV.Clone();
        generalizationofwrittendata("plain.bin",testdata.Length,1,encryptedFile,transform,testdata,0x0abbccdd,0x01223344,0x09887766);
    }

    private void buttonDecrypt_Click(object sender, EventArgs e)
    {
        RijndaelManaged rjndl = new RijndaelManaged();
        rjndl.KeySize = 256;
        rjndl.BlockSize = 256;
        rjndl.Mode = CipherMode.CBC;
        var transform = rjndl.CreateDecryptor(key, iv);
        test(encryptedFile, testdata.Length, 1, "decrypted.bin", transform);
    }

The other data is read as {0x12,0x34,0x56}, h1 to h3 are the values I supplied and decrypted.bin is the same as plain.bin.

This points to a problem with the key you are supplying to the decryptor.

Update 1:

I have modded my test harness to use Aes:

    private void buttonCrypt_Click(object sender, EventArgs e)
    {
        ICryptoTransform transform;
        AesManaged Aes = new AesManaged();
        Aes.KeySize = 256;
        Aes.BlockSize = 128;
        Aes.Mode = CipherMode.CBC;
        Aes.Padding = PaddingMode.PKCS7;
        transform = Aes.CreateEncryptor();
        key = (byte[])Aes.Key.Clone();
        iv = (byte[])Aes.IV.Clone();
        generalizationofwrittendata("plain.bin",testdata.Length,1,encryptedFile,transform,testdata,0x0abbccdd,0x01223344,0x09887766);
    }

    private void buttonDecrypt_Click(object sender, EventArgs e)
    {
        AesManaged Aes = new AesManaged();
        Aes.KeySize = 256;
        Aes.BlockSize = 128;
        Aes.Mode = CipherMode.CBC;
        Aes.Padding = PaddingMode.PKCS7;
        var transform = Aes.CreateDecryptor(key, iv);
        test(encryptedFile, testdata.Length, 1, "decrypted.bin", transform);
    }

The results are identical, it still works as you originally posted it.

I am getting Aes to create a key and initialisation vector which I save, you need to check that the encryption and decryption both call your Aes generator with exactly the same values. Also, ensure that you are using Aes.CreateEncyptor() to encrypt and Aes.CreateDecryptor() to decrypt.

The problem really does have to be in the keys so my suggestion is to break after you create the encryptor and dump the key/iv, then do the same after you create the decryptor and check that they are byte for byte identical.