Android应用内计费Dot Net中收据验证(C#)

发布于 2024-10-31 17:43:05 字数 644 浏览 1 评论 0原文

我有一个提供应用程序内计费的 Android 应用程序,我们有一个应用程序服务器,Android 应用程序连接到该服务器为用户提供服务,在应用程序内购买时,我们希望将收据推送到服务器进行验证过程。

现在的问题是我不知道如何转换 Security.java< /a> dot net(C#) 中的文件,因为我们的服务器是用 dot net 编写的

注意:此文件附带 android 应用内计费相同的应用程序,该应用程序提供消息签名功能,我只需要在 dot net 中的等效功能。

有关此问题的更多详细信息,请访问 http://social.msdn .microsoft.com/Forums/en-US/netfxbcl/thread/66bb5683-fde6-47ca-92d7-de255cc8655a

I have a Android application which provides in-app billing and we have our application server to which android application connects to provide services to the user, on in-app purchase we want to push receipt to the server for verification process.

Now problem is I don't know how to convert Security.java file in dot net(C#) as our server is written in dot net

NOTE: This file comes with android in-app billing same application which provides message signing functions i just need their equivalent in dot net.

More Detail regarding this problem is available at
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/66bb5683-fde6-47ca-92d7-de255cc8655a

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

输什么也不输骨气 2024-11-07 17:43:05

这是一个纯 C# 实现,来自 Checking Google在 .Net 上播放签名

创建一个控制台应用程序项目,将公钥转换为 RSACryptoServiceProvider 所需的 XML 格式。将 PEMKeyLoader.cs 添加到控制台应用程序项目。

using PublicKeyConvert;
using System.Security.Cryptography;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            RSACryptoServiceProvider provider = PEMKeyLoader.CryptoServiceProviderFromPublicKeyInfo(MY_BASE64_PUBLIC_KEY);
            System.Console.WriteLine(provider.ToXmlString(false));
        }

        const string MY_BASE64_PUBLIC_KEY = "Paste your base64 Google public key here.";
    }
}

运行该控制台应用程序将输出(到控制台)RSACryptoServiceProvider 所需的 XML 格式。

现在您已经有了 XML 格式的公钥,您可以使用它来验证签名:

public static bool Verify(string message, string base64Signature, string xmlPublicKey)
{
    // Create the provider and load the KEY
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
    provider.FromXmlString(xmlPublicKey);

    // The signature is supposed to be encoded in base64 and the SHA1 checksum
    // of the message is computed against the UTF-8 representation of the message
    byte[] signature = System.Convert.FromBase64String(base64Signature);
    SHA1Managed sha = new SHA1Managed();
    byte[] data = System.Text.Encoding.UTF8.GetBytes(message);

    return provider.VerifyData(data, sha, signature);
}

Here's a pure C# implementation, from Checking Google Play Signatures on .Net.

Create a console application project to convert the public key into the XML format that RSACryptoServiceProvider expects. Add PEMKeyLoader.cs to the console application project.

using PublicKeyConvert;
using System.Security.Cryptography;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            RSACryptoServiceProvider provider = PEMKeyLoader.CryptoServiceProviderFromPublicKeyInfo(MY_BASE64_PUBLIC_KEY);
            System.Console.WriteLine(provider.ToXmlString(false));
        }

        const string MY_BASE64_PUBLIC_KEY = "Paste your base64 Google public key here.";
    }
}

Running that console application will output (to the console) the XML format that RSACryptoServiceProvider expects.

Now that you have your XML-formatted public key, you can use it verify signatures:

public static bool Verify(string message, string base64Signature, string xmlPublicKey)
{
    // Create the provider and load the KEY
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
    provider.FromXmlString(xmlPublicKey);

    // The signature is supposed to be encoded in base64 and the SHA1 checksum
    // of the message is computed against the UTF-8 representation of the message
    byte[] signature = System.Convert.FromBase64String(base64Signature);
    SHA1Managed sha = new SHA1Managed();
    byte[] data = System.Text.Encoding.UTF8.GetBytes(message);

    return provider.VerifyData(data, sha, signature);
}
沒落の蓅哖 2024-11-07 17:43:05

我找到了解决方案,要实现这一点,您首先必须转换公钥格式,因为点网使用不同的密钥作为输入。

