libgdx / gdx-pay

A libGDX cross-platform API for InApp purchasing.
Apache License 2.0
224 stars 83 forks source link

Missing data signature in Google Billing #190

Closed compbatant closed 5 years ago

compbatant commented 5 years ago

Hi, Correct me if I am wrong but I think this line: transaction.setTransactionDataSignature(purchase.getSignature());

is missing in following method: PurchaseManagerGoogleBilling.handlePurchase()

MrStahlfelge commented 5 years ago

That's correct, the line is missing. There are some other issues for googleplay implementation unresolved, so that's apparently not the right place to look for a solution.

As I am not doing server-side verification, I don't know for sure if this line is needed or if there is even more information needed and every implementation would be a shot in the dark, so it is better if this is done by someone who really uses the feature.

compbatant commented 5 years ago

Only TransactionDataSignature and TransactionData is needed for purchase veryfication.

in PurchaseVerifierAndroidGoogle add this:

private PublicKey publicKey;

public void setPublicKey(String publicKeyString) {
       KeyFactory keyFactory = KeyFactory.getInstance("RSA");
       X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
       publicKey = keyFactory.generatePublic(publicKeySpec);
}

@Override
public boolean isValid (Transaction transaction) {
        return Security.verify(publicKey, transaction.getTransactionData(), getTransactionDataSignature());

}

And here is Security class:

import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.X509EncodedKeySpec;

public class Security {

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

    /**
     * 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 (SignatureException e) {

        } catch (Exception e) {
            //L.error(Security.class, "exception", e);
        }
        return false;
    }

}

I am using it and it is working. Replace Base64 in my Security class with Base64Util from com.badlogic.gdx.pay.server.util;

MrStahlfelge commented 5 years ago

Thank you. I've added the code, please also check it. It is published in the 0.12.0-SNAPSHOT.

MrStahlfelge commented 5 years ago

Closing because no reaction.