从公钥正确创建 RSACryptoServiceProvider

2023-11-21

我目前正在尝试创建一个RSACryptoServiceProvider仅来自解码的 PEM 文件的对象。经过几天的搜索,我确实设法找到了一个可行的解决方案,但它还不是一个可以投入生产的解决方案。

简而言之,为了创建一个RSACryptoServiceProvider要从构成 PEM 文件中公钥的字节中获取对象,我必须创建指定密钥大小的对象(具体而言,当前使用 SHA256 为 2048),然后导入RSAParameters对象与Exponent and Modulus放。我就是这样做的;

byte[] publicKeyBytes = Convert.FromBase64String(deserializedPublicKey.Replace("-----BEGIN PUBLIC KEY-----", "")
                                                                      .Replace("-----END PUBLIC KEY-----", ""));

// extract the modulus and exponent based on the key data
byte[] exponentData = new byte[3];
byte[] modulusData = new byte[256];
Array.Copy(publicKeyBytes, publicKeyBytes.Length - exponentData.Length, exponentData, 0, exponentData.Length);
Array.Copy(publicKeyBytes, 9, modulusData, 0, modulusData.Length);


// import the public key data (base RSA - works)
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(dwKeySize: 2048);
RSAParameters rsaParam = rsa.ExportParameters(false);
rsaParam.Modulus = modulusData;
rsaParam.Exponent = exponentData;
rsa.ImportParameters(rsaParam);

虽然这可行,但假设deserializedPublicKey正好是 270 字节,我需要的模数在位置 9 处找到,并且长度始终为 256 字节。

如何更改它以正确挑选给定一组公钥字节的模数和指数字节?我试图理解 ASN.1 标准,但没能从中找到我需要的东西 - 标准有点复杂。

任何帮助表示赞赏。


您无需导出现有参数,然后在其之上重新导入。这会迫使您的机器生成 RSA 密钥,然后将其丢弃。因此,为构造函数指定密钥大小并不重要(如果您不使用该密钥,它通常不会生成密钥)。

公钥文件是 DER 编码的 blob。

-----BEGIN PUBLIC KEY-----
MIGgMA0GCSqGSIb3DQEBAQUAA4GOADCBigKBggC8rLGlNJ17NaWArDs5mOsV6/kA
7LMpvx91cXoAshmcihjXkbWSt+xSvVry2w07Y18FlXU9/3unyYctv34yJt70SgfK
Vo0QF5ksK0G/5ew1cIJM8fSxWRn+1RP9pWIEryA0otCP8EwsyknRaPoD+i+jL8zT
SEwV8KLlRnx2/HYLVQkCAwEAAQ==
-----END PUBLIC KEY-----

如果你获取 PEM 盔甲内的内容,它是一个 Base64 编码的字节数组。

30 81 A0 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 
05 00 03 81 8E 00 30 81 8A 02 81 82 00 BC AC B1 
A5 34 9D 7B 35 A5 80 AC 3B 39 98 EB 15 EB F9 00 
EC B3 29 BF 1F 75 71 7A 00 B2 19 9C 8A 18 D7 91 
B5 92 B7 EC 52 BD 5A F2 DB 0D 3B 63 5F 05 95 75 
3D FF 7B A7 C9 87 2D BF 7E 32 26 DE F4 4A 07 CA 
56 8D 10 17 99 2C 2B 41 BF E5 EC 35 70 82 4C F1 
F4 B1 59 19 FE D5 13 FD A5 62 04 AF 20 34 A2 D0 
8F F0 4C 2C CA 49 D1 68 FA 03 FA 2F A3 2F CC D3 
48 4C 15 F0 A2 E5 46 7C 76 FC 76 0B 55 09 02 03 
01 00 01 

ITU-T X.690定义了如何读取根据基本编码规则(BER)、规范编码规则(CER,我从未见过明确使用的)和杰出编码规则(DER)编码的内容。在大多数情况下,CER 限制 BER,而 DER 限制 CER,使得 DER 最容易阅读。 (ITU-T X.680描述了抽象语法符号一 (ASN.1),这是 DER 的二进制编码的语法)

