从公钥和私钥创建 RSAParamaters 对象

发布于 2024-10-22 18:53:41 字数 185 浏览 1 评论 0原文

我需要使用私钥和公钥(.key 和 .cer 文件)在 .Net 中创建 RSAParameters 对象。是否可以在.Net 中做到这一点而不使用第三方软件?如果是这样,我应该去哪里寻找。

我最终需要从该对象中提取指数、模数、D、P、Q、DP、DQ、InverseQ,以便为 cryptoServer 创建密钥块。

谢谢!

I need to create a RSAParameters object in .Net using a private and public key (.key and .cer file). Is it possible to do this in .Net without the use of third party software? If so, where should I be looking.

I ultimately need to extract the Exponent, Modulus, D, P, Q, DP, DQ, InverseQ from this object in order to create a keyblob for a cryptoServer.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

反目相谮 2024-10-29 18:53:41

“.key”和“.cer”文件扩展名绝不是密钥编码方式的明确规范。然而,“.cer”文件似乎是一个 X.509 证书,其中包含(以及许多其他内容)公钥;因此,您可能需要使用 X509CertificateX509Certificate2 类(位于 System.Security.Cryptography.X509Certificates 命名空间中)来解码证书并提取公钥。

但是,您需要私钥,而不是公钥。 关于 X509Certificate2 的 MSDN 文档令人困惑,因为它使用术语“证书”来指定公共部分(“.cer”文件中的内容)或公共和私有部分的联合,作为单个文件(按照 MSDN 描述的格式“ PKCS7(验证码)”)。

编码的 RSA 私钥通常遵循 PKCS#1 中描述的格式,这并不复杂,但仍然依赖于 ASN.1,其使用需要小心。有时,此类 RSA 密钥会被包装到更大的结构中,该结构还指定密钥类型(即密钥用于 RSA);有关详细信息,请参阅 PKCS#8。此外,这两种密钥编码通常以 PEM 格式呈现:即 Base64 ,带有标头 (< code>-----BEGIN RSA PRIVATE KEY-----) 和页脚。当然,您的私钥可以是任何格式(“.key”扩展名并不会提供太多信息)。或者,PKCS#8 和 PEM 都可以对称加密(使用密码派生密钥)。还有 PKCS#12 格式,可以将其视为证书和私钥集合的存档格式,环绕以前的格式; PKCS#12 包含多层加密,在 Microsoft 世界中以“PFX”(或“证书文件”,这一直令人困惑)的名称而闻名。

可以使用一些代码来解码所有这些格式,但此时建议使用已经完成此类工作的库,而不是自己开发。 Bouncy Castle 是这项工作的常见嫌疑人。

OpenSSL 命令行工具可以帮助您在某些密钥和证书格式之间进行转换。

编辑:如果您的私钥采用 PKCS#8 DER 格式并且不受密码保护(PKCS#8 可以做到这一点),那么您可以使用相对简单的代码。 DER 是一组用于将结构化数据转换为字节序列的规则。数据元素被编码为三个连续的部分:

  • 标签,它告诉它是什么类型的值
  • 长度,它编码第三部分中的字节数
  • value 被解释为由标签指定,

因此名称为“TLV”(即“标签、长度、值”)。某些元素本身是包含子元素的结构,在这种情况下,值包含子元素编码的串联,每个子元素都有自己的标签、长度和值。

标签通常是一个字节;对于 PKCS#8 和 RSA 密钥,您感兴趣的是标签 0x30(对于“SEQUENCE”,即具有子元素的元素)、0x02(“INTEGER”:整数值)和 0x04(“OCTET STRING”:一个 blob) 。

长度被编码为以下任一形式:

  • 0 到 127(含)之间的单字节值 n:这对长度 n 进行编码;
  • n 等于或大于 129 的字节,后跟正好 n-128 字节,以大端格式编码长度。例如,长度 324 将被编码为三个字节:0x82 0x01 0x44。其读作是:“0x82 是 128+2,因此我必须读取两个额外字节;长度是 256*0x01+0x44 = 324”。

对于 INTEGER,该值应使用有符号、大端约定进行解释(第一个字节是最高有效的,第一个字节的高位指定整数符号;对于 RSA,所有值都是正数,因此第一个字节应其值介于 0 到 127 之间)。请注意,.NET 4.0 中的 System.Numerics.BigInteger 有一个可以解码一堆字节的构造函数,但它期望它们采用小端约定,而不是大端约定,因此您可以反转字节的顺序。

