对大文件使用 Rijndael 加密

2024-03-21

我面临的情况是,我需要安全地加密/解密 n 长度的文件,最好使用 Rijndael,但绝对是 256 位加密。

我以前玩过加密,并且非常高兴地加密/解密了字符串和字节数组。 但是,因为我不知道文件的大小(并且有问题的文件可能非常大(〜2.5gb)是非常可行的,所以我不能将它们加载到字节数组中并在其中进行编码/解密像我以前一样的单一界限。

因此,在 Google 上阅读了一些内容后,我知道答案是分块加密和解密文件,因此我生成了以下代码:

private static void Enc(string decryptedFileName, string encryptedFileName)
{            
   FileStream fsOutput = File.OpenWrite(encryptedFileName);
   FileStream fsInput = File.OpenRead(decryptedFileName);

   byte[] IVBytes = Encoding.ASCII.GetBytes("1234567890123456");

   fsOutput.Write(BitConverter.GetBytes(fsInput.Length), 0, 8);
   fsOutput.Write(IVBytes, 0, 16);

   RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC};
   ICryptoTransform encryptor = symmetricKey.CreateEncryptor(passwordDB.GetBytes(256 / 8), IVBytes);
   CryptoStream cryptoStream = new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write);

   for (long i = 0; i < fsInput.Length; i += chunkSize)
   {
      byte[] chunkData = new byte[chunkSize];
      fsInput.Read(chunkData, 0, chunkSize);
      cryptoStream.Write(chunkData, 0, chunkData.Length);
   }
   cryptoStream.Close();
   fsInput.Close();
   fsInput.Dispose();
   cryptoStream.Dispose();
}

private static void Dec(string encryptedFileName, string decryptedFileName)
{
    FileStream fsInput = File.OpenRead(encryptedFileName);
    FileStream fsOutput = File.OpenWrite(decryptedFileName);

    byte[] buffer = new byte[8];
    fsInput.Read(buffer, 0, 8);

    long fileLength = BitConverter.ToInt64(buffer, 0);

    byte[] IVBytes = new byte[16];
    fsInput.Read(IVBytes, 0, 16);

    RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC };
    ICryptoTransform decryptor = symmetricKey.CreateDecryptor(passwordDB.GetBytes(256 / 8), IVBytes);
    CryptoStream cryptoStream = new CryptoStream(fsOutput,decryptor,CryptoStreamMode.Write);

    for (long i = 0; i < fsInput.Length; i += chunkSize)
    {
        byte[] chunkData = new byte[chunkSize];
        fsInput.Read(chunkData, 0, chunkSize);
        cryptoStream.Write(chunkData, 0, chunkData.Length);
    }
    cryptoStream.Close();
    cryptoStream.Dispose();
    fsInput.Close();
    fsInput.Dispose();                      
} 

这一切对我来说“看起来”都不错,但可悲的是,看起来似乎是骗人的!

加密工作没有错误,但在解密过程中,“cryptoStream.Close()”方法抛出以下异常:

System.Security.Cryptography.CryptographicException 未处理消息=“填充是 无效且无法删除。”
来源=“mscorlib”堆栈跟踪: 在 System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] 输入缓冲区,Int32 输入偏移,Int32 输入计数,字节[]和输出缓冲区, Int32 输出偏移、PaddingMode paddingMode,布尔值 fLast) 在 System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] 输入缓冲区,Int32 输入偏移,Int32 输入计数) 在 System.Security.Cryptography.CryptoStream.FlushFinalBlock() 在 System.Security.Cryptography.CryptoStream.Dispose(布尔值 处置) 在 System.IO.Stream.Close()

未加密的文件大小似乎与预期的文件大小不匹配(范围从大约 8 个字节到大约 60 个字节)

我通过更改 RijndaelManaged 对象创建行以包含填充类型来“修复”该异常,如下所示:

RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.None };

但文件大小仍然不匹配,并且可以预见的是,新近未加密的文件是胡说八道!

我承认我现在已经超出了加密/解密的舒适区,这可能是一个菜鸟错误 - 但我无法发现它!

任何有关解决此问题的帮助将不胜感激!


问题是我正在使用:

passwordDB.GetBytes(256 / 8)

在加密和解密方法中的 RijndaelManaged 对象的构造函数中,并且在尝试解密之前我没有重新初始化 passwordDB 对象。

