Serializing object at specific byte index - c#

In VS2015, I would like to serialize a data table to a file, beginning at byte 16, since the file is to be encrypted and the IV uses the bytes 0-15. I have not yet found a serialization method taking an offset parameter, so should I convert the table to a byte array? There must be a cleaner approach. Here is one of the functions:
internal static void EncryptData(DataTable dTable, string userName, string password, string fileName)
{
using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
{
using (Aes aes = SetAes(userName, password)) // simply performs aes initialization
{
fs.Write(aes.IV, 0, 16); // writing the IV
using (CryptoStream cs = new CryptoStream(fs, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
dTable.WriteXml(cs, XmlWriteMode.WriteSchema); // This is overwriting the bytes 0-15 :(
}
}
}
}
EDIT: Adding deserialization function, which throws the exception "Length of the data to decrypt is invalid"
internal static void DecryptData(DataTable dTable, string userName, string password, string fileName)
{
using (FileStream fs = new FileStream(fileName, FileMode.Open))
{
byte[] IV = new byte[16];
fs.Read(IV, 0, 16);
using (Aes aes = SetAes(userName, password, IV)) // simply setting aes
{
using (CryptoStream cs = new CryptoStream(fs, aes.CreateDecryptor(), CryptoStreamMode.Read))
{
dTable.ReadXml(cs);
}
}
}
}
FINAL EDIT: The solution: Add IV bytes with File.WriteAllBytes and use FileStream filemode.Append in the serializing method(EncryptData):
using (Aes aes = SetAes(userName, password))
{
File.WriteAllBytes(fileName, aes.IV);
using (FileStream fs = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (CryptoStream cs = new CryptoStream(fs, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
dTable.WriteXml(cs, XmlWriteMode.WriteSchema);
}
}
}

Related

How to decode and unzip text back?

I want to create big text, squeeze it, encode and save into file. Then I want to decipher and extract that text and save it into the simple text file.
I haven't problem with first step (create encrypted and squeezed file) but I have it with second ones - to get info back (read the comment in my code, please). What I did wrong?
using System;
using System.IO;
using System.Text;
using System.IO.Compression;
using System.Security.Cryptography;
static class Program
{
static void Main()
{
Console.WriteLine("Create encrypted archive...");
var fileName = #"data.xgzip";
byte[] key = null;
byte[] iv = null;
// I want to create big text, squeeze it, encode and save into file:
// 1. Create big text.
// 2. Squeeze text.
// 3. Encode squeezed text.
// 4. Write result to file.
using (var stream = new FileStream(fileName, FileMode.Create,
FileAccess.Write, FileShare.None, 0x1000, FileOptions.None))
{
using (var rijn = Rijndael.Create())
{
key = rijn.Key;
iv = rijn.IV;
var encryptor = rijn.CreateEncryptor(key, iv);
using (var encStream = new CryptoStream(stream, encryptor,
CryptoStreamMode.Write))
{
using (var zip = new DeflateStream(encStream,
CompressionLevel.Optimal))
{
using (var writer = new StreamWriter(zip, new UTF8Encoding(
encoderShouldEmitUTF8Identifier: false,
throwOnInvalidBytes: true), 0x1000, true))
{
var text = "One, two, three, four, five...";
for (int n = 0; n < 1000; n++)
{
writer.WriteLine(text);
}
}
Console.WriteLine("zip.Length = {0}", stream.Length);
}
}
}
}
var fi = new FileInfo(fileName);
Console.WriteLine("File size: {0}", fi.Length);
// Now I want to decipher and extract my file into simple text file.
// 1. Decode squeezed data.
// 2. Unpack decoded data.
// 4. Write result to text file.
Console.WriteLine("Extract encrypted archive...");
var fileName2 = #"data.txt";
using (var stream = new FileStream(fileName, FileMode.Open,
FileAccess.Read, FileShare.None, 0x1000, FileOptions.None))
{
using (var rijn = Rijndael.Create())
{
var encryptor = rijn.CreateEncryptor(key, iv);
using (var cryptoStream = new CryptoStream(stream, encryptor,
CryptoStreamMode.Read))
{
using (var zip = new DeflateStream(cryptoStream,
CompressionMode.Decompress))
{
using (var reader = new StreamReader(zip,
new UTF8Encoding(encoderShouldEmitUTF8Identifier: false,
throwOnInvalidBytes: true)))
{
// System.IO.InvalidDataException:
// "The archive entry was compressed using an unsupported
// compression method."
var text = reader.ReadToEnd();
// Write the result into the simple text file.
using (var stream2 = new FileStream(fileName2,
FileMode.Create, FileAccess.Write, FileShare.None,
0x1000, FileOptions.None))
{
using (var writer = new StreamWriter(stream2,
new UTF8Encoding(encoderShouldEmitUTF8Identifier: false,
throwOnInvalidBytes: true), 0x1000, true))
{
writer.Write(text);
}
Console.WriteLine("stream.Length = {0}", stream.Length);
}
}
}
}
}
}
var fi2 = new FileInfo(fileName2);
Console.WriteLine("File size: {0}", fi2.Length);
Console.WriteLine("Press any key for exit...");
Console.ReadKey();
}
}
In the decode part you are still using the encryptor to decrypt the content, the correct way should be using a decryptor.
update the below lines in the decode part
var encryptor = rijn.CreateEncryptor(key, iv);
using (var cryptoStream = new CryptoStream(stream, encryptor,
CryptoStreamMode.Read))
to
var decryptor = rijn.CreateDecryptor(key, iv);
using (var cryptoStream = new CryptoStream(stream, decryptor,
CryptoStreamMode.Read))
Then you code should work

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.
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.

C# Encryption using RijndaelManaged - Save file in base64 format

Scenario - I have multiple files on my server and as per policy we can keep only encrypted files. We are doing some data migration, for this we have to move these files on to cloud and as per documentations Base64 is the best way to transfer encrypted data over network. I am new in encryption and stuck between this. Let me know if this help you.
How to save file in base64 format?
================================================================
I am new in Encryption and got below code from net and trying to encrypting files using RijndaelManaged and the following code is working fine
public static void EncryptFile(string inputFile, string outputFile)
{
try
{
string password = #"myKey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
string cryptFile = outputFile;
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateEncryptor(key, key),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
catch
{
}
}
When I try to decrypt using Convert.FromBase64String, it returns an error
public static string DecryptFile(string inputFile)
{
var myRijndael = new RijndaelManaged { Key = _key, IV = _key, Padding = PaddingMode.PKCS7 };
_decryptor = myRijndael.CreateDecryptor(myRijndael.Key, myRijndael.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(inputFile)))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, _decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
return srDecrypt.ReadToEnd();
}
}
}
}
Please help me to solve this issue