我不知道其他方法,但我们可以使用 java 代码获取点网格式密钥,您只需运行一次即可生成点网友好的 RSA 公钥。
(仅当给定的公众不会快速变化时才建议这样做,例如在 Android 市场应用内计费的情况下)

以下 Java 代码对我有用

public static DotNetRSA GenerateDotNetKey(String base64PubKey)
            throws IOException, NoSuchAlgorithmException,
            InvalidKeySpecException {
        /*
         * String base64PubKey - 
         * Is a Key retrieved from Google Checkout Merchant Account
         */
        BASE64Decoder decoder = new BASE64Decoder();

        byte[] publicKeyBytes = decoder.decodeBuffer(base64PubKey);

        EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
        RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);

        byte[] modulusBytes = publicKey.getModulus().toByteArray();
        byte[] exponentBytes = publicKey.getPublicExponent().toByteArray();

        modulusBytes = stripLeadingZeros(modulusBytes);

        BASE64Encoder encoder = new BASE64Encoder();
        String modulusB64 = encoder.encode(modulusBytes);
        String exponentB64 = encoder.encode(exponentBytes);

        return new DotNetRSA(modulusB64, exponentB64);
    }

      private static byte[] stripLeadingZeros(byte[] a) {
        int lastZero = -1;
        for (int i = 0; i < a.length; i++) {
          if (a[i] == 0) {
            lastZero = i;
          }
          else {
            break;
          }
        }
        lastZero++;
        byte[] result = new byte[a.length - lastZero];
        System.arraycopy(a, lastZero, result, 0, result.length);
        return result;
      }

现在要验证数字签名,您可以在 dot net 程序中使用以下代码(c#)假设 GCHO_PUB_KEY_EXP 是您的指数,GCHO_PUB_KEY_MOD 是您通过上述 Java 代码提取的模数,

public static bool VerifyDataSingature(string data, string sign)
{
     using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
     {
         RSAParameters rsaKeyInfo = new RSAParameters() 
         { 
             Exponent = Convert.FromBase64String(GCHO_PUB_KEY_EXP), 
             Modulus = Convert.FromBase64String(GCHO_PUB_KEY_MOD) 
         };
         rsa.ImportParameters(rsaKeyInfo);

         return rsa.VerifyData(Encoding.ASCII.GetBytes(data), 
                               "SHA1", 
                               Convert.FromBase64String(sign));
     }
}

我希望它对每个人都适用,就像对我一样。感谢

代码项目文章

I found the solution, to achieve you first have to convert the public key format as dot net uses sort of different Key as an input.

I don't know the other ways but we can get dot net format key using a java Code which you have to run only once to generate the dot net friendly RSA Public Key.
(this is only recommended when the given public do not changes rapidly e.g. in case of Android market in-app billing)

following Java Code worked for me

public static DotNetRSA GenerateDotNetKey(String base64PubKey)
            throws IOException, NoSuchAlgorithmException,
            InvalidKeySpecException {
        /*
         * String base64PubKey - 
         * Is a Key retrieved from Google Checkout Merchant Account
         */
        BASE64Decoder decoder = new BASE64Decoder();

        byte[] publicKeyBytes = decoder.decodeBuffer(base64PubKey);

        EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
        RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);

        byte[] modulusBytes = publicKey.getModulus().toByteArray();
        byte[] exponentBytes = publicKey.getPublicExponent().toByteArray();

        modulusBytes = stripLeadingZeros(modulusBytes);

        BASE64Encoder encoder = new BASE64Encoder();
        String modulusB64 = encoder.encode(modulusBytes);
        String exponentB64 = encoder.encode(exponentBytes);

        return new DotNetRSA(modulusB64, exponentB64);
    }

      private static byte[] stripLeadingZeros(byte[] a) {
        int lastZero = -1;
        for (int i = 0; i < a.length; i++) {
          if (a[i] == 0) {
            lastZero = i;
          }
          else {
            break;
          }
        }
        lastZero++;
        byte[] result = new byte[a.length - lastZero];
        System.arraycopy(a, lastZero, result, 0, result.length);
        return result;
      }

