Deserializing encrypted objects from file - c#

I want to deserialize encrypted objects (multiple instances of the same object type) from a file, that were added during execution of a program. The objects were encrypted using CryptoStream.
However, when deserializing i cannot loop through cryptoStream as I intended.
I can serialize and encrypt the objects and the file grows with every object added.
I can also deserialize the first encrypted object. However, following objects cannot be restored.
I have tried different approaches to loop though the stream. Also I tried other cryptostreams and working around that problem.
Serializing:
private void EncryptObjectToFile(TraceMessage pMessage, FileInfo pFileInfo)
{
if (pFileInfo == null) { pFileInfo = m_LogFile; }
m_Formatter.Serialize(m_SerializedStream, pMessage);
m_SerializedStream.Position = 0;
using (FileStream logfile = new FileStream(m_LogFile.FullName, FileMode.Append))
{
using (CryptoStream cryptoStream = new CryptoStream(logfile, m_Algorythm.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
cryptoStream.Write(m_SerializedStream.ToArray(), 0, (int)m_SerializedStream.Length);
cryptoStream.FlushFinalBlock();
}
}
}
Deserializing:
private List<TraceMessage> DecryptObjectsFromFile(FileInfo pFileInfo)
{
List<TraceMessage> tmp = new List<TraceMessage>();
try
{
READWRITELOCK.AcquireReaderLock(READERTIMEOUTS);
Interlocked.Increment(ref READS);
try
{
if (pFileInfo == null) { pFileInfo = m_LogFile; }
m_SerializedStream.Position = 0;
using (FileStream logfile = new FileStream(m_LogFile.FullName, FileMode.Open))
{
using (var cryptoStream = new CryptoStream(logfile, m_Algorythm.CreateDecryptor(key, iv), CryptoStreamMode.Read))
{
if (cryptoStream.CanRead)
{
while (cryptoStream.Position < cryptoStream.Length)
{
tmp.Add((TraceMessage)m_Formatter.Deserialize(cryptoStream));
}
}
}
}
}
catch(Exception exp) { }
finally
{
READWRITELOCK.ReleaseReaderLock();
Interlocked.Decrement(ref READS);
}
}
catch (Exception) { }
return tmp;
}
In the end what i am trying to achieve is, to encrypt objects (multiple instances of the same object type) and add them to a file. As files can be added any time and cannot be collected in a list and then written to file, I want to add those objects to an already existing file.
Later I want to recreate each object that was encrypted and serialized to the file.

Related

Cannot access a closed stream when passing stream to another function

I need to pass a stream to a couple of functions in another class, but its throwing an error
Cannot access a closed stream
Here's the code:
first method:
Here it opens a file with File.Open method and then creates a memorystream object and it copies FileStream to MemoryStream. then sets Position to 0 (i set position to 0, because i was that in a solution, but not helping tho). Then it creates an object of class DocxConvert and call the Converto method by passing MemoryStream to it.
using (var stream = File.Open(tempPath2, FileMode.Open))
{
using(var ms = new MemoryStream())
{
stream.CopyTo(ms);
ms.Position = 0;
using (var docx = new DocxConvert())
{
return docx.Converto(ms);
}
}
}
DocxConvert Class:
It takes stream and then calls copyStream method by passing the accepted stream.
copyStream method in DocxConvert Class: it should copy the accepted stream to another stream called _memoryStream which is a class property.
public class DocxConvert
{
private MemoryStream _memoryStream = new MemoryStream();
public bool Converto(Stream stream)
{
try
{
copyStream(stream);
//more code
}
catch (IOException ex)
{
Debug.WriteLine(ex);
}
return true;
}
private void copyStream(Stream stream)
{
stream.CopyTo(_memoryStream); //here it throws the error
}
}
p.s. I search for this error here before posting, but non of the topics helped me.
SOLVED by restarting PC, the code it ok.
I am not aware about your question .But here in the code bellow no excepion
private void button1_Click(object sender, EventArgs e)
{
string tempPath2 = Application.StartupPath + "//" + "test.txt";
using (var stream = File.Open(tempPath2, FileMode.Open))
{
using (var ms = new MemoryStream())
{
stream.CopyTo(ms);
ms.Position = 0;
var docx = new DocxConvert();
var isok = docx.Converto(ms);
}
}
}
The bellow is the calss defined where _memorystream is defined at top
MemoryStream _memoryStream = new MemoryStream();
public bool Converto(Stream stream)
{
try
{
copyStream(stream);
//more code
}
catch (IOException ex)
{
// Debug.WriteLine(ex);
}
return true;
}
private void copyStream(Stream stream)
{
try
{
stream.CopyTo(_memoryStream);
}
catch (Exception)
{
}
}

Serialise\Deserialize between .net web service and Android client

I have an android client that communicates with .net web service.
objToFormat is a List of my custom type.
public static byte[] ToByteArray(object objToFormat)
{
try
{
if (objToFormat == null) return null;
MemoryStream stream = new MemoryStream();
GZipStream zipped = new GZipStream(stream, CompressionMode.Compress, true);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(zipped, objToFormat);
zipped.Close();
zipped.Dispose();
return (stream.GetBuffer());
}
}
In my Android client i use the ksoap2 library and i receive the serialized string from the web service.
this is my android code :
byte[] decoded = Base64.decode(response, Base64.DEFAULT);
Object res = deserializeObject(decoded);
how do i deserialize the object ?
Thank you
You need to use a file stream to deserialize the object. The example below uses a Hashtable to save the deserialized content:
// Declare the hashtable reference.
Hashtable responseFromWebService = null;
// Open the file containing the data that you want to deserialize.
FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
try
{
BinaryFormatter formatter = new BinaryFormatter();
// Deserialize the hashtable from the file and
// assign the reference to the local variable.
responseFromWebService = (Hashtable) formatter.Deserialize(fs);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to deserialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
You can find the MSDN documentation on Deserialization here:
https://msdn.microsoft.com/en-us/library/system.runtime.serialization.iformatter.deserialize(v=vs.110).aspx
EDIT in response to new information about it needing to be in Java
Your class needs has to have implements Serializable unless you're using an ArrayList object (or similar) which already implements this.
You also need to cast it back to what the object was (for example, the above hashtable)
Usage:
Hashtable deserializedData = (Hashtable) deserializeObject(someBytes)
public static Hashtable deserializeObject(byte[] b)
{
try
{
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(b));
Hashtable htable = in.readObject();
in.close();
return htable;
}
catch(ClassNotFoundException cnfe)
{
Log.e("deserializeObject", "class not found error", cnfe);
return null;
}
catch(IOException ioe)
{
Log.e("deserializeObject", "io error", ioe);
return null;
}
}

Read file.inputstream twice

I need to read csv file twice. but after first reading:
using (var csvReader = new StreamReader(file.InputStream))
{
fileFullText += csvReader.ReadToEnd();
file.InputStream.Seek(0, SeekOrigin.Begin);
csvReader.Close();
}
using file in enother function:
public static List<string> ParceCsv(HttpPostedFileBase file)
{
//file.InputStream.Seek(0, SeekOrigin.Begin);
using (var csvReader = new StreamReader(file.InputStream))
{
// csvReader.DiscardBufferedData();
// csvReader.BaseStream.Seek(0, SeekOrigin.Begin);
string inputLine = "";
var values = new List<string>();
while ((inputLine = csvReader.ReadLine()) != null)
{
values.Add(inputLine.Trim().Replace(",", "").Replace(" ", ""));
}
csvReader.Close();
return values;
}
}
The file.Length is 0.
Can anybody help?
The reason is that SteramReader's Dispose() method also closes the underlying stream; In your case file.InputStream. The using statement calls Dispose() implicitly. Try to replace using with disposes of both your StreamReaded-s after you finished both read operations. As I remember some stream classes have a bool option to leave underlying stream open after dispose.
.NET 4.5 fixed this issue by introducing leaveOpen parameter in SteamReader constructor. See: MSDN
public StreamReader(
Stream stream,
Encoding encoding,
bool detectEncodingFromByteOrderMarks,
int bufferSize,
bool leaveOpen
)
One more thing. You do not need to close SteramReader yourself (the line with csvReader.Close();) when you wrap it in using statement, thus Dispose() and Close() are the same in case of StreamReader.
if your using HttpPostedFileBase you need to clone it first,
use the code this git here
or just add this as a class in your namespace:
public static class HttpPostedFileBaseExtensions
{
public static Byte[] ToByteArray(this HttpPostedFileBase value)
{
if (value == null)
return null;
var array = new Byte[value.ContentLength];
value.InputStream.Position = 0;
value.InputStream.Read(array, 0, value.ContentLength);
return array;
}
}
now you can read the HttpPostedFileBase like so:
private static void doSomeStuff(HttpPostedFileBase file)
{
try
{
using (var reader = new MemoryStream(file.ToByteArray()))
{
// do some stuff... say read it to xml
using (var xmlTextReader = new XmlTextReader(reader))
{
}
}
}
catch (Exception ex)
{
throw ex;
}
}
after using this you can still write in your main code:
file.SaveAs(path);
and it will save it to the file.

BinaryFormatter & CryptoStream problem when deserializing

I'm getting a bit desperate here. I'm trying to write an encrypted file with a serialized object to disk and later retrieve the file, decrypt it and deserialize the object back.
UPDATE:
I refactored the code to this:
using (Stream innerStream = File.Create(this.GetFullFileNameForUser(securityContext.User, applicationName)))
{
using (Stream cryptoStream = new CryptoStream(innerStream, GetCryptoProvider().CreateEncryptor(), CryptoStreamMode.Write))
{
// 3. write to the cryptoStream
//BinaryFormatter bf = new BinaryFormatter();
//bf.Serialize(cryptoStream, securityContext);
XmlSerializer xs = new XmlSerializer(typeof(SecurityContextDTO));
xs.Serialize(cryptoStream, securityContext);
}
}
using (Stream innerStream = File.Open(this.GetFullFileNameForUser(user, applicationName), FileMode.Open))
{
using (Stream cryptoStream = new CryptoStream(innerStream, GetCryptoProvider().CreateDecryptor(), CryptoStreamMode.Read))
{
//BinaryFormatter bf = new BinaryFormatter();
//return (SecurityContextDTO)bf.Deserialize(cryptoStream);
XmlSerializer xs = new XmlSerializer(typeof(SecurityContextDTO));
//CryptographicException here
return (SecurityContextDTO)xs.Deserialize(cryptoStream);
}
}
Now I'm getting a cryptographic exception on deserialize: Bad Data
ORIGINAL:
I'm doing this:
public void StoreToFile(SecurityContextDTO securityContext, string applicationName)
{
if (securityContext.LoginResult.IsOfflineMode == false)
{
Stream stream = null;
CryptoStream crStream = null;
try
{
TripleDESCryptoServiceProvider cryptic = GetCryptoProvider();
stream = File.Open(this.GetFullFileNameForUser(securityContext.User, applicationName), FileMode.Create);
crStream = new CryptoStream(stream,
cryptic.CreateEncryptor(), CryptoStreamMode.Write);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(crStream, securityContext);
}
catch(Exception)
{
throw;
}
finally
{
if (crStream != null)
crStream.Close();
}
}
}
public SecurityContextDTO RetrieveFromFile(UserDTO user,string applicationName)
{
SecurityContextDTO objectToSerialize;
Stream stream = null;
CryptoStream crStream=null;
try
{
stream = File.Open(this.GetFullFileNameForUser(user, applicationName), FileMode.Open);
crStream= new CryptoStream(stream,
GetCryptoProvider().CreateDecryptor(), CryptoStreamMode.Read);
BinaryFormatter bFormatter = new BinaryFormatter();
//Exception here
objectToSerialize = (SecurityContextDTO)bFormatter.Deserialize(crStream);
}
catch (Exception)
{
objectToSerialize = null;
}
finally
{
if (crStream!=null)
crStream.Close();
}
return objectToSerialize;
}
private static TripleDESCryptoServiceProvider GetCryptoProvider()
{
TripleDESCryptoServiceProvider cryptic = new TripleDESCryptoServiceProvider();
try
{
cryptic.Key = ASCIIEncoding.ASCII.GetBytes(CrypKey);
Rfc2898DeriveBytes db = new Rfc2898DeriveBytes("sdddsdsd", 8);
cryptic.IV = db.GetBytes(8);
}
catch (Exception)
{
throw;
}
finally
{
cryptic.Dispose();
}
return cryptic;
}
Encrypting and writing works fine, the file appears on the disk and the content is there (encrypted of course). But when I call the retrieve method I always get a SerializationException
Binary stream '30' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.
When I leave the cryptographic methods out everything works fine.
So,
You realize that in this code
private static TripleDESCryptoServiceProvider GetCryptoProvider()
{
TripleDESCryptoServiceProvider cryptic = new TripleDESCryptoServiceProvider();
try
{
cryptic.Key = ASCIIEncoding.ASCII.GetBytes(CrypKey);
Rfc2898DeriveBytes db = new Rfc2898DeriveBytes("sdddsdsd", 8);
cryptic.IV = db.GetBytes(8);
}
catch (Exception)
{
throw;
}
finally
{
cryptic.Dispose(); // <------- Don't do this until you are done decrypting.
}
return cryptic;
}
you will ALWAYS dispose of the provider meaning you are always using a random key and iv
You are close. However, the stream you pass into the creation of CryptoStream is always, always, always the buffer that will hold your end result. It is not the stream that holds the data you want to encrypt or decrypt. I put the emphasis in there because I remember learning this for the first time and I did exactly what you were doing. So here:
// this is for encryption
var memStreamEncryptedData = new MemoryStream();
var encryptStream = new CryptoStream(memStreamEncryptedData,
transform, CryptoStreamMode.Write);
// this is for decryption
var memStreamDecryptedData = new MemoryStream();
var decryptStream = new CryptoStream(memStreamDecryptedData,
transform, CryptoStreamMode.Write);
Notice in both cases, CryptoStream is being initialized with a blank output stream. Your stream does not enter into the picture until later. So, during a write, you will do the following:
encryptStream.Write(dataToBeEncrypted);
encryptStream.FlushFinalBlock();
encryptStream.Close();
// memStreamEncryptedData now safely holds your encrypted data
And during the read, you will:
decryptStream.Write(dataToBeDecrypted);
encryptStream.FlushFinalBlock();
encryptStream.Close();
// memStreamDecryptedData now safely holds your decrypted data
So, to save you some trouble, here's a nice simple Symmetric method that will perform both encryption and decryption. The only difference between this and yours is that I am working directly on byte arrays, but perhaps that augmentation can be an exercise:
public static byte[] Symmetric(bool encrypt, byte[] plaintext, string ikey)
{
if (plaintext.Length == 0) return plaintext;
// setting up the services can be very expensive, so I'll cache them
// into a static dictionary.
SymmetricSetup setup;
if (!_dictSymmetricSetup.TryGetValue(ikey, out setup))
{
setup = new SymmetricSetup();
setup.des = new DESCryptoServiceProvider { Mode = CipherMode.CBC,
Padding = PaddingMode.Zeros };
setup.hash = Hash(Encoding.ASCII.GetBytes(ikey));
setup.key = setup.hash.ForceLength(8, 0);
setup.IV = Encoding.ASCII.GetBytes("init vec");
setup.des.Key = setup.key;
setup.des.IV = setup.IV;
setup.encrypt = setup.des.CreateEncryptor(setup.des.Key, setup.des.IV);
setup.decrypt = setup.des.CreateDecryptor(setup.des.Key, setup.des.IV);
_dictSymmetricSetup[ikey] = setup;
}
var transform = encrypt ? setup.encrypt : setup.decrypt;
var memStreamEncryptedData = new MemoryStream();
var encStream = new CryptoStream(memStreamEncryptedData, transform, CryptoStreamMode.Write);
if (encrypt)
encStream.Write(new[] {(byte) ((8 - (plaintext.Length + 1)%8)%8)}, 0, 1);
encStream.Write(plaintext, 0, plaintext.Length);
encStream.FlushFinalBlock();
encStream.Close();
memStreamEncryptedData.Flush();
var ciphertext = memStreamEncryptedData.ToArray();
byte b;
if (!encrypt)
if (byte.TryParse("" + ciphertext[0], out b))
ciphertext = ciphertext.Skip(1).Take(ciphertext.Length - b - 1).ToArray();
return ciphertext;
}
And to call it, you might do something like this:
static public byte[] DecryptData(this byte[] source, string password) {
return Symmetric(false, source, password);
}
static public byte[] EncryptData(this byte[] source, string password) {
return Symmetric(true, source, password);
}
Again, you'll do something slightly different to work with streams, but hopefully you get the gist. Instead of MemoryStream, it will be whatever stream you need to feed into your serializer.
Some previous posts that can be of use:
How do I encrypt a string in vb.net using RijndaelManaged, and using PKCS5 padding?
Does BinaryFormatter apply any compression?
In later, you can see how I stacked compression with encryption with serialization. And it works.

Datacontractserializer doesn't overwrite all data

I've noticed that if I persist an object back into file using a Datacontractserializer, if the length of the new xml is shorter than the xml originally present in the file the remnants of the original xml outwith the length of the new xml will remain in the file and will break the xml.
Does anyone have a good solution to fix this?
Here's the code I am using to persist the object:
/// <summary>
/// Flushes the current instance of the given type to the datastore.
/// </summary>
private void Flush()
{
try
{
string directory = Path.GetDirectoryName(this.fileName);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
FileStream stream = null;
try
{
stream = new FileStream(this.fileName, FileMode.OpenOrCreate);
for (int i = 0; i < 3; i++)
{
try
{
using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, new System.Text.UTF8Encoding(false)))
{
stream = null;
// The serializer is initialized upstream.
this.serializer.WriteObject(writer, this.objectValue);
}
break;
}
catch (IOException)
{
Thread.Sleep(200);
}
}
}
finally
{
if (stream != null)
{
stream.Dispose();
}
}
}
catch
{
// TODO: Localize this
throw;
//throw new IOException(String.Format(CultureInfo.CurrentCulture, "Unable to save persistable object to file {0}", this.fileName));
}
}
It's because of how you are opening your stream with:
stream = new FileStream(this.fileName, FileMode.OpenOrCreate);
Try using:
stream = new FileStream(this.fileName, FileMode.Create);
See FileMode documentation.
I believe this is due to using FileMode.OpenOrCreate. If the file already exits, I think the file is being opened and parts of the data are being overwritten from the start byte. If you change to using FileMode.Create it forces any existing files to be overwritten.

Categories

Resources