Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Verify android in app purchase in c#

In our app, we have an in app purchase. The client request a purchase from google play, and send all the information received from google play (the receipt, with nonce, orders, etc. and the signature) to the server, written in c#, for verification. I'm working with the code example from this post

The problem is that the verification fails.

note: The client sends all the data in JSon format and for that to work we manipulate the string returned from google play like so:

in client side

data = data.replace("\"", "\\\"");

in server side

data = data.Replace("\\", "");

Edited: JSon code example, from App to server

{
    "data": "{\\\"nonce\\\":3768004882572571381,\\\"orders\\\":[{\\\"notificationId\\\":\\\"android.test.purchased\\\",\\\"packageName\\\":\\\"com.company.appname\\\",\\\"orderId\\\":\\\"transactionId.android.test.purchased\\\",\\\"purchaseState\\\":0,\\\"productId\\\":\\\"android.test.purchased\\\",\\\"purchaseTime\\\":1335790350398}]}",
    "signature": "ML6ocr89x3+oT3ZKnQBEE2mNEVj6LHwt+L4I/bnhl+xCpJcjhsAIhfAumeCKwXonJV4Oh9n3Sa7SVT0F7S9XcgE2xGcf2zOZmxHB1wQcyM7fQiGj39Cyb2zuYf3T6Cs1eerDzHaO1teVQZyIhBPJf4cszD/WikSpHcF8zBTvV58FkRVwl2NR4CEvI2FrKFek8Xq2O4CsclCpS5UJorMKRAer9pcSD1BkFzynQJffbaDcRLFZ7i9vABV+GZ/xWxMGPuYYE77GYk8Q2fejgmwiZ3ysY0VjEfGRCpSA==",
    "userId": 1
}

Edited: that test fails. verified is a boolean variable, supposed to be true

using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                RSAParameters rsaKeyInfo = new RSAParameters()
                {
                    Exponent = Convert.FromBase64String(ConfigurationManager.AppSettings["RsaKeyInfo.Exponent"]),
                    Modulus = Convert.FromBase64String(ConfigurationManager.AppSettings["RsaKeyInfo.Modulus"])
                };
                rsa.ImportParameters(rsaKeyInfo);
                verified = rsa.VerifyData(Encoding.ASCII.GetBytes(data), "SHA1", Convert.FromBase64String(signature));
            }
like image 483
Itai Navot Avatar asked Dec 06 '25 03:12

Itai Navot


1 Answers

The problem was the client converted the JSON string, received from google, to a JSONObject and then converted it back toString(). This caused the position of some of the json items to change inside the string, which created a different bytes object for the signature, which failed.

for example - this was the JSON received from google:

{
    "nonce": 1165723044405495300,
    "orders": [
        {
            "notificationId": "android.test.purchased",
            "orderId": "transactionId.android.test.purchased",
            "packageName": "com.company.appname",
            "productId": "android.test.purchased",
            "purchaseTime": 1335874740360,
            "purchaseState": 0
        }
    ]
}

if you manipulate it to a JSONObject (new JSONObject(json)) and then back to a string (json.toString()), it can be resulted with a position change for some of the json items, for example (notice the orderId is not second in the orders array anymore):

{
        "nonce": 1165723044405495300,
        "orders": [
            {
                "notificationId": "android.test.purchased",
                "packageName": "com.company.appname",
                "productId": "android.test.purchased",
                "purchaseTime": 1335874740360,
                "orderId": "transactionId.android.test.purchased",
                "purchaseState": 0
            }
        ]
    }

The GetBytes(data) doesn't return the same result, therefor the verification fails.

The solution is of course to avoid manipulating the json string received from google. Just put it in the JSONObject you're building. jsonObj.put("data", jsonStringFromGoogle).

like image 117
Lior Iluz Avatar answered Dec 08 '25 18:12

Lior Iluz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!