使用Base64编码的公钥来验证RSA签名

时间:2012-02-14 20:28:35

标签: c# .net hash cryptography public-key-encryption

简而言之,这是我的问题:

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命令从用于此公钥字符串的Modulus和Exponent加载byte []。但由于此公钥可能在将来发生变化,因此我希望能够将其以原始形式存储在数据库中。必须有一种更直接的方式来解决这个问题。

到目前为止,我所阅读的很多示例都是通过将生成的私钥和公钥导入密钥容器对象并从密钥容器对象导入私钥和公钥来避免此问题,并在同一段代码中使用它,因此不会“转移”某些字符串中的键形式内存不足。有些人在StackOverflow和其他网站上都表达了同样的问题,但我还没有找到令人满意的答案。

任何想法都非常受欢迎。

背景资料: 我的通信伙伴从可变长度的输入字符串计算一个20字节的SHA1哈希值,该字符串由ASCII编码消息的几个字段中包含的信息组成。然后使用我的合作伙伴的私钥对此哈希进行RSA签名,并将ASCII消息一起发送给我。到达后,我自己使用ASCII消息中的相同字段计算SHA1哈希,然后尝试通过调用VerifyHash来验证这些字段是否未被更改。

密钥以2种形式提供:常规和'noNL'。 noNL版本包含在上面的代码中,常规版本是:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFO
GwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWp
bY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5y
GPhGAAmqYrm8YiupwQIDAQAB
-----END PUBLIC KEY-----

3 个答案:

答案 0 :(得分:14)

您的字符串是SubjectPublicKeyInfo的base64编码。您可以使用Bouncycastle.net对其进行解码:

byte[] publicKeyBytes = Convert.FromBase64String(publicKeyString);
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters) asymmetricKeyParameter;
RSAParameters rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);

答案 1 :(得分:4)

首先 base64 只是某些二进制数据的编码。以二进制方式编码RSA公钥的方法不止一种。但是,如果从OpenSSL获得此信息,则可能是DER编码的RSAPublicKey结构。

 RSAPublicKey ::= SEQUENCE {
     modulus            INTEGER,    -- n
     publicExponent     INTEGER  }  -- e

一般情况下,您需要一个ASN.1解码器,Mono.Security.dll提供one,但对于这样一个简单的结构,您可能希望自ASN以来手动执行 。 1基本上是标记长度

答案 2 :(得分:0)

如果您的合作伙伴也使用.NET,他/她可以从Mono的makecert https://github.com/mono/mono/blob/bf55818da11240bd108dc51b374fae3d3b5482ce/mcs/tools/security/makecert.cs派生出来生成证书文件并直接发送给您。

在这种情况下,您可以轻松加载证书而不是原始字节,

http://www.lextm.com/2012/02/simple-publicprivate-key-signing-sample-code/