Now to verify the Digital Signature you can use the following code in your dot net program(c#) provided GCHO_PUB_KEY_EXP is your Exponent and GCHO_PUB_KEY_MOD is your Modulus extracted by above Java Code

public static bool VerifyDataSingature(string data, string sign)
{
     using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
     {
         RSAParameters rsaKeyInfo = new RSAParameters() 
         { 
             Exponent = Convert.FromBase64String(GCHO_PUB_KEY_EXP), 
             Modulus = Convert.FromBase64String(GCHO_PUB_KEY_MOD) 
         };
         rsa.ImportParameters(rsaKeyInfo);

         return rsa.VerifyData(Encoding.ASCII.GetBytes(data), 
                               "SHA1", 
                               Convert.FromBase64String(sign));
     }
}

I hope it will work for everyone as worked for me. Thanks

Credit Goes to Code Project Artical

一腔孤↑勇 2024-11-07 17:43:05

对于所有需要验证签名的人来说,这里有一个完整的 C# 实现,使用 BouncyCastle dll 来提供帮助。

如果您使用 Google 公钥向课程提供信息,您将能够验证签名,而不需要任何 Java 代码。玩得开心。格茨·马丁

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using System.Security.Cryptography;

namespace GoogleEncryptTest
{
    class GoogleSignatureVerify
{
    RSAParameters _rsaKeyInfo;

    public GoogleSignatureVerify(String GooglePublicKey)
    {
        RsaKeyParameters rsaParameters= (RsaKeyParameters) PublicKeyFactory.CreateKey(Convert.FromBase64String(GooglePublicKey)); 

        byte[] rsaExp   = rsaParameters.Exponent.ToByteArray();
        byte[] Modulus  = rsaParameters.Modulus.ToByteArray();

        // Microsoft RSAParameters modulo wants leading zero's removed so create new array with leading zero's removed
        int Pos = 0;
        for (int i=0; i<Modulus.Length; i++)
        {
            if (Modulus[i] == 0) 
            {
                Pos++;
            }
            else
            {
                break;
            }
        }
        byte[] rsaMod = new byte[Modulus.Length-Pos];
        Array.Copy(Modulus,Pos,rsaMod,0,Modulus.Length-Pos);

        // Fill the Microsoft parameters
        _rsaKeyInfo = new RSAParameters()
        {
            Exponent    = rsaExp,
            Modulus     = rsaMod
        };
    }

    public bool Verify(String Message,String Signature)
    {
        using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
        {      
            rsa.ImportParameters(_rsaKeyInfo);  
            return rsa.VerifyData(Encoding.ASCII.GetBytes(Message), "SHA1", Convert.FromBase64String(Signature));  
        }           
    }
}
}

For all folks who need to verify signature here is a complete c# implementation using the BouncyCastle dll to assist.

If you feed the class with your Google public key you will be able to verify signatures, without the need for any Java code. Have fun with it. grtz Martien

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using System.Security.Cryptography;

namespace GoogleEncryptTest
{
    class GoogleSignatureVerify
{
    RSAParameters _rsaKeyInfo;

    public GoogleSignatureVerify(String GooglePublicKey)
    {
        RsaKeyParameters rsaParameters= (RsaKeyParameters) PublicKeyFactory.CreateKey(Convert.FromBase64String(GooglePublicKey)); 

        byte[] rsaExp   = rsaParameters.Exponent.ToByteArray();
        byte[] Modulus  = rsaParameters.Modulus.ToByteArray();

        // Microsoft RSAParameters modulo wants leading zero's removed so create new array with leading zero's removed
        int Pos = 0;
        for (int i=0; i<Modulus.Length; i++)
        {
            if (Modulus[i] == 0) 
            {
                Pos++;
            }
            else
            {
                break;
            }
        }
        byte[] rsaMod = new byte[Modulus.Length-Pos];
        Array.Copy(Modulus,Pos,rsaMod,0,Modulus.Length-Pos);

        // Fill the Microsoft parameters
        _rsaKeyInfo = new RSAParameters()
        {
            Exponent    = rsaExp,
            Modulus     = rsaMod
        };
    }

    public bool Verify(String Message,String Signature)
    {
        using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
        {      
            rsa.ImportParameters(_rsaKeyInfo);  
            return rsa.VerifyData(Encoding.ASCII.GetBytes(Message), "SHA1", Convert.FromBase64String(Signature));  
        }           
    }
}
}
黄昏下泛黄的笔记 2024-11-07 17:43:05

供大家搜索,这里是完整的 Java 文件,以及 VB.NET 中的函数。

/**
 * <p>Title: RSA Security</p>
 * Description: This class generates a RSA private and public key, reinstantiates
 * the keys from the corresponding key files.It also generates compatible .Net Public Key,
 * which we will read later in C# program using .Net Securtiy Framework
 * The reinstantiated keys are used to sign and verify the given data.</p>
 *
 * @author Shaheryar
 * @version 1.0
 */

import java.security.*;
import java.security.spec.*;
import java.io.*;
import java.security.interfaces.*;
import java.security.cert.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class SecurityManager {

  private KeyPairGenerator keyGen; //Key pair generator for RSA
  private PrivateKey privateKey; // Private Key Class
  private PublicKey publicKey; // Public Key Class
  private KeyPair keypair; // KeyPair Class
  private Signature sign; // Signature, used to sign the data
  private String PRIVATE_KEY_FILE; // Private key file.
  private String PUBLIC_KEY_FILE; // Public key file.
  private String DOT_NET_PUBLIC_KEY_FILE; // File to store .Net Compatible Key Data

  /**
   * Default Constructor. Instantiates the key paths and signature algorithm.
 * @throws IOException 
 * @throws InvalidKeySpecException 
 * @throws NoSuchAlgorithmException 
   */
  public SecurityManager() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {

  }


  public static void main(String args[]) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException{
      GenerateDotNetKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp6340BNzismmb/n98sTcYfNEmmzNGumdWnK1e7NNWntM6mjZMnQaVZ9HiJKmMgtn69dAU4gaMVUWACDsuup1GBxN8dLgDbtR26M0u1jf1G8AQehcKfqxqSYzxKquXXotffdYsJPpjseZbi96Y7j47kz9CjNP3y1BzjJNTWQUx9fc9e2Bpsi0GtqJ8porPBuIGTjcCnlKM14tIv6YlHtECW1L1wcOBkoj/5liI1nhlYDth/DNXg1OY11JqIIP1fO2vQPtKEpdtcTBTjmB9M45O1N8K/shTcMntFjwVTpL0hRd+eaN1bUjpMvrhFik0VcF/ZNN6Hn0Coqe+ey18dLosQIDAQAB");
  }
  public static void GenerateDotNetKey(String base64PubKey)
          throws IOException, NoSuchAlgorithmException,
          InvalidKeySpecException {
      /*
       * String base64PubKey - 
       * Is a Key retrieved from Google Checkout Merchant Account
       */
      BASE64Decoder decoder = new BASE64Decoder();

      byte[] publicKeyBytes = decoder.decodeBuffer(base64PubKey);

      EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
      RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);

      byte[] modulusBytes = publicKey.getModulus().toByteArray();
      byte[] exponentBytes = publicKey.getPublicExponent().toByteArray();

      modulusBytes = stripLeadingZeros1(modulusBytes);

      BASE64Encoder encoder = new BASE64Encoder();
      String modulusB64 = encoder.encode(modulusBytes);
      String exponentB64 = encoder.encode(exponentBytes);
int i=0;
     // return new DotNetRSA(modulusB64, exponentB64);
  }

    private static byte[] stripLeadingZeros1(byte[] a) {
      int lastZero = -1;
      for (int i = 0; i < a.length; i++) {
        if (a[i] == 0) {
          lastZero = i;
        }
        else {
          break;
        }
      }
      lastZero++;
      byte[] result = new byte[a.length - lastZero];
      System.arraycopy(a, lastZero, result, 0, result.length);
      return result;
    }


  }

