After any exchange between the app and Google play to purchase some goods, 
the app must then forward this request to some external content-delivery 
server requesting that the purchased goods be delivered.

Obviously, there is no way to prevent the user from modifying the source 
code of their app from simply sending any arbitrary message -- such as a 
"purchase was successful" message to your server (obfuscation may slow down 
attackers, but isn't truly secure).

Therefore, the only way to be secure is if the "purchase successful" 
message has been digitally signed by Google play.  The only mention of this 
I found in the documentation is here:
http://developer.android.com/guide/google/play/billing/billing_integrate.html

where it says:  "*Your application must also provide a way to verify the 
signatures that accompany every PURCHASE_STATE_CHANGED broadcast intent. 
The Security.java file in the sample application shows you how to do this.*"

Now, if we look at the source code for Security.java (inside the Dungeons 
example they are referring to), then we find the "verifyPurchase" function, 
which contains this code:

/**
             * Compute your public key (that you got from the Android 
Market publisher site).
             *
             * Instead of just storing the entire literal string here 
embedded in the
             * program,  construct the key at runtime from pieces or
             * use bit manipulation (for example, XOR with some other 
string) to hide
             * the actual key.  The key itself is not secret information, 
but we don't
             * want to make it easy for an adversary to replace the public 
key with one
             * of their own and then fake messages from the server.
             *
             * Generally, encryption keys / passwords should only be kept 
in memory
             * long enough to perform the operation they need to perform.
             */
            String base64EncodedPublicKey = 
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqiPOV7jXSWomX32h9KYRfWXOLEbmakAQJhq5lq1j1tEC3Tz8qvO9RUAmaCKF1x51Wyc5zI4weX5N1Wix/RdpvAFPk4O5PmGcCpA78grFMPFLZtwI9R1cOtlOSwoRBMc2PDdGVWsLWyWoNhsnkOXMvfOk78daT0reFFFdMPmACzROcwcW/Dq+gkE4sTb2fgtLlYLOAy186PTHuES+j+532jbuOBFLLVw64UYjTcP29LdIVC/XBvqqiMdMLeDblvQyQVhoQcFvOwf0+k0ZJUdNcZcJXgQJC0fsMOaWu/aTzqm5fqQcboYDko/lG76+lNqS71wkWefKAzzkGHjyrZS6AwIDAQAB";
            PublicKey key = 
Security.generatePublicKey(base64EncodedPublicKey);
            verified = Security.verify(key, signedData, signature);
            if (!verified) {
                Log.w(TAG, "signature does not match data.");
                return null;
            }


Now, this seems odd to me...because they are using OUR OWN public key to 
verify the signature.  The Security.Verify would verify that the supplied 
public key had been signed with the corresponding PRIVATE key.  But Google 
Play does not have access to our private key...so how could they have 
signed it for us?  

Secondly, it does not make sense to do verification on the client side.  
The verification needs to be done by the content-delivery server, to verify 
that the message came from Google Play -- which means that Google should 
have signed it with THEIR private key.

Please help me understand how this makes any sense!

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to