PKCS#8 的结构是:

PrivateKeyInfo ::= SEQUENCE {
        version              Version,
        privateKeyAlgorithm  AlgorithmIdentifier,
        privateKey           OCTET STRING,
        attributes           [0] Attributes OPTIONAL
}

Version ::= INTEGER { v1(0) }

这是 ASN.1 表示法。这里必须理解的是,该对象是一个 SEQUENCE 元素:它被编码为一个 SEQUENCE 标记 (0x30),然后是一个长度 (n),然后是一个值 (n) > 字节,准确地说)。该值由一系列编码元素组成,每个元素都采用 TLV 格式。第一个元素是一个 INTEGER,在正常情况下其数值应为 0(零编码为“0x02 0x01 0x00”)。第二个元素是一个AlgorithmIdentifier,我在这里不详细说明;它实际上是一个 SEQUENCE 并且它标识密钥类型(这里应该说“这是一个 RSA 密钥”);只需读取标签(应为 0x30),然后读取长度,然后跳过该值。第三个元素是一个 OCTET STRING:一个 0x04 标记,然后是一个长度 m 和一个 m 字节的值。这就是我们感兴趣的。应该提取该值,即八位字节字符串的内容;我们将在下一段中对其进行解码。 PrivateKeyInfo SEQUENCE 的第四个元素是可选的(它可能根本不存在,并且通常不会),可用于对此格式的各种扩展进行编码。

假设您已提取 OCTET STRING 的内容。这是一个字节序列,实际上是结构的 DER 编码,在 ASN.1 中,该结构如下所示:

RSAPrivateKey ::= SEQUENCE {
        version            INTEGER,
        modulus            INTEGER,  -- n
        publicExponent     INTEGER,  -- e
        privateExponent    INTEGER,  -- d
        prime1             INTEGER,  -- p
        prime2             INTEGER,  -- q
        exponent1          INTEGER,  -- d mod (p-1)
        exponent2          INTEGER,  -- d mod (q-1)
        coefficient        INTEGER,  -- (inverse of q) mod p
        otherPrimeInfos    OtherPrimeInfos OPTIONAL
                -- otherPrimeInfos must be absent if version is two-prime,
                -- present if version is multi-prime.
}

因此 OCTET STRING 的内容应以 0x30(SEQUENCE 标记)开头,然后是长度 (< em>r),然后是 r 字节。这些r字节是九个整数的编码。第一个 INTEGER 应该是 0;如果不是,那么 RSA 密钥有两个以上素因数,那么你就完蛋了。随后的八个 INTEGER 就是您要查找的整数;只需解码它们,就完成了。最后一个字段 (otherPrimeInfos) 是可选的,如果您的 RSA 密钥是“正常”RSA 密钥(具有两个质因数,而不是三个或更多),则应该不存在。

".key" and ".cer" file extensions are in no way an unambiguous specification of how the keys are encoded. However, it is plausible that the ".cer" file is an X.509 certificate, which contains (among many other things) the public key; hence, you may want to use the X509Certificate and X509Certificate2 classes (in the System.Security.Cryptography.X509Certificates namespace) to decode the certificate and extract the public key.

However, you need the private key, not the public key. The MSDN documentation on X509Certificate2 is quite confusing because it uses the term "certificate" to designate either the public part (what you have in your ".cer" file) or the union of the public and private part, as a single file (under the format which MSDN describes as "PKCS7 (Authenticode)").

An encoded RSA private key usually follows the format described in PKCS#1, which is not complex, but still relies on ASN.1, whose usage requires a bit of care. Sometimes, such RSA keys are wrapped into a bigger structure which also specifies the key type (i.e. that the key is for RSA); see PKCS#8 for details. Also, both kind of key encodings are commonly presented in PEM format: that's Base64 with a header (-----BEGIN RSA PRIVATE KEY-----) and a footer. Of course, your private key could be in any format (the ".key" extension is not overly informative). Optionally, both PKCS#8 and PEM can be symmetrically encrypted (with a password-derived key). There is also the PKCS#12 format, which can be viewed as an archive format for a collection of certificates and private keys, wrapping around the previous formats; PKCS#12 includes many layers of encryption, and is known in the Microsoft world under the name of "PFX" (or "certificate file", which keeps on being confusing).

