C# 中的数字签名,无需使用 BouncyCastle

2024-04-02

不使用第 3 方 BouncyCastle 库,有没有办法读取自定义私钥并签署消息? (sha256哈希+使用私钥加密)


从技术上来说,是的。根据您拥有的密钥类型,答案会变得更加棘手。

编辑(2019 年 10 月):.NET Core 3.0 以 DER 编码(与 PEM 编码)形式内置支持所有这些格式。我在每个文件格式的子标题后添加 .NET Core 3.0+ 答案。

PKCS#8 PrivateKeyInfo(PEM“开始私钥”)

如果您有这种类型的文件,并且您使用的是 .NET 4.6 或更高版本,那么可以。您需要具有 DER 编码(与 PEM 编码)数据 blob(如果是 PEM,请参见下文)。

using (CngKey key = CngKey.Import(blob, CngKeyBlobFormat.Pkcs8PrivateBlob))
using (RSA rsa = new RSACng(key))
{
    return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}

RSA 需要 4.6,ECDSA 需要 4.6.1,DSA 需要 4.6.2。

.NET Core 3.0+ PKCS#8 私钥信息

The ImportPkcs8PrivateKey方法声明于AsymmetricAlgorithm,以及所有不对称内置类型(RSA, DSA, ECDsa, ECDiffieHellman)支持。

using (RSA rsa = RSA.Create())
{
    rsa.ImportPkcs8PrivateKey(blob, out _);
    return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}

PKCS#8 EncryptedPrivateKeyInfo(PEM“开始加密的私钥”)

恭喜,您的私钥传输能力很强。遗憾的是,如果您想实际处理它,则需要编写最大数量的代码。你不想处理它。你真的真的想要

  • 为密钥创建证书
  • 将证书和密钥放入 PFX 文件中
  • 将 PFX 加载到 X509Certificate2
  • 使用 cert.GetRSAPrivateKey()、cert.GetDSAPrivateKey() 或 cert.GetECDsaPrivateKey()(根据需要)

See pem 证书中的私钥是如何加密的? https://stackoverflow.com/q/43674870/6535399,然后继续下一节,了解艰难之路上的入门知识。不过,你的工作比它所谈论的要多得多。您需要读取文件,了解加密方案和参数,解密 blob,然后使用 CNG 读取 PKCS#8,或者继续深入兔子洞并享受您的文件解析器。

.NET Core 3.0+ PKCS#8 加密的PrivateKeyInfo

The ImportEncryptedPkcs8PrivateKey方法声明于AsymmetricAlgorithm,以及所有不对称内置类型(RSA, DSA, ECDsa, ECDiffieHellman)支持。

using (RSA rsa = RSA.Create())
{
    rsa.ImportEncryptedPkcs8PrivateKey(password, blob, out _);
    return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}

PKCS#1 RSAPrivateKey(PEM“开始 RSA 私钥”)

不幸的是,你正处于“相对简单”和“相对困难”的交汇点,这被数学专业人士称为“留给读者的练习”。

强烈考虑使用 EncryptedPrivateKeyInfo 的 PFX 方法。或者,您可以在自定义代码中执行此操作。自定义代码?好吧,我们就这样做吧。此时您需要的参考文本是

  1. .
  • 这定义了 ASN.1 语言,它告诉您如何读取 RSAPrivateKey(等)对象结构定义。
  • 对于 RSAPrivateKey 这主要是可选的,因为它使用的 SEQUENCE 没有太多细微差别,而且 INTEGER 非常简单。
  • 本文档描述了 ASN.1 的 BER(和 CER)和 DER 编码规则。
  • 这些关键文件位于 DER 中。 (除非它们在 PEM 中,但我们很快就会解决这个问题)
  1. 适合您的对象类型的 RFC。
  • RSA私钥 https://www.rfc-editor.org/rfc/rfc3447#appendix-A.1.2(RFC 3447)
  • 加密私钥信息 https://www.rfc-editor.org/rfc/rfc5208#section-6(RFC 5208)
  • 私钥信息 https://www.rfc-editor.org/rfc/rfc5208#section-5(也是 RFC 5208)
  • 其他格式在其他 RFC 中。

