15

I have implemented In-App billing in my app - and very recently google has updated it,previously i was testing the in-app billing with "android.test.purchased" and it was working fine (Buy full Version and Restore full version).

Now i took the changed classes from here https://code.google.com/p/marketbilling/source/detail?r=7bc191a004483a1034b758e1df0bda062088d840

After that i am not able to test the app it gives the following error in the Logcat "IabHelper: In-app billing error: Purchase signature verification FAILED for sku android.test.purchased ".

I have checked with my key, package name and also app version all is proper, has any one faced this issue?

Please help me with this.

Goofy
  • 6,098
  • 17
  • 90
  • 156
  • Are you testing directly from the eclipse, I mean directly run on device instead of signed build? if yes then try to test by signed apk and let me reply what happens. – Maulik Oct 23 '13 at 07:55
  • @Maulik how does that matter , because previously i was just installing from eclipse and testing it was working perfectly fine,only now after adding the changes it showing me the error, any ways will check once – Goofy Oct 23 '13 at 08:47
  • @Maulik i checked it, its still showing the same error – Goofy Oct 23 '13 at 08:57
  • @Bruno Oliveira, sir, please check this issue and kindly let us know for the solution, I got below reason(given in my answer) why it is happens. – Maulik Oct 24 '13 at 07:00
  • Its been three years, and it hasn't been fixed :( – Ruchir Baronia Apr 01 '16 at 02:03

2 Answers2

31

This is because of the verifyPurchase() method in the Security class that has been change in the new fixes. Let me show you what is the exact problem is:

Security class changes

OLD CODE

 public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
          if (signedData == null) {
            Log.e(TAG, "data is null");
            return false;
        }

        boolean verified = false;
        if (!TextUtils.isEmpty(signature)) {
            PublicKey key = Security.generatePublicKey(base64PublicKey);
            verified = Security.verify(key, signedData, signature);
            if (!verified) {
                Log.w(TAG, "signature does not match data.");
                return false;
            }
        }
        return true;
    }

New Code

public static boolean verifyPurchase(String base64PublicKey,
            String signedData, String signature) {

    if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
                || TextUtils.isEmpty(signature)) {
        Log.e(TAG, "Purchase verification failed: missing data.");
            return false;
    }

    PublicKey key = Security.generatePublicKey(base64PublicKey);
    return Security.verify(key, signedData, signature);

}

According to what I have searched and tested from New code,

Why it happens because we will not get any signature while we are using dummy product like "android.test.purchased". So in the old code it is working good because we were return true even if signature is not given and for the New code we are returning false.

more information about the signature data null or blank from link1 and link2

So I suggest you just replace old code method verifyPurchase() instead of New Code method.

I think may be New Code will work fine for the real product but not in the dummy product. But yet I have not tested for the real product.

Let me search more about this, why they changed code and what is the purpose behind that.

EDIT:

BuildConfig.DEBUG will also give you the solution for the test purchases.

In the verifyPurchase I changed return false to:

 Log.e(TAG, "Purchase verification failed: missing data.");
        if (BuildConfig.DEBUG) {
                return true;
        }
        return false;

but you should be aware to use this only in test scenario's.

This will return true, if you have a debug build, and the signature data is missing. Since the BuildConfig.DEBUG will be false in a production build this should be OK. But better is to remove this code after everything is debugged.

I have edited some code in the verifyPurchase() method, check it below:

public static boolean verifyPurchase(String base64PublicKey,
        String signedData, String signature) {

    if (signedData == null) {
        Log.e(TAG, "data is null");
        return false;
    }

    if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
            || TextUtils.isEmpty(signature)) {
        Log.e(TAG, "Purchase verification failed: missing data.");
        if (BuildConfig.DEBUG) {
            Log.d("DeBUG", ">>>"+BuildConfig.DEBUG);
            return true;
        }
        return false;
    }

    PublicKey key = Security.generatePublicKey(base64PublicKey);
    return Security.verify(key, signedData, signature);
}

I got this from GvS's answer android in app billing purchase verification failed.

hope it is helpful for you.

Community
  • 1
  • 1
Maulik
  • 3,316
  • 20
  • 31
  • 1
    yes you are correct, i have done some research on this too, see here https://code.google.com/p/marketbilling/issues/list?can=2&q=&sort=-id&colspec=ID%20Type%20Status%20Google%20Priority%20Milestone%20Owner%20Summary defect 150 – Goofy Oct 23 '13 at 10:49
  • Yes, i was using old code, google has sent me a mail that they have updated the api and we need to update that, so i was trying on that – Goofy Oct 23 '13 at 10:50
  • Let me know if you get any new updates for the same. – Maulik Oct 23 '13 at 10:56
  • 1
    one temp solution is also given in GvS answer in below link: http://stackoverflow.com/questions/19732025/android-in-app-billing-purchase-verification-failed/19735453?noredirect=1#comment29448973_19735453 – Maulik Nov 06 '13 at 13:36
  • it could be better to use this: if (signedData.contains("android.test.purchased")) { return true; } – L.Grillo Aug 17 '15 at 12:14
  • What do we import for BuildConfig? There are multiple classes by that name. Thanks – Ruchir Baronia Apr 01 '16 at 01:42
7

I was the one informing Google Security Team about these security bugs. Please be patient until I do public disclosure of these bugs, as I granted Google time to fix them. If no big sites write about this problem I will disclose with a working exploit on 6 November.

As you already looked at verifyPurchase(), the bug should be obvious. If given signature is an empty String the method still returns true (as it returns true on default).