Decoding all those formats is possible with a bit of code, but at that point it is recommended to use a library which already does such work, instead of rolling your own. Bouncy Castle is the usual suspect for that job.

The OpenSSL command-line tool can help you convert between some key and certificate formats.

Edit: if your private key is in PKCS#8 DER format and is not protected by a password (PKCS#8 can do that), then you can decode it with relatively simple code. DER is a set of rules for transforming structured data into a sequence of bytes. A data element is encoded as three successive parts:

  • a tag which tells what kind of value it is
  • a length which encodes the number of bytes in the third part
  • a value which is to be interpreted as specified by the tag

hence the name "TLV" (as "Tag, Length, Value"). Some elements are themselves structures containing sub-elements, in which case the value consists in the concatenation of the encodings of the sub-elements, each with its own tag, length and value.

A tag is usually a single byte; for PKCS#8 and RSA keys, you are interested in tags 0x30 (for 'SEQUENCE', i.e. an element with sub-elements), 0x02 ('INTEGER': an integer value) and 0x04 ('OCTET STRING': a blob).

A length is encoded as either of:

  • a single byte of value n between 0 and 127 (inclusive): this encodes the length n;
  • a byte of value n equal to or greater than 129, followed by exactly n-128 bytes which encode the length in big-endian format. For instance, a length of 324 will be encoded as three bytes: 0x82 0x01 0x44. This reads as: "0x82 is 128+2, hence I must read two extra bytes; the length is 256*0x01+0x44 = 324".

For an INTEGER, the value shall be interpreted with signed, big-endian convention (first byte is most significant, and high-order bit of the first byte specifies the integer sign; for RSA, all values are positive, so the first byte shall have a value between 0 and 127). Note that System.Numerics.BigInteger, in .NET 4.0, has a constructor which can decode a bunch of bytes, but it expects them in little-endian convention, not big-endian, so you would have to reverse the order of the bytes.

The structure of PKCS#8 is:

PrivateKeyInfo ::= SEQUENCE {
        version              Version,
        privateKeyAlgorithm  AlgorithmIdentifier,
        privateKey           OCTET STRING,
        attributes           [0] Attributes OPTIONAL
}

Version ::= INTEGER { v1(0) }

That's ASN.1 notation. What must be understood here is that the object is a SEQUENCE element: it is encoded as a SEQUENCE tag (0x30), then a length (n), then a value (n bytes, exactly). The value then consists in a succession of encoded elements, each in TLV format. First element is an INTEGER, which should have numerical value 0 under normal conditions (a zero encodes as '0x02 0x01 0x00'). Second element is an AlgorithmIdentifier, which I do not detail here; it is actually a SEQUENCE and it identifies the key type (here, it should say "this is a RSA key"); just read the tag (should be 0x30), then the length, and skip the value. Third element is an OCTET STRING: a 0x04 tag, then a length m, and a value of m bytes. That's what we are interested in. That value, which is the contents of the OCTET STRING, should be extracted; we will decode it in the next paragraph. The fourth element of the PrivateKeyInfo SEQUENCE is optional (it may not be there at all, and usually will not) and can be used to encode various extensions to this format.

Suppose that you have extracted the contents of the OCTET STRING. This is a sequence of bytes, which is actually the DER encoding of a structure which, in ASN.1, looks like this:

RSAPrivateKey ::= SEQUENCE {
        version            INTEGER,
        modulus            INTEGER,  -- n
        publicExponent     INTEGER,  -- e
        privateExponent    INTEGER,  -- d
        prime1             INTEGER,  -- p
        prime2             INTEGER,  -- q
        exponent1          INTEGER,  -- d mod (p-1)
        exponent2          INTEGER,  -- d mod (q-1)
        coefficient        INTEGER,  -- (inverse of q) mod p
        otherPrimeInfos    OtherPrimeInfos OPTIONAL
                -- otherPrimeInfos must be absent if version is two-prime,
                -- present if version is multi-prime.
}

So the contents of the OCTET STRING should begin with a 0x30 (tag of SEQUENCE), then a length (r), then r bytes. Those r bytes are the encodings of nine INTEGERs. The first INTEGER should be 0; if it is not, then the RSA key has more than two prime factors, and you are doomed. The eight subsequent INTEGERs are the integers you are looking for; just decode them, and you are done. The last field (otherPrimeInfos) is optional and should be absent if your RSA key is a "normal" RSA key (with two prime factors, not three or more).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文