只需添加到一个新的 Java 项目并作为带有断点(int i=0;)的 java 应用程序运行即可提取您的密钥,代码不是我的,只是由我来处理,感谢原作者,上面的链接

和VB.NET

Private Function VerifyDataSignature(ByVal data As String, ByVal sign As String) As Boolean
    Using rsa As New RSACryptoServiceProvider()
        Dim rsaKeyInfo As RSAParameters = New RSAParameters()
        rsaKeyInfo.Exponent = Convert.FromBase64String("ExponentFromJava")
        rsaKeyInfo.Modulus = Convert.FromBase64String("ModulusFromJava")
        rsa.ImportParameters(rsaKeyInfo)
        Return rsa.VerifyData(Encoding.ASCII.GetBytes(data), "SHA1", Convert.FromBase64String(sign))
    End Using
End Function

FYI for peeps searching, here is the complete Java file, and the function in VB.NET.

/**
 * <p>Title: RSA Security</p>
 * Description: This class generates a RSA private and public key, reinstantiates
 * the keys from the corresponding key files.It also generates compatible .Net Public Key,
 * which we will read later in C# program using .Net Securtiy Framework
 * The reinstantiated keys are used to sign and verify the given data.</p>
 *
 * @author Shaheryar
 * @version 1.0
 */

