How to encrypt and save a binary stream after serialization and read it back?

I'm having some problems using CryptoStream when I want to encrypt a binary stream after binary serialization and save it to a file. I get the following exception

System.ArgumentException : Stream was not readable. 

Can someone show me how to encrypt a binary stream and save it to a file and deserialize it correctly?

The code is as follows:

 class Program { public static void Main(string[] args) { var b = new B {Name = "BB"}; WriteFile<B>(@"C:\test.bin", b, true); var bb = ReadFile<B>(@"C:\test.bin", true); Console.WriteLine(b.Name == bb.Name); Console.ReadLine(); } public static T ReadFile<T>(string file, bool decrypt) { T bObj = default(T); var _binaryFormatter = new BinaryFormatter(); Stream buffer = null; using (var stream = new FileStream(file, FileMode.OpenOrCreate)) { if(decrypt) { const string strEncrypt = "*#4$%^.++q~!cfr0(_!# $@ $!&#&#*&@(7cy9rn8r265& $@ &*E^184t44tq2cr9o3r6329"; byte[] dv = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}; CryptoStream cs; DESCryptoServiceProvider des = null; var byKey = Encoding.UTF8.GetBytes(strEncrypt.Substring(0, 8)); using (des = new DESCryptoServiceProvider()) { cs = new CryptoStream(stream, des.CreateEncryptor(byKey, dv), CryptoStreamMode.Read); } buffer = cs; } else buffer = stream; try { bObj = (T) _binaryFormatter.Deserialize(buffer); } catch(SerializationException ex) { Console.WriteLine(ex.Message); } } return bObj; } public static void WriteFile<T>(string file, T bObj, bool encrypt) { var _binaryFormatter = new BinaryFormatter(); Stream buffer; using (var stream = new FileStream(file, FileMode.Create)) { try { if(encrypt) { const string strEncrypt = "*#4$%^.++q~!cfr0(_!# $@ $!&#&#*&@(7cy9rn8r265& $@ &*E^184t44tq2cr9o3r6329"; byte[] dv = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}; CryptoStream cs; DESCryptoServiceProvider des = null; var byKey = Encoding.UTF8.GetBytes(strEncrypt.Substring(0, 8)); using (des = new DESCryptoServiceProvider()) { cs = new CryptoStream(stream, des.CreateEncryptor(byKey, dv), CryptoStreamMode.Write); buffer = cs; } } else buffer = stream; _binaryFormatter.Serialize(buffer, bObj); buffer.Flush(); } catch(SerializationException ex) { Console.WriteLine(ex.Message); } } } } [Serializable] public class B { public string Name {get; set;} } 

It throws a serialization exception as follows

The input stream is not a valid binary format. The initial contents (in bytes) are: 3F-17-2E-20-80-56-A3-2A-46-63-22-C4-49-56-22-B4-DA ...

+6
c # serialization cryptography
source share
2 answers

If you do it like this, it should work:

 // A: encrypting when writing // 1. create backing storage stream. In your case a file stream using(Stream innerStream = File.Create(path)) // 2. create a CryptoStream in write mode using(Stream cryptoStream = new CryptoStream(innerStream, encryptor, CryptoStreamMode.Write)) { // 3. write to the cryptoStream binaryFormatter.Serialize(cryptoStream, obj); } // B: decrypting when reading // 1. create backing storage stream. In your case a file stream using(Stream innerStream = File.Open(path, FileMode.Open)) // 2. create a CryptoStream in read mode using(Stream cryptoStream = new CryptoStream(innerStream, decryptor, CryptoStreamMode.Read)) { // 3. read from the cryptoStream obj = binaryFormatter.Deserialize(cryptoStream); } 

There are several problems in your code:

  • When reading, the cipher is used. It was probably a typo, but it should be a transcript.

  • You clear the buffer , but this is not enough when using CryptoStream . Ciphers and decoders work on blocks of a fixed size. The last block may not have this size, so it needs special processing. The last block is the one that was written before the stream was closed, and not blushed. Flushing CryptoStream does nothing useful, because it cannot write anything smaller than the size of the encryption / decoder input block, unless that is the last thing to write. And in addition to this, in general, you should always close your threads, no matter what. The using recommendation is the recommended way:

     using(buffer) _binaryFormatter.Serialize(buffer, bObj); 
+4
source share

There is a great example of how to do this in the MSDN documentation: CryptoStream MSDN in the Examples section.

The procedure is basically as follows:

  • create cryptostream (empty stream)
  • write content to crypto stream (encrypt)
  • save cryptostream to file
  • create cryptostream from file contents
  • reading from a cryptostom (decryption)
+1
source share

All Articles