热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C#学习教程:从公钥正确创建RSACryptoServiceProvider分享

从公钥正确创建RSACryptoServiceProvider我目前正在尝试仅从解码的PEM文件创建RSACryptoServiceProvider对象。经过几天的搜索,我确实设法

从公钥正确创建RSACryptoServiceProvider

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

简而言之,为了从组成PEM文件中的公钥的字节创建RSACryptoServiceProvider对象,我必须创建指定keysize的对象(当前使用SHA256的2048),然后使用Exponent导入RSAParameters对象和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 

这标识了一个SEQUENCE(0x10),其中CONSTRUCTED位设置为(0x20),这意味着它包含其他DER / tagged值。 (SEQUENCE总是在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是OBJECT IDENTIFIER,有效载荷为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。 BIT STRING编码为[tag] [length] [未使用位数]。 未使用的位基本上始终为零。 所以这是一个位序列, 0x8E字节长,并且所有这些都被使用。

从技术上讲,我们应该停在那里,因为没有设置CONSTRUCTED。 但是因为我们碰巧知道这个结构的格式,所以我们将值视为CONSTRUCTED位的设置:

 30 81 8A 

这是我们的朋友CONSTRUCTED SEQUENCE, 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://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,您需要从Modulus中删除前导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 } 

经过很长一段时间,搜索和bartonjs的出色响应,这样做的代码实际上是直截了当的,尽管对于不熟悉公钥结构的人来说有点不直观。

公钥PEM可以描述各种键类型,而不仅仅是RSA,而不是new RSACryptoServiceProvider(pemBytes) ,我们必须根据其结构/语法ASN.1解析PEM,然后告诉我们它是否是RSA密钥(可能是其他一系列密钥)。 知道;

 const string rsaOid = "1.2.840.113549.1.1.1"; // found under System.Security.Cryptography.CngLightup.RsaOid but it's marked as private Oid oid = new Oid(rsaOid); AsnEncodedData keyValue = new AsnEncodedData(publicKeyBytes); // see question AsnEncodedData keyParam = new AsnEncodedData(new byte[] { 05, 00 }); // ASN.1 code for NULL PublicKey pubKeyRdr = new PublicKey(oid, keyParam, keyValue); var rsaCryptoServiceProvider = (RSACryptoServiceProvider)pubKeyRdr.Key; 

注意:上面的代码没有生产就绪! 您需要在对象创建周围放置适当的防护(例如,公钥可能不是RSA),转换为RSACryptoServiceProvider等。此处的代码示例简短,以说明它可以合理地干净地完成。

我怎么得到这个? 通过ILSpy中的Cryptographic命名空间,我注意到了AsnEncodedData ,它用bartonjs的描述敲响了钟声。 做了更多的研究,我发现这篇文章(看起来很熟悉?)。 这是试图确定密钥大小,但它在此过程中创建了必要的RSACryptoServiceProvider

我把bartonjs的回答留给了Accepted,这是正确的。 上面的代码是这项研究的结果,我将它留在这里,以便其他想要做同样事情的人可以干净利落地完成,而不会像我在OP中那样进行arrays复制。

此外,出于解码和测试目的,您可以使用ASN.1解码器检查您的公钥是否可解析。

UPDATE

在.NET路线图中,通过针对Core> 2.1.0的ASN.1解析 ,可以更轻松地实现这一目标。

更新2

现在Core .NET 2.1.1中有一个私有实现。 MS是dogfooding直到满意一切都很好,我们(希望)在后续版本中看到公共API。

PEM文件只是一系列base64编码的DER文件,而.net允许直接导入DER文件,所以你可以做这样的事情(我假设你只使用公钥,因为你声明你只使用它):

上述就是C#学习教程:从公钥正确创建RSACryptoServiceProvider分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—编程笔记

 byte[] certBytes = Convert.FromBase64String(deserializedPublicKey .Replace("-----BEGIN PUBLIC KEY-----", "") .Replace("-----END PUBLIC KEY-----", "")); X509Certificate2 cert = new X509Certificate2(certBytes); RSACryptoServiceProvider publicKeyProvider = (RSACryptoServiceProvider)cert.PublicKey.Key; 


推荐阅读
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了如何将CIM_DateTime解析为.Net DateTime,并分享了解析过程中可能遇到的问题和解决方法。通过使用DateTime.ParseExact方法和适当的格式字符串,可以成功解析CIM_DateTime字符串。同时还提供了关于WMI和字符串格式的相关信息。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • 本文详细介绍了cisco路由器IOS损坏时的恢复方法,包括进入ROMMON模式、设置IP地址、子网掩码、默认网关以及使用TFTP服务器传输IOS文件的步骤。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
author-avatar
怪话greenup
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有