import java.security.*;
import java.security.spec.*;
import java.io.*;
import java.security.interfaces.*;
import java.security.cert.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class SecurityManager {

  private KeyPairGenerator keyGen; //Key pair generator for RSA
  private PrivateKey privateKey; // Private Key Class
  private PublicKey publicKey; // Public Key Class
  private KeyPair keypair; // KeyPair Class
  private Signature sign; // Signature, used to sign the data
  private String PRIVATE_KEY_FILE; // Private key file.
  private String PUBLIC_KEY_FILE; // Public key file.
  private String DOT_NET_PUBLIC_KEY_FILE; // File to store .Net Compatible Key Data

  /**
   * Default Constructor. Instantiates the key paths and signature algorithm.
 * @throws IOException 
 * @throws InvalidKeySpecException 
 * @throws NoSuchAlgorithmException 
   */
  public SecurityManager() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {

  }


  public static void main(String args[]) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException{
      GenerateDotNetKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp6340BNzismmb/n98sTcYfNEmmzNGumdWnK1e7NNWntM6mjZMnQaVZ9HiJKmMgtn69dAU4gaMVUWACDsuup1GBxN8dLgDbtR26M0u1jf1G8AQehcKfqxqSYzxKquXXotffdYsJPpjseZbi96Y7j47kz9CjNP3y1BzjJNTWQUx9fc9e2Bpsi0GtqJ8porPBuIGTjcCnlKM14tIv6YlHtECW1L1wcOBkoj/5liI1nhlYDth/DNXg1OY11JqIIP1fO2vQPtKEpdtcTBTjmB9M45O1N8K/shTcMntFjwVTpL0hRd+eaN1bUjpMvrhFik0VcF/ZNN6Hn0Coqe+ey18dLosQIDAQAB");
  }
  public static void GenerateDotNetKey(String base64PubKey)
          throws IOException, NoSuchAlgorithmException,
          InvalidKeySpecException {
      /*
       * String base64PubKey - 
       * Is a Key retrieved from Google Checkout Merchant Account
       */
      BASE64Decoder decoder = new BASE64Decoder();

      byte[] publicKeyBytes = decoder.decodeBuffer(base64PubKey);

      EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
      RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);

      byte[] modulusBytes = publicKey.getModulus().toByteArray();
      byte[] exponentBytes = publicKey.getPublicExponent().toByteArray();

      modulusBytes = stripLeadingZeros1(modulusBytes);

      BASE64Encoder encoder = new BASE64Encoder();
      String modulusB64 = encoder.encode(modulusBytes);
      String exponentB64 = encoder.encode(exponentBytes);
int i=0;
     // return new DotNetRSA(modulusB64, exponentB64);
  }

    private static byte[] stripLeadingZeros1(byte[] a) {
      int lastZero = -1;
      for (int i = 0; i < a.length; i++) {
        if (a[i] == 0) {
          lastZero = i;
        }
        else {
          break;
        }
      }
      lastZero++;
      byte[] result = new byte[a.length - lastZero];
      System.arraycopy(a, lastZero, result, 0, result.length);
      return result;
    }


  }

Just add to a new Java project and run as java app with a break point (int i=0;) to extract your keys, code not mine, just bodged by me, props to the original author, link above

and VB.NET

Private Function VerifyDataSignature(ByVal data As String, ByVal sign As String) As Boolean
    Using rsa As New RSACryptoServiceProvider()
        Dim rsaKeyInfo As RSAParameters = New RSAParameters()
        rsaKeyInfo.Exponent = Convert.FromBase64String("ExponentFromJava")
        rsaKeyInfo.Modulus = Convert.FromBase64String("ModulusFromJava")
        rsa.ImportParameters(rsaKeyInfo)
        Return rsa.VerifyData(Encoding.ASCII.GetBytes(data), "SHA1", Convert.FromBase64String(sign))
    End Using