解决方案是简单地将 passwordDB 对象的构造包含在 Enc 和 Dec 方法的第一行中,如下所示:

        private static void Enc(string decryptedFileName, string encryptedFileName)
        {
            PasswordDeriveBytes passwordDB = new PasswordDeriveBytes("ThisIsMyPassword", Encoding.ASCII.GetBytes("thisIsMysalt!"), "MD5", 2);
            byte[] passwordBytes = passwordDB.GetBytes(128 / 8);

            using (FileStream fsOutput = File.OpenWrite(encryptedFileName))
            {
                using(FileStream fsInput = File.OpenRead(decryptedFileName))
                {
                    byte[] IVBytes = Encoding.ASCII.GetBytes("1234567890123456");

                    fsOutput.Write(BitConverter.GetBytes(fsInput.Length), 0, 8);
                    fsOutput.Write(IVBytes, 0, 16);

                    RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.ANSIX923};
                    ICryptoTransform encryptor = symmetricKey.CreateEncryptor(passwordBytes, IVBytes);                   

                    using (CryptoStream cryptoStream = new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write))
                    {
                        for (long i = 0; i < fsInput.Length; i += chunkSize)
                        {
                            byte[] chunkData = new byte[chunkSize];
                            int bytesRead = 0;
                            while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0)
                            {
                                if (bytesRead != 16)
                                {
                                    for (int x = bytesRead - 1; x < chunkSize; x++)
                                    {
                                        chunkData[x] = 0;
                                    }
                                }
                                cryptoStream.Write(chunkData, 0, chunkSize);
                            }
                        }
                        cryptoStream.FlushFinalBlock();
                    }
                }
            }            
        }

        private static void Dec(string encryptedFileName, string decryptedFileName)
        {
            PasswordDeriveBytes passwordDB = new PasswordDeriveBytes("ThisIsMyPassword", Encoding.ASCII.GetBytes("thisIsMysalt!"), "MD5", 2);
            byte[] passwordBytes = passwordDB.GetBytes(128 / 8);

            using (FileStream fsInput = File.OpenRead(encryptedFileName))
            {
                using (FileStream fsOutput = File.OpenWrite(decryptedFileName))
                {
                    byte[] buffer = new byte[8];
                    fsInput.Read(buffer, 0, 8);

                    long fileLength = BitConverter.ToInt64(buffer, 0);

                    byte[] IVBytes = new byte[16];
                    fsInput.Read(IVBytes, 0, 16);


                    RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.ANSIX923};
                    ICryptoTransform decryptor = symmetricKey.CreateDecryptor(passwordBytes, IVBytes);

                    using (CryptoStream cryptoStream = new CryptoStream(fsOutput, decryptor, CryptoStreamMode.Write))
                    {
                        for (long i = 0; i < fsInput.Length; i += chunkSize)
                        {
                            byte[] chunkData = new byte[chunkSize];
                            int bytesRead = 0;
                            while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0)
                            {
                                cryptoStream.Write(chunkData, 0, bytesRead);
                            }
                        }
                    }
                }
            }
        }

知道这一定是小学生的错误:P

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对大文件使用 Rijndael 加密 的相关文章