好吧,我们继续吧。

  1. 如果文件是 PEM 编码的(“-----BEGIN RSA PRIVATE KEY-----”或“-----BEGIN PRIVATE KEY-----”等),则需要“un-PEM”它。
  • The PEM format is
    • (换行符或文件开头)
    • 5 个连字符、BEGIN、空格、类型标识符、5 个连字符、换行符
    • Base64 编码的有效负载(每 72 个文本字符后有换行符)
    • 换行符(除非您以换行符结尾,因为您是 72 个文本字符的倍数)
    • 5 个连字符,END,与之前相同的类型标识符,5 个连字符
  • 我们想要的部分是有效负载。通过 Convert.FromBase64String 运行它,现在我们有了 DER 编码的byte[]为关键对象。
  1. 使用类型定义和 ITU 文档,为您的密钥文件格式编写解析器。
  2. 解析密钥。
  3. 将解析后的密钥转换为 RSAParameters 对象(或 DSAParameters 或 ECParameters,视情况而定)
  4. 调用 RSA.Create() (等)
  5. 通过 ImportParameters 方法加载密钥。
  6. 很好,可以走了。

对于第4步,有一些事情需要注意。具体来说,ASN.1/DER INTEGER 组件有两条 RSAParameters 不喜欢的规则。

  • 所有前导 0x00 值均被删除。
  • 如果前导字节设置为高位 (>=0x80),但数字应该为正数,则插入 0x00。

.NET 希望这些值作为大端字节数组(与 DER 编码的字节顺序相同),具有以下关系:

  • 指数需要多大就多大,只要它不以 0x00 开头即可。
  • 模数需要多大就多大,只要它不以 0x00 开头即可。
  • D 的大小必须与模数相同(根据需要插入 0x00)
  • P 必须是模数 ((Modulus.Length + 1) / 2) 大小的“半舍入”,根据需要插入 0x00。
  • Q、DP、DQ 和 InverseQ 的长度必须与 P 相同。(根据需要插入 0x00)。

.NET Core 3.0+ PKCS#1 RSAPrivateKey

The ImportRSAPrivateKey方法声明于RSA,并且由于它解析数据并调用ImportParameters它适用于所有人RSA派生类型(假设它们已经支持参数导入)。

using (RSA rsa = RSA.Create())
{
    rsa.ImportRSAPrivateKey(blob, out _);
    return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}

其他一些格式

确定 RFC 为您的密钥格式定义的 ASN.1 结构,然后记住这一点并评估 RSAPrivateKey 部分。

DSAParameters 和 ECParameters 各自有自己的空间期望。

进一步阅读

