【问题标题】:Create a RSAParamaters Object from public+private key从公钥+私钥创建一个 RSAParamaters 对象
【发布时间】:2011-03-18 20:15:12
【问题描述】:

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

我最终需要从该对象中提取 Exponent、Modulus、D、P、Q、DP、DQ、InverseQ 以便为 cryptoServer 创建一个 keyblob。

谢谢!

【问题讨论】:

    标签: .net cryptography rsa x509certificate private-key


    【解决方案1】:

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

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

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

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

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

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

    • 一个标签,告诉它是什么类型的值
    • 一个length,它对第三部分的字节数进行编码
    • 一个,将被解释为标签指定的

    因此名称为“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 之间)。请注意,System.Numerics.BigInteger,在 .NET 4.0 中,有一个可以解码一堆字节的构造函数,但它希望它们采用 little-endian 约定,而不是 big-endian,因此您必须颠倒字节的顺序。

    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 格式。第一个元素是一个整数,在正常情况下应该有数值 0(零编码为 '0x02 0x01 0x00')。第二个元素是AlgorithmIdentifier,这里不详述;它实际上是一个 SEQUENCE 并且它标识了密钥类型(这里应该说“这是一个 RSA 密钥”);只需读取标签(应为 0x30),然后读取长度,然后跳过该值。第三个元素是一个 OCTET STRING:一个 0x04 标记,然后是一个长度 m 和一个 m 个字节的值。这就是我们感兴趣的内容。应该提取 OCTET STRING 的内容。我们将在下一段中对其进行解码。 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 的标记)开始,然后是长度 (r),然后是 r 字节。那些 r 字节是九个 INTEGER 的编码。第一个 INTEGER 应该是 0;如果不是,那么 RSA 密钥有两个以上的主要因素,你注定要失败。随后的八个 INTEGER 是您要查找的整数;只需解码它们,你就完成了。最后一个字段 (otherPrimeInfos) 是可选的,如果您的 RSA 密钥是“普通”RSA 密钥(具有两个素因子,而不是三个或更多),则应该不存在。

    【讨论】:

    • 也许如果我提供更多关于我的“钥匙”的细节。首先它是一个 RSA 密钥,容器是 PKCS#8 DER 格式。我有密钥和证书,但我需要提取参数(如上所述)以便进一步处理。命令行工具不是一个很好的选择,所有的处理都需要在代码中完成。我希望在 .net 框架内实现这一点,而很少或根本不使用额外的库。还有其他推荐吗?
    • 我在回复中添加了对 DER 编码规则的描述。这应该包含您所追求的足够信息。
    • 非常感谢您的回答以及您花时间详细说明您的回答。我相信它对许多人会有很大的用处和参考。对我来说,这似乎超出了我的范围 =D 我一直在为不熟悉密码学的人寻找一个稍微简单的实现。你在我的书中有一个 A+。 PS - PKCS#8 容器受密码保护 =)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-15
    • 1970-01-01
    相关资源
    最近更新 更多