随机推荐

  • 如何使用 java 更改 Nimbus 外观和感觉的背景颜色

    在 Java Swing 应用程序中 我正在尝试 nimbus 的外观和感觉 它在 JdesktopPane 控件中看起来非常好 但我希望我的所有桌面窗格具有不同的颜色 但主题很好 有什么方法可以改变 Nimbus 外观和感觉的背景颜色吗
  • PHP中如何分割汉字?

    我需要一些关于如何在 PHP 中拆分与英文单词和数字混合的汉字的帮助 例如 如果我读到 FrontPage 2000中文版應用大全 我希望得到 FrontPage 2000 中 文 版 應 用 大 全 or FrontPage 2 0 0
  • Android Studio 中 gitIgnore 文件放在哪里?

    我正在开发一个应用程序 我必须将该项目带到 GitHub 现在 我必须制作 gitIgnore 文件 我知道该文件用于忽略我的项目中的某些指定文件 我使用了 gitIgnore io 服务并收到了生成的文件 这是我的 gitIgnore 文
  • 宅基地安装

    我不知道我在哪里犯了错误 我的命令vagrant up回复以下几行 vagrant up Check your Homestead yaml file the path to your private key does not exist
  • Rails 和 Mutli Nesting 中的祖先宝石

    我正在使用 Rails 中的祖先 gem 来嵌套一些注释 我想要的是让您能够获取所有注释 然后将它们全部嵌套 当我输入时 我如何得到以下信息 comments post comments arrange serializable进入我的评论
  • 仅在Gitlab CI中测试失败,本地成功

    我刚刚开始使用 Gitlab CI 使用 docker 执行器 在面对并解决了一些初学者的问题之后 我现在面临着一个非常奇怪的问题 我所有的单元测试都在本地成功 但是当我使用 CI 运行它们时 其中一些测试失败了 一个例子 2018 12
  • 如何等待鼠标点击

    class GameFrameClass extends javax swing JFrame public void MyFunc UserButton setText Str UserButton addActionListener n
  • 无法访问通过 Visual Studio 创建的数据库?

    我已经创建了一个数据库电子邮件数据库 它存储在 C Program Files Microsoft SQL Server MSSQL10 MSSQLSERVER MSSQL DATA 在 Visual Studio 中 我使用Server
  • 实现多个接口是否违反单一职责原则?

    From 维基百科 http en wikipedia org wiki Single responsibility principle 单一责任原则规定每个类都应该有一个 单一责任 并且该责任应该完全由 由类封装 这是否意味着实现多个接口
  • Mongoid has_and_belongs_to_many 关联

    我试图让 mongoid 来保存关联 但我只能让一侧工作 如果我有以下测试 test should add a user as a follower when a user follows the group do cali group f
  • 没有“isPresent()”检查的“Optional.get()”

    我有以下 Java 搜索代码 return getTableViewController getMe getColumns stream filter gt Database equalsColumnName getId columnId
  • ActionController::Live 是否可以检查连接是否仍然有效?

    我正在尝试使用 Rails 4 的实时流媒体来实现文本 事件流 它工作得很好 我遇到的唯一麻烦是我无法在不发送任何消息的情况下检查连接是否有效 我想到的唯一解决方案是使用循环刻度生成器创建支持通道 以便某些后台任务会定期向那里发送消息 但看
  • 调用构造函数重新初始化对象

    是否可以使用类的构造函数重新初始化类的对象 有点 给定 A 类 A a a A 最后一条语句不是初始化 而是赋值 但它可能会执行您想要的操作
  • 如何在jboss中生成resteasy的wadl文件

    我想为我的项目生成一个 wadl 文件 该文件使用resteasy Jboss 6 4 Maven 有很多关于球衣的例子 但不是关于resteasy的 有人用它来resteasy吗 Resteasy 从 3 0 14 Final 开始支持
  • 对 Cassandra 术语感到困惑(行与分区)

    我希望有人能够消除我对 Cassandra 中的行和分区之间的区别的困惑 我认为一行将是一组列 就像在 SQL 数据库中 如架构中指定的那样 按分区键跨节点分布 并按每个分区内的集群键排序 但后来我遇到了这个教程 https academy
  • 我应该如何处理非常非常长的 URL?

    我想知道这是否是一个错误 但现在我对所有搜索 URL 都使用 GET 原因是 通过 GET Url 用户可以简单地复制地址栏上的链接并轻松共享或保存 例如 Google 似乎也使用 GET Url 表单 由于它是一个带有过滤器 排序器等的搜
  • 在nodebox opengl中向图形的边缘添加标签

    我正在尝试向图表中的每个边添加标签 如下所示 基本上上面的每个边缘都有标签在中心 当我向每个图表添加边时 我尝试添加标签 就像这样 对于图表g g add edge label edge distance 经过一番研究 我发现这样的标签是可
  • 将值分配给特定的 data.table 列和行

    仍然理解这个伟大的包 有人可以解释一下这个错误的原因吗 谢谢 library data table DT lt data table id LETTERS var1 rnorm 26 var2 rnorm 26 gt DT 2 list v
  • 如何在heroku上的两个不同应用程序之间共享worker?

    我有两个独立的应用程序在heroku上运行并指向同一个数据库 第一个负责user interface第二个为admin interface 我在用sidekiq with redis对于后台作业处理 我添加了一个工作人员 并且可以通过设置指
  • 对大文件使用 Rijndael 加密

    我面临的情况是 我需要安全地加密 解密 n 长度的文件 最好使用 Rijndael 但绝对是 256 位加密 我以前玩过加密 并且非常高兴地加密 解密了字符串和字节数组 但是 因为我不知道文件的大小 并且有问题的文件可能非常大 2 5gb