How to close a stream when it returns a stream

public Stream DecryptFile(string inputFile)//, string outputFile)
{
{
string password = #"mykey"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Read);
StreamReader sr = new StreamReader(cs);
Stream s = sr.BaseStream;
//sr.Close();
//fsCrypt.Close();
return s;
}
}
In this code there is a problem that stream is not closing properly.
If I close it before returning the value then it throws an error.
fsCrypt.Close(); should be performed, but sr.Close(); should not be performed, since the caller of your function should be able to use the Stream.
Also, in order to properly close streams when errors occur, use a disposable context:
using (FileStream fsCrypt = new FileStream(inputFile, FileMode.Open))
{
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Read);
StreamReader sr = new StreamReader(cs);
Stream s = sr.BaseStream;
return s;
}
The caller should also use this pattern:
using (var stream = DecryptFile(string inputFile))
{
// do something with decrypted file
}
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
//code here
}
I think it was introduced in ,NET 3.0 or so, and you donĀ“t need to close streams anymore
Everything inside the using brackets will be automatically closed and be disposed of when the code leaves that part
Its propably much better to realize it with usings. Usings close and dispose the underlying stream for you.
public Stream DecryptFile(string inputFile)//, string outputFile)
{
string password = #"mykey"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
using(var fsCrypt = new FileStream(inputFile, FileMode.Open)
{
RijndaelManaged RMCrypto = new RijndaelManaged();
using(CryptoStream cs = new CryptoStream(fsCrypt, RMCrypto.CreateDecryptor(key, key), CryptoStreamMode.Read))
{
StreamReader sr = new StreamReader(cs);
Stream s = sr.BaseStream;
return s;
}
}
}

Encrypting and Decrypting a file with AES generates a broken file

I'm trying to encrypt and decrypt a file using AES. The problem that I have is that when the file gets decrypted, it is broken and you can't open it. The original file has a length of 81.970 bytes and the decrypted file has a length of 81.984 bytes...so there are 14 bytes added for some reason. The problem could be in the way the file gets encrypted but I don't know what I'm doing wrong.
What am I missing here? Could it be the way I'm processing the password, the iv and the padding?
Thanks for your time!
This is the code I use to encrypt:
private AesManaged aesManaged;
private string filePathToEncrypt;
public Encrypt(AesManaged aesManaged, string filePathToEncrypt)
{
this.aesManaged = aesManaged;
this.filePathToEncrypt = filePathToEncrypt;
}
public void DoEncryption()
{
byte[] cipherTextBytes;
byte[] textBytes = File.ReadAllBytes(this.filePathToEncrypt);
using(ICryptoTransform encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV))
using (MemoryStream ms = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(textBytes, 0, textBytes.Length);
cs.FlushFinalBlock();
cipherTextBytes = ms.ToArray();
}
File.WriteAllBytes("EncryptedFile.aes", cipherTextBytes);
}
This is the code I use to decrypt:
private AesManaged aesManaged;
private string filePathToDecrypt;
public Decrypt(AesManaged aesManaged, string filePathToDecrypt)
{
this.aesManaged = aesManaged;
this.filePathToDecrypt = filePathToDecrypt;
}
public void DoDecrypt()
{
byte[] cypherBytes = File.ReadAllBytes(this.filePathToDecrypt);
byte[] clearBytes = new byte[cypherBytes.Length];
ICryptoTransform encryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV);
using (MemoryStream ms = new MemoryStream(cypherBytes))
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Read))
{
cs.Read(clearBytes, 0, clearBytes.Length);
clearBytes = ms.ToArray();
}
File.WriteAllBytes("DecryptedFile.gif", clearBytes);
}
And here is how I call the functions:
string filePathToEncrypt = "dilbert.gif";
string filePathToDecrypt = "EncryptedFile.aes";
string password = "Password";
string passwordSalt = "PasswordSalt";
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(passwordSalt));
var aesManaged = new AesManaged
{
Key = deriveBytes.GetBytes(128 / 8),
IV = deriveBytes.GetBytes(16),
Padding = PaddingMode.PKCS7
};
Console.WriteLine("Encrypting File...");
var encryptor = new Encrypt(aesManaged, filePathToEncrypt);
encryptor.DoEncryption();
Thread.Sleep(300);
Console.WriteLine("Decrypting File...");
var decryptor = new Decrypt(aesManaged, filePathToDecrypt);
decryptor.DoDecrypt();
Thread.Sleep(300);
Try with:
public void DoEncryption()
{
byte[] cipherBytes;
byte[] textBytes = File.ReadAllBytes(this.filePathToEncrypt);
using (ICryptoTransform encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV))
using (MemoryStream input = new MemoryStream(textBytes))
using (MemoryStream output = new MemoryStream())
using (CryptoStream cs = new CryptoStream(output, encryptor, CryptoStreamMode.Write))
{
input.CopyTo(cs);
cs.FlushFinalBlock();
cipherBytes = output.ToArray();
}
File.WriteAllBytes("EncryptedFile.aes", cipherBytes);
}
and
public void DoDecrypt()
{
byte[] cypherBytes = File.ReadAllBytes(this.filePathToDecrypt);
byte[] textBytes;
using (ICryptoTransform decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV))
using (MemoryStream input = new MemoryStream(cypherBytes))
using (MemoryStream output = new MemoryStream())
using (CryptoStream cs = new CryptoStream(input, decryptor, CryptoStreamMode.Read))
{
cs.CopyTo(output);
textBytes = output.ToArray();
}
File.WriteAllBytes("DecryptedFile.gif", textBytes);
}
Note that the code could be modified to not use temporary byte[] and read/write directly to input/output streams.
In general you can't desume the length of the plaintext from the length of the cyphertext, so this line:
new byte[cypherBytes.Length]
was totally wrong.
And please, don't use Encoding.ASCII in 2016. It is so like previous century. Use Encoding.UTF8 to support non-english characters.
The answer may be very simple. I don't see where do u try to choose a cipher mode, so by default it probably takes CBC, as IV was inited. Then, 81.970 are padded by 14 bytes, to be divisible by 32. So when it happens, the memory you allocated was just 81.970, so the padding bytes doesn't write correctly, cause of some sort of memory leak, and when decrypt is started, unpadding doesn't work correctly.

Categories

Resources