为什么我的解密方法抛出“要解密的数据长度无效”加密异常

2024-04-23

这是一个非常常见的异常,但显然我找到的解决方案都没有解决我的问题。

我有一个加密和一个解密方法;我加密一个字符串并将其写入文件,然后从文件中读取该字符串并解密(理论上)。事实上,我得到了一个

加密异常:要解密的数据长度无效

在该过程的解密方面。

这是Main()完成所有工作的方法:

public static void Main()
{
    var filename = "test.encrypted";
    var plainText = "Lorem Ipsum is simply dummy text of the printing and typesetting industry.";

    string password = "A better password than this";
    string salt = "Sodium Chloride";

    var padding = PaddingMode.Zeros; // I have tried every padding mode to no avail

    var encrypted = Encrypt<AesManaged>(plainText, password, salt, padding);
    File.WriteAllBytes(filename, encrypted);

    var fileBytes = File.ReadAllBytes(filename);
    var decrypted = Decrypt<AesManaged>(fileBytes, password, salt, padding);

    Console.ReadLine();
}

加密端:

static byte[] Encrypt<T>(string plainText, string password, string salt, PaddingMode padding)
    where T : SymmetricAlgorithm, new()
{
    var saltBytes = Encoding.Unicode.GetBytes(salt);
    var derivedBytes = new Rfc2898DeriveBytes(password, saltBytes);

    using (var algorithm = new T())
    {
        algorithm.Padding = padding;

        var key = derivedBytes.GetBytes(algorithm.KeySize >> 3);
        byte[] iv = new byte[algorithm.BlockSize >> 3];
        RNGCryptoServiceProvider.Create().GetNonZeroBytes(iv);

        var transform = algorithm.CreateEncryptor(key, iv);


        using (MemoryStream buffer = new MemoryStream())
        using (CryptoStream cryptoStream = new CryptoStream(buffer, transform, CryptoStreamMode.Write))
        using (StreamWriter writer = new StreamWriter(cryptoStream, Encoding.Unicode))
        {
            writer.Write(plainText);
            writer.Flush();  
             
            // cryptoStream.FlushFinalBlock() is called after writer.Flush()
            // or as part of the Dispose().
            // Calling it here causes a "you can't call that twice" exception.

            // prepend IV to the data
            return iv.Concat(buffer.ToArray()).ToArray();
        }
    }
}

...还有另一面


static byte[] Decrypt<T>(byte[] encryptedData, string password, string salt, PaddingMode padding)
      where T : SymmetricAlgorithm, new()
{
    var saltBytes = Encoding.Unicode.GetBytes(salt);

    var derivedBytes = new Rfc2898DeriveBytes(password, saltBytes);

    using (var algorithm = new T())
    {
        algorithm.Padding = padding;

        var key = derivedBytes.GetBytes(algorithm.KeySize >> 3);

        //IV is at the beginning of the data
        var iv = encryptedData.Take(algorithm.BlockSize >> 3).ToArray();
        encryptedData = encryptedData.Skip(iv.Length).ToArray();

        var transform = algorithm.CreateDecryptor(key, iv);

        using (MemoryStream buffer = new MemoryStream())
        using (CryptoStream stream = new CryptoStream(buffer, transform, CryptoStreamMode.Write))
        using (StreamWriter writer = new StreamWriter(stream, Encoding.Unicode))
        {
            writer.Write(encryptedData);
            writer.Flush();
            return buffer.ToArray();
        }
    }
}

我认为最简单的方法是遵循 MS 模式,例如here https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-6.0:

  • 对于加密:

    using (MemoryStream buffer = new MemoryStream())
    using (CryptoStream cryptoStream = new CryptoStream(buffer, transform, CryptoStreamMode.Write))
    {
        using (StreamWriter writer = new StreamWriter(cryptoStream, Encoding.Unicode))
        {
            writer.Write(plainText);
        }
        return iv.Concat(buffer.ToArray()).ToArray();
    }
    
  • 以及解密:

    using (MemoryStream buffer = new MemoryStream(encryptedData))
    using (CryptoStream stream = new CryptoStream(buffer, transform, CryptoStreamMode.Read))
    using (StreamReader reader = new StreamReader(stream, Encoding.Unicode))
    {
        return Encoding.Unicode.GetBytes(reader.ReadToEnd());
    }
    