我们现在可以做一些解析:

30

这标识了带有 CONSTRUCTED 位设置 (0x20) 的 SEQUENCE (0x10),这意味着它包含其他 DER/标记值。 (SEQUENCE 始终在 DER 中构建)

81 A0

下一部分是长度。由于它具有高位设置(> 0x7F),因此第一个字节是“长度长度”值。它表示真实长度编码在接下来的 1 个字节中(lengthLength & 0x7F)。因此该SEQUENCE 的内容总共为160 字节。 (在这种情况下,“其余数据”,但序列可能包含在其他内容中)。那么我们来读一下内容:

30 0D

我们再次看到我们构建的序列(0x30),长度值为0x0D,所以我们有一个 13 字节的有效负载。

06 09 2A 86 48 86 F7 0D 01 01 01 05 00 

The 06是对象标识符,带有0x09字节有效负载。 OID 有一种稍微不直观的编码,但这相当于文本表示1.2.840.113549.1.1.1,即id-rsaEncryption (http://www.oid-info.com/get/1.2.840.113549.1.1.1).

这仍然给我们留下了两个字节(05 00)我们看到的是 NULL(具有 0 字节有效负载,因为它是 NULL)。

到目前为止我们已经

SEQUENCE
  SEQUENCE
    OID 1.2.840.113549.1.1.1
    NULL
  143 more bytes.

继续:

03 81 8E 00

The 03表示位串。 BIT STRING 被编码为 [tag] [length] [未使用的位数]。未使用的位基本上始终为零。所以这是一个位序列,0x8E字节长,并且全部被使用。

从技术上讲,我们应该到此为止,因为尚未设置 CONSTRUCTED。但由于我们碰巧知道该结构的格式,因此我们将该值视为已设置 CONSTRUCTED 位:

30 81 8A

这是我们的朋友的构造序列,0x8A有效负载字节,它方便地对应于“剩下的一切”。

02 81 82

02标识一个 INTEGER,并且这个有0x82有效负载字节:

00 BC AC B1 A5 34 9D 7B 35 A5 80 AC 3B 39 98 EB 
15 EB F9 00 EC B3 29 BF 1F 75 71 7A 00 B2 19 9C 
8A 18 D7 91 B5 92 B7 EC 52 BD 5A F2 DB 0D 3B 63 
5F 05 95 75 3D FF 7B A7 C9 87 2D BF 7E 32 26 DE 
F4 4A 07 CA 56 8D 10 17 99 2C 2B 41 BF E5 EC 35 
70 82 4C F1 F4 B1 59 19 FE D5 13 FD A5 62 04 AF 
20 34 A2 D0 8F F0 4C 2C CA 49 D1 68 FA 03 FA 2F 
A3 2F CC D3 48 4C 15 F0 A2 E5 46 7C 76 FC 76 0B 
55 09 

前导 0x00 将违反 DER,除非下一个字节设置了高位。这意味着 0x00 是为了防止符号位被设置,从而使其成为正数。

02 03 01 00 01

另一个 INTEGER,3 个字节,值01 00 01。我们就完成了。

SEQUENCE
  SEQUENCE
    OID 1.2.840.113549.1.1.1
    NULL
  BIT STRING
    SEQUENCE
      INTEGER 00 BC AC ... 0B 55 09
      INTEGER 01 00 01

收获https://www.rfc-editor.org/rfc/rfc5280我们看到这看起来很像SubjectPublicKeyInfo结构:

SubjectPublicKeyInfo  ::=  SEQUENCE  {
  algorithm            AlgorithmIdentifier,
  subjectPublicKey     BIT STRING  }

AlgorithmIdentifier  ::=  SEQUENCE  {
  algorithm               OBJECT IDENTIFIER,
  parameters              ANY DEFINED BY algorithm OPTIONAL  }
                            -- contains a value of the type
                            -- registered for use with the
                            -- algorithm object identifier value

当然,它不知道RSA公钥格式是什么。但 oid-info 网站告诉我们去看看RFC 2313,我们看到的地方

An RSA public key shall have ASN.1 type RSAPublicKey:

RSAPublicKey ::= SEQUENCE {
  modulus INTEGER, -- n
  publicExponent INTEGER -- e }

也就是说,我们读取的第一个 INTEGER 是模值,第二个是(公共)指数。

DER编码是big-endian,这也是RSAParameters编码,但是对于RSAParameters你需要删除前导0x00来自模数的值。

虽然这并不像给您提供代码那么容易,但根据这些信息为 RSA 密钥编写解析器应该相当简单。我建议你把它写成internal static RSAParameters ReadRsaPublicKey(...),然后你只需要做

RSAParameters rsaParameters = ReadRsaPublicKey(...);

using (RSA rsa = RSA.Create())
{
    rsa.ImportParameters(rsaParameters);
    // things you want to do with the key go here
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从公钥正确创建 RSACryptoServiceProvider 的相关文章

  • 在C语言中使用“void”

    我很困惑为什么我们需要通过void转换为 C 函数 int f void return 0 versus int f return 0 什么是正确的做法以及为什么 In C int f 是一种老式的声明 它说f需要固定但未指定数量和类型的参
  • 具有子列表属性映射问题的自动映射器

    我有以下型号 Models public class Dish Required public Int64 ID get set Required public string Name get set Required public str
  • 查找哪些页面不再与写入时复制共享

    假设我在 Linux 中有一个进程 我从中fork 另一个相同的过程 后forking 因为原始进程将开始写入内存 Linux写时复制机制将为进程提供与分叉进程使用的不同的唯一物理内存页 在执行的某个时刻 我如何知道原始进程的哪些页面已被写
  • 进程何时获得 SIGABRT(信号 6)?

    C 中进程获得 SIGABRT 的场景有哪些 该信号是否始终来自进程内部 或者该信号可以从一个进程发送到另一个进程吗 有没有办法识别哪个进程正在发送该信号 abort 向调用进程发送SIGABRT信号 就是这样abort 基本上有效 abo
  • ASP.NET MVC 中的经典 ASP (C#)

    我有一个应用程序想要 最终 转换为 ASP NET MVC 我想要进行全面的服务升级 到 ASP NET 但想要使用当前的 ASP 内容来运行当前的功能 这样我就可以在对新框架进行增量升级的同时升级小部分 该站点严重依赖于不太成熟的 VB6
  • 如何在 Android NDK 中创建新的 NativeWindow 而无需 Android 操作系统源代码?

    我想编译一个 Android OpenGL 控制台应用程序 您可以直接从控制台启动 Android x86 运行 或者从 Android x86 GUI 内的 Android 终端应用程序运行 这个帖子 如何在 Android NDK 中创
  • C++:重写已弃用的虚拟方法时出现弃用警告

    我有一个纯虚拟类 它有一个纯虚拟方法 应该是const 但不幸的是不是 该接口位于库中 并且该类由单独项目中的其他几个类继承 我正在尝试使用这个方法const不会破坏兼容性 至少在一段时间内 但我找不到在非常量方法重载时产生警告的方法 以下
  • 如何配置 WebService 返回 ArrayList 而不是 Array?

    我有一个在 jax ws 上实现的 java Web 服务 此 Web 服务返回用户的通用列表 它运行得很好 Stateless name AdminToolSessionEJB RemoteBinding jndiBinding Admi
  • 从多个类访问串行端口

    我正在尝试使用串行端口在 arduino 和 C 程序之间进行通信 我对 C 编程有点陌生 该程序有多种用户控制形式 每一个都需要访问串口来发送数据 我需要做的就是从每个类的主窗体中写入串行端口 我了解如何设置和写入串行端口 这是我的 Fo
  • 如何从 C# 控制器重定向到外部 url

    我使用 C 控制器作为网络服务 在其中我想将用户重定向到外部网址 我该怎么做 Tried System Web HttpContext Current Response Redirect 但没有成功 使用控制器的重定向 http msdn
  • Qt 创建布局并动态添加小部件到布局

    我正在尝试在 MainWindow 类中动态创建布局 我有四个框架 它们是用网格布局对象放置的 每个框架都包含一个自定义的 ClockWidget 我希望 ClockWidget 对象在调整主窗口大小时相应地调整大小 因此我需要将它们添加到
  • Azure 事件中心 - 按顺序接收事件

    我使用下面的代码从 Azure Event Hub 接收事件 https learn microsoft com en us azure event hubs event hubs dotnet framework getstarted s
  • C# 中条件编译符号的编译时检查(参见示例)?

    在 C C 中你可以这样做 define IN USE 1 define NOT IN USE 1 define USING system 1 system 1 IN USE 进而 define MY SYSTEM IN USE if US
  • 如何一步步遍历目录树?

    我发现了很多关于遍历目录树的示例 但我需要一些不同的东西 我需要一个带有某种方法的类 每次调用都会从目录返回一个文件 并逐渐遍历目录树 请问我该怎么做 我正在使用函数 FindFirstFile FindNextFile 和 FindClo
  • 在类的所有方法之前运行一个方法

    在 C 3 或 4 中可以做到这一点吗 也许有一些反思 class Magic RunBeforeAll public void BaseMethod runs BaseMethod before being executed public
  • 为什么拆箱枚举会产生奇怪的结果?

    考虑以下 Object box 5 int int int box int 5 int nullableInt box as int nullableInt 5 StringComparison enum StringComparison
  • 结构体指针的动态数组

    我必须使用以下代码块来完成学校作业 严格不进行任何修改 typedef struct char firstName char lastName int id float mark pStudentRecord pStudentRecord
  • 使用 CSharpCodeProvider 类编译 C# 7.3 的 C# 编译器版本是什么?

    我想使用 Microsoft CSharp CSharpCodeProvider 类来编译 C 7 3 代码 编译器版本在 IDictionary 中指定 在创建新的 CSharpCodeProvider 时将其作为输入 例如 Compil
  • Googletest:如何异步运行测试?

    考虑到一个包含数千个测试的大型项目 其中一些测试需要几分钟才能完成 如果按顺序执行 整套测试需要一个多小时才能完成 通过并行执行测试可以减少测试时间 据我所知 没有办法直接从 googletest mock 做到这一点 就像 async选项
  • 是否可以在 C# 中强制接口实现为虚拟?

    我今天遇到了一个问题 试图重写尚未声明为虚拟的接口方法的实现 在这种情况下 我无法更改接口或基本实现 而必须尝试其他方法 但我想知道是否有一种方法可以强制类使用虚拟方法实现接口 Example interface IBuilder

随机推荐

  • Scala 中数组的按元素求和

    如何计算数组的逐元素总和 val a new Array Int 5 val b new Array Int 5 assign values desired output Array gt a 0 b 0 a 1 b 1 a 2 b 2 a
  • Java中有互斥体吗?

    java中有互斥对象或者创建互斥对象的方法吗 我这样问是因为用 1 个许可证初始化的信号量对象对我没有帮助 想想这个案例 try semaphore acquire do stuff semaphore release catch Exce
  • 可以在Python中声明一个抽象异常吗?

    我想在 Python 中声明用户定义异常的层次结构 但是 我想要我的顶级用户定义类 TransactionException 变得抽象 也就是说 我打算TransactionException指定其子类需要定义的方法 然而 Transact
  • 什么时候应该使用 PHP mysqli_real_escape_string() 函数? [复制]

    这个问题在这里已经有答案了 我知道mysqli real escape string可以使用函数来防止SQL注入 但是 mysql real escape string 不会保护您免受某些注入 我的问题是我什么时候应该使用 mysqli r
  • 多态性和 SwiftUI

    给出以下示例 class ProfileTab Identifiable let id UUID let name String init name String self name name class ProfileQuoteTab P
  • 如何设置静态 UITableView 作为 UIView 的子视图?

    当我与一个TableViewController我可以在故事板中设置所有内容 自从我使用静态单元格代替动态属性对于我的表视图 我发现这种方法更方便且更容易实现 我连接新的 UITableView 类并简单地删除所有委托方法 工作起来就像一个
  • 将图块的 xyz 坐标转换为经度/纬度

    我想使用 openlayers 制作地图 但以独特的方式将其居中 例如 我的 z x y 坐标为 12 2045 1362 如何将其转换为经度 纬度 这与此完全相反 如何通过点击Leaflet地图获取tile的X Y Z坐标 我很难理解上述
  • 如何在 Clojure 中评估一系列不纯函数?

    如何评估 Clojure 中的 不纯 函数列表 例如 println 1 println 2 println 3 预期输出是 1 2 3 有没有一种方法可以在不使用宏的情况下实现这一目标 就像是 map evaluate fns seq m
  • JavaScript中如何检查字符串是否包含子字符串?

    这个问题的答案是社区努力 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 通常我会期望String contains 方法 但好像没有 检查此问题的合理方法是什么 推出 ECMAScript 6String prototype inc
  • PerRequestLifetimeManager 只能在 HTTP 请求的上下文中使用

    我有一个 MVC 应用程序 它使用 Unity 作为其 IoC 容器 并使用以下方式在我的应用程序中定义了多个服务 PerRequestLifetimeManager container RegisterType
  • 在 pycharm 中创建项目结构的正确方法是什么?

    我是 python 新手 不知道如何以正确的方式组织项目结构 因此所有自动导入都可以在 pycharm 中工作 这就是我目前的结构 在 PublisherSubscriberTest pycharm 生成此导入 from Rabbit Ra
  • 从库中查找 argc 和 argv

    我如何找到一个程序argc and argv来自共享对象 我正在用 C 编写一个库 将通过以下方式加载LD PRELOAD 我可以通过两种不同的方式找到堆栈 Read rsp通过内联 asm call Read proc
  • 为什么java rmi一直连接到127.0.1.1。当ip是192.168.X.X时?

    我有一个 java rmi 应用程序 我只是这样做 Client Registry registry LocateRegistry getRegistry localhost costApi CostApi registry lookup
  • 如果已安装,则无法重新运行 Java JPackage 安装程序,第二次只是退出而不发出警告

    无法重新运行JPackage安装程序如果已经安装 则第二次即可似乎退出没有警告 这在 Windows 上是正确的行为吗 你可能会问我为什么要这么做 就我而言 我正在尝试为我的 Java 应用程序构建 JPackage 安装程序 因此我正在构
  • 如何在 C# 中自动递增数字?

    我正在使用 C 2008 Windows 窗体应用程序 我的项目中有一个TextBox控制 因为我想为样本 s00 自动生成数字 接下来当我再次返回表单时 它应该像 s01 s02 s03 这样递增 请帮我 很容易 保留一个变量来保留当前数
  • ASP.NET MVC 中的脚本和 CSS 注册助手?

    我尝试使用 ASP NET MVC 一段时间 然后遇到一个问题 我不想将所有 js 和 css 包含在母版页中 但是如何从我的特定视图将其注册到母版页的头部 默认母版页模板包括用于头部的内容占位符 如果没有 您可以轻松添加一个
  • 通用方法 - 无法将类型“string”隐式转换为 T

    可能是一个简单的问题 我有一个界面 public interface ISanitizer T Sanitize
  • Jenkins - 将构建推广到不同的环境

    我希望获得一些关于通过其环境促进构建的最佳方式的指导 我们有 3 个环境 DEV STAGING PROD DEV Jenkins 构建在持续集成设置中运行 当代码签入到 subversion 时 Jenkins 将运行新的构建 清理 编译
  • 实例化一个特质意味着什么?

    我是 Scala 新手 在 O Reilly 的 Scala 编程 一书中 作者展示了一些实例化特征的代码 鉴于特征在某种程度上类似于 Java 中的接口 尽管我知道特征是作为字节代码中的类实现的 实例化特征意味着什么 以及适当的用例 设计
  • 从公钥正确创建 RSACryptoServiceProvider

    我目前正在尝试创建一个RSACryptoServiceProvider仅来自解码的 PEM 文件的对象 经过几天的搜索 我确实设法找到了一个可行的解决方案 但它还不是一个可以投入生产的解决方案 简而言之 为了创建一个RSACryptoSer