如何加密和序列化后保存二进制流和读回? [英] How to encrypt and save a binary stream after serialization and read it back?

查看:215
本文介绍了如何加密和序列化后保存二进制流和读回?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有在使用的CryptoStream,当我想要加密二进制序列化后的二进制流,并将其保存到一个文件中的一些问题。我收到以下异常

I am having some problems in using CryptoStream when I want to encrypt a binary stream after binary serialization and save it to a file. I am getting the following exception

System.ArgumentException : Stream was not readable.

任何人都可以请告诉我如何加密二进制流,并将其保存到一个文件,并回正确的反序列化?

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

在code是如下:

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 the serialization exception as follows

输入流不是一个有效的二进制格式。起始含量(以字节计) 主要有:3F-17-2E-20-80-56-A3-2A-46-63-22-C4-49-56-22-B4-DA ...

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

推荐答案

如果你不喜欢这样,它应该工作:

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);
}

有您的code两个问题:

There are a couple of problems with your code:

  1. 您正在使用加密阅读时。这可能是一个错字,但它应该是一个解密。

  1. You're using an encryptor when reading. This was probably a typo, but it should be a decryptor.

正在冲洗缓存,但这是远远不够的,当使用的CryptoStream 。加密器和解密器上的固定尺寸的块的工作。最后的块可能不具有该大小,因此它需要特殊的处理。最后一个块是一个流之前写的关闭的,不会的刷新的。冲洗上的CryptoStream没有任何用处,因为它可以不写尺寸小于加密/解密的输入块大小的东西,除非是过去的事情被写入。而在此之上,一般你应该总是关闭流,不管是什么。该使用语句是这样做的推荐方法:

You are flushing the buffer, but that is not enough when using a CryptoStream. Encryptors and decryptors work on blocks of a fixed size. The last block may not have that size, so it needs special treatment. The last block is the one written before the stream is closed, not flushed. Flushing on a CryptoStream does nothing useful, because it cannot write anything of size less than the input block size of the encryptor/decryptor, unless it is the last thing to be written. And on top of this, in general you should always close your streams, no matter what. The using statement is the recommended way of doing it:

using(buffer)
    _binaryFormatter.Serialize(buffer, bObj);

这篇关于如何加密和序列化后保存二进制流和读回?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