C# 通过签名和 RSA 公钥验证 Json 字符串



我正在为当地的Android市场创建一个IAP插件,我认为它具有与Google Play相似的API。

我构建了一个Android端,它将把市场的所有反应都返回到统一c# side
所有部分工作正常,但我无法弄清楚如何验证响应的签名。

我是密码学的新手,每天都在搜索这个。

如果我错了,请纠正我。

  1. 他们使用hash算法对数据进行签名并使用private key加密该hash
    我必须用public key解密签名并比较哈希。

这是我public key(Base64):

MIHNMA0GCSqGSIb3DQEBAQUAA4G7ADCBtwKBrwDltnT/AaF3oMt+F3lza5JEvce0GLS1L9v9Z53lQ3LNluGk0eI2ukgWm7tAiIOLQgn11Sb9mW2VWkYTWGnZ1AZtY0GwdUQJUr7u3CWNznE6XH4UCVOVhGDCLnFrG8BcfDelhcfReGZQ3izOefhc4Oq6vZf5PfLwximK+FH27fR6XL8vg3yyK4LSwT764Dfd6H3IGes6EdTx/C3C690jdyMvhi2Q3qBiqfepHzW/jV8CAwEAAQ==

此密钥采用ASN.1DER格式。

我把它分解出来,找到这个数据:

SEQUENCE
SEQUENCE
OBJECT IDENTIFIER 1.2.840.113549.1.1.1 rsaEncryption(PKCS #1)
NULL
BIT STRING
SEQUENCE
INTEGER 969837669069837851043825067021609343597253227631794160042862620526559…
INTEGER 65537
  1. 正如我在网上读到的那样,第一个INTEGERModules,第二个INTEGERExponent

所以在 c# 中编写这样的代码 =>

var parameter = new RSAParameters
{
Modulus = HexToByteArray(/* "first_INTEGET" */),
Exponent = BitConverter.GetBytes(/* "second_INTEGER" */)
};

市场给我发了这样Json

{"orderId": "0j8oJgE0Bett-neB", "purchaseToken": "0j8oJgE0Bett-neB", "developerPayload": "payload", "packageName": "com.some.market", "purchaseState": 0, "purchaseTime": 1520676644872, "productId": "card-1"}

签名是这样的:

hTFeQd25PZJ2DhGmXd0eO+C+oBeWsg983I4e5ztXtKAUrOIaNBaqAxHU3vW8acBs1I9fE5cxx/DI/sQGY4QSvpDnSm9aYz3do3joHPOXIVvXjSJfejxwzp9DKMUPd6LrgtxkaGevG+94NuKHFxpCdZlovEPXRJZyEznbASuYLqeW0KjP3jnvvw2O5iNlQRdh98h4Q18bSsaxq9zaRKExFLHkhNf/yO5m84kRB1G8

我正在寻找一种方法来做到这一点,但我不知道哪种方法对我来说是正确的。 我的验证码是这样的:

using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(parameter);
var hash = new SHA1Managed();
bool dataOK = 
rsa.VerifyData(hash.ComputeHash(Encoding.UTF8.GetBytes(json)), CryptoConfig.MapNameToOID("SHA1"), Encoding.UTF8.GetBytes(signature));
}
  1. 如何真正将signature转换为byte[]进行验证?(编码还是什么???)

我搜索了很多,但更多的搜索更混乱。

我走错了路还是用错了方法或...?

  1. 为什么工作流程要复杂?

请问谁能帮我?

谢谢。

好的,我会按顺序回答:

  1. 他们使用哈希算法对数据进行签名,并使用私钥对该哈希进行加密。我必须使用公钥解密签名并比较哈希。

    不,这是不正确的。您应该像当前一样使用签名验证方法。将签名视为哈希加密是不正确的;即使是最新的 RSA 标准也特意解释了这一点。对于 RSA,内部填充方法是不同的。对于 ECDSA,使用相同的方案无法直接加密/解密。

  2. 正如我在网上读到的那样,第一个整数是模块,第二个整数是指数

    是的,虽然它是拼写模数,而不是模块。它是公共指数,私钥还有一个私有指数。也没有盖子。

  3. 如何真正将签名转换为 byte[] 进行验证?(编码还是什么???)

    标准基础 64 已在评论部分提及。请注意,密钥和签名大小并不常见(但这本身没关系)。

  4. 为什么工作流程应该很复杂?

    好吧,最终必须有人对其进行编码,而加密很难。但为了方便起见:整个 ASN.1 结构称为 SubjectPublicKeyInfo 结构;如果您在互联网上查找,您会发现从此类结构导入的预制代码。

要最终验证结构:请确保使用正确的签名格式(RSA-PKCS#1 v1.5 或 RSA-PSS),并且确切知道将哪些二进制数据馈送到签名生成函数。例如,JSON上的签名可以是ASCII或UTF-8,也可以是UTF-16 LE或BE。

最好询问签名的创建者。

最新更新