关于C#:使用base64编码的公钥验证RSA签名

Using Base64 encoded Public Key to verify RSA signature

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

1
2
3
4
5
6
7
8
9
10
11
12
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命令加载了从这个公钥字符串派生的模数和指数的byte[]。但是由于这个公钥将来可能会改变,我希望能够将它以原始形式存储在数据库中。必须有一种更直接的方法来处理这个问题。

到目前为止,我已经阅读了很多示例,通过将生成的私有和公共密钥导出到密钥容器对象和从该对象导入到密钥容器对象,并在同一段代码中使用它,从而避免了在内存中以某种字符串形式"传输"密钥,从而避免了这个问题。有些人在StackOverflow和其他网站上都表达了同样的问题,但是我还没有找到一个令人满意的答案。

任何想法都不受欢迎。

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

密钥有两种形式:常规和非L。非L版本包含在上述代码中,常规版本如下:

1
2
3
4
5
6
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFO
GwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWp
bY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5y
GPhGAAmqYrm8YiupwQIDAQAB
-----END PUBLIC KEY-----

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

1
2
3
4
5
6
7
8
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);


FirstBase64只是一些二进制数据的编码。有多种方法可以用二进制编码RSA公钥。但是,如果您从openssl得到这个,它很可能是一个der编码的RSAPublicKey结构。

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

一般来说,您需要一个asn.1解码器,mono.security.dll提供了一个解码器,但是对于这样一个简单的结构,您可能需要手工完成,因为asn.1基本上是一个标记、长度和值。


如果您的合作伙伴也使用.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/