c# 多层流中的加密 read/write

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

存在从多层数据创建的文件:

    //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" 以预期的方式完美运行。

现在的问题是将所有数据从文件中分离出来:

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

这种方法根本行不通。只有 h1,h2,h3 可以通过这种方式被接收回来。一些数据会有所不同,写入的文件会比原始数据长,这让我认为问题出在 CryptoStream+BinaryReader 从文件开头读取。 可能你会建议我使用MemoryStream,但这只对小文件有效,因此会导致内存超出范围异常。 我找到的唯一其他解决方案是 SubStream 实现,但不幸的是,当我在 "fs" 和 "cs" 之间使用它时,它导致了错误的 "somedata" 并且结果文件也有错误的数据.

也许有一种方法可以使用 Memory-Mapped Files 来做到这一点?但我不太确定我需要如何以这种方式处理它。 或者也许我遗漏了其他东西,因为使用 BinaryWriter 写入 "generalizationofwrittendata",然后使用 CryptoStream 似乎工作得很好。

更新#1:

因此,在收到回复后,我重新检查了所有代码,尤其是与 ICryptoTransform 相关的代码。 ICryptoTransform 绝对不是问题,这两种方法完全相同。

我注意到的另一件事是我无缘无故地使用了 "BinaryReader br2",所以我删除了它:

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

但不幸的是,这并没有解决问题,一些数据和写入文件的数据与原始数据不一样。

更新#2:

所以这是一个愚蠢的问题 - 我创建了 CreateEncryptor() 而不是 CreateDecryptor() 用于解密。

可能是我脸皮厚,你找fs合适的位置继续用同样的二进制文件不行吗reader?

我会试试这个,但设置加密密钥需要一些时间。

编辑:此外,您确定在解密时正确构建了 CryptoTransform 吗?

编辑: 当我使用以下代码时,您的代码按照您提供的方式工作:

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

其他数据读取为{0x12,0x34,0x56},h1到h3是我提供的值,decrypted.bin与plain.bin相同。

这表明您提供给解密器的密钥存在问题。

更新 1:

我修改了我的测试工具以使用 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);
    }

结果是一样的,它仍然像你最初发布的那样有效。

我正在让 Aes 创建一个密钥和我保存的初始化向量,您需要检查加密和解密都使用 完全 相同的值调用您的 Aes 生成器。另外,请确保您使用 Aes.CreateEncyptor() 进行加密并使用 Aes.CreateDecryptor() 进行解密。

问题确实出在密钥上,所以我的建议是在创建加密器并转储 key/iv 后中断,然后在创建解密器并检查它们是否为字节后执行相同操作字节相同。