gpt4 book ai didi

c# - 从公钥正确创建 RSACryptoServiceProvider

转载 作者:太空狗 更新时间:2023-10-29 17:29:11 28 4
gpt4 key购买 nike

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

简而言之,为了创建一个RSACryptoServiceProvider从构成 PEM 文件中的公钥的字节中创建对象,我必须创建指定 key 大小的对象(目前使用 SHA256 为 2048,特别是),然后导入 RSAParameters对象与 ExponentModulus放。我就是这样做的;

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 key ,然后将其丢弃。因此,为构造函数指定 key 大小并不重要(如果您不使用 key ,则通常不会生成 key ……)。

公钥文件是一个 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) 的序列 (0x10),这意味着它包含其他 DER/标记值。 (序列始终在 DER 中构建)
81 A0

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

我们再次看到我们的 CONSTRUCTED SEQUENCE ( 0x30 ),长度值为 0x0D ,所以我们有一个 13 字节的有效载荷。
06 09 2A 86 48 86 F7 0D 01 01 01 05 00 
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
03表示位串。 BIT STRING 被编码为 [tag] [length] [未使用的位数]。未使用的位基本上总是零。所以这是一个位序列, 0x8E字节长,并且所有这些都被使用。

从技术上讲,我们应该到此为止,因为未设置 CONSTRUCTED。但是因为我们碰巧知道这个结构的格式,所以我们把这个值当作 CONSTRUCTED 位被设置了一样:
30 81 8A

这是我们的 friend 再次构建序列, 0x8A有效载荷字节,方便地对应于“剩下的一切”。
02 81 82
02标识一个整数,这个有 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

另一个整数,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://tools.ietf.org/html/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 是 Modulus 值,第二个是 (public)Exponent。

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

虽然这并不像为您提供代码那样容易,但根据这些信息为 RSA key 编写解析器应该相当简单。我建议你把它写成 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
}

关于c# - 从公钥正确创建 RSACryptoServiceProvider,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41808094/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com