End Function
花间憩 2024-11-07 17:43:05

我的解决方案基于 BouncyCastle C# nuget。

将消息、签名和密钥替换为您的消息、签名和密钥并进行测试。不需要 java 来获取模数或指数。

[TestMethod]
public void ValidadeMessageTest()
{
    //Base64-encoded RSA public key obtained from Google PlayStore, for the app. Go to DevelomentTools->Service & APIs
    var GooglePlayPK = "<put your key here>";

    bool validateReceipt(String message,String  messageSignature)
    {
        const String SIGNATURE_ALGORITHM = "SHA1";

        var rsaParameters = new RSAParameters();
        byte[] publicKeyBytes = Convert.FromBase64String(GooglePlayPK);
        AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes);
        RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
        rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
        rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();

        using (var rsa = new RSACryptoServiceProvider())
        {
            var encoder = new ASCIIEncoding();
            byte[] bytesToVerify = encoder.GetBytes(message);
            byte[] signedBytes = Convert.FromBase64String(messageSignature);

                rsa.ImportParameters(rsaParameters);
                return  rsa.VerifyData(bytesToVerify, CryptoConfig.MapNameToOID(SIGNATURE_ALGORITHM), signedBytes);                   
        }        
    }
    //test your receipt
    Assert.IsTrue(validateReceipt(<original>, <signature>));
}

My solution based on BouncyCastle C# nuget.

Replace the message, signature and key with your one and test it. No need for java to get the Modulus or Exponent.

[TestMethod]
public void ValidadeMessageTest()
{
    //Base64-encoded RSA public key obtained from Google PlayStore, for the app. Go to DevelomentTools->Service & APIs
    var GooglePlayPK = "<put your key here>";

    bool validateReceipt(String message,String  messageSignature)
    {
        const String SIGNATURE_ALGORITHM = "SHA1";

        var rsaParameters = new RSAParameters();
        byte[] publicKeyBytes = Convert.FromBase64String(GooglePlayPK);
        AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes);
        RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
        rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
        rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();

        using (var rsa = new RSACryptoServiceProvider())
        {
            var encoder = new ASCIIEncoding();
            byte[] bytesToVerify = encoder.GetBytes(message);
            byte[] signedBytes = Convert.FromBase64String(messageSignature);

                rsa.ImportParameters(rsaParameters);
                return  rsa.VerifyData(bytesToVerify, CryptoConfig.MapNameToOID(SIGNATURE_ALGORITHM), signedBytes);                   
        }        
    }
    //test your receipt
    Assert.IsTrue(validateReceipt(<original>, <signature>));
}
草莓酥 2024-11-07 17:43:05

对于任何可能仍然感兴趣的人,这里有一个纯 C# 解决方案(使用 .NET 5.0 测试):

        public static bool IsSignatureValid(string message,
            string signature, string publicKey)
        {
            try {
                var publicKeyBytes = Convert.FromBase64String(
                    publicKey);

                var rsa = RSA.Create();
                rsa.ImportSubjectPublicKeyInfo(
                    publicKeyBytes, out var _);

                using var rsaProvider = new RSACryptoServiceProvider();
                rsaProvider.ImportParameters(
                    rsa.ExportParameters(false));

                return rsaProvider.VerifyData(
                    Encoding.UTF8.GetBytes(message),
                    HashAlgorithmName.SHA256.Name,
                    Convert.FromBase64String(signature));
            } catch (Exception ex) {
                Console.WriteLine(ex);

                return false;
            }
        }

For anyone that might still be interested, here's a pure C# solution (tested with .NET 5.0):

        public static bool IsSignatureValid(string message,
            string signature, string publicKey)
        {
            try {
                var publicKeyBytes = Convert.FromBase64String(
                    publicKey);

                var rsa = RSA.Create();
                rsa.ImportSubjectPublicKeyInfo(
                    publicKeyBytes, out var _);

                using var rsaProvider = new RSACryptoServiceProvider();
                rsaProvider.ImportParameters(
                    rsa.ExportParameters(false));

                return rsaProvider.VerifyData(
                    Encoding.UTF8.GetBytes(message),
                    HashAlgorithmName.SHA256.Name,
                    Convert.FromBase64String(signature));
            } catch (Exception ex) {
                Console.WriteLine(ex);

                return false;
            }
        }

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文