Android Question Google Play In-app signature verification

Discussion in 'Android Questions' started by peacemaker, Jun 19, 2015.

  1. peacemaker

    peacemaker Well-Known Member Licensed User

    HI, All
    In-app are cheated by Freedom or LuckyPatcher application. So each purchase must be checked, verified that really made on Google side. Google signs his reply.
    Please, help to make working module for this verification.

    I read http://www.b4x.com/android/forum/threads/inapp_purchase_data-and-inapp_data_signature.46545/ , googled a lot and made this sketch:
    No idea right or not way, please, suggest, i did not try yet.

    Code:
    'Code module
    'Subs in this code module will be accessible from all modules.
    Sub Process_Globals
        
    'These global variables will be declared once when the application starts.
        'These variables can be accessed from all modules.
        Private nativeMe As JavaObject
    End Sub


    'PublicKey = RSA public encription key like "MIIBIjANBgkqhkiG9w0BAQ....." from Google Play app API console
    Sub Verify (PublicKey As String, Product As Purchase)
    Dim OriginalJson, base64Signature As String

    Dim jo As JavaObject = Product
    base64Signature = jo.RunMethod(
    "getSignature"Null)
    OriginalJson = jo.RunMethod(
    "getOriginalJson"Null)

    nativeMe.InitializeContext
    Dim Params(3As String
    Params(
    0) = PublicKey    'RSA public encription key like "MIIBIjANBgkqhkiG9w0BAQ....." from Google Play app API console
    Params(1) = OriginalJson    'signedData
    Params(2) = base64Signature    'signature
    Dim result As Boolean = nativeMe.RunMethod("verify", Params)
    Log("result=" & result)
    End Sub

    #If JAVA
    public class Security {

        public final static Logger logger = Logger.getLogger(Security.class.getName());

        private static final String KEY_FACTORY_ALGORITHM = "RSA";
        private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";

        /**
         * Generates a PublicKey instance from a string containing the
         * Base64-encoded public key.
         *
         * @param encodedPublicKey
         *            Base64-encoded public key
         * @throws IllegalArgumentException
         *             if encodedPublicKey is invalid
         */
        public static PublicKey generatePublicKey(String encodedPublicKey) {
            try {
                byte[] decodedKey = Base64.decode(encodedPublicKey);
                KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
                return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
            }
            catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
            catch (InvalidKeySpecException e) {
                logger.error("Invalid key specification.", e);
                throw new IllegalArgumentException(e);
            }
            catch (Base64DecoderException e) {
                logger.error("Base64 decoding failed.", e);
                throw new IllegalArgumentException(e);
            }
        }

        /**
         * Verifies that the signature from the server matches the computed
         * signature on the data. Returns true if the data is correctly signed.
         *
         * @param publicKey
         *            public key associated with the developer account
         * @param signedData
         *            signed data from server
         * @param signature
         *            server signature
         * @return true if the data and signature match
         */
        public static boolean verify(PublicKey publicKey, String signedData, String signature) {
            Signature sig;
            try {
                sig = Signature.getInstance(SIGNATURE_ALGORITHM);
                sig.initVerify(publicKey);
                sig.update(signedData.getBytes());
                byte[] decodedSig = Base64.decode(signature);
                if (!sig.verify(decodedSig)) {
                    logger.error("Signature verification failed.");
                    return false;
                }
                return true;
            }
            catch (NoSuchAlgorithmException e) {
                logger.error("NoSuchAlgorithmException.");
            }
            catch (InvalidKeyException e) {
                logger.error("Invalid key specification.");
            }
            catch (SignatureException e) {
                logger.error("Signature exception.");
            }
            catch (Base64DecoderException e) {
                logger.error("Base64 decoding failed.");
            }
            return false;
        }

    }
    #End If
     
  2. peacemaker

    peacemaker Well-Known Member Licensed User

    During compilation try i got errors:
    1) Firstly
    Code:
    error: cannot find symbol
        
    public final static Logger logger = Logger.getLogger(Security.class.getName());
                            ^
      symbol:   class Logger
      
    location: class googleplaypurchaseguard.Security
    2) After commenting "logger" Java lines
    Code:
    error: cannot find symbol
        
    public static PublicKey generatePublicKey(String encodedPublicKey) {
                      ^
      symbol:   class PublicKey
      
    location: class googleplaypurchaseguard.Security
     
  3. DonManfred

    DonManfred Expert Licensed User

    I cannot see any "import" commands. You need to import the needed classes.
     
    lemonisdead likes this.
  4. peacemaker

    peacemaker Well-Known Member Licensed User

    Thanks for help !

    I have added these imports after googling:
    Code:
    import java.util.logging.Logger;
        import java.security.KeyFactory;
        import java.security.PrivateKey;
        import java.security.PublicKey;
        import java.security.spec.PKCS8EncodedKeySpec;
        import java.security.spec.RSAPublicKeySpec;
    import android.util.Base64;
    Now it is:
    Code:
    error: Illegal static declaration in inner class googleplaypurchaseguard.Security
        
    public final static Logger logger = Logger.getLogger(Security.class.getName());
                                   ^
      modifier 
    'static' is only allowed in constant variable declarations
    OK, removed "static".

    Now it is
    Code:
    cannot find symbol
                byte[] decodedKey = 
    Base64.decode(encodedPublicKey);
                                    ^
      symbol:   variable 
    Base64
    import android.util.Base64; has no "decode" with single argument...

    Code:
    cannot find symbol
            
    catch (Base64DecoderException e) {
                   ^
      symbol:   class Base64DecoderException
     
    Last edited: Jun 23, 2015
  5. peacemaker

    peacemaker Well-Known Member Licensed User

    Oh, f...ng sh.t Java...
    Seems here is better code, but it always gives error about "static" declaration or using non-static declaration in static context... or something...

    Code:
    #If JAVA
    import android.text.TextUtils;
    import android.util.Base64;
    import android.util.Log;

    import java.security.InvalidKeyException;
    import java.security.KeyFactory;
    import java.security.NoSuchAlgorithmException;
    import java.security.PublicKey;
    import java.security.Signature;
    import java.security.SignatureException;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.X509EncodedKeySpec;

    class Security {
        private static final String TAG = "IABUtil/Security";

        private static final String KEY_FACTORY_ALGORITHM = "RSA";
        private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";

        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);
        }

        public static PublicKey generatePublicKey(String encodedPublicKey) {
            try {
                byte[] decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT);
                KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
                return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            } catch (InvalidKeySpecException e) {
                Log.e(TAG, "Invalid key specification.");
                throw new IllegalArgumentException(e);
            } catch (IllegalArgumentException e) {
                Log.e(TAG, "Base64 decoding failed.");
                throw e;
            }
        }
        Public boolean verify(PublicKey publicKey, String signedData, String signature) {
            Signature sig;
            try {
                sig = Signature.getInstance(SIGNATURE_ALGORITHM);
                sig.initVerify(publicKey);
                sig.update(signedData.getBytes());
                if (!sig.verify(Base64.decode(signature, Base64.DEFAULT))) {
                    Log.e(TAG, "Signature verification failed.");
                    return false;
                }
                return true;
            } catch (NoSuchAlgorithmException e) {
                Log.e(TAG, "NoSuchAlgorithmException.");
            } catch (InvalidKeyException e) {
                Log.e(TAG, "Invalid key specification.");
            } catch (SignatureException e) {
                Log.e(TAG, "Signature exception.");
            } catch (IllegalArgumentException e) {
                Log.e(TAG, "Base64 decoding failed.");
            }
            return false;
        }
    }
    #End If
     
Loading...