其中一些包括并不总是优雅但经常运行的代码:

  • 将私钥/公钥从 X509 证书导出到 PEM https://stackoverflow.com/q/43928064/6535399
  • 如何在C#中解析(转换为RSA参数)X.509私钥? https://stackoverflow.com/q/44106066/6535399
  • 如何修复 DecodeRSAPrivateKey 的错误长度错误? https://stackoverflow.com/q/46968514/6535399
  • 如何使用 rsa 从 PEM 文件解密 https://stackoverflow.com/q/46948083/6535399
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 中的数字签名,无需使用 BouncyCastle 的相关文章

  • ASP MVC4 - 通过视图模型传递列表以查看

    我有一个模型人物 其中包括出生日期等字段 我想将所有人的列表以及每个人的计算年龄传递给视图 因此 视图模型 public class vm PersonList public Person Person get set public int
  • C++ 最大非负整数

    以下内容是否会在所有平台 int 大小等上按预期工作 或者有更容易接受的方法吗 我做了以下的事情 define MAX NON NEGATIVE INT int unsigned int 1 2 我不会通过解释它在做什么来侮辱你的智商 编辑
  • __libc_start_main 发生了什么?

    我真的很想理解从高级代码到可执行文件的步骤 但是遇到了一些困难 我写了一个空的int main C 文件并尝试通过以下方式破译反汇编objdump d 这是发生的事情 in start 设置对齐方式 将参数压入堆栈 调用 libc star
  • 我可以在 WinRT / Windows 8 Store 应用程序中绑定 DynamicObject

    我有以下代码 public class MyClass DynamicObject INotifyPropertyChanged Dictionary
  • 仅使用 1 行 C++ 初始化 2d 向量

    我需要能够初始化一个 2D 向量 int同一条线我在其中创建它 更具体地说 我必须创建一个3x2大小 2D 向量并将其所有值设置为 0 仅使用1行代码 有没有一种方法可以在不使用 for 循环和几行代码的情况下完成此操作 尝试这个 std
  • clang-tidy - 忽略第三方标头代码

    我正在为我的项目使用 CMake 并且我想向项目引入 clang tidy 检查 我用于此目的CMAKE CXX CLANG TIDY and clang tidy用于检查设置的文件 我想在 CI 中使用警告作为错误来可靠地检查提交是否引入
  • CRTP 能否完全取代小型设计的虚拟功能?

    Is CRTP http en wikipedia org wiki Curiously recurring template pattern有足够的能力智胜virtual功能齐全 我认为 CRTP 的唯一缺点是为每个重复模式生成大量代码
  • 从文本文件中读取所有内容 - C

    我正在尝试从文本文件中读取所有内容 这是我写的代码 include
  • C - '=' 标记之前的预期表达式...在没有 '=' 的行上

    我疯狂地试图找出这个与现实 我的代码没有明显联系的错误消息 我一直在这里搜索并得出一个结论 你会讨厌 typedef 隐藏的指针 抱歉 这超出了我的控制范围 教授以这种方式提供了代码 我正在编辑问题中指定的代码 我弹出完整节点以避免每个推送
  • 使用工作表作为数据源的 VSTO Excel 的简单示例

    我想我遇到了 最简单的答案是最难找到的答案 的情况 而且我还没有遇到过任何搜索能够以直接的方式给我这个答案 这是为了Excel 2010 and VS 2010在现有 VSTO C 项目中 我有一个 Excel 工作表 其中包含 4 列数据
  • 如何测试 PARTIAL 视图在 C# ASP .NET MVC 中呈现

    我有一个视图 它内部有部分视图渲染 div class partialViewDiv Html RenderPartial partial Model SomeModelProperty div 和一个返回此视图的控制器 public Ac
  • 使用正在运行的进程的共享内存收集核心转储

    核心转储仅收集进程空间 而不收集为进程间通信创建的共享内存 如何使核心转储也包含正在运行的进程的共享内存 设置核心文件过滤器 proc PID coredump filter per http man7 org linux man page
  • 策略模式的现实示例

    我一直在读关于OCP原理 http en wikipedia org wiki Open closed principle以及如何使用策略模式来实现这一目标 我打算尝试向几个人解释这一点 但我能想到的唯一例子是根据 订单 的状态使用不同的验
  • 在javascript中调用c#函数[重复]

    这个问题在这里已经有答案了 可能的重复 从 Javascript 调用 ASP NET 函数 https stackoverflow com questions 3713 call asp net function from javascr
  • 在 QtCreator 中查看数组内容

    调试时是否可以在 Qt Creator 中查看数组的内容 似乎检测到我的数组是一个数组而不是一个指针 此外 我可以点击一个箭头 就像展开一样 但之后什么也没有显示 当我试穿的时候std vector Qt Creator 设法按预期显示内容
  • 创建 .ICS 文件,添加到 Outlook

    我正在创建一个简单的应用程序 允许用户下载 ICS 文件 并将其导入到他们选择的日历应用程序 站点中 我对创建过程感到满意 但对在 Outlook 中打开它们有疑问 将使用C ASP NET进行开发 当我打开一个日历时 它会添加一个新日历
  • 使用 std::set 时重载运算符<

    这是我第一次使用 std set 容器 并且我对操作符 std less 遇到了问题 我声明该集合 std set
  • 从原始 URL 获取重定向 URL

    我的数据库中有一个表 其中包含一些网站的 URL 我必须打开这些 URL 并验证这些页面上的一些链接 问题是某些 URL 被重定向到其他 URL 对于这样的 URL 我的逻辑是失败的 有什么方法可以传递原始 URL 字符串并获取重定向的 U
  • 如何检查多个变量是否等于同一值?

    如何比较多个项目 例如 我希望检查所有变量 A B 和 C 是否都等于字符 X 或所有三个变量都等于 O 如果其中 2 个为 X 1 个为 O 则应返回 false I tried if A B C X A B C O Do whateve
  • C 警告函数调用中缺少标记

    这是我的警告 Missing sentinel in function call 我怎样才能删除它 我正在使用 linux 和 gcc 编译器 看来您可能没有终止数组声明NULL 如果没有 null 您可能会遇到一些内存怪异 因为运行时将不

随机推荐