通过这个构造的调用Close(), FlushFinalBlock()等是通过隐式触发的Dispose()以正确的顺序调用(有关详细信息,另请参阅here https://stackoverflow.com/q/68202243).

旧的实现则不然,导致加解密不完整。此外,密文在解密过程中被 Unicode(更准确地说是 UTF-16LE)编码损坏(这是发布异常的原因)。


另请记住以下几点:

  • 如果您稍后对解密的数据进行 Unicode 解码(这很可能),则返回字符串而不是返回字符串会更有效byte[] in Decrypt() (i.e. return reader.ReadToEnd()).
  • 至于填充,应使用 PKCS7 填充而不是零填充,因为 PKCS#7 填充更可靠(相对于代码中的注释)。
  • Using StreamReader#.ReadToEnd()防止相关问题.NET 6 中的重大变化 https://stackoverflow.com/a/69911546/9014097.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么我的解密方法抛出“要解密的数据长度无效”加密异常 的相关文章

随机推荐

  • 字符串前后的通配符 - MySql、PSQL

    我需要执行Contains列中的操作 对于包含操作 我们需要在单词前后使用通配符 例如 个性化 查询 gt like sonal 因为这种类型的查询不能使用索引 有什么办法可以提高搜索速度 注意 我使用MySql InnoDB 和PSQL
  • Backbone.js / Marionette.js 中的路由 - 无主题标签、路由列表和子路由器

    我对 Backbone js Marionette js 中的路由有三个问题 1 如何获取我的应用程序路由器已注册的所有路由的列表 例如对于 Express js 在 Node js 中 它将是app routes 我尝试对 Backbon
  • Linux c++:api 与 /proc 文件?

    我正在开发一个应用程序来收集和发送各种系统信息 分区空间 可用空间 笔记本电脑电池信息等 我没有成功地以直接 c api 的形式获取这些信息 尽管它都可以通过 proc 或类似 中的文件获得 所以 我想知道在我的 C 应用程序中读取 解析这
  • 如何获取 bash 中的第 n 个位置参数?

    如何获得nBash 中的第一个位置参数 其中n是变量吗 使用 Bash 的间接功能 bin bash n 3 echo n 运行该文件 ind apple banana cantaloupe dates 生产 cantaloupe Edit
  • Minecraft Forge 1.8 - 加载块纹理

    我刚刚开始学习 Java 同时修改 Minecraft 我看过有关使用 Minecraft Forge API 将块添加到游戏中的教程 但我遇到了问题 不再有 setBlockTextureName 方法 所以我不知道该怎么办 我在游戏中添
  • css 中 & 的作用是什么

    我正在查看一些遗留代码 并在 css 文件中发现如下内容 user modal width auto height auto modal fade in margin top 0 margin left 0 top 83px 这里 的目的是
  • 向后滑动 - InteractivePopGestureRecognizer 不起作用

    我有像这张照片这样的屏幕 HomeViewController 将推送到 maintabbar 并且选项卡栏项目将推送到detailScreen 为什么向后滑动不起作用 我认为这是IOS默认的 请帮我 p s 如果我在 cocoapods
  • 奇怪的 bash 脚本行为 - 生成的命令在复制粘贴时有效,但在脚本中无效

    出于安全原因 我编写了一个简短的 bash 脚本来包装 ansible playbook 命令 这并不复杂 而且大部分脚本在这里都是无关紧要的 最后 我将脚本参数生成的变量中的 ansible 命令放在一起 如下所示 ansible pla
  • Spring:文件上传RESTFUL Web服务

    我正在使用 Spring 4 0 为 RESTFUL Web 服务创建 POC 如果我们只传递字符串或任何其他基本数据类型 它就可以正常工作 RequestMapping value upload file method RequestMa
  • 适用于 MYSQL 的 Logstash Jdbc 输入插件

    我在 Windows 中使用 Logstash 我无法安装输入 jdbc 插件 因此我手动下载了 zip 文件 并将插件中的logstash 文件夹放入我的logstash 1 5 2 文件夹中 文件夹结构 D elastic search
  • Matplotlibight_layout——删除多余的白色/空白区域

    我想尽量减少人物周围的空白 但不确定如何 a 为我的图像周围的 savefig 命令精确指定一个边界框 并且 b 为什么紧密布局命令在我的工作示例中不起作用 In my current example I set up an axis en
  • 使 ASP.NET MVC 应用程序为 Web Farm 做好准备

    使 ASP NET MVC 应用程序 Web 场做好准备的最有效方法是什么 最重要的是共享当前用户的信息 上下文 和 不太重要 缓存的对象 例如查找项目 州 街道类型 县等 我听说过 读过 MemCache 但还没有看到关于如何实现和测试它
  • PHP 将整数转换为 hh:mm:ss

    我有一个 hh mm ss 格式的字符串 我将其转换为表示总秒数的整数 例如 01 43 03 01 3600 43 60 03 1 上面的示例生成整数值 6183 使用该值执行一些逻辑后 我需要将整数转换回严格的 hh mm ss 格式
  • ActiveAdmin:按子对象计数过滤

    在严重依赖 ActiveAdmin 的 Ruby on Rails 应用程序中 我有一个赞助商模型 它与赞助商模型关联 一sponsor可以资助很多孩子 所以一个sponsor可以有很多sponsorships 我想做的是能够在赞助商索引页
  • 无法使用 RVM、Ruby 1.9.2 和 Rails 3 运行 RubyMine 调试器

    我已经设置了全新的 Ubuntu 安装并遵循本指南 http ryanbigg com 2010 12 ubuntu ruby rvm rails and you安装 RVM Ruby 1 9 2 和 Rails 3 然后我安装了RubyM
  • ADAL.js 和 MSAL.js 有什么区别?

    我正在尝试处理使用 Microsoft Graph 的应用程序的身份验证 这两个库有什么区别 JavaScript 的 Active Directory 身份验证库 ADAL js https github com AzureAD azur
  • java中如何读取xep文件数据

    有没有办法在 pdf 完全渲染之前获取总页数并输入我们提供 xml 文件 xslt 是页面布局的样式表 我们使用 RenderX 从 xslt 进行 pdf 转换 将其转换为 xsl fo 文件 从 xsl fo 转换为 xep 文件 从
  • Foreman/Puma 未使用开发环境中指定的端口

    我在 application yml 中将端口设置为 3000 figaro 管理环境变量 rails s使用端口 3000 但当我跑步时foreman start 根据 Heroku 的推荐 我得到以下输出 14 53 23 web 1
  • 错误:找不到函数“geom_sf”

    我目前在 Windows 上运行 R 版本 3 4 2 并拥有 ggplot2 通过 tidyverse 和 sf 包版本 3 4 2 我正在尝试使用 ggplot2 sf 套件来绘制空间数据 尝试运行 geom sf 时 我收到错误 co
  • 为什么我的解密方法抛出“要解密的数据长度无效”加密异常

    这是一个非常常见的异常 但显然我找到的解决方案都没有解决我的问题 我有一个加密和一个解密方法 我加密一个字符串并将其写入文件 然后从文件中读取该字符串并解密 理论上 事实上 我得到了一个 加密异常 要解密的数据长度无效 在该过程的解密方面