【问题标题】:Using Base64 encoded Public Key to verify RSA signature使用 Base64 编码的公钥验证 RSA 签名
【发布时间】:2012-03-06 05:22:39
【问题描述】:

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

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 消息一起发送给我。到达后,我自己计算 SHA1 哈希,使用 ASCII 消息中的相同字段,然后尝试通过调用 VerifyHash 来验证这些字段是否未更改。

密钥以 2 种形式提供:常规和“非NL”。上面的代码中包含了noNL版本,普通版本是这样的:

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

【问题讨论】:

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


    【解决方案1】:

    您的字符串是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);
    

    【讨论】:

    • 谢谢,这很容易。我将研究 BouncyCastle 库,但您确定没有办法仅使用 .NET 本身中的 Cryptography 库来完成此任务吗?
    • @jscheppers:您可以按照 poupou 的建议手动执行此操作,但 .NET 中不直接支持该格式。快速搜索发现这个手动解码的例子:jensign.com/JavaScience/dotnet/pempublic/pempublic.cs,但那个看起来有点乱。
    • 我想我更喜欢你的 BouncyCastle 解决方案 ;) 我已经在我当前的实现中尝试过它并且它有效。我会把你的帖子标记为答案!
    【解决方案2】:

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

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

    一般来说,您需要 ASN.1 解码器,Mono.Security.dll 提供 one,但是对于这样一个简单的结构,您可能需要手动完成,因为 ASN.1 基本上是一个标签长度

    【讨论】:

    • 提供公钥的组织没有提到密钥的格式,但是因为我可以使用 OpenSSL '读取'它们并且因为密钥包含 -----BEGIN PUBLIC KEY----- 和 -----END PUBLIC KEY----- 标签(我将把它添加到我的原始帖子中)我相当肯定它是一个 DER 编码密钥。您将如何手动将此字符串转换为 ASN.1 结构?当字节发挥作用时,我对自己不太确定 :)
    • 注意它实际上是一个SubjectPublicKeyInfo 包含一个RSAPublicKey
    【解决方案3】:

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

    【讨论】:

    • 这将是一个很好的可能性,但我无法控制密钥的生成方式。密钥按原样提供,没有可用的证书在此密钥所在的位置。
    猜你喜欢
    • 2015-02-23
    • 2022-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多