使用Base64编码的公钥验证RSA签名
简而言之,这是我的问题:
private string publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFOGwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWpbY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5yGPhGAAmqYrm8YiupwQIDAQAB";
/* Some transformation required, using publicKeyString to initiate a new RSACryptoServiceProvider object
*/
//for now:
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
byte[] selfComputedHash = new byte[]; //left out of the example
byte[] signature = new byte[];
bool result = rsa.VerifyHash(selfComputedHash, CryptoConfig.MapNameToOID("SHA1"), signature);
如您所见,问题是使用给定的 Base64 编码的公钥字符串启动新的 RSACryptoServiceProvider。我已经能够使用 RSAParameters 对象进行实例化,该对象加载了使用 OpenSSL shell 命令从该公钥字符串派生的模数和指数的字节[]。但由于这个公钥将来可能会发生变化,我希望能够将其以其原始形式存储在数据库中。必须有一种更直接的方法来处理这个问题。
到目前为止,我读过的许多示例都通过将生成的私钥和公钥导出到密钥容器对象或从密钥容器对象导入生成的私钥和公钥来避免此问题,并在同一代码段中使用它,因此不会“传输”密钥某些字符串形式内存不足。有些人在 StackOverflow 和其他网站上都表达了同样的问题,但我还没有找到满意的答案。
任何想法都非常受欢迎。
背景资料: 我的通信伙伴根据可变长度的输入字符串计算 20 字节的 SHA1 哈希值,该字符串由 ASCII 编码消息的多个字段中包含的信息组成。然后使用我合作伙伴的私钥对该哈希值进行 RSA 签名,并与 ASCII 消息一起发送给我。到达后,我使用 ASCII 消息中的相同字段自行计算 SHA1 哈希值,然后尝试通过调用VerifyHash 来验证这些字段是否未被更改。
密钥以两种形式提供:常规和“noNL”。上面的代码中包含了noNL版本,常规版本是这样的:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFO
GwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWp
bY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5y
GPhGAAmqYrm8YiupwQIDAQAB
-----END PUBLIC KEY-----
In a nutshell, this is my problem:
private string publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFOGwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWpbY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5yGPhGAAmqYrm8YiupwQIDAQAB";
/* Some transformation required, using publicKeyString to initiate a new RSACryptoServiceProvider object
*/
//for now:
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
byte[] selfComputedHash = new byte[]; //left out of the example
byte[] signature = new byte[];
bool result = rsa.VerifyHash(selfComputedHash, CryptoConfig.MapNameToOID("SHA1"), signature);
As you can see, the problem is initiating a new RSACryptoServiceProvider with the given Base64 encoded public key string. I've been able to do the instantiation using an object RSAParameters, loaded with the byte[]'s for Modulus and Exponent derived from this public key string using an OpenSSL shell command. But since this public key may change in the future I want to be able to store it in its original form in a database. There must be a more straightforward way of dealing with this.
A lot of the examples I've read so far avoid this problem by exporting and importing the generated private and public keys to and from a key-container object and use it in the same piece of code and thus not 'transferring' the key in some string form out of memory. Some people have expressed the same problem, both here on StackOverflow and on other sites, but I have not been able to find a satisfying answer yet.
Any idea's are more than welcome.
Background info:
My communication partner computes a 20-byte SHA1-hash from an input string of variable length, composed of the information contained in several fields of an ASCII encoded message. This hash is then RSA-signed with my partner's private key and sent along with the ASCII message to me. Upon arrival, I compute the SHA1 hash myself, using the same fields from the ASCII message and then try to verify if these fields were not altered by calling VerifyHash.
The key is provided in 2 forms: regular and 'noNL'. The noNL version is included in the code above, the regular version is this:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFO
GwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWp
bY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5y
GPhGAAmqYrm8YiupwQIDAQAB
-----END PUBLIC KEY-----
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您的字符串是 SubjectPublicKeyInfo 的 Base64 编码。您可以使用 Bouncycastle.net 对其进行解码,如下所示:
Your string is the base64 encoding of a SubjectPublicKeyInfo. You can use Bouncycastle.net to decode it like this:
首先base64只是一些二进制数据的编码。对 RSA 公钥进行二进制编码的方法不止一种。但是,如果您从 OpenSSL 获得此信息,它可能是 DER 编码的
RSAPublicKey
结构。一般来说,您需要一个 ASN.1 解码器,Mono.Security。 dll 提供 one,但对于如此简单的结构,您可能需要手动,因为 ASN.1 基本上是一个标签,< strong>长度和值。
First base64 is only an encoding of some binary data. There's more than one way to encode, in binary, an RSA public key. However if you got this from OpenSSL it's likely a DER-encoded
RSAPublicKey
structure.In general you would need a ASN.1 decoder, Mono.Security.dll provides one, but for such a simple structure you might want to do it by hand since ASN.1 is basically a Tag, Length and a Value.
如果没有外部库,您可以从 DER 编码的 X.509 公钥获取
指数
和模
,如下所示:请参阅https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importsubjectpublickeyinfo?view=net-7.0
Without an external library, you can get
exponent
andmodulus
from a DER-encoded X.509 public key as follows:see https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importsubjectpublickeyinfo?view=net-7.0
如果您的合作伙伴也使用 .NET,他/她可以从 Mono 的 makecert https://github.com/mono/mono/blob/bf55818da11240bd108dc51b374fae3d3b5482ce/mcs/tools/security/makecert.cs生成证书文件并直接发送给您。
在这种情况下,您可以轻松加载证书而不是原始字节,
https://docs.lextudio.com/blog/simple-public-private-key-signing-sample-code-6f95d19fdbc
If your partner also uses .NET, he/she can derive from Mono's makecert https://github.com/mono/mono/blob/bf55818da11240bd108dc51b374fae3d3b5482ce/mcs/tools/security/makecert.cs to generate certificate files and send to you directly.
In that case, you can easily load certificates instead of raw bytes,
https://docs.lextudio.com/blog/simple-public-private-key-signing-sample-code-